From 36aed1a2d368630c1e29d858f99a79403958d7b0 Mon Sep 17 00:00:00 2001 From: Anton Tarasenko Date: Wed, 8 Mar 2023 04:48:12 +0700 Subject: [PATCH] Change how map lists work This patch enables support of per-game mode lists --- sources/AcediaLauncherMut.uc | 1 - sources/GameModes/BaseGameMode.uc | 5 + sources/StartUp.uc | 1 + sources/VotingHandlerAdapter.uc | 153 +++++++++++++++++++++++------- 4 files changed, 125 insertions(+), 35 deletions(-) diff --git a/sources/AcediaLauncherMut.uc b/sources/AcediaLauncherMut.uc index 9a36456..05c71d5 100644 --- a/sources/AcediaLauncherMut.uc +++ b/sources/AcediaLauncherMut.uc @@ -46,7 +46,6 @@ simulated function PreBeginPlay() } if (votingAdapter != none) { votingAdapter.InjectIntoVotingHandler(); - votingAdapter.TrySetupMapList(); } SetupMutatorSignals(); } diff --git a/sources/GameModes/BaseGameMode.uc b/sources/GameModes/BaseGameMode.uc index 7b45f1e..533fe51 100644 --- a/sources/GameModes/BaseGameMode.uc +++ b/sources/GameModes/BaseGameMode.uc @@ -431,6 +431,11 @@ public function array GetIncludedMutators() return StringToTextArray(validatedMutators); } +public function array GetIncludedMapLists() +{ + return StringToTextArray(includeMaps); +} + defaultproperties { configName = "AcediaGameModes" diff --git a/sources/StartUp.uc b/sources/StartUp.uc index 184603c..2210404 100644 --- a/sources/StartUp.uc +++ b/sources/StartUp.uc @@ -61,6 +61,7 @@ private function InitializeServer() _ = class'Global'.static.GetInstance(); _server = class'ServerGlobal'.static.GetInstance(); class'ServerLevelCore'.static.CreateLevelCore(self); + class'MapList'.static.Initialize(); for (i = 0; i < class'Packages'.default.package.length; i += 1) { _.environment.RegisterPackage_S(class'Packages'.default.package[i]); } diff --git a/sources/VotingHandlerAdapter.uc b/sources/VotingHandlerAdapter.uc index b892455..b2936c7 100644 --- a/sources/VotingHandlerAdapter.uc +++ b/sources/VotingHandlerAdapter.uc @@ -66,6 +66,9 @@ var private NativeActorRef votingHandlerReference; // otherwise Acedia will alter its config var private array backupVotingHandlerConfig; +// Maps map pseudonims we've used in voting handler to real map names +var private HashTable pseudonimToMap; + // Setting value of this flag to `true` indicates that map switching just // occurred and we need to recover some information from the previous map. var private config bool isServerTraveling; @@ -88,7 +91,7 @@ var private const array normalSynonyms; var private const array longSynonyms; var private LoggerAPI.Definition fatNoXVotingHandler, fatBadGameConfigIndexVH; -var private LoggerAPI.Definition fatBadGameConfigIndexAdapter; +var private LoggerAPI.Definition fatBadGameConfigIndexAdapter, warnMissingMapList; protected function Finalizer() { @@ -103,10 +106,10 @@ protected function Finalizer() * Backup of replaced configs is made internally, so that they can be restored * on map change. */ -// TODO ADD ME! public final function InjectIntoVotingHandler() { local int i; + local string nextGameModePrefix; local GameMode nextGameMode; local XVotingHandler votingHandler; local array newVotingHandlerConfig; @@ -121,13 +124,17 @@ public final function InjectIntoVotingHandler() _.logger.Auto(fatNoXVotingHandler); return; } + pseudonimToMap = _.collections.EmptyHashTable(); votingHandlerReference = _server.unreal.ActorRef(votingHandler); availableGameModes = class'GameMode'.static.AvailableConfigs(); - for (i = 0; i < availableGameModes.length; i += 1) - { + votingHandler.mapCount = 0; + votingHandler.mapList.length = 0; + for (i = 0; i < availableGameModes.length; i += 1) { + nextGameModePrefix = "GM" $ i; nextGameMode = GameMode(class'GameMode'.static .GetConfigInstance(availableGameModes[i])); - newVotingHandlerConfig[i] = BuildVotingHandlerConfig(nextGameMode); + newVotingHandlerConfig[i] = BuildVotingHandlerConfig(nextGameMode, nextGameModePrefix); + LoadGameModeMaps(nextGameMode, nextGameModePrefix, votingHandler); // Setup proper game mode index if (availableGameModes[i].ToString() == targetGameMode) { votingHandler.currentGameConfig = i; @@ -140,57 +147,134 @@ public final function InjectIntoVotingHandler() votingHandler.gameConfig = newVotingHandlerConfig; } -public function TrySetupMapList() { - local Text currentConfigName; - local MapList currentConfig; +private function LoadGameModeMaps( + GameMode gameMode, + string gameModePrefix, + XVotingHandler votingHandler +) { + local int i; + local ArrayList gameModeMaps; + local Text mapNameReal, mapNamePseudonim; + local VotingHandler.MapHistoryInfo nextMapInfo; + local VotingHandler.MapVoteMapList nextRecord; + local array newMaps; + + nextRecord.bEnabled = true; + gameModeMaps = GetAllGameModeMaps(gameMode); + for (i = 0; i < gameModeMaps.GetLength(); i += 1) { + // Make a pseudonim to map connection + mapNameReal = gameModeMaps.GetText(i); + mapNamePseudonim = MakeMapPseudonim(mapNameReal, gameModePrefix); + pseudonimToMap.SetItem(mapNamePseudonim, mapNameReal); + // Setup `VotingHandler.MapVoteMapList` struct for next map + nextRecord.mapName = mapNamePseudonim.ToString(); + if (votingHandler.history != none) { + nextMapInfo = votingHandler.history.GetMapHistory(nextRecord.mapName); + nextRecord.playCount = nextMapInfo.p; + nextRecord.sequence = nextMapInfo.s; + } else { + nextRecord.playCount = 0; + nextRecord.sequence = 0; + } + newMaps[newMaps.length] = nextRecord; + } + AppendMapsIntoHandler(votingHandler, newMaps); +} - if (currentConfigName != none) { - currentConfig = MapList(class'MapList'.static.GetConfigInstance(currentConfigName)); +private function Text MakeMapPseudonim(Text realName, string gameModePrefix) { + local Parser parser; + local MutableText prefix, nameBody; + local MutableText result; + + result = _.text.FromStringM(gameModePrefix); + result.Append(P("-")); + parser = realName.Parse(); + parser.MUntil(prefix, _.text.GetCharacter("-")); + parser.Match(P("-")); + if (parser.Ok()) { + nameBody = parser.GetRemainderM(); + result.Append(nameBody); } - if (currentConfig != none) { - ReplaceHandlerMaps(XVotingHandler(votingHandlerReference.Get()), currentConfig.map); - } else { - warn("currentConfig is none! Aborting!"); + else { + result.Append(realName); } - _.memory.Free(currentConfig); - _.memory.Free(currentConfigName); - _.memory.Free(mapListFeature); + _.memory.Free(nameBody); + _.memory.Free(prefix); + _.memory.Free(parser); + return result.IntoText(); } -// TODO add map reps and play count from KFMapVoteHistory.ini -public function ReplaceHandlerMaps(XVotingHandler votingHandler, array maps) { - local VotingHandler.MapVoteMapList nextRecord; - local array recordArray; +private function ArrayList GetAllGameModeMaps(GameMode gameMode) { + local int i, j; + local HashTable uniqueMapSet; + local ArrayList result; + local array usedMapLists; + local MapList nextMapConfig; + local array nextMapArray; + local Text nextMapName, lowerMapName; + + uniqueMapSet = _.collections.EmptyHashTable(); // to quickly make sure we add each map only once + result = _.collections.EmptyArrayList(); + usedMapLists = gameMode.GetIncludedMapLists(); + for (i = 0; i < usedMapLists.length; i += 1) { + // Get maps from `MapList` config + nextMapConfig = MapList(class'MapList'.static.GetConfigInstance(usedMapLists[i])); + nextMapArray.length = 0; + if (nextMapConfig != none) { + nextMapArray = nextMapConfig.map; + } else { + _.logger.Auto(warnMissingMapList).Arg(usedMapLists[i].Copy()); + } + _.memory.Free(nextMapConfig); + // Add maps we haven't yet added from other lists + for (j = 0; j < nextMapArray.length; j += 1) { + nextMapName = _.text.FromString(nextMapArray[j]); + lowerMapName = nextMapName.LowerCopy(); + if (!uniqueMapSet.HasKey(lowerMapName)) { + uniqueMapSet.SetItem(lowerMapName, none); + result.AddItem(nextMapName); + } + _.memory.Free(lowerMapName); + _.memory.Free(nextMapName); + } + } + _.memory.Free(uniqueMapSet); + _.memory.FreeMany(usedMapLists); + return result; +} + +private function AppendMapsIntoHandler( + XVotingHandler votingHandler, + array newMaps +) { local int i; + local array mapListCopy; if (votingHandler == none) { warn("votingHandler is none!"); return; } - if (maps.length == 0) { - warn("maps.length is 0!"); + if (newMaps.length == 0) { + warn("newMaps.length is 0!"); return; } - recordArray = votingHandler.mapList; - warn(">>> recordArray.length =" $ recordArray.length); - recordArray.length = maps.length; - votingHandler.mapCount = maps.length; - nextRecord.bEnabled = true; - for (i = 0; i < maps.length; i += 1) { - nextRecord.mapName = maps[i]; - recordArray[i] = nextRecord; + mapListCopy = votingHandler.mapList; + for (i = 0; i < newMaps.length; i += 1) { + mapListCopy[mapListCopy.length] = newMaps[i]; } - votingHandler.mapList = recordArray; + votingHandler.mapList = mapListCopy; + votingHandler.mapCount += newMaps.length; } private function VotingHandler.MapVoteGameConfig BuildVotingHandlerConfig( - GameMode gameMode) + GameMode gameMode, + string gameModePrefix) { local MutableText nextColoredName; local VotingHandler.MapVoteGameConfig result; result.gameClass = _.text.IntoString(gameMode.GetGameTypeClass()); - result.prefix = _.text.IntoString(gameMode.GetMapPrefix()); + result.prefix = gameModePrefix $ "-"; nextColoredName = gameMode .GetTitle() .IntoMutableText() @@ -404,6 +488,7 @@ defaultproperties normalSynonyms(1) = "medium" normalSynonyms(2) = "regular" longSynonyms(0) = "long" + warnMissingMapList = (l=LOG_Warning,m="Cannot find map list `%1`.") fatNoXVotingHandler = (l=LOG_Fatal,m="`XVotingHandler` class is missing. Make sure your server setup supports Acedia's game modes (by used voting handler derived from `XVotingHandler`).") fatBadGameConfigIndexVH = (l=LOG_Fatal,m="`XVotingHandler`'s `currentGameConfig` variable value of %1 is out-of-bounds for `XVotingHandler.gameConfig` of length %2. Report this issue.") fatBadGameConfigIndexAdapter = (l=LOG_Fatal,m="`XVotingHandler`'s `currentGameConfig` variable value of %1 is out-of-bounds for `VHAdapter` of length %2. Report this issue.")