diff --git a/sources/MapList/MapTool.uc b/sources/MapList/MapTool.uc
new file mode 100644
index 0000000..a1d8dc8
--- /dev/null
+++ b/sources/MapList/MapTool.uc
@@ -0,0 +1,187 @@
+/**
+ * Copyright 2023 Anton Tarasenko
+ *------------------------------------------------------------------------------
+ * This file is part of Acedia.
+ *
+ * Acedia is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Acedia is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Acedia. If not, see .
+ */
+class MapTool extends AcediaObject;
+
+// Finding voting handler is not cheap, so only do it once and then store it.
+var private NativeActorRef votingHandlerReference;
+// Maps map pseudonims we've used in voting handler to real map names
+var private HashTable pseudonimToMap;
+var private array outputMapList;
+var private int gameModesSeen;
+
+protected function Constructor() {
+ pseudonimToMap = _.collections.EmptyHashTable();
+}
+
+protected function Finalizer() {
+ _.memory.Free(votingHandlerReference);
+ _.memory.Free(pseudonimToMap);
+ votingHandlerReference = none;
+ pseudonimToMap = none;
+ outputMapList.length = 0;
+ gameModesSeen = 0;
+}
+
+public function bool Initialize(NativeActorRef initVotingHandlerReference) {
+ if (initVotingHandlerReference == none) return false;
+ if (XVotingHandler(initVotingHandlerReference.Get()) == none) return false;
+
+ initVotingHandlerReference.NewRef();
+ votingHandlerReference = initVotingHandlerReference;
+ return true;
+}
+
+public function string LoadGameModeMaps(GameMode gameMode) {
+ local int i;
+ local XVotingHandler votingHandler;
+ local ArrayList gameModeMaps;
+ local Text mapNameReal, mapNamePseudonim;
+ local VotingHandler.MapHistoryInfo nextMapInfo;
+ local VotingHandler.MapVoteMapList nextRecord;
+ local array newMaps;
+ local string gameModePrefix;
+
+ votingHandler = GetVotingHandler();
+ if (votingHandler == none) {
+ return "!!!";
+ }
+ gameModePrefix = ("KF" $ gameModesSeen);
+ 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(mapNameReal.ToString());
+ nextRecord.playCount = nextMapInfo.p;
+ nextRecord.sequence = nextMapInfo.s;
+ } else {
+ nextRecord.playCount = 0;
+ nextRecord.sequence = 0;
+ }
+ newMaps[newMaps.length] = nextRecord;
+ }
+ AppendMapsIntoHandler(newMaps);
+ gameModesSeen += 1;
+ return gameModePrefix;
+}
+
+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);
+ }
+ else {
+ result.Append(realName);
+ }
+ _.memory.Free(nameBody);
+ _.memory.Free(prefix);
+ _.memory.Free(parser);
+ return result.IntoText();
+}
+
+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(array newMaps) {
+ local int i;
+ local XVotingHandler votingHandler;
+
+ votingHandler = GetVotingHandler();
+ if (votingHandler == none) {
+ warn("votingHandler is none!");
+ return;
+ }
+ if (newMaps.length == 0) {
+ warn("newMaps.length is 0!");
+ return;
+ }
+ for (i = 0; i < newMaps.length; i += 1) {
+ outputMapList[outputMapList.length] = newMaps[i];
+ }
+}
+
+public final function InjectMaps() {
+ local XVotingHandler votingHandler;
+
+ votingHandler = GetVotingHandler();
+ if (votingHandler != none) {
+ votingHandler.mapList = outputMapList;
+ votingHandler.mapCount = outputMapList.length;
+ }
+}
+
+private function XVotingHandler GetVotingHandler() {
+ if (votingHandlerReference != none) {
+ return XVotingHandler(votingHandlerReference.Get());
+ }
+ return none;
+}
+
+defaultproperties {
+}
\ No newline at end of file
diff --git a/sources/VotingHandlerAdapter.uc b/sources/VotingHandlerAdapter.uc
index b2936c7..e338685 100644
--- a/sources/VotingHandlerAdapter.uc
+++ b/sources/VotingHandlerAdapter.uc
@@ -66,9 +66,6 @@ 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;
@@ -113,6 +110,7 @@ public final function InjectIntoVotingHandler()
local GameMode nextGameMode;
local XVotingHandler votingHandler;
local array newVotingHandlerConfig;
+ local MapTool mapTool;
if (votingHandlerReference != none) {
return;
@@ -124,17 +122,17 @@ public final function InjectIntoVotingHandler()
_.logger.Auto(fatNoXVotingHandler);
return;
}
- pseudonimToMap = _.collections.EmptyHashTable();
votingHandlerReference = _server.unreal.ActorRef(votingHandler);
+ mapTool = MapTool(_.memory.Allocate(class'MapTool'));
+ mapTool.Initialize(votingHandlerReference); //TODO check return value
availableGameModes = class'GameMode'.static.AvailableConfigs();
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]));
+ nextGameModePrefix = mapTool.LoadGameModeMaps(nextGameMode);
newVotingHandlerConfig[i] = BuildVotingHandlerConfig(nextGameMode, nextGameModePrefix);
- LoadGameModeMaps(nextGameMode, nextGameModePrefix, votingHandler);
// Setup proper game mode index
if (availableGameModes[i].ToString() == targetGameMode) {
votingHandler.currentGameConfig = i;
@@ -142,128 +140,12 @@ public final function InjectIntoVotingHandler()
// Report omitted mutators / server options
nextGameMode.ReportBadMutatorNames();
nextGameMode.ReportBadOptions();
+ _.memory.Free(nextGameMode);
}
backupVotingHandlerConfig = votingHandler.gameConfig;
votingHandler.gameConfig = newVotingHandlerConfig;
-}
-
-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);
-}
-
-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);
- }
- else {
- result.Append(realName);
- }
- _.memory.Free(nameBody);
- _.memory.Free(prefix);
- _.memory.Free(parser);
- return result.IntoText();
-}
-
-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 (newMaps.length == 0) {
- warn("newMaps.length is 0!");
- return;
- }
- mapListCopy = votingHandler.mapList;
- for (i = 0; i < newMaps.length; i += 1) {
- mapListCopy[mapListCopy.length] = newMaps[i];
- }
- votingHandler.mapList = mapListCopy;
- votingHandler.mapCount += newMaps.length;
+ mapTool.InjectMaps();
+ _.memory.Free(mapTool);
}
private function VotingHandler.MapVoteGameConfig BuildVotingHandlerConfig(