AutoLoader
Here's an /example on how to use this class
00001 //----------------------------------------------------------- 00002 // ConfigManager.AutoLoader 00003 // 00004 // This class has two functions: 00005 // 1. Perform all required ini changes needed for your mod. Will also UNDO 00006 // any changes made to the ini if your mod is deactivated. 00007 // Additional benefit of auto-installation of your mutator on a dedicated 00008 // server (to enable set bEnableMyLoader=True in defaultproperties) 00009 // 00010 // 2. Pass FillPlayInfo() calls to mutators which are not part of the game's 00011 // mutator list (such as mutators which only require ServerActors= lines in ini) 00012 // 00013 //----------------------------------------------------------- 00014 class AutoLoader extends Info 00015 abstract; 00016 00017 // Quick note about debugging - By setting DEBUG=True in defaultproperties of your 00018 // AutoLoader subclass when compiling, you can receive large amounts of debug data. 00019 // However, you will quickly encounter the 1024 byte limit if you use ucc.exe to 00020 // start the testing server. By starting a server using the "ut2003 -server" command, 00021 // you will bypass this limit, since ut2003.exe does not have these limitations. 00022 00023 var const bool DEBUG; 00024 var const bool DEBUGPROPS; 00025 00026 var ConfigMaster Manager; // Pointer to ConfigMaster mutator 00027 var string InteractionClass; // Not yet implemented 00028 00029 //======================================= 00030 // Loading ServerActors 00031 //======================================= 00032 // Pointer to GameEngine 00033 var GameEngine GE; 00034 00035 // This loader includes a server-side only mutator or server actor 00036 // that will not be part of the mutator chain (will receive FillPlayInfo() calls) 00037 var() bool bIncludeServerActor; 00038 00039 // Classname of the ServerActor this loader loads 00040 // Same value as what would otherwise be your mod's 00041 // ServerActors= line in the .ini file. 00042 var() string ActorClass; 00043 00044 // Friendly Name of the Server Actor class 00045 // Used by webadmin/adminmenu as the name of the server actor 00046 var() localized string FriendlyName; 00047 var() localized string ActorDescription; 00048 00049 // Lock this loader to a certain version (or higher) of your mod 00050 var() string RequiredVersion; // Required version of actor 00051 var() localized string VersionWarning; // Message to write to server log if version not enough 00052 var() localized string DownloadMsg; // Message to write to log 00053 00054 //======================================= 00055 // Automatic configuration changes 00056 //======================================= 00057 // A single ini change 00058 struct IniEntry 00059 { 00060 var() string ClassFrom; // Class which contains the setting we want to change 00061 var() string PropName; // Name of the variable we're trying to change 00062 var() string PropValue; // Value to apply 00063 }; 00064 00065 // Array of ini settings required by this mod 00066 var() array<IniEntry> RequiredIniEntries; 00067 var array<Property> Properties; 00068 00069 00070 //################################################################### 00071 //################################################################### 00072 // 00073 // Public methods - should be subclassed to customize loader's response 00074 00075 // if return true, loader class will be spawned 00076 static function bool IsActive() 00077 { 00078 return false; 00079 } 00080 00081 // should be subclassed - set loader to active/will be included next match 00082 static function bool EnableLoader(optional string SpecialActor) 00083 { 00084 return false; 00085 } 00086 00087 // should be subclassed 00088 static function bool DisableLoader(optional string SpecialActor) 00089 { 00090 return true; 00091 } 00092 00093 // called on all loader classes - used to activate loader based on active mutators 00094 static function bool CheckCurrentMutators(string URL) 00095 { 00096 return false; 00097 } 00098 00099 // called on all loader classes which have bIncludeServerActor=True - used to activate loader based on manual ServerActor entry 00100 static function bool CheckStrayActors(string ServerActors) 00101 { 00102 local int i; 00103 local bool bAddMe; 00104 00105 if (default.bIncludeServerActor) 00106 if (InStr(ServerActors,default.ActorClass) != -1) 00107 bAddMe = EnableLoader(); 00108 00109 for (i = 0; i < default.RequiredIniEntries.Length; i++) 00110 if (!bAddMe && default.RequiredIniEntries[i].ClassFrom ~= "Engine.GameEngine" && default.RequiredIniEntries[i].PropName ~= "ServerActors") 00111 if (InStr(ServerActors,default.RequiredIniEntries[i].PropValue) != -1) 00112 bAddMe = EnableLoader(); 00113 00114 if (default.DEBUG) 00115 { 00116 log(default.Class@"Received string value:"$ServerActors,'CheckStrayActors'); 00117 log(default.Class@"Returning"@bAddMe,'CheckStrayActors'); 00118 } 00119 return bAddMe; 00120 } 00121 00122 // Only managed actors can be added to Ladder profiles 00123 // Normally, only the ActorClass of your loader (if bIncludeServerActor=True) would be need to be managed 00124 static function array<string> GetManagedActors() 00125 { 00126 local int i; 00127 local string A, B, C; 00128 local array<string> ABC; 00129 00130 i = -1; 00131 while (static.AddManagedActor(i++,A,B,C)) 00132 ABC[ABC.Length] = A$","$B$","$C; 00133 00134 return ABC; 00135 } 00136 00137 // Managed actors will be passed FillPlayInfo() calls 00138 static function bool AddManagedActor(int Idx, out string ActorClassName, out string ActorName, out string ActorDesc) 00139 { 00140 if (Idx == -1 && default.bIncludeServerActor) 00141 { 00142 ActorClassName = default.ActorClass; 00143 ActorName = default.FriendlyName; 00144 ActorDesc = default.ActorDescription; 00145 return true; 00146 } 00147 00148 return false; 00149 } 00150 00151 // Optional hook for version filtering 00152 static function bool MatchesVersion(float ActorVersion, optional bool bExact, optional string NewURL) 00153 { 00154 local float CurrentVersion; 00155 local string LogText; 00156 00157 if (default.RequiredVersion == "") 00158 return true; 00159 00160 CurrentVersion = float(default.RequiredVersion); 00161 00162 // Return false if loader version is higher than actor version 00163 // Return false if loader version is lower than actor version and bExact=True 00164 if ((ActorVersion < CurrentVersion) || (ActorVersion > CurrentVersion && bExact)) 00165 { 00166 if (default.VersionWarning != "") 00167 { 00168 LogText = static.ReplaceTag(default.VersionWarning,"%CurVer%",CurrentVersion); 00169 LogText = static.ReplaceTag(LogText,"%ReqVer%",ActorVersion); 00170 log(LogText); 00171 } 00172 00173 if (NewURL != "") 00174 log(static.ReplaceTag(default.DownloadMsg,"%URL%",NewURL)); 00175 00176 return false; 00177 } 00178 00179 return true; 00180 } 00181 00182 // To prevent your loader from causing a server crash, add your checks here 00183 // return false to prevent your loader from being loaded 00184 00185 // You only need to override this function if bIncludeServerActor=False in your loader, 00186 // or if you have RequiredIniChanges that reference additional custom packages 00187 static function bool ValidateLoader() 00188 { 00189 local class<Info> MyActor; 00190 00191 if (default.bIncludeServerActor && default.ActorClass != "") 00192 { 00193 // Specify True for 3rd param in DynamicLoadObject to prevent log spam if MyActor isn't on server 00194 MyActor = class<Info>(DynamicLoadObject(default.ActorClass,class'Class',True)); 00195 if (MyActor == None) 00196 return false; 00197 } 00198 00199 return true; 00200 } 00201 00202 // Hook for loader to cancel external removal request, or effect any specialized ini changes to make before removal 00203 function bool AcceptRemoval(optional array<Property> Props) 00204 { 00205 if (Props.Length > 0) 00206 Properties = Props; 00207 00208 RemoveMe(); 00209 return true; 00210 } 00211 00212 // should be subclassed 00213 // always use "return !bEnableMyLoader;" 00214 // see LadderLoader.LadderLoader or TeamBalanceLoader.BalanceLoader for examples 00215 function bool WantsToBeDisabled() 00216 { 00217 return false; 00218 } 00219 00220 // called for each RequiredIniEntry 00221 // return true to apply the RequiredIniEntry.PropValue 00222 function bool ObjectNeedsUpdate(Object O, string PropName, string PropValue) 00223 { 00224 local string Temp; 00225 00226 Temp = O.GetPropertyText(PropName); 00227 if ( InStr(Caps(Temp),Caps(PropValue)) < 0 ) 00228 return true; 00229 00230 return false; 00231 } 00232 00233 // notification of pending update - return false to skip update for loader 00234 function bool ApplyUpdate() 00235 { 00236 if (DEBUG) log(class@"Returning"@IsActive(),'ApplyUpdate'); 00237 return IsActive(); 00238 } 00239 00240 // return -1 if want to simply add entry 00241 // return index of array entry if want to overwrite 00242 function int CheckArrayEntry(string PropName, array<string> PropArray) 00243 { 00244 return -1; 00245 } 00246 00247 // To maintain consistency, always add to "Server Actors" page 00248 // static function FillPlayInfo(PlayInfo PI) 00249 // { 00250 // Super.FillPlayInfo(PI); 00251 // PI.AddSetting("ServerActors",.... 00252 // } 00253 // 00254 //################################################################### 00255 //################################################################### 00256 // 00257 // Public Final Methods 00258 // These are used to operate the internal mechanisms of the auto loader system. 00259 // 00260 // 00261 00262 // Called by ConfigMaster when Level.ServerTravel is called 00263 00264 // Removes loader if WantsToBeDisabled() returns True 00265 // Applies value for RequiredIniProperties if ObjectNeedsUpdate returns true 00266 final function UpdateConfiguration(array<Property> Props) 00267 { 00268 local Object O; 00269 local Property P; 00270 00271 local string N,V; 00272 local int i, j; 00273 00274 local array<string> Arr; 00275 local string ArrS; 00276 00277 if (DEBUG) 00278 log("Update configuration in"@class,'UpdateConfiguration'); 00279 00280 ResetConfig(); 00281 Properties = Props; 00282 00283 if (WantsToBeDisabled()) 00284 { 00285 RemoveMe(); 00286 return; 00287 } 00288 00289 if (bIncludeServerActor && ActorClass != "") 00290 { 00291 O = GetObjectOfClass(class'Engine.GameEngine'); 00292 if (O != None) 00293 { 00294 if (ObjectNeedsUpdate(O, "ServerActors", ActorClass)) 00295 { 00296 ArrS = O.GetPropertyText("ServerActors"); 00297 if (ArrS != "") 00298 Arr = GenerateArray(ArrS); 00299 00300 j = -1; 00301 if (Arr.Length > 0) 00302 j = CheckArrayEntry("ServerActors", Arr); 00303 00304 if (j < 0) 00305 O.SetPropertyText("ServerActors",AddDynArrayMember(O,"ServerActors",ActorClass)); 00306 00307 else O.SetPropertyText("ServerActors",InsertArrayMember(O, "ServerActors", ActorClass, j)); 00308 O.SaveConfig(); 00309 } 00310 } 00311 } 00312 00313 for (i = 0;i<RequiredIniEntries.Length;i++) 00314 { 00315 O = GetObjectForEntry(RequiredIniEntries[i]); 00316 if (O == None) continue; 00317 00318 if (!ObjectNeedsUpdate(O, RequiredIniEntries[i].PropName, RequiredIniEntries[i].PropValue)) continue; 00319 00320 N = RequiredIniEntries[i].PropName; 00321 V = RequiredIniEntries[i].PropValue; 00322 P = GetProperty(O, N); 00323 if (DEBUG) 00324 log(class@"got property"@p,'UpdateConfiguration'); 00325 00326 if (P == None) continue; 00327 00328 j = -1; 00329 00330 if (PropIsArray(P)) 00331 { 00332 ArrS = O.GetPropertyText(N); 00333 if (ArrS != "") 00334 Arr = GenerateArray(ArrS); 00335 00336 if (Arr.Length > 0) 00337 j = CheckArrayEntry(N, Arr); 00338 00339 if (j < 0) 00340 O.SetPropertyText(N,AddDynArrayMember(O,N,V)); 00341 00342 else O.SetPropertyText(N,InsertArrayMember(O, N, V, j)); 00343 } 00344 00345 else 00346 { 00347 StoreDefaultValue(O, N); 00348 O.SetPropertyText(N,V); 00349 } 00350 00351 O.SaveConfig(); 00352 } 00353 } 00354 00355 // Regarding OriginalValues 00356 final function StoreDefaultValue(Object O, string PropName) 00357 { 00358 local int i, idx; 00359 local IniEntry NewDefault; 00360 local string CurrentValue, Quote; 00361 local array<string> Ar; 00362 00363 if (DEBUG) 00364 log(class@"storing default"@o@propname,'StoreDefaultValue'); 00365 00366 for (i = 0; i < ConfigMaster(Owner).OriginalValues.Length; i++) 00367 if (ConfigMaster(Owner).OriginalValues[i].ClassFrom == string(O.Class) && ConfigMaster(Owner).OriginalValues[i].PropName == PropName) 00368 return; 00369 00370 NewDefault.ClassFrom = string(O.Class); 00371 // Check if this property name is a single array member 00372 i = -1; idx = -1; 00373 i = InStr(PropName, "§"); 00374 if (i != -1) 00375 { 00376 idx = int(Left(PropName, i)); 00377 PropName = Mid(PropName, i + 1); 00378 CurrentValue = O.GetPropertyText(PropName); 00379 Ar = GenerateArray(CurrentValue); 00380 CurrentValue = Ar[idx]; 00381 00382 // Remove literal string wrapper 00383 if (Left(CurrentValue,1) == "\"") 00384 { 00385 CurrentValue = Mid(CurrentValue,1,Len(CurrentValue) - 2); 00386 Quote = "¶"; 00387 } 00388 CurrentValue = idx $ "§" $ CurrentValue $ Quote; 00389 } 00390 00391 else CurrentValue = O.GetPropertyText(PropName); 00392 00393 NewDefault.PropName = PropName; 00394 NewDefault.PropValue = CurrentValue; 00395 if (DEBUG) 00396 log(class@"old value:"@NewDefault.PropValue,'StoreDefaultValue'); 00397 00398 ConfigMaster(Owner).OriginalValues[ConfigMaster(Owner).OriginalValues.Length] = NewDefault; 00399 ConfigMaster(Owner).SaveConfig(); 00400 } 00401 00402 final function bool RestoreOriginalValue(Object O, string PropName) 00403 { 00404 local int i, j, idx; 00405 local string CurrentValue, StoredValue; 00406 local array<string> Ar; 00407 00408 for (i = 0; i < ConfigMaster(Owner).OriginalValues.Length; i++) 00409 { 00410 if (ConfigMaster(Owner).OriginalValues[i].ClassFrom ~= string(O.Class) && ConfigMaster(Owner).OriginalValues[i].PropName ~= PropName) 00411 { 00412 StoredValue = ConfigMaster(Owner).OriginalValues[i].PropValue; 00413 // First check if this was a single array member 00414 j = InStr(StoredValue, "§"); 00415 if (j != -1) 00416 { 00417 idx = int(Left(StoredValue, j)); 00418 StoredValue = Mid(StoredValue, j + 1); 00419 if (Right(StoredValue, 1) == "¶") 00420 { 00421 StoredValue = Left(StoredValue, Len(StoredValue) - 1); 00422 StoredValue = "\"" $ StoredValue $ "\""; 00423 } 00424 CurrentValue = O.GetPropertyText(PropName); 00425 Ar = GenerateArray(CurrentValue); 00426 Ar[idx] = StoredValue; 00427 StoredValue = "(" $ Join(Ar,",",True) $")"; 00428 } 00429 00430 if (DEBUG) 00431 log(class@"Assigning"@StoredValue@"to property"@string(O.Class)$"."$PropName,'RestoreOriginalValue'); 00432 O.SetPropertyText(PropName, StoredValue); 00433 O.SaveConfig(); 00434 break; 00435 } 00436 } 00437 00438 if (i < ConfigMaster(Owner).OriginalValues.Length) 00439 { 00440 ConfigMaster(Owner).OriginalValues.Remove(i, 1); 00441 ConfigMaster(Owner).SaveConfig(); 00442 return true; 00443 } 00444 00445 return false; 00446 } 00447 00448 //################################################################### 00449 //################################################################### 00450 // 00451 // Internal Methods 00452 // These are used to control the internal operation of the loader itself. 00453 // These methods may only be called by other methods within the loader. 00454 // 00455 00456 protected final function RemoveMe() 00457 { 00458 local int i; 00459 local Object O; 00460 local Property P; 00461 00462 if (DEBUG) 00463 log(class@"being removed.",'RemoveMe'); 00464 00465 if (bIncludeServerActor && ActorClass != "") 00466 { 00467 O = GetObjectOfClass(class'Engine.GameEngine'); 00468 if (O != None) 00469 RemoveArrayEntry(O, "ServerActors", ActorClass); 00470 } 00471 00472 for (i = 0; i < RequiredIniEntries.Length; i++) 00473 { 00474 O = GetObjectForEntry(RequiredIniEntries[i]); 00475 if (O == None) continue; 00476 00477 P = GetProperty(O,RequiredIniEntries[i].PropName); 00478 if (P != None && PropIsArray(P)) 00479 RemoveArrayEntry(O,RequiredIniEntries[i].PropName,RequiredIniEntries[i].PropValue); 00480 00481 else RestoreOriginalValue(O, RequiredIniEntries[i].PropName); 00482 } 00483 00484 DisableLoader(); 00485 } 00486 00487 protected final function string InsertArrayMember(Object Obj, string PropName, string NewValue, int Pos) 00488 { 00489 local string CurValue, Quote, Tmp; 00490 local array<string> Members; 00491 local bool bStatic; 00492 00493 if (Obj == None) 00494 { 00495 Warn("Object is None"); 00496 return ""; 00497 } 00498 00499 CurValue = Obj.GetPropertyText(PropName); 00500 Members = GenerateArray(CurValue); 00501 00502 if (DEBUG) 00503 { 00504 log(class$":Inserting new member at position"@Pos@"to"@Obj$"."$PropName$":"@NewValue,'InsertArrayMember'); 00505 log(class$":Current Value:"$CurValue,'InsertArrayMember'); 00506 } 00507 00508 // Check for literal string 00509 if (InStr(Caps(CurValue), Caps(NewValue)) < 0 && Members.Length > 0) 00510 { 00511 bStatic = Left(Members[pos], Len(PropName) + 1) ~= (PropName $ "["); 00512 Tmp = StringIf(bStatic, Mid(Members[pos],InStr(Members[pos],"=") + 1), Members[0]); 00513 Quote = StringIf(Left(Tmp,1) == "\"" && Left(NewValue,1) != "\"","\"",""); 00514 00515 NewValue = StringIf(bStatic, PropName $ "=" $ Quote $ NewValue $ Quote, Quote $ NewValue $ Quote); 00516 if (DEBUG) 00517 log(InStr(Caps(CurValue),Caps(NewValue))@InStr(Caps(CurValue),Caps(NewValue))<0@Caps(CurValue)@"||"@Caps(NewValue),'AddDynArrayMember'); 00518 00519 if (NewValue != "" && Pos > -1) 00520 { 00521 StoreDefaultValue(Obj, Pos$"§"$PropName); 00522 Members[Pos] = NewValue; 00523 } 00524 00525 CurValue = "(" $ Join(Members,",",True) $ ")"; 00526 } 00527 00528 if (DEBUG) 00529 { 00530 log(class@"Returning:"$CurValue,'InsertArrayMember'); 00531 log(class@"",'InsertArrayMember'); 00532 } 00533 00534 return CurValue; 00535 } 00536 00537 // Currently, UT2003 does not support setting static arrays through the use of SetPropertyText 00538 protected final function string AddStaticArrayMember(Object Obj, string PropName, string NewValue) 00539 { 00540 local int i; 00541 local array<string> Members; 00542 local string Quote, TempValue, CurValue; 00543 00544 if (Obj == None) 00545 { 00546 Warn("Object was None for property"@PropName); 00547 return ""; 00548 } 00549 00550 CurValue = Obj.GetPropertyText(PropName); 00551 Members = GenerateArray(CurValue); 00552 00553 if (InStr(Caps(CurValue), Caps(NewValue)) < 0) 00554 { 00555 if (Members.Length > 0) 00556 { 00557 TempValue = Mid(Members[0],InStr(Members[0],"=")+1); 00558 00559 // Check for literal string 00560 Quote = StringIf(Left(TempValue,1) == "\"" && Left(NewValue,1) != "\"", "\"", ""); 00561 for (i = 0; i < Members.Length; i++) 00562 { 00563 if (Members[i] == "") 00564 { 00565 Members[i] = PropName $ "[" $ i $ "]=" $ Quote $ NewValue $ Quote; 00566 break; 00567 } 00568 } 00569 CurValue = "(" $ Join(Members,",") $")"; 00570 } 00571 00572 else CurValue = "(" $ PropName $ "[0]=" $ NewValue $ ")"; 00573 } 00574 00575 return CurValue; 00576 } 00577 00578 protected final function string AddDynArrayMember(Object Obj, string PropName, string NewValue) 00579 { 00580 local string CurValue, Quote; 00581 local array<string> Members; 00582 00583 if (Obj == None) 00584 { 00585 Warn("Object is None"); 00586 return ""; 00587 } 00588 00589 CurValue = Obj.GetPropertyText(PropName); 00590 Members = GenerateArray(CurValue); 00591 if (DEBUG) 00592 { 00593 log(class$":Adding new member to"@Obj$"."$PropName$":"@NewValue,'AddDynArrayMember'); 00594 log(class$":Current Value:"$CurValue,'AddDynArrayMember'); 00595 } 00596 00597 // Check for literal string 00598 if (InStr(Caps(CurValue), Caps(NewValue)) < 0) 00599 { 00600 if (Members.Length > 0) 00601 { 00602 if (DEBUG) 00603 log(InStr(Caps(CurValue),Caps(NewValue))@InStr(Caps(CurValue),Caps(NewValue))<0@Caps(CurValue)@"||"@Caps(NewValue),'AddDynArrayMember'); 00604 00605 Quote = StringIf(Left(Members[0],1) == "\"" && Left(NewValue,1) != "\"", "\"", ""); 00606 Members[Members.Length] = Quote $ NewValue $ Quote; 00607 CurValue = "(" $ Join(Members,",",True) $ ")"; 00608 } 00609 else CurValue = "(" $ NewValue $ ")"; 00610 } 00611 00612 if (DEBUG) 00613 { 00614 log(class@"Returning:"$CurValue,'AddDynArrayMember'); 00615 log(class@"",'AddDynArrayMember'); 00616 } 00617 00618 return CurValue; 00619 } 00620 00621 // UT2003 currently does not support setting the value of static arrays 00622 protected final function RemoveArrayEntry(Object O, string PropName, string PropValue) 00623 { 00624 local int i, j; 00625 local array<string> Members; 00626 local string ArrayString, Quote, Tmp; 00627 local bool bStatic; 00628 00629 if (O == None) 00630 { 00631 Warn("Object was none for property"@PropName); 00632 return; 00633 } 00634 00635 ArrayString = O.GetPropertyText(PropName); 00636 if (ArrayString == "") 00637 { 00638 Warn("Property was not found:"@PropName); 00639 return; 00640 } 00641 00642 if (DEBUG) 00643 { 00644 log(class$": Removing array member"@string(O.Class)$"."$PropName$":"$ArrayString,'RemoveArrayEntry'); 00645 log(class$": Member to be removed:"$PropValue,'RemoveArrayEntry'); 00646 } 00647 00648 Members = GenerateArray(ArrayString); 00649 bStatic = Left(Members[0], Len(PropName) + 1) ~= (PropName $ "["); 00650 Tmp = StringIf(bStatic, Mid(Members[0],InStr(Members[0],"=") + 1), Members[0]); 00651 Quote = StringIf(Left(Tmp,1) == "\"" && Left(PropValue,1) != "\"","\"",""); 00652 00653 PropValue = StringIf(bStatic, PropName $ "=" $ Quote $ PropValue $ Quote, Quote $ PropValue $ Quote); 00654 for (i = 0; i < Members.Length; i++) 00655 { 00656 if (DEBUG) 00657 log(class@"Comparing"@i@PropValue@"to"@Members[i],'RemoveArrayEntry'); 00658 00659 if (Members[i] ~= PropValue) 00660 break; 00661 } 00662 00663 if (i < Members.Length) 00664 { 00665 if (DEBUG) log(class@"Removing array member"@i$":"$Members[i],'RemoveArrayEntry'); 00666 00667 // Check if we should restore a previous value 00668 for (j = 0; j < ConfigMaster(Owner).OriginalValues.Length; j++) 00669 { 00670 if (DEBUG) 00671 { 00672 log(class@"Checking Backup Value"@j@"class:"$ConfigMaster(Owner).OriginalValues[j].ClassFrom@"against"@string(O.Class),'RemoveArrayEntry'); 00673 log(class@"Checking Backup Value"@j@"Property:"$ConfigMaster(Owner).OriginalValues[j].PropName@"against"@PropName,'RemoveArrayEntry'); 00674 } 00675 00676 if (ConfigMaster(Owner).OriginalValues[j].ClassFrom ~= string(O.Class) && 00677 ConfigMaster(Owner).OriginalValues[j].PropName ~= PropName ) 00678 { 00679 RestoreOriginalValue(O, PropName); 00680 break; 00681 } 00682 } 00683 00684 if (j < ConfigMaster(Owner).OriginalValues.Length) 00685 return; 00686 00687 Members.Remove(i,1); 00688 } 00689 00690 else return; 00691 00692 PropValue = "(" $ Join(Members,",") $ ")"; 00693 if (DEBUG) 00694 log(class@"Assigning"@PropValue@"to property"@string(O.Class)$"."$PropName,'RemoveArrayEntry'); 00695 O.SetPropertyText(PropName,PropValue); 00696 O.SaveConfig(); 00697 if (DEBUG) 00698 log(class@"Returning"@O.GetPropertyText(PropName),'RemoveArrayEntry'); 00699 } 00700 00701 // Just a function to handle safe object creation 00702 protected final function Object GetObjectForEntry(IniEntry ThisEntry) 00703 { 00704 local Object O; 00705 local class<Object> OClass; 00706 00707 if (DEBUG) 00708 log(class@"Getting"@ThisEntry.ClassFrom@ThisEntry.PropName@ThisEntry.PropValue,'GetObjectForEntry'); 00709 00710 OClass = class<Object>(DynamicLoadObject(ThisEntry.ClassFrom,class'Class')); 00711 if (OClass == None) 00712 { 00713 Warn("Could not load class"@ThisEntry.ClassFrom); 00714 return None; 00715 } 00716 00717 O = GetObjectOfClass(OClass); 00718 if (O == None) 00719 Warn("Unable to access object for class"@OClass); 00720 00721 return O; 00722 } 00723 00724 protected final function Object GetObjectOfClass(class<Object> ObjClass) 00725 { 00726 local Object Obj; 00727 local Actor A; 00728 00729 if (DEBUG) 00730 log(class@"Finding"@ObjClass,'GetObjectOfClass'); 00731 00732 // Check for GameEngine 00733 if (ObjClass == class'GameEngine') 00734 return GE; 00735 00736 // First try the easy way 00737 foreach AllObjects(ObjClass,Obj) 00738 return Obj; 00739 00740 // Object may not be loaded right now, so attempt to load it 00741 // If actor, spawn it 00742 if (ClassIsChildOf(ObjClass,class'Actor')) 00743 { 00744 A = Spawn(class<Actor>(ObjClass)); 00745 A.GoToState(''); 00746 return A; 00747 } 00748 00749 // if object, new it 00750 Obj = new(None) ObjClass; 00751 00752 // might be property 00753 if (Obj == None) 00754 Obj = new(Class) ObjClass; 00755 00756 // Don't know if this will even work ? 00757 if (Obj == None) 00758 Obj = New(ObjClass.default.Outer) ObjClass; 00759 00760 if (DEBUG) 00761 { 00762 log(class@"Could not create new object"@ObjClass,'GetObjectOfClass'); 00763 log(class@ObjClass@"outer is"@ObjClass.default.Outer,'GetObjectOfClass'); 00764 log(class@"",'GetObjectOfClass'); 00765 } 00766 00767 return Obj; 00768 } 00769 00770 protected final function Property GetProperty(Object O, string PropName) 00771 { 00772 local int i; 00773 local Class ClassOuter; 00774 local bool classexact, classchild, propn, seenclass; 00775 00776 for (i=0;i<Properties.Length;i++) 00777 { 00778 seenclass = Class(Properties[i].Outer) == ClassOuter; 00779 00780 ClassOuter = Class(Properties[i].Outer); 00781 if (DEBUGPROPS) 00782 { 00783 if (ClassOuter == None) 00784 { 00785 log(class@"Property Outer is not a class!",'GetProperty'); 00786 continue; 00787 } 00788 00789 if (!seenclass) 00790 { 00791 log(class@"Compare Obj Class"@O.Class@"to"@Properties[i].Outer,'GetProperty'); 00792 if (O.Class==Properties[i].Outer) 00793 classexact = true; 00794 } 00795 00796 if (!classchild && ClassIsChildOf(O.Class,ClassOuter)) 00797 { 00798 log(class@"Obj class"@O.Class@"is child of"@ClassOuter,'GetProperty'); 00799 classchild = true; 00800 } 00801 00802 else if (!classchild && ClassIsChildOf(ClassOuter,O.Class)) 00803 { 00804 log(class@"Obj class"@O.Class@"is parent of"@ClassOuter,'GetProperty'); 00805 classchild = true; 00806 } 00807 00808 if (!propn && classexact) 00809 { 00810 log(class@"Compare Name"@PropName@"to"@Properties[i].Name,'GetProperty'); 00811 if (PropName == string(Properties[i].Name)) 00812 propn = true; 00813 } 00814 } 00815 00816 if ((ClassIsChildOf(O.Class,ClassOuter)||O.Class == Properties[i].Outer||ClassIsChildOf(ClassOuter,O.Class)) && string(Properties[i].Name) == PropName) 00817 { 00818 if (DEBUG) 00819 { 00820 log(class@"Returning Property"@Properties[i],'GetProperty'); 00821 log(class@"",'GetProperty'); 00822 } 00823 00824 return Properties[i]; 00825 } 00826 } 00827 00828 return None; 00829 } 00830 00831 protected final function bool PropIsArray(Property P) 00832 { 00833 if (DEBUG) 00834 log(class@"Checking Property"@P.Outer$"."$P.Name$":"@P.Class,'PropIsArray'); 00835 return P.Class == class'ArrayProperty'; 00836 } 00837 00838 protected static final function array<string> GenerateArray(string ArrayString) 00839 { 00840 local array<string> Members; 00841 local int i; 00842 local string S; 00843 00844 if (ArrayString != "") 00845 { 00846 // Remove the array wrapper ( ) 00847 ArrayString = Mid(ArrayString,1,Len(ArrayString)-2); 00848 00849 // If string contains internal containers, then have to split differently 00850 if (Left(ArrayString,1) == "(") 00851 { 00852 do { 00853 do { 00854 if (Left(ArrayString,1) == ")") 00855 i--; 00856 else if (Left(ArrayString,1) == "(") 00857 i++; 00858 Eat(S, ArrayString, 1); 00859 } until (i == 0); 00860 00861 Members[Members.Length] = S; 00862 S = ""; 00863 if (ArrayString != "" && Left(ArrayString,1) == ",") 00864 ArrayString = Mid(ArrayString,1); 00865 } until (ArrayString == ""); 00866 } 00867 00868 else Split2(ArrayString,",",Members); 00869 } 00870 00871 return Members; 00872 } 00873 00874 protected static final function bool NotInPlayInfo(PlayInfo PI, class<Info> NewInfo) 00875 { 00876 local int i; 00877 if (PI == None) 00878 { 00879 Warn("Invalid PlayInfo Object!"); 00880 return false; 00881 } 00882 00883 for (i=0;i<PI.InfoClasses.Length;i++) 00884 { 00885 if (PI.InfoClasses[i] == NewInfo) 00886 return false; 00887 } 00888 00889 return true; 00890 } 00891 00892 00893 //################################################################### 00894 //################################################################### 00895 // 00896 // Utility Methods 00897 // These are used perform various tedious operations. 00898 // 00899 // Moves Num elements from Source to Dest 00900 static final function Eat(out string Dest, out string Source, int Num) 00901 { 00902 Dest = Dest $ Left(Source, Num); 00903 Source = Mid(Source, Num); 00904 } 00905 00906 static final function string StringIf(bool Condition, string IfTrue, string IfFalse) 00907 { 00908 if (Condition) return IfTrue; 00909 return IfFalse; 00910 } 00911 00912 // Based on AccessControlIni & Object.ReplaceText() 00913 static final function string ReplaceTag(string from, string tag, coerce string with) 00914 { 00915 local int i; 00916 local string t; 00917 00918 // InStr() is case-sensitive 00919 i = InStr(Caps(from), Caps(tag)); 00920 while (i != -1) 00921 { 00922 t = t $ Left(from,i) $ with; 00923 from = mid(from,i+len(tag)); 00924 i = InStr(Caps(from), Caps(tag)); 00925 } 00926 00927 t = t $ from; 00928 return t; 00929 } 00930 00931 // Following functions from wUtils103 by El_Muerte[TDS] 00932 // Included by permission (copied to avoid package dependancy) 00933 00934 // Shifts an element off a string 00935 // example (delim = ' '): 'this is a string' -> 'is a string' 00936 // if quotechar = " : '"this is" a string' -> 'a string' 00937 static final function string StrShift(out string line, string delim, optional string quotechar) 00938 { 00939 local int delimpos, quotepos; 00940 local string result; 00941 00942 if ( quotechar != "" && Left(line, Len(quotechar)) == quotechar ) { 00943 do { 00944 quotepos = InstrFrom(line, quotechar, quotepos + 1); 00945 } until (quotepos == -1 || quotepos + Len(quotechar) == Len(line) 00946 || Mid(line, quotepos + len(quotechar), len(delim)) == delim); 00947 } 00948 if ( quotepos != -1 ) { 00949 delimpos = InstrFrom(line, delim, quotepos); 00950 } 00951 else { 00952 delimpos = Instr(line, delim); 00953 } 00954 00955 if (delimpos == -1) 00956 { 00957 result = line; 00958 line = ""; 00959 } 00960 else { 00961 result = Left(line,delimpos); 00962 line = Mid(line,delimpos+len(delim)); 00963 } 00964 if ( quotechar != "" && Left(result, Len(quotechar)) == quotechar ) { 00965 result = Mid(result, Len(quotechar), Len(result)-(Len(quotechar)*2)); 00966 } 00967 return result; 00968 } 00969 00970 // Join the elements of a string array to an array 00971 static final function string Join(array< string > ar, optional string delim, optional bool bIgnoreEmpty) 00972 { 00973 local string result; 00974 local int i; 00975 for (i = 0; i < ar.length; i++) 00976 { 00977 if (bIgnoreEmpty && ar[i] == "") continue; 00978 if (result != "") result = result$delim; 00979 result = result$ar[i]; 00980 } 00981 00982 return result; 00983 } 00984 00985 // Fixed split method 00986 // no problems when it starts with a delim 00987 // no problems with ending spaces 00988 // delim can be a string 00989 static final function int Split2(coerce string src, string delim, out array<string> parts, optional bool ignoreEmpty, optional string quotechar) 00990 { 00991 local string temp; 00992 Parts.Remove(0, Parts.Length); 00993 if (delim == "" || Src == "" ) return 0; 00994 while (src != "") 00995 { 00996 temp = StrShift(src, delim, quotechar); 00997 if (temp == "") 00998 { 00999 if (!ignoreEmpty) 01000 { 01001 parts.length = parts.length+1; 01002 parts[parts.length-1] = temp; 01003 } 01004 } 01005 else { 01006 parts.length = parts.length+1; 01007 parts[parts.length-1] = temp; 01008 } 01009 } 01010 return parts.length; 01011 } 01012 01013 // InStr starting from an offset 01014 static final function int InStrFrom(coerce string StrText, coerce string StrPart, optional int OffsetStart) 01015 { 01016 local int OffsetPart; 01017 01018 OffsetPart = InStr(Mid(StrText, OffsetStart), StrPart); 01019 if (OffsetPart >= 0) 01020 OffsetPart += OffsetStart; 01021 return OffsetPart; 01022 }
Wormbo: Hmm, a little documentation instead of the source code wouldn't hurt. E.g. how can you use this to enable/disable a server actor?
El Muerte TDS: like this: [ChatFilter AutoLoader], maybe write a [/example] based on it... first lunch