The three virtues of a programmer: Laziness, Impatience, and Hubris. – Larry Wall

Legacy:ConfigMaster

From Unreal Wiki, The Unreal Engine Documentation Site

Jump to: navigation, search
UT2003 :: Object >> Actor >> Info >> Mutator >> ConfigMaster (ConfigManager)

This is a custom class, which is part of the ConfigManager for UT2003.

  1. //-----------------------------------------------------------
  2. // ConfigManager.ConfigMaster version 1.8
  3. // Allows for ServerActors & Mutators to add to PlayInfo
  4. //
  5. // The latest version of ConfigManager is always available at
  6. // http://www.organized-evolution.com/ConfigManager/
  7. //-----------------------------------------------------------
  8.  
  9. class ConfigMaster extends Mutator DependsOn(AutoLoader) config(ConfigMaster);
  10.  
  11. // If 2184 or earlier, crash the server
  12. var int                                         GameVersion;
  13.  
  14. // Contains previous values of modified IniEntries, unless there is already
  15. // a previous value for an IniEntry.  When a managed loader is de-activated,
  16. // the original value of the IniEntry is restored.
  17. var config array<AutoLoader.IniEntry>   OriginalValues;
  18.  
  19. // Holder for properties which aren't needed - used by loaders that get activated at the end of the match
  20. var array<Property>                     IrrelevantProperties;
  21.  
  22. struct SA
  23. {
  24.         var class<Info>                 SAClass;
  25.         var string                              SAName;
  26.         var string                              SADescription;
  27. };
  28.  
  29. struct AL
  30. {
  31.         var class<AutoLoader>   AutoLoaderClass;
  32.         var string                              AutoLoaderDesc;
  33. };
  34.  
  35. var array<SA>                           ManagedActors;          // Info about Loaders' ActorClasses
  36. var array<AL>                           LoaderClasses;          // All Loader Classes found
  37. var array<AutoLoader>           Loaders;                        // Active Loaders
  38. var array<string>                       ActiveMutators;         // Currently active mutator classes
  39. var bool                                        bInitialized;           // Initialization
  40. var bool                                        bHangRestart;           // Don't let server travel yet
  41.  
  42. var GameEngine                          GE;
  43.  
  44. const VERSION = 1.71;
  45. const LOGNAME = 'Config Manager';
  46. var const bool  DEBUG;
  47. var const bool  DEBUGPROPS;
  48.  
  49. // Localization
  50. var localized string LoadSuccess;
  51. var localized string RequiredVersion;
  52. var localized string UpgradeOrDie;
  53. var localized string RemovalCancelled;
  54.  
  55. // Errors
  56. var localized string InvalidLoaderClass;
  57. var localized string InvalidPI;
  58.  
  59. event PreBeginPlay()
  60. {
  61.         GameVersion = int(Level.EngineVersion);
  62.  
  63.         log(" -"@LOGNAME@VERSION@LoadSuccess,LOGNAME);
  64.         if (GameVersion < 2199)
  65.         {
  66.                 log(RequiredVersion@LOGNAME$".",LOGNAME);
  67.                 log(UpgradeOrDie,LOGNAME);
  68.                 log("",'ConfigManager');
  69.                 Assert(False);
  70.         }
  71.  
  72.         GetGameEngine();
  73. }
  74.  
  75. event PostBeginPlay()
  76. {
  77.         local int i;
  78.  
  79.         if (DEBUG)
  80.         {
  81.                 log(class@"Beginning initialization",'PostBeginPlay');
  82.                 log("START OF GAME SERVERACTORS",'PostBeginPlay');
  83.                 for (i = 0; i < GE.ServerActors.Length; i++)
  84.                         log("ServerActor["$i$"]:"$GE.ServerActors[i],'PostBeginPlay');
  85.  
  86.                 log("START OF GAME SERVERPACKAGES",'PostBeginPlay');
  87.                 for (i = 0; i < GE.ServerPackages.Length; i++)
  88.                         log("ServerPackages["$i$"]:"$GE.ServerPackages[i],'PostBeginPlay');
  89.  
  90.                 log("",'PostBeginPlay');
  91.         }
  92. //      Level.Game.AddMutator("ConfigManagerGUI.ConfigManagerGUIMaster");
  93.  
  94.         InitLoaders();
  95.         if (DEBUG)
  96.                 log(class@"finished loading all actors and loaders",'PostBeginPlay');
  97.  
  98.         Super.PostBeginPlay();
  99. }
  100.  
  101. // Sends a list of currently active mutators to all loader classes
  102. // Loader classes may want to check if its mutator was loaded without using the loader
  103. // (added at command line, etc.)
  104. function GetGameEngine()
  105. {
  106.         foreach AllObjects(class'Engine.GameEngine', GE)
  107.                 break;
  108. }
  109.  
  110. function AddMutator(Mutator M)
  111. {
  112.         local int i;
  113.  
  114.         for (i = 0; i < ActiveMutators.Length; i++)
  115.                 if (ActiveMutators[i] ~= string(M.Class))
  116.                         break;
  117.  
  118.         if (i == ActiveMutators.Length)
  119.                 ActiveMutators[ActiveMutators.Length] = string(M.Class);
  120.  
  121.         if (DEBUG)
  122.                 for (i = 0; i < ActiveMutators.Length; i++)
  123.                         log("ActiveMutators["$i$"]:"@ActiveMutators[i],'AddMutator');
  124.  
  125.         Super.AddMutator(M);
  126. }
  127.  
  128. // Do not show ConfigMaster in server browser as active mutator
  129. function GetServerDetails( out GameInfo.ServerResponseLine ServerState )
  130. {
  131. }
  132.  
  133. function InitLoaders()
  134. {
  135.         FindAllLoaders();
  136.         CreateLoaders();
  137. }
  138.  
  139. function FindAllLoaders()
  140. {
  141.         local int i, j;
  142.         local AL TempAL;
  143.         local SA TempSA;
  144.  
  145.         local class<AutoLoader> LoaderClass;
  146.         local class<Info>               ServerActorClass;
  147.         local string                    LoaderClassName, LoaderClassDescription,
  148.                                                         ActorClass, ServerActorName, ServerActorDesc;
  149.  
  150.         GetNextIntDesc("ConfigManager.AutoLoader",0,LoaderClassName,LoaderClassDescription);
  151.         while (LoaderClassName != "")
  152.         {
  153.                 // Hack to prevent Config Loader from being loaded
  154.                 if (LoaderClassName ~= "ConfigManagerLoader.SampleLoader")
  155.                 {
  156.                         GetNextIntDesc("ConfigManager.AutoLoader",++i,LoaderClassName,LoaderClassDescription);
  157.                         continue;
  158.                 }
  159.                 if (DEBUG)
  160.                         log("Found a new AutoLoader:"@LoaderClassName@LoaderClassDescription,'FindAllLoaders');
  161.  
  162.                 LoaderClass = class<AutoLoader>(DynamicLoadObject(LoaderClassName,Class'Class'));
  163.                 if (LoaderClass != None)
  164.                 {
  165.                         if (ShouldAddLoaderClass(LoaderClass))
  166.                         {
  167.                                 TempAL.AutoLoaderClass = LoaderClass;
  168.                                 TempAL.AutoLoaderDesc = LoaderClassDescription;
  169.                                 LoaderClasses[LoaderClasses.Length] = TempAL;
  170.                                 j = -1;
  171.                                 while (LoaderClass.static.AddManagedActor(j++, ActorClass, ServerActorName, ServerActorDesc))
  172.                                 {
  173.                                         if (ActorClass != "" && ServerActorName != "" && ServerActorDesc != "")
  174.                                         {
  175.                                                 ServerActorClass = class<Info>(DynamicLoadObject(ActorClass,class'Class'));
  176.                                                 if (ServerActorClass != None)
  177.                                                 {
  178.                                                         TempSA.SAClass = ServerActorClass;
  179.                                                         TempSA.SAName = ServerActorName;
  180.                                                         TempSA.SADescription = ServerActorDesc;
  181.  
  182.                                                         ManagedActors[ManagedActors.Length] = TempSA;
  183.                                                 }
  184.                                         }
  185.                                 }
  186.                         }
  187.                 }
  188.                 else Warn(InvalidLoaderClass@LoaderClassName);
  189.  
  190.                 GetNextIntDesc("ConfigManager.AutoLoader",++i, LoaderClassName, LoaderClassDescription);
  191.         }
  192.  
  193.         return;
  194. }
  195.  
  196. function bool ShouldAddLoaderClass(class<AutoLoader> NewClass)
  197. {
  198.         local int i;
  199.  
  200.         if (DEBUG)
  201.                 log("Loader Class"@NewClass,'ShouldAddLoaderClass');
  202.  
  203.         // Don't add if it's already in the list
  204.         for (i = 0;i < LoaderClasses.Length; i++)
  205.                 if (LoaderClasses[i].AutoLoaderClass == NewClass)
  206.                         return false;
  207.  
  208.         return true;
  209. }
  210.  
  211. function CreateLoaders()
  212. {
  213.         local int i;
  214.         local AutoLoader Loader;
  215.  
  216.         if (DEBUG)
  217.                 log("LoaderClasses"@LoaderClasses.Length,'CreateLoaders');
  218.  
  219.         for (i = 0;i<LoaderClasses.Length;i++)
  220.         {
  221.                 if (ShouldAddLoader(LoaderClasses[i].AutoLoaderClass))
  222.                 {
  223.                         Loader = AddLoader(LoaderClasses[i].AutoLoaderClass);
  224.                         if (Loader != None)
  225.                                 Loaders[Loaders.Length] = Loader;
  226.                 }
  227.         }
  228. }
  229.  
  230. function bool LoaderNotActive(class<AutoLoader> NewClass)
  231. {
  232.         local int i;
  233.  
  234.         for (i = 0; i < Loaders.Length; i++)
  235.                 if (Loaders[i].Class == NewClass)
  236.                         return false;
  237.  
  238.         return true;
  239. }
  240.  
  241. function bool ShouldAddLoader(class<AutoLoader> NewClass)
  242. {
  243.         local bool bShouldAdd;
  244.  
  245.         bShouldAdd = LoaderNotActive(NewClass) && GE != None;
  246.  
  247.         if (bShouldAdd)
  248.                 bShouldAdd = NewClass.static.CheckStrayActors(GE.GetPropertyText("ServerActors")) || NewClass.static.IsActive();
  249.  
  250.         bShouldAdd = bShouldAdd && NewClass.static.ValidateLoader();
  251.  
  252.         if (DEBUG)
  253.                 log(NewClass@"will be added:"$bShouldAdd,'ShouldAddLoader');
  254.  
  255.         return bShouldAdd;
  256. }
  257.  
  258. function AutoLoader AddLoader(class<AutoLoader> NewClass)
  259. {
  260.         local AutoLoader Loader;
  261.         if (NewClass == None) return None;
  262.  
  263.         Loader = Spawn(NewClass,Self);
  264.         if (Loader != None && GE != None)
  265.                 Loader.GE = GE;
  266.  
  267.         if (DEBUG)
  268.                 log("Returning"@Loader,'AddLoader');
  269.  
  270.         return Loader;
  271. }
  272.  
  273. // Make sure to remain as Game.BaseMutator.NextMutator so we will know about every mutator that is added.
  274. event Tick(float DeltaTime)
  275. {
  276.         local int i;
  277.  
  278.         if (bInitialized && Level != None && Level.NextURL != "")
  279.         {
  280.                 if (bHangRestart)
  281.                         Level.NextSwitchCountdown = 4.0;
  282.  
  283.                 else if (Loaders.Length > 0)
  284.                 {
  285.                         bHangRestart = True;
  286.                         SetTimer(0.2,False);
  287.                 }
  288.         }
  289.  
  290.         // Do not replace BaseMutator, or DMMutator will show up in server browser as an active mutator
  291.         if (Level != None && Level.Game != None && Level.Game.BaseMutator != None)
  292.         {
  293.                 if (Level.Game.BaseMutator.NextMutator != None)
  294.                 {
  295.                         if (Level.Game.BaseMutator.NextMutator != Self)
  296.                         {
  297.                         // Some other ConfigManager as BaseMutator.NextMutator, but it isn't me????
  298.                         // Maybe added ConfigManager as a serveractor?
  299.                         // Disable or server will crash
  300.                                 if (!bInitialized && Level.Game.BaseMutator.NextMutator.Class == Class)
  301.                                 {
  302.                                         Destroy();
  303.                                         return;
  304.                                 }
  305.  
  306.                                 // We have been replaced by another mutator wanting
  307.                                 // to be the first mutator.
  308.                                 if (Level.Game.BaseMutator.NextMutator.NextMutator == Self)
  309.                                 {
  310.                                         if (NextMutator != None)
  311.                                                 Level.Game.BaseMutator.NextMutator.NextMutator = NextMutator;
  312.                                         else Level.Game.BaseMutator.NextMutator.NextMutator = None;
  313.                                 }
  314.  
  315.                                 NextMutator = Level.Game.BaseMutator.NextMutator;
  316.                                 Level.Game.BaseMutator.NextMutator = Self;
  317.                         }
  318.                 }
  319.  
  320.                 else Level.Game.BaseMutator.NextMutator = Self;
  321.         }
  322.  
  323.         if (!bInitialized)
  324.         {
  325.                 for (i = 0; i < LoaderClasses.Length; i++)
  326.                 {
  327.                         if (LoaderNotActive(LoaderClasses[i].AutoLoaderClass) && LoaderClasses[i].AutoLoaderClass.static.CheckCurrentMutators(GetURLOption("Mutator")))
  328.                         {
  329.                                 if (DEBUG)
  330.                                         log("Adding previously non-active loader"@LoaderClasses[i].AutoLoaderClass,'Tick');
  331.                                 Loaders[Loaders.Length] = AddLoader(LoaderClasses[i].AutoLoaderClass);
  332.                         }
  333.                 }
  334.  
  335.                 bInitialized = True;
  336.         }
  337. }
  338.  
  339. event Timer()
  340. {
  341.         Super.Timer();
  342.         ApplyLoaderSettings();
  343. }
  344.  
  345. function array<Property> LoadProperties()
  346. {
  347.         local array<Property>   AllProperties;
  348.         local array<class>              RelevantActors;
  349.         local array<string>             RelevantPropNames;
  350.         local class                             RelevantClass;
  351.         local Property P;
  352.         local int i, j, k;
  353.  
  354.         // Build a array of properties which are relevant to the currently loaded loaders
  355.         // so that the amount of time it will take each loader to update their settings will
  356.         // be dramatically reduced -
  357.         // Typical number of Property objects in the game: 200,000
  358.         // Typical number of properties relevant to current loaders: 50
  359.  
  360.  
  361.         // Start by first getting a list of actors/objects which will be relevant
  362.  
  363.         // All ManagedActors are relevant (Loader's ActorClass)
  364.         for (i = 0; i < ManagedActors.Length; i++)
  365.         {
  366.                 for (j = 0; j < RelevantActors.Length; j++)
  367.                         if (RelevantActors[j] == ManagedActors[i].SAClass)
  368.                                 break;
  369.  
  370.                 if (j < RelevantActors.Length)
  371.                         continue;
  372.  
  373.                 RelevantActors[RelevantActors.Length] = ManagedActors[i].SAClass;
  374.         }
  375.  
  376.         if (DEBUG)
  377.                 log("Loaders"@LoaderClasses.Length,'LoadProperties');
  378.  
  379.         for (i = 0; i < LoaderClasses.Length; i++)
  380.         {
  381.                 // If ActorClass was already added to list, skip it
  382.                 for (j = 0; j < RelevantActors.Length; j++)
  383.                         if (string(RelevantActors[j]) ~= LoaderClasses[i].AutoLoaderClass.default.ActorClass)
  384.                                 break;
  385.  
  386.                 if (j == RelevantActors.Length)
  387.                 {
  388.                         if (LoaderClasses[i].AutoLoaderClass.default.ActorClass != "")
  389.                                 RelevantClass = class(DynamicLoadObject(LoaderClasses[i].AutoLoaderClass.default.ActorClass,class'Class'));
  390.  
  391.                         if (RelevantClass != None)
  392.                                 RelevantActors[RelevantActors.Length] = RelevantClass;
  393.                 }
  394.  
  395.                 // Begin building a list of property names to mark as relevant
  396.                 // We'll match these names to the Property.Name variable later when we iterate AllObjects for class'Property'
  397.                 for (j = 0; j < LoaderClasses[i].AutoLoaderClass.default.RequiredIniEntries.Length; j++)
  398.                 {
  399.  
  400.                         for (k = 0; k < RelevantPropNames.Length; k++)
  401.                         {
  402.                                 if (RelevantPropNames[k] == LoaderClasses[i].AutoLoaderClass.default.RequiredIniEntries[j].PropName)
  403.                                         break;
  404.                         }
  405.  
  406.                         if ( k == RelevantPropNames.Length )
  407.                         {
  408.                                 RelevantPropNames[RelevantPropNames.Length] = LoaderClasses[i].AutoLoaderClass.default.RequiredIniEntries[j].PropName;
  409.                                 if (DEBUGPROPS)
  410.                                         log("Added new Relevant Property Name:"$RelevantPropNames[k],'LoadProperties');
  411.                         }
  412.  
  413.                         RelevantClass = class(DynamicLoadObject(LoaderClasses[i].AutoLoaderClass.default.RequiredIniEntries[j].ClassFrom,Class'class',True));
  414.                         if (RelevantClass == None) continue;
  415.  
  416.                         // Find out if this entry's associated class is already in the relevant actors list
  417.                         // If not, add it
  418.                         for (k = 0; k < RelevantActors.Length; k++)
  419.                         {
  420.                                 if (DEBUGPROPS)
  421.                                         log("Compare"@LoaderClasses[i].AutoLoaderClass.default.RequiredIniEntries[j].ClassFrom@"to Relevant Actor"@k$":"@RelevantActors[k],'LoadProperties');
  422.  
  423.                                 if (RelevantActors[k] == RelevantClass)
  424.                                         break;
  425.                         }
  426.                         if (DEBUGPROPS)
  427.                                 log("Breaking on"@k$", Total Relevant Actors:"@RelevantActors.Length,'LoadProperties');
  428.  
  429.                         if (k < RelevantActors.Length)
  430.                                 continue;
  431.  
  432.                         RelevantActors[RelevantActors.Length] = RelevantClass;
  433.                         if (DEBUGPROPS)
  434.                                 log("Added new relevant actor:"$LoaderClasses[i].AutoLoaderClass.default.RequiredIniEntries[j].ClassFrom,'LoadProperties');
  435.                 }
  436.         }
  437.  
  438.         // Finished building relevant actors and relevant names
  439.         // Iterate AllObjects, looking for Property objects
  440.         foreach AllObjects(class'Property', P)
  441.         {
  442.                 RelevantClass = None;
  443.                 // Some property types should be skipped
  444.                 if ( ValidProp(P) )
  445.                 {
  446.                         if (Class(P.Outer) != None) RelevantClass = Class(P.Outer);
  447.                         if (RelevantClass != None)
  448.                         {
  449.                                 for (i = 0; i < RelevantActors.Length; i++)
  450.                                 {
  451.                                         // The Outer variable for properties is the class that the property is contained in
  452.                                         // If this property's Outer is an object that is relevant, add it to the list
  453.                                         if (RelevantClass == RelevantActors[i])
  454.                                         {
  455.                                                 for (j = 0; j < RelevantPropNames.Length; j++)
  456.                                                         if (RelevantPropNames[j] == string(P.Name))
  457.                                                         {
  458.                                                                 if (DEBUGPROPS)
  459.                                                                         log("Adding Initial Relevant Property:"$P.Outer$"."$P.Name,'LoadProperties');
  460.                                                                 AllProperties[AllProperties.Length] = P;
  461.                                                                 break;
  462.                                                         }
  463.  
  464.                                                 if (j < RelevantPropNames.Length)
  465.                                                         break;
  466.                                         }
  467.                                 }
  468.                         }
  469.  
  470.                         // OK, this property's Outer wasn't relevant
  471.                         // Check the property against the relevant name list
  472.                         if (i == RelevantActors.Length)
  473.                         {
  474.                                 for (i = 0; i < RelevantPropNames.Length; i++)
  475.                                 {
  476.                                 // If we find a match, then we should check the relevant objects list again,
  477.                                 // in case the relevant object is a superclass of the property's Outer
  478.                                         if (RelevantPropNames[i] == string(P.Name))
  479.                                         {
  480.                                                 if (DEBUGPROPS)
  481.                                                         log("Compare Property:"@i@RelevantPropNames[i]@"to"@string(P.Name),'LoadProperties');
  482.  
  483.                                                 for (j = 0; j < RelevantActors.Length; j ++)
  484.                                                 {
  485.                                                         if (RelevantClass == None) continue;
  486.  
  487.                                                         if (DEBUGPROPS)
  488.                                                                 log("Relevant Actor Check:"@j@RelevantActors[j]@"is child of"@class(P.Outer)@":"$ClassIsChildOf(RelevantActors[j],Class(P.Outer)),'LoadProperties');
  489.  
  490.                                                         if (ClassIsChildOf(RelevantActors[j], RelevantClass))
  491.                                                         {
  492.                                                                 if (DEBUGPROPS)
  493.                                                                         log("Adding Additional Relevant Property:"$P.Outer$"."$P.Name,'LoadProperties');
  494.  
  495.                                                                 AllProperties[AllProperties.Length] = P;
  496.                                                                 break;
  497.                                                         }
  498.                                                 }
  499.  
  500.                                                 if (j < RelevantActors.Length)
  501.                                                         break;
  502.                                         }
  503.                                 }
  504.                         }
  505.                 }
  506.         }
  507.  
  508.         return AllProperties;
  509. }
  510.  
  511. // Update Properties array with newly loaded loaders
  512. // No longer used
  513. function CheckRelevantProperties(AutoLoader L, out array<Property> Props)
  514. {
  515.         local int i, j;
  516.         local array<class> Classes, Outers;
  517.  
  518.         local class TempClass;
  519.         local Property P;
  520.  
  521.         if (DEBUGPROPS) log("Checking relevant properties for new loader"@L,'CheckRelevantProperties');
  522.  
  523.         for (i = 0; i < Props.Length; i++)
  524.         {
  525.                 TempClass = Class(Props[i].Outer);
  526.                 if (TempClass == None) continue;
  527.  
  528.                 for (j = 0; j < Outers.Length; j++)
  529.                         if (TempClass == Outers[j])
  530.                                 break;
  531.  
  532.                 if (j < Outers.Length) continue;
  533.  
  534.                 Outers[Outers.Length] = TempClass;
  535.         }
  536.  
  537.         if (L.bIncludeServerActor && L.ActorClass != "")
  538.         {
  539.                 if (DEBUGPROPS) log("Checking for existence of"@L.ActorClass@"properties",'CheckRelevantProperties');
  540.  
  541.                 TempClass = class(DynamicLoadObject(L.ActorClass,class'Class',True));
  542.                 if (TempClass != None)
  543.                 {
  544.                         for (i = 0; i < Outers.Length; i++)
  545.                                 if (TempClass == Outers[i])
  546.                                         break;
  547.  
  548.                         if (i == Outers.Length)
  549.                                 Classes[Classes.Length] = TempClass;
  550.  
  551.                         else if (DEBUGPROPS)
  552.                                 log(TempClass@"has already been added to the properties array.",'CheckRelevantProperties');
  553.                 }
  554.         }
  555.  
  556.         for (i = 0; i < L.RequiredIniEntries.Length; i++)
  557.         {
  558.                 if (DEBUGPROPS) log("Checking for existence of relevant class"@L.RequiredIniEntries[i].ClassFrom,'CheckRelevantProperties');
  559.  
  560.                 TempClass = class(DynamicLoadObject(L.RequiredIniEntries[i].ClassFrom,class'Class',True));
  561.                 if (TempClass != None)
  562.                 {
  563.                         for (j = 0; j < Classes.Length; j++)
  564.                                 if (Classes[j] == TempClass) break;
  565.  
  566.                         if (j < Classes.Length) continue;
  567.  
  568.                         for (j = 0; j < Outers.Length; j++)
  569.                                 if (Outers[j] == TempClass) break;
  570.  
  571.                         if (j < Outers.Length) continue;
  572.  
  573.                         Classes[Classes.Length] = TempClass;
  574.                 }
  575.                 else if (DEBUGPROPS)
  576.                         log("Could not load RequiredIniEntry["$i$"].ClassFrom:"@L.RequiredIniEntries[i].ClassFrom,'CheckRelevantProperties');
  577.         }
  578.  
  579.         if (DEBUGPROPS && Classes.Length == 0)
  580.                 log("All relevant classes from this loader already existed in properties array",'CheckRelevantProperties');
  581.  
  582.         for (i = 0; i < Classes.Length; i++)
  583.         {
  584.                 if (DEBUGPROPS)
  585.                 {
  586.                         log("");
  587.                         log("Adding properties from class"@Classes[i]@"to properties array.",'CheckRelevantProperties');
  588.                 }
  589.  
  590.                 for (j = 0; j < IrrelevantProperties.Length; j++)
  591.                 {
  592.                         P = IrrelevantProperties[j];
  593.                         TempClass = Class(P.Outer);
  594.  
  595.                         if (TempClass == None || TempClass != Classes[i]) continue;
  596.  
  597.                         if (DEBUGPROPS) log("    Adding property"@P.Name,'CheckRelevantProperties');
  598.  
  599.                         Props[Props.Length] = P;
  600.                         IrrelevantProperties.Remove(j--, 1);
  601.                 }
  602.         }
  603. }
  604.  
  605. // TODO: Add support for structs
  606. final function bool ValidProp(Property P)
  607. {
  608.         return P.Class != class'ObjectProperty' &&
  609.                    P.Class != class'DelegateProperty' &&
  610.                    P.Class != class'PointerProperty' &&
  611.                    P.Class != class'MapProperty' &&
  612.                    P.Class != class'StructProperty';
  613. }
  614.  
  615. // Fills PlayInfo for ServerActors
  616. final function CallManagedActorPlayInfo(PlayInfo PI)
  617. {
  618.         local int i, j;
  619.  
  620.         for (i = 0; i < LoaderClasses.Length; i++)
  621.         {
  622.                 if (DEBUG)
  623.                         log("Checking for LoaderClass"@i@"in playinfo:"$loaderclasses[i].autoloaderclass,'ManagedActorFillPlayInfo');
  624.  
  625.                 if (NotInPlayInfo(PI,LoaderClasses[i].AutoLoaderClass))
  626.                 {
  627.                         if (DEBUG)
  628.                                 log("Calling FillPlayInfo() for LoaderClass"@i$":"$loaderclasses[i].autoloaderclass,'ManagedActorFillPlayInfo');
  629.  
  630.                         LoaderClasses[i].AutoLoaderClass.static.FillPlayInfo(PI);
  631.                         PI.PopClass();
  632.                 }
  633.  
  634.                 for (j = 0; j < ManagedActors.Length; j++)
  635.                 {
  636.                         if (LoaderClasses[i].AutoLoaderClass.default.ActorClass != string(ManagedActors[j].SAClass))
  637.                                 continue;
  638.  
  639.                         if (DEBUG)
  640.                                 log("Checking for ManagedActor"@j@"in playinfo:"$ManagedActors[j].SAClass,'ManagedActorFillPlayInfo');
  641.  
  642.                         if (LoaderClasses[i].AutoLoaderClass.static.IsActive())
  643.                         {
  644.                                 ManagedActors[j].SAClass.static.FillPlayInfo(PI);
  645.                                 PI.PopClass();
  646.                         }
  647.                 }
  648.         }
  649. }
  650.  
  651. // Only webadmin calls Mutator.MutatorFillPlayInfo()?
  652. function MutatorFillPlayInfo(PlayInfo PI)
  653. {
  654.         if (