Once I get that upgrade to 36-hour days, I will tackle that. – Mychaeel

Legacy:AutoLoader

From Unreal Wiki, The Unreal Engine Documentation Site

Jump to: navigation, search
UT2003 :: Actor >> Info >> AutoLoader (Package: ConfigManager)

Here's an Legacy:AutoLoader/Example on how to use this class

  1. //-----------------------------------------------------------
    
  2. //	ConfigManager.AutoLoader
    
  3. //
    
  4. //	This class has two functions:
    
  5. //	1. Perform all required ini changes needed for your mod.  Will also UNDO
    
  6. //	   any changes made to the ini if your mod is deactivated.
    
  7. //	   Additional benefit of auto-installation of your mutator on a dedicated
    
  8. //	   server (to enable set bEnableMyLoader=True in defaultproperties)
    
  9. //
    
  10. //	2.	Pass FillPlayInfo() calls to mutators which are not part of the game's
    
  11. //		mutator list (such as mutators which only require ServerActors= lines in ini)
    
  12. //
    
  13. //-----------------------------------------------------------
    
  14. class AutoLoader extends Info
    
  15. 	abstract;
    
  16.  
    
  17. // Quick note about debugging - By setting DEBUG=True in defaultproperties of your
    
  18. // AutoLoader subclass when compiling, you can receive large amounts of debug data.
    
  19. // However, you will quickly encounter the 1024 byte limit if you use ucc.exe to
    
  20. // start the testing server.  By starting a server using the "ut2003 -server" command,
    
  21. // you will bypass this limit, since ut2003.exe does not have these limitations.
    
  22.  
    
  23. var const bool DEBUG;
    
  24. var const bool DEBUGPROPS;
    
  25.  
    
  26. var ConfigMaster				Manager; 			// Pointer to ConfigMaster mutator
    
  27. var string						InteractionClass;	// Not yet implemented
    
  28.  
    
  29. //=======================================
    
  30. //	Loading ServerActors
    
  31. //=======================================
    
  32. // Pointer to GameEngine
    
  33. var GameEngine					GE;
    
  34.  
    
  35. // This loader includes a server-side only mutator or server actor
    
  36. // that will not be part of the mutator chain (will receive FillPlayInfo() calls)
    
  37. var() bool						bIncludeServerActor;
    
  38.  
    
  39. // Classname of the ServerActor this loader loads
    
  40. // 	Same value as what would otherwise be your mod's
    
  41. // 	ServerActors= line in the .ini file.
    
  42. var() string ActorClass;
    
  43.  
    
  44. // Friendly Name of the Server Actor class
    
  45. // 	Used by webadmin/adminmenu as the name of the server actor
    
  46. var() localized string 			FriendlyName;
    
  47. var() localized string			ActorDescription;
    
  48.  
    
  49. // Lock this loader to a certain version (or higher) of your mod
    
  50. var() string			RequiredVersion;	// Required version of actor
    
  51. var() localized string 	VersionWarning;		// Message to write to server log if version not enough
    
  52. var() localized string 	DownloadMsg;		// Message to write to log
    
  53.  
    
  54. //=======================================
    
  55. //	Automatic configuration changes
    
  56. //=======================================
    
  57. // A single ini change
    
  58. struct IniEntry
    
  59. {
    
  60. 	var() string ClassFrom;	// Class which contains the setting we want to change
    
  61. 	var() string PropName;	// Name of the variable we're trying to change
    
  62. 	var() string PropValue;	// Value to apply
    
  63. };
    
  64.  
    
  65. // Array of ini settings required by this mod
    
  66. var() 	array<IniEntry>					RequiredIniEntries;
    
  67. var 	array<Property>					Properties;
    
  68.  
    
  69.  
    
  70. //###################################################################
    
  71. //###################################################################
    
  72. //
    
  73. //  Public methods - should be subclassed to customize loader's response
    
  74.  
    
  75. // if return true, loader class will be spawned
    
  76. static function bool IsActive()
    
  77. {
    
  78. 	return false;
    
  79. }
    
  80.  
    
  81. // should be subclassed - set loader to active/will be included next match
    
  82. static function bool EnableLoader(optional string SpecialActor)
    
  83. {
    
  84. 	return false;
    
  85. }
    
  86.  
    
  87. // should be subclassed
    
  88. static function bool DisableLoader(optional string SpecialActor)
    
  89. {
    
  90. 	return true;
    
  91. }
    
  92.  
    
  93. // called on all loader classes - used to activate loader based on active mutators
    
  94. static function bool CheckCurrentMutators(string URL)
    
  95. {
    
  96. 	return false;
    
  97. }
    
  98.  
    
  99. // called on all loader classes which have bIncludeServerActor=True - used to activate loader based on manual ServerActor entry
    
  100. static function bool CheckStrayActors(string ServerActors)
    
  101. {
    
  102. 	local int i;
    
  103. 	local bool bAddMe;
    
  104.  
    
  105. 	if (default.bIncludeServerActor)
    
  106. 		if (InStr(ServerActors,default.ActorClass) != -1)
    
  107. 			bAddMe = EnableLoader();
    
  108.  
    
  109. 	for (i = 0; i < default.RequiredIniEntries.Length; i++)
    
  110. 		if (!bAddMe && default.RequiredIniEntries[i].ClassFrom ~= "Engine.GameEngine" && default.RequiredIniEntries[i].PropName ~= "ServerActors")
    
  111. 			if (InStr(ServerActors,default.RequiredIniEntries[i].PropValue) != -1)
    
  112. 				bAddMe = EnableLoader();
    
  113.  
    
  114. 	if (default.DEBUG)
    
  115. 	{
    
  116. 		log(default.Class@"Received string value:"$ServerActors,'CheckStrayActors');
    
  117. 		log(default.Class@"Returning"@bAddMe,'CheckStrayActors');
    
  118. 	}
    
  119. 	return bAddMe;
    
  120. }
    
  121.  
    
  122. // Only managed actors can be added to Ladder profiles
    
  123. // Normally, only the ActorClass of your loader (if bIncludeServerActor=True) would be need to be managed
    
  124. static function array<string> GetManagedActors()
    
  125. {
    
  126. 	local int i;
    
  127. 	local string A, B, C;
    
  128. 	local array<string> ABC;
    
  129.  
    
  130. 	i = -1;
    
  131. 	while (static.AddManagedActor(i++,A,B,C))
    
  132. 		ABC[ABC.Length] = A$","$B$","$C;
    
  133.  
    
  134. 	return ABC;
    
  135. }
    
  136.  
    
  137. // Managed actors will be passed FillPlayInfo() calls
    
  138. static function bool AddManagedActor(int Idx, out string ActorClassName, out string ActorName, out string ActorDesc)
    
  139. {
    
  140. 	if (Idx == -1 && default.bIncludeServerActor)
    
  141. 	{
    
  142. 		ActorClassName = default.ActorClass;
    
  143. 		ActorName = default.FriendlyName;
    
  144. 		ActorDesc = default.ActorDescription;
    
  145. 		return true;
    
  146. 	}
    
  147.  
    
  148. 	return false;
    
  149. }
    
  150.  
    
  151. // Optional hook for version filtering
    
  152. static function bool MatchesVersion(float ActorVersion, optional bool bExact, optional string NewURL)
    
  153. {
    
  154. 	local float CurrentVersion;
    
  155. 	local string LogText;
    
  156.  
    
  157. 	if (default.RequiredVersion == "")
    
  158. 		return true;
    
  159.  
    
  160. 	CurrentVersion = float(default.RequiredVersion);
    
  161.  
    
  162. 	// Return false if loader version is higher than actor version
    
  163. 	// Return false if loader version is lower than actor version and bExact=True
    
  164. 	if ((ActorVersion < CurrentVersion) || (ActorVersion > CurrentVersion && bExact))
    
  165. 	{
    
  166. 		if (default.VersionWarning != "")
    
  167. 		{
    
  168. 			LogText = static.ReplaceTag(default.VersionWarning,"%CurVer%",CurrentVersion);
    
  169. 			LogText = static.ReplaceTag(LogText,"%ReqVer%",ActorVersion);
    
  170. 			log(LogText);
    
  171. 		}
    
  172.  
    
  173. 		if (NewURL != "")
    
  174. 			log(static.ReplaceTag(default.DownloadMsg,"%URL%",NewURL));
    
  175.  
    
  176. 		return false;
    
  177. 	}
    
  178.  
    
  179. 	return true;
    
  180. }
    
  181.  
    
  182. // To prevent your loader from causing a server crash, add your checks here
    
  183. // return false to prevent your loader from being loaded
    
  184.  
    
  185. // You only need to override this function if bIncludeServerActor=False in your loader,
    
  186. // or if you have RequiredIniChanges that reference additional custom packages
    
  187. static function bool ValidateLoader()
    
  188. {
    
  189. 	local class<Info>	MyActor;
    
  190.  
    
  191. 	if (default.bIncludeServerActor && default.ActorClass != "")
    
  192. 	{
    
  193. 		// Specify True for 3rd param in DynamicLoadObject to prevent log spam if MyActor isn't on server
    
  194. 		MyActor = class<Info>(DynamicLoadObject(default.ActorClass,class'Class',True));
    
  195. 		if (MyActor == None)
    
  196. 			return false;
    
  197. 	}
    
  198.  
    
  199. 	return true;
    
  200. }
    
  201.  
    
  202. // Hook for loader to cancel external removal request, or effect any specialized ini changes to make before removal
    
  203. function bool AcceptRemoval(optional array<Property> Props)
    
  204. {
    
  205. 	if (Props.Length > 0)
    
  206. 		Properties = Props;
    
  207.  
    
  208. 	RemoveMe();
    
  209. 	return true;
    
  210. }
    
  211.  
    
  212. // should be subclassed
    
  213. // always use "return !bEnableMyLoader;"
    
  214. // see LadderLoader.LadderLoader or TeamBalanceLoader.BalanceLoader for examples
    
  215. function bool WantsToBeDisabled()
    
  216. {
    
  217. 	return false;
    
  218. }
    
  219.  
    
  220. // called for each RequiredIniEntry
    
  221. // return true to apply the RequiredIniEntry.PropValue
    
  222. function bool ObjectNeedsUpdate(Object O, string PropName, string PropValue)
    
  223. {
    
  224. 	local string Temp;
    
  225.  
    
  226. 	Temp = O.GetPropertyText(PropName);
    
  227. 	if ( InStr(Caps(Temp),Caps(PropValue)) < 0 )
    
  228. 		return true;
    
  229.  
    
  230. 	return false;
    
  231. }
    
  232.  
    
  233. // notification of pending update - return false to skip update for loader
    
  234. function bool ApplyUpdate()
    
  235. {
    
  236. 	if (DEBUG) log(class@"Returning"@IsActive(),'ApplyUpdate');
    
  237. 	return IsActive();
    
  238. }
    
  239.  
    
  240. // return -1 if want to simply add entry
    
  241. // return index of array entry if want to overwrite
    
  242. function int CheckArrayEntry(string PropName, array<string> PropArray)
    
  243. {
    
  244. 	return -1;
    
  245. }
    
  246.  
    
  247. // To maintain consistency, always add to "Server Actors" page
    
  248. // static function FillPlayInfo(PlayInfo PI)
    
  249. // {
    
  250. // 		Super.FillPlayInfo(PI);
    
  251. //		PI.AddSetting("ServerActors",....
    
  252. // }
    
  253. //
    
  254. //###################################################################
    
  255. //###################################################################
    
  256. //
    
  257. //	Public Final Methods
    
  258. //	These are used to operate the internal mechanisms of the auto loader system.
    
  259. //
    
  260. //
    
  261.  
    
  262. // Called by ConfigMaster when Level.ServerTravel is called
    
  263.  
    
  264. // Removes loader if WantsToBeDisabled() returns True
    
  265. // Applies value for RequiredIniProperties if ObjectNeedsUpdate returns true
    
  266. final function UpdateConfiguration(array<Property> Props)
    
  267. {
    
  268. 	local Object 			O;
    
  269. 	local Property			P;
    
  270.  
    
  271. 	local string 			N,V;
    
  272. 	local int 				i, j;
    
  273.  
    
  274. 	local array<string>		Arr;
    
  275. 	local string			ArrS;
    
  276.  
    
  277. 	if (DEBUG)
    
  278. 		log("Update configuration in"@class,'UpdateConfiguration');
    
  279.  
    
  280. 	ResetConfig();
    
  281. 	Properties = Props;
    
  282.  
    
  283. 	if (WantsToBeDisabled())
    
  284. 	{
    
  285. 		RemoveMe();
    
  286. 		return;
    
  287. 	}
    
  288.  
    
  289. 	if (bIncludeServerActor && ActorClass != "")
    
  290. 	{
    
  291. 		O = GetObjectOfClass(class'Engine.GameEngine');
    
  292. 		if (O != None)
    
  293. 		{
    
  294. 			if (ObjectNeedsUpdate(O, "ServerActors", ActorClass))
    
  295. 			{
    
  296. 				ArrS = O.GetPropertyText("ServerActors");
    
  297. 				if (ArrS != "")
    
  298. 					Arr = GenerateArray(ArrS);
    
  299.  
    
  300. 				j = -1;
    
  301. 				if (Arr.Length > 0)
    
  302. 					j = CheckArrayEntry("ServerActors", Arr);
    
  303.  
    
  304. 				if (j < 0)
    
  305. 					O.SetPropertyText("ServerActors",AddDynArrayMember(O,"ServerActors",ActorClass));
    
  306.  
    
  307. 				else O.SetPropertyText("ServerActors",InsertArrayMember(O, "ServerActors", ActorClass, j));
    
  308. 				O.SaveConfig();
    
  309. 			}
    
  310. 		}
    
  311. 	}
    
  312.  
    
  313. 	for (i = 0;i<RequiredIniEntries.Length;i++)
    
  314. 	{
    
  315. 		O = GetObjectForEntry(RequiredIniEntries[i]);
    
  316. 		if (O == None) continue;
    
  317.  
    
  318. 		if (!ObjectNeedsUpdate(O, RequiredIniEntries[i].PropName, RequiredIniEntries[i].PropValue)) continue;
    
  319.  
    
  320. 		N = RequiredIniEntries[i].PropName;
    
  321. 		V = RequiredIniEntries[i].PropValue;
    
  322. 		P = GetProperty(O, N);
    
  323. 		if (DEBUG)
    
  324. 			log(class@"got property"@p,'UpdateConfiguration');
    
  325.  
    
  326. 		if (P == None) continue;
    
  327.  
    
  328. 		j = -1;
    
  329.  
    
  330. 		if (PropIsArray(P))
    
  331. 		{
    
  332. 			ArrS = O.GetPropertyText(N);
    
  333. 			if (ArrS != "")
    
  334. 				Arr = GenerateArray(ArrS);
    
  335.  
    
  336. 			if (Arr.Length > 0)
    
  337. 				j = CheckArrayEntry(N, Arr);
    
  338.  
    
  339. 			if (j < 0)
    
  340. 				O.SetPropertyText(N,AddDynArrayMember(O,N,V));
    
  341.  
    
  342. 			else O.SetPropertyText(N,InsertArrayMember(O, N, V, j));
    
  343. 		}
    
  344.  
    
  345. 		else
    
  346. 		{
    
  347. 			StoreDefaultValue(O, N);
    
  348. 			O.SetPropertyText(N,V);
    
  349. 		}
    
  350.  
    
  351. 		O.SaveConfig();
    
  352. 	}
    
  353. }
    
  354.  
    
  355. // Regarding OriginalValues
    
  356. final function StoreDefaultValue(Object O, string PropName)
    
  357. {
    
  358. 	local int i, idx;
    
  359. 	local IniEntry NewDefault;
    
  360. 	local string CurrentValue, Quote;
    
  361. 	local array<string> Ar;
    
  362.  
    
  363. 	if (DEBUG)
    
  364. 		log(class@"storing default"@o@propname,'StoreDefaultValue');
    
  365.  
    
  366. 	for (i = 0; i < ConfigMaster(Owner).OriginalValues.Length; i++)
    
  367. 		if (ConfigMaster(Owner).OriginalValues[i].ClassFrom == string(O.Class) && ConfigMaster(Owner).OriginalValues[i].PropName == PropName)
    
  368. 			return;
    
  369.  
    
  370. 	NewDefault.ClassFrom = string(O.Class);
    
  371. 	// Check if this property name is a single array member
    
  372. 	i = -1; idx = -1;
    
  373. 	i = InStr(PropName, "§");
    
  374. 	if (i != -1)
    
  375. 	{
    
  376. 		idx = int(Left(PropName, i));
    
  377. 		PropName = Mid(PropName, i + 1);
    
  378. 		CurrentValue = O.GetPropertyText(PropName);
    
  379. 		Ar = GenerateArray(CurrentValue);
    
  380. 		CurrentValue = Ar[idx];
    
  381.  
    
  382. 		// Remove literal string wrapper
    
  383. 		if (Left(CurrentValue,1) == "\"")
    
  384. 		{
    
  385. 			CurrentValue = Mid(CurrentValue,1,Len(CurrentValue) - 2);
    
  386. 			Quote = "¶";
    
  387. 		}
    
  388. 		CurrentValue = idx $ "§" $ CurrentValue $ Quote;
    
  389. 	}
    
  390.  
    
  391. 	else CurrentValue = O.GetPropertyText(PropName);
    
  392.  
    
  393. 	NewDefault.PropName = PropName;
    
  394. 	NewDefault.PropValue = CurrentValue;
    
  395. 	if (DEBUG)
    
  396. 		log(class@"old value:"@NewDefault.PropValue,'StoreDefaultValue');
    
  397.  
    
  398. 	ConfigMaster(Owner).OriginalValues[ConfigMaster(Owner).OriginalValues.Length] = NewDefault;
    
  399. 	ConfigMaster(Owner).SaveConfig();
    
  400. }
    
  401.  
    
  402. final function bool RestoreOriginalValue(Object O, string PropName)
    
  403. {
    
  404. 	local int i, j, idx;
    
  405. 	local string CurrentValue, StoredValue;
    
  406. 	local array<string> Ar;
    
  407.  
    
  408. 	for (i = 0; i < ConfigMaster(Owner).OriginalValues.Length; i++)
    
  409. 	{
    
  410. 		if (ConfigMaster(Owner).OriginalValues[i].ClassFrom ~= string(O.Class) && ConfigMaster(Owner).OriginalValues[i].PropName ~= PropName)
    
  411. 		{
    
  412. 			StoredValue = ConfigMaster(Owner).OriginalValues[i].PropValue;
    
  413. 			// First check if this was a single array member
    
  414. 			j = InStr(StoredValue, "§");
    
  415. 			if (j != -1)
    
  416. 			{
    
  417. 				idx = int(Left(StoredValue, j));
    
  418. 				StoredValue = Mid(StoredValue, j + 1);
    
  419. 				if (Right(StoredValue, 1) == "¶")
    
  420. 				{
    
  421. 					StoredValue = Left(StoredValue, Len(StoredValue) - 1);
    
  422. 					StoredValue = "\"" $ StoredValue $ "\"";
    
  423. 				}
    
  424. 				CurrentValue = O.GetPropertyText(PropName);
    
  425. 				Ar = GenerateArray(CurrentValue);
    
  426. 				Ar[idx] = StoredValue;
    
  427. 				StoredValue = "(" $ Join(Ar,",",True) $")";
    
  428. 			}
    
  429.  
    
  430. 			if (DEBUG)
    
  431. 				log(class@"Assigning"@StoredValue@"to property"@string(O.Class)$"."$PropName,'RestoreOriginalValue');
    
  432. 			O.SetPropertyText(PropName, StoredValue);
    
  433. 			O.SaveConfig();
    
  434. 			break;
    
  435. 		}
    
  436. 	}
    
  437.  
    
  438. 	if (i < ConfigMaster(Owner).OriginalValues.Length)
    
  439. 	{
    
  440. 		ConfigMaster(Owner).OriginalValues.Remove(i, 1);
    
  441. 		ConfigMaster(Owner).SaveConfig();
    
  442. 		return true;
    
  443. 	}
    
  444.  
    
  445. 	return false;
    
  446. }
    
  447.  
    
  448. //###################################################################
    
  449. //###################################################################
    
  450. //
    
  451. //	Internal Methods
    
  452. //	These are used to control the internal operation of the loader itself.
    
  453. //	These methods may only be called by other methods within the loader.
    
  454. //
    
  455.  
    
  456. protected final function RemoveMe()
    
  457. {
    
  458. 	local int i;
    
  459. 	local Object O;
    
  460. 	local Property P;
    
  461.  
    
  462. 	if (DEBUG)
    
  463. 		log(class@"being removed.",'RemoveMe');
    
  464.  
    
  465. 	if (bIncludeServerActor && ActorClass != "")
    
  466. 	{
    
  467. 		O = GetObjectOfClass(class'Engine.GameEngine');
    
  468. 		if (O != None)
    
  469. 			RemoveArrayEntry(O, "ServerActors", ActorClass);
    
  470. 	}
    
  471.  
    
  472. 	for (i = 0; i < RequiredIniEntries.Length; i++)
    
  473. 	{
    
  474. 		O = GetObjectForEntry(RequiredIniEntries[i]);
    
  475. 		if (O == None) continue;
    
  476.  
    
  477. 		P = GetProperty(O,RequiredIniEntries[i].PropName);
    
  478. 		if (P != None && PropIsArray(P))
    
  479. 			RemoveArrayEntry(O,RequiredIniEntries[i].PropName,RequiredIniEntries[i].PropValue);
    
  480.  
    
  481. 		else RestoreOriginalValue(O, RequiredIniEntries[i].PropName);
    
  482. 	}
    
  483.  
    
  484. 	DisableLoader();
    
  485. }
    
  486.  
    
  487. protected final function string InsertArrayMember(Object Obj, string PropName, string NewValue, int Pos)
    
  488. {
    
  489. 	local string CurValue, Quote, Tmp;
    
  490. 	local array<string>	Members;
    
  491. 	local bool bStatic;
    
  492.  
    
  493. 	if (Obj == None)
    
  494. 	{
    
  495. 		Warn("Object is None");
    
  496. 		return "";
    
  497. 	}
    
  498.  
    
  499. 	CurValue = Obj.GetPropertyText(PropName);
    
  500. 	Members = GenerateArray(CurValue);
    
  501.  
    
  502. 	if (DEBUG)
    
  503. 	{
    
  504. 		log(class$":Inserting new member at position"@Pos@"to"@Obj$"."$PropName$":"@NewValue,'InsertArrayMember');
    
  505. 		log(class$":Current Value:"$CurValue,'InsertArrayMember');
    
  506. 	}
    
  507.  
    
  508. // Check for literal string
    
  509. 	if (InStr(Caps(CurValue), Caps(NewValue)) < 0 && Members.Length > 0)
    
  510. 	{
    
  511. 		bStatic = Left(Members[pos], Len(PropName) + 1) ~= (PropName $ "[");
    
  512. 		Tmp = StringIf(bStatic, Mid(Members[pos],InStr(Members[pos],"=") + 1), Members[0]);
    
  513. 		Quote = StringIf(Left(Tmp,1) == "\"" && Left(NewValue,1) != "\"","\"","");
    
  514.  
    
  515. 		NewValue = StringIf(bStatic, PropName $ "=" $ Quote $ NewValue $ Quote, Quote $ NewValue $ Quote);
    
  516. 		if (DEBUG)
    
  517. 			log(InStr(Caps(CurValue),Caps(NewValue))@InStr(Caps(CurValue),Caps(NewValue))<0@Caps(CurValue)@"||"@Caps(NewValue),'AddDynArrayMember');
    
  518.  
    
  519. 		if (NewValue != "" && Pos > -1)
    
  520. 		{
    
  521. 			StoreDefaultValue(Obj, Pos$"§"$PropName);
    
  522. 			Members[Pos] = NewValue;
    
  523. 		}
    
  524.  
    
  525. 		CurValue = "(" $ Join(Members,",",True) $ ")";
    
  526. 	}
    
  527.  
    
  528. 	if (DEBUG)
    
  529. 	{
    
  530. 		log(class@"Returning:"$CurValue,'InsertArrayMember');
    
  531. 		log(class@"",'InsertArrayMember');
    
  532. 	}
    
  533.  
    
  534. 	return CurValue;
    
  535. }
    
  536.  
    
  537. // Currently, UT2003 does not support setting static arrays through the use of SetPropertyText
    
  538. protected final function string AddStaticArrayMember(Object Obj, string PropName, string NewValue)
    
  539. {
    
  540. 	local int i;
    
  541. 	local array<string>	Members;
    
  542. 	local string Quote, TempValue, CurValue;
    
  543.  
    
  544. 	if (Obj == None)
    
  545. 	{
    
  546. 		Warn("Object was None for property"@PropName);
    
  547. 		return "";
    
  548. 	}
    
  549.  
    
  550. 	CurValue = Obj.GetPropertyText(PropName);
    
  551. 	Members = GenerateArray(CurValue);
    
  552.  
    
  553. 	if (InStr(Caps(CurValue), Caps(NewValue)) < 0)
    
  554. 	{
    
  555. 		if (Members.Length > 0)
    
  556. 		{
    
  557. 			TempValue = Mid(Members[0],InStr(Members[0],"=")+1);
    
  558.  
    
  559. 			// Check for literal string
    
  560. 			Quote = StringIf(Left(TempValue,1) == "\"" && Left(NewValue,1) != "\"", "\"", "");
    
  561. 			for (i = 0; i < Members.Length; i++)
    
  562. 			{
    
  563. 				if (Members[i] == "")
    
  564. 				{
    
  565. 					Members[i] = PropName $ "[" $ i $ "]=" $ Quote $ NewValue $ Quote;
    
  566. 					break;
    
  567. 				}
    
  568. 			}
    
  569. 			CurValue = "(" $ Join(Members,",") $")";
    
  570. 		}
    
  571.  
    
  572. 		else CurValue = "(" $ PropName $ "[0]=" $ NewValue $ ")";
    
  573. 	}
    
  574.  
    
  575. 	return CurValue;
    
  576. }
    
  577.  
    
  578. protected final function string AddDynArrayMember(Object Obj, string PropName, string NewValue)
    
  579. {
    
  580. 	local string CurValue, Quote;
    
  581. 	local array<string>	Members;
    
  582.  
    
  583. 	if (Obj == None)
    
  584. 	{
    
  585. 		Warn("Object is None");
    
  586. 		return "";
    
  587. 	}
    
  588.  
    
  589. 	CurValue = Obj.GetPropertyText(PropName);
    
  590. 	Members = GenerateArray(CurValue);
    
  591. 	if (DEBUG)
    
  592. 	{
    
  593. 		log(class$":Adding new member to"@Obj$"."$PropName$":"@NewValue,'AddDynArrayMember');
    
  594. 		log(class$":Current Value:"$CurValue,'AddDynArrayMember');
    
  595. 	}
    
  596.  
    
  597. // Check for literal string
    
  598. 	if (InStr(Caps(CurValue), Caps(NewValue)) < 0)
    
  599. 	{
    
  600. 		if (Members.Length > 0)
    
  601. 		{
    
  602. 			if (DEBUG)
    
  603. 				log(InStr(Caps(CurValue),Caps(NewValue))@InStr(Caps(CurValue),Caps(NewValue))<0@Caps(CurValue)@"||"@Caps(NewValue),'AddDynArrayMember');
    
  604.  
    
  605. 			Quote = StringIf(Left(Members[0],1) == "\"" && Left(NewValue,1) != "\"", "\"", "");
    
  606. 			Members[Members.Length] = Quote $ NewValue $ Quote;
    
  607. 			CurValue = "(" $ Join(Members,",",True) $ ")";
    
  608. 		}
    
  609. 		else CurValue = "(" $ NewValue $ ")";
    
  610. 	}
    
  611.  
    
  612. 	if (DEBUG)
    
  613. 	{
    
  614. 		log(class@"Returning:"$CurValue,'AddDynArrayMember');
    
  615. 		log(class@"",'AddDynArrayMember');
    
  616. 	}
    
  617.  
    
  618. 	return CurValue;
    
  619. }
    
  620.  
    
  621. // UT2003 currently does not support setting the value of static arrays
    
  622. protected final function RemoveArrayEntry(Object O, string PropName, string PropValue)
    
  623. {
    
  624. 	local int i, j;
    
  625. 	local array<string> Members;
    
  626. 	local string ArrayString, Quote, Tmp;
    
  627. 	local bool bStatic;
    
  628.  
    
  629. 	if (O == None)
    
  630. 	{
    
  631. 		Warn("Object was none for property"@PropName);
    
  632. 		return;
    
  633. 	}
    
  634.  
    
  635. 	ArrayString = O.GetPropertyText(PropName);
    
  636. 	if (ArrayString == "")
    
  637. 	{
    
  638. 		Warn("Property was not found:"@PropName);
    
  639. 		return;
    
  640. 	}
    
  641.  
    
  642. 	if (DEBUG)
    
  643. 	{
    
  644. 		log(class$": Removing array member"@string(O.Class)$"."$PropName$":"$ArrayString,'RemoveArrayEntry');
    
  645. 		log(class$": Member to be removed:"$PropValue,'RemoveArrayEntry');
    
  646. 	}
    
  647.  
    
  648. 	Members = GenerateArray(ArrayString);
    
  649. 	bStatic = Left(Members[0], Len(PropName) + 1) ~= (PropName $ "[");
    
  650. 	Tmp = StringIf(bStatic, Mid(Members[0],InStr(Members[0],"=") + 1), Members[0]);
    
  651. 	Quote = StringIf(Left(Tmp,1) == "\"" && Left(PropValue,1) != "\"","\"","");
    
  652.  
    
  653. 	PropValue = StringIf(bStatic, PropName $ "=" $ Quote $ PropValue $ Quote, Quote $ PropValue $ Quote);
    
  654. 	for (i = 0; i < Members.Length; i++)
    
  655. 	{
    
  656. 		if (DEBUG)
    
  657. 			log(class@"Comparing"@i@PropValue@"to"@Members[i],'RemoveArrayEntry');
    
  658.  
    
  659. 		if (Members[i] ~= PropValue)
    
  660. 			break;
    
  661. 	}
    
  662.  
    
  663. 	if (i < Members.Length)
    
  664. 	{
    
  665. 		if (DEBUG) log(class@"Removing array member"@i$":"$Members[i],'RemoveArrayEntry');
    
  666.  
    
  667. 		// Check if we should restore a previous value
    
  668. 		for (j = 0; j < ConfigMaster(Owner).OriginalValues.Length; j++)
    
  669. 		{
    
  670. 			if (DEBUG)
    
  671. 			{
    
  672. 				log(class@"Checking Backup Value"@j@"class:"$ConfigMaster(Owner).OriginalValues[j].ClassFrom@"against"@string(O.Class),'RemoveArrayEntry');
    
  673. 				log(class@"Checking Backup Value"@j@"Property:"$ConfigMaster(Owner).OriginalValues[j].PropName@"against"@PropName,'RemoveArrayEntry');
    
  674. 			}
    
  675.  
    
  676. 			if (ConfigMaster(Owner).OriginalValues[j].ClassFrom ~= string(O.Class) &&
    
  677. 				ConfigMaster(Owner).OriginalValues[j].PropName ~= PropName )
    
  678. 			{
    
  679. 				RestoreOriginalValue(O, PropName);
    
  680. 				break;
    
  681. 			}
    
  682. 		}
    
  683.  
    
  684. 		if (j < ConfigMaster(Owner).OriginalValues.Length)
    
  685. 			return;
    
  686.  
    
  687. 		Members.Remove(i,1);
    
  688. 	}
    
  689.  
    
  690. 	else return;
    
  691.  
    
  692. 	PropValue = "(" $ Join(Members,",") $ ")";
    
  693. 	if (DEBUG)
    
  694. 		log(class@"Assigning"@PropValue@"to property"@string(O.Class)$"."$PropName,'RemoveArrayEntry');
    
  695. 	O.SetPropertyText(PropName,PropValue);
    
  696. 	O.SaveConfig();
    
  697. 	if (DEBUG)
    
  698. 		log(class@"Returning"@O.GetPropertyText(PropName),'RemoveArrayEntry');
    
  699. }
    
  700.  
    
  701. // Just a function to handle safe object creation
    
  702. protected final function Object GetObjectForEntry(IniEntry ThisEntry)
    
  703. {
    
  704. 	local Object O;
    
  705. 	local class<Object> OClass;
    
  706.  
    
  707. 	if (DEBUG)
    
  708. 		log(class@"Getting"@ThisEntry.ClassFrom@ThisEntry.PropName@ThisEntry.PropValue,'GetObjectForEntry');
    
  709.  
    
  710. 	OClass = class<Object>(DynamicLoadObject(ThisEntry.ClassFrom,class'Class'));
    
  711. 	if (OClass == None)
    
  712. 	{
    
  713. 		Warn("Could not load class"@ThisEntry.ClassFrom);
    
  714. 		return None;
    
  715. 	}
    
  716.  
    
  717. 	O = GetObjectOfClass(OClass);
    
  718. 	if (O == None)
    
  719. 		Warn("Unable to access object for class"@OClass);
    
  720.  
    
  721. 	return O;
    
  722. }
    
  723.  
    
  724. protected final function Object GetObjectOfClass(class<Object> ObjClass)
    
  725. {
    
  726. 	local Object Obj;
    
  727. 	local Actor A;
    
  728.  
    
  729. 	if (DEBUG)
    
  730. 		log(class@"Finding"@ObjClass,'GetObjectOfClass');
    
  731.  
    
  732. 	// Check for GameEngine
    
  733. 	if (ObjClass == class'GameEngine')
    
  734. 		return GE;
    
  735.  
    
  736. 	// First try the easy way
    
  737. 	foreach AllObjects(ObjClass,Obj)
    
  738. 		return Obj;
    
  739.  
    
  740. 	// Object may not be loaded right now, so attempt to load it
    
  741. 	// If actor, spawn it
    
  742. 	if (ClassIsChildOf(ObjClass,class'Actor'))
    
  743. 	{
    
  744. 		A = Spawn(class<Actor>(ObjClass));
    
  745. 		A.GoToState('');
    
  746. 		return A;
    
  747. 	}
    
  748.  
    
  749. 	// if object, new it
    
  750. 	Obj = new(None) ObjClass;
    
  751.  
    
  752. 	// might be property
    
  753. 	if (Obj == None)
    
  754. 		Obj = new(Class) ObjClass;
    
  755.  
    
  756. 	// Don't know if this will even work ?
    
  757. 	if (Obj == None)
    
  758. 		Obj = New(ObjClass.default.Outer) ObjClass;
    
  759.  
    
  760. 	if (DEBUG)
    
  761. 	{
    
  762. 		log(class@"Could not create new object"@ObjClass,'GetObjectOfClass');
    
  763. 		log(class@ObjClass@"outer is"@ObjClass.default.Outer,'GetObjectOfClass');
    
  764. 		log(class@"",'GetObjectOfClass');
    
  765. 	}
    
  766.  
    
  767. 	return Obj;
    
  768. }
    
  769.  
    
  770. protected final function Property GetProperty(Object O, string PropName)
    
  771. {
    
  772. 	local int i;
    
  773. 	local Class ClassOuter;
    
  774. 	local bool classexact, classchild, propn, seenclass;
    
  775.  
    
  776. 	for (i=0;i<Properties.Length;i++)
    
  777. 	{
    
  778. 		seenclass = Class(Properties[i].Outer) == ClassOuter;
    
  779.  
    
  780. 		ClassOuter = Class(Properties[i].Outer);
    
  781. 		if (DEBUGPROPS)
    
  782. 		{
    
  783. 			if (ClassOuter == None)
    
  784. 			{
    
  785. 				log(class@"Property Outer is not a class!",'GetProperty');
    
  786. 				continue;
    
  787. 			}
    
  788.  
    
  789. 			if (!seenclass)
    
  790. 			{
    
  791. 				log(class@"Compare Obj Class"@O.Class@"to"@Properties[i].Outer,'GetProperty');
    
  792. 				if (O.Class==Properties[i].Outer)
    
  793. 					classexact = true;
    
  794. 			}
    
  795.  
    
  796. 			if (!classchild && ClassIsChildOf(O.Class,ClassOuter))
    
  797. 			{
    
  798. 				log(class@"Obj class"@O.Class@"is child of"@ClassOuter,'GetProperty');
    
  799. 				classchild = true;
    
  800. 			}
    
  801.  
    
  802. 			else if (!classchild && ClassIsChildOf(ClassOuter,O.Class))
    
  803. 			{
    
  804. 				log(class@"Obj class"@O.Class@"is parent of"@ClassOuter,'GetProperty');
    
  805. 				classchild = true;
    
  806. 			}
    
  807.  
    
  808. 			if (!propn && classexact)
    
  809. 			{
    
  810. 				log(class@"Compare Name"@PropName@"to"@Properties[i].Name,'GetProperty');
    
  811. 				if (PropName == string(Properties[i].Name))
    
  812. 					propn = true;
    
  813. 			}
    
  814. 		}
    
  815.  
    
  816. 		if ((ClassIsChildOf(O.Class,ClassOuter)||O.Class == Properties[i].Outer||ClassIsChildOf(ClassOuter,O.Class)) && string(Properties[i].Name) == PropName)
    
  817. 		{
    
  818. 			if (DEBUG)
    
  819. 			{
    
  820. 				log(class@"Returning Property"@Properties[i],'GetProperty');
    
  821. 				log(class@"",'GetProperty');
    
  822. 			}
    
  823.  
    
  824. 			return Properties[i];
    
  825. 		}
    
  826. 	}
    
  827.  
    
  828. 	return None;
    
  829. }
    
  830.  
    
  831. protected final function bool PropIsArray(Property P)
    
  832. {
    
  833. 	if (DEBUG)
    
  834. 		log(class@"Checking Property"@P.Outer$"."$P.Name$":"@P.Class,'PropIsArray');
    
  835. 	return P.Class == class'ArrayProperty';
    
  836. }
    
  837.  
    
  838. protected static final function array<string> GenerateArray(string ArrayString)
    
  839. {
    
  840. 	local array<string>	Members;
    
  841. 	local int i;
    
  842. 	local string S;
    
  843.  
    
  844. 	if (ArrayString != "")
    
  845. 	{
    
  846. 		// Remove the array wrapper ( )
    
  847. 		ArrayString = Mid(ArrayString,1,Len(ArrayString)-2);
    
  848.  
    
  849. 		// If string contains internal containers, then have to split differently
    
  850. 		if (Left(ArrayString,1) == "(")
    
  851. 		{
    
  852. 			do {
    
  853. 				do {
    
  854. 					if (Left(ArrayString,1) == ")")
    
  855. 						i--;
    
  856. 					else if (Left(ArrayString,1) == "(")
    
  857. 						i++;
    
  858. 					Eat(S, ArrayString, 1);
    
  859. 				} until (i == 0);
    
  860.  
    
  861. 				Members[Members.Length] = S;
    
  862. 				S = "";
    
  863. 				if (ArrayString != "" && Left(ArrayString,1) == ",")
    
  864. 					ArrayString = Mid(ArrayString,1);
    
  865. 			} until (ArrayString == "");
    
  866. 		}
    
  867.  
    
  868. 		else Split2(ArrayString,",",Members);
    
  869. 	}
    
  870.  
    
  871. 	return Members;
    
  872. }
    
  873.  
    
  874. protected static final function bool NotInPlayInfo(PlayInfo PI, class<Info> NewInfo)
    
  875. {
    
  876. 	local int i;
    
  877. 	if (PI == None)
    
  878. 	{
    
  879. 		Warn("Invalid PlayInfo Object!");
    
  880. 		return false;
    
  881. 	}
    
  882.  
    
  883. 	for (i=0;i<PI.InfoClasses.Length;i++)
    
  884. 	{
    
  885. 		if (PI.InfoClasses[i] == NewInfo)
    
  886. 			return false;
    
  887. 	}
    
  888.  
    
  889. 	return true;
    
  890. }
    
  891.  
    
  892.  
    
  893. //###################################################################
    
  894. //###################################################################
    
  895. //
    
  896. //	Utility Methods
    
  897. //	These are used perform various tedious operations.
    
  898. //
    
  899. // Moves Num elements from Source to Dest
    
  900. static final function Eat(out string Dest, out string Source, int Num)
    
  901. {
    
  902. 	Dest = Dest $ Left(Source, Num);
    
  903. 	Source = Mid(Source, Num);
    
  904. }
    
  905.  
    
  906. static final function string StringIf(bool Condition, string IfTrue, string IfFalse)
    
  907. {
    
  908. 	if (Condition) return IfTrue;
    
  909. 	return IfFalse;
    
  910. }
    
  911.  
    
  912. // Based on AccessControlIni & Object.ReplaceText()
    
  913. static final function string ReplaceTag(string from, string tag, coerce string with)
    
  914. {
    
  915. 	local int i;
    
  916. 	local string t;
    
  917.  
    
  918. 	// InStr() is case-sensitive
    
  919. 	i = InStr(Caps(from), Caps(tag));
    
  920. 	while (i != -1)
    
  921. 	{
    
  922. 		t = t $ Left(from,i) $ with;
    
  923. 		from = mid(from,i+len(tag));
    
  924. 		i = InStr(Caps(from), Caps(tag));
    
  925. 	}
    
  926.  
    
  927. 	t = t $ from;
    
  928. 	return t;
    
  929. }
    
  930.  
    
  931. // Following functions from wUtils103 by El_Muerte[TDS]
    
  932. // Included by permission (copied to avoid package dependancy)
    
  933.  
    
  934. // Shifts an element off a string
    
  935. // example (delim = ' '): 'this is a string' -> 'is a string'
    
  936. // if quotechar = " : '"this is" a string' -> 'a string'
    
  937. static final function string StrShift(out string line, string delim, optional string quotechar)
    
  938. {
    
  939.     local int delimpos, quotepos;
    
  940.     local string result;
    
  941.  
    
  942.     if ( quotechar != "" && Left(line, Len(quotechar)) == quotechar ) {
    
  943.         do {
    
  944.             quotepos = InstrFrom(line, quotechar, quotepos + 1);
    
  945.         } until (quotepos == -1 || quotepos + Len(quotechar) == Len(line)
    
  946.                 || Mid(line, quotepos + len(quotechar), len(delim)) == delim);
    
  947.     }
    
  948.     if ( quotepos != -1 ) {
    
  949.         delimpos = InstrFrom(line, delim, quotepos);
    
  950.     }
    
  951.     else {
    
  952.         delimpos = Instr(line, delim);
    
  953.     }
    
  954.  
    
  955.     if (delimpos == -1)
    
  956.     {
    
  957.         result = line;
    
  958.         line = "";
    
  959.     }
    
  960.     else {
    
  961.         result = Left(line,delimpos);
    
  962.         line = Mid(line,delimpos+len(delim));
    
  963.     }
    
  964.     if ( quotechar != "" && Left(result, Len(quotechar)) == quotechar ) {
    
  965.       result = Mid(result, Len(quotechar), Len(result)-(Len(quotechar)*2));
    
  966.     }
    
  967.     return result;
    
  968. }
    
  969.  
    
  970. // Join the elements of a string array to an array
    
  971. static final function string Join(array< string > ar, optional string delim, optional bool bIgnoreEmpty)
    
  972. {
    
  973.   local string result;
    
  974.   local int i;
    
  975.   for (i = 0; i < ar.length; i++)
    
  976.   {
    
  977.     if (bIgnoreEmpty && ar[i] == "") continue;
    
  978.     if (result != "") result = result$delim;
    
  979.     result = result$ar[i];
    
  980.   }
    
  981.  
    
  982.   return result;
    
  983. }
    
  984.  
    
  985. // Fixed split method
    
  986. // no problems when it starts with a delim
    
  987. // no problems with ending spaces
    
  988. // delim can be a string
    
  989. static final function int Split2(coerce string src, string delim, out array<string> parts, optional bool ignoreEmpty, optional string quotechar)
    
  990. {
    
  991.   local string temp;
    
  992.   Parts.Remove(0, Parts.Length);
    
  993.   if (delim == "" || Src == "" ) return 0;
    
  994.   while (src != "")
    
  995.   {
    
  996.     temp = StrShift(src, delim, quotechar);
    
  997.     if (temp == "")
    
  998.     {
    
  999.       if (!ignoreEmpty)
    
  1000.       {
    
  1001.         parts.length = parts.length+1;
    
  1002.         parts[parts.length-1] = temp;
    
  1003.       }
    
  1004.     }
    
  1005.     else {
    
  1006.       parts.length = parts.length+1;
    
  1007.       parts[parts.length-1] = temp;
    
  1008.     }
    
  1009.   }
    
  1010.   return parts.length;
    
  1011. }
    
  1012.  
    
  1013. // InStr starting from an offset
    
  1014. static final function int InStrFrom(coerce string StrText, coerce string StrPart, optional int OffsetStart)
    
  1015. {
    
  1016.   local int OffsetPart;
    
  1017.  
    
  1018.   OffsetPart = InStr(Mid(StrText, OffsetStart), StrPart);
    
  1019.   if (OffsetPart >= 0)
    
  1020.     OffsetPart += OffsetStart;
    
  1021.   return OffsetPart;
    
  1022. }
    

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

Personal tools