Adds support for a map rotation system. (#7162)
* Adds support for a map rotation system. It is now the default way of selecting a map, map votes have been disabled. * whoops * Randomize the map it starts off with, too. (it'd pick bagel every time otherwise) * Address review * remove knight from rotation due to it being an unmaintained map. * minor cleanup
This commit is contained in:
@@ -71,7 +71,7 @@ namespace Content.Server.GameTicking
|
||||
DefaultMap = _mapManager.CreateMap();
|
||||
_mapManager.AddUninitializedMap(DefaultMap);
|
||||
var startTime = _gameTiming.RealTime;
|
||||
var maps = new List<GameMapPrototype>() { _gameMapManager.GetSelectedMapChecked(true) };
|
||||
var maps = new List<GameMapPrototype>() { _gameMapManager.GetSelectedMapChecked(true, true) };
|
||||
|
||||
// Let game rules dictate what maps we should load.
|
||||
RaiseLocalEvent(new LoadingMapsEvent(maps));
|
||||
|
||||
@@ -22,8 +22,11 @@ public sealed class GameMapManager : IGameMapManager
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||
|
||||
private readonly Queue<string> _previousMaps = new Queue<string>();
|
||||
private GameMapPrototype _currentMap = default!;
|
||||
private bool _currentMapForced;
|
||||
private bool _mapRotationEnabled;
|
||||
private int _mapQueueDepth = 1;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
@@ -35,6 +38,25 @@ public sealed class GameMapManager : IGameMapManager
|
||||
throw new ArgumentException($"Unknown map prototype {value} was selected!");
|
||||
}, true);
|
||||
_configurationManager.OnValueChanged(CCVars.GameMapForced, value => _currentMapForced = value, true);
|
||||
_configurationManager.OnValueChanged(CCVars.GameMapRotation, value => _mapRotationEnabled = value, true);
|
||||
_configurationManager.OnValueChanged(CCVars.GameMapMemoryDepth, value =>
|
||||
{
|
||||
_mapQueueDepth = value;
|
||||
// Drain excess.
|
||||
while (_previousMaps.Count > _mapQueueDepth)
|
||||
{
|
||||
_previousMaps.Dequeue();
|
||||
}
|
||||
}, true);
|
||||
|
||||
var maps = AllVotableMaps().ToArray();
|
||||
_random.Shuffle(maps);
|
||||
foreach (var map in maps)
|
||||
{
|
||||
if (_previousMaps.Count >= _mapQueueDepth)
|
||||
break;
|
||||
_previousMaps.Enqueue(map.ID);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<GameMapPrototype> CurrentlyEligibleMaps()
|
||||
@@ -75,17 +97,18 @@ public sealed class GameMapManager : IGameMapManager
|
||||
public void SelectRandomMap()
|
||||
{
|
||||
var maps = CurrentlyEligibleMaps().ToList();
|
||||
_random.Shuffle(maps);
|
||||
_currentMap = maps[0];
|
||||
_currentMap = _random.Pick(maps);
|
||||
_currentMapForced = false;
|
||||
}
|
||||
|
||||
public GameMapPrototype GetSelectedMap()
|
||||
{
|
||||
return _currentMap;
|
||||
if (!_mapRotationEnabled || _currentMapForced)
|
||||
return _currentMap;
|
||||
return SelectMapInQueue() ?? CurrentlyEligibleMaps().First();
|
||||
}
|
||||
|
||||
public GameMapPrototype GetSelectedMapChecked(bool loud = false)
|
||||
public GameMapPrototype GetSelectedMapChecked(bool loud = false, bool markAsPlayed = false)
|
||||
{
|
||||
if (!_currentMapForced && !IsMapEligible(GetSelectedMap()))
|
||||
{
|
||||
@@ -100,7 +123,11 @@ public sealed class GameMapManager : IGameMapManager
|
||||
}
|
||||
}
|
||||
|
||||
return GetSelectedMap();
|
||||
var map = GetSelectedMap();
|
||||
|
||||
if (markAsPlayed)
|
||||
_previousMaps.Enqueue(map.ID);
|
||||
return map;
|
||||
}
|
||||
|
||||
public bool CheckMapExists(string gameMap)
|
||||
@@ -127,4 +154,39 @@ public sealed class GameMapManager : IGameMapManager
|
||||
else
|
||||
return gameMap.MapName;
|
||||
}
|
||||
|
||||
public int GetMapQueuePriority(string gameMapProtoName)
|
||||
{
|
||||
var i = 0;
|
||||
foreach (var map in _previousMaps.Reverse())
|
||||
{
|
||||
if (map == gameMapProtoName)
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
|
||||
return _mapQueueDepth;
|
||||
}
|
||||
|
||||
public GameMapPrototype? SelectMapInQueue()
|
||||
{
|
||||
var eligible = CurrentlyEligibleMaps()
|
||||
.Where(x => x.Votable)
|
||||
.Select(x => (proto: x, weight: GetMapQueuePriority(x.ID)))
|
||||
.OrderByDescending(x => x.weight).ToArray();
|
||||
if (eligible.Length is 0)
|
||||
return null;
|
||||
|
||||
var weight = eligible[0].weight;
|
||||
return eligible.Where(x => x.Item2 == weight).OrderBy(x => x.proto.ID).First().proto;
|
||||
}
|
||||
|
||||
private void EnqueueMap(string mapProtoName)
|
||||
{
|
||||
_previousMaps.Enqueue(mapProtoName);
|
||||
while (_previousMaps.Count > _mapQueueDepth)
|
||||
{
|
||||
_previousMaps.Dequeue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public interface IGameMapManager
|
||||
/// Gets the currently selected map, double-checking if it can be used.
|
||||
/// </summary>
|
||||
/// <returns>selected map</returns>
|
||||
GameMapPrototype GetSelectedMapChecked(bool loud = false);
|
||||
GameMapPrototype GetSelectedMapChecked(bool loud = false, bool markAsPlayed = false);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the given map exists
|
||||
|
||||
@@ -126,6 +126,19 @@ namespace Content.Shared.CCVar
|
||||
public static readonly CVarDef<bool>
|
||||
GameMapForced = CVarDef.Create("game.mapforced", false, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// The depth of the queue used to calculate which map is next in rotation.
|
||||
/// This is how long the game "remembers" that some map was put in play. Default is 16 rounds.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<int>
|
||||
GameMapMemoryDepth = CVarDef.Create("game.map_memory_depth", 16, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// Is map rotation enabled?
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool>
|
||||
GameMapRotation = CVarDef.Create<bool>("game.map_rotation", true, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// Whether a random position offset will be applied to the station on roundstart.
|
||||
/// </summary>
|
||||
@@ -562,7 +575,7 @@ namespace Content.Shared.CCVar
|
||||
/// See vote.enabled, but specific to map votes
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> VoteMapEnabled =
|
||||
CVarDef.Create("vote.map_enabled", true, CVar.SERVERONLY);
|
||||
CVarDef.Create("vote.map_enabled", false, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// The required ratio of the server that must agree for a restart round vote to go through.
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
!type:NanotrasenNameGenerator
|
||||
prefixCreator: '14'
|
||||
mapPath: /Maps/knightship.yml
|
||||
votable: false
|
||||
minPlayers: 0
|
||||
maxPlayers: 8
|
||||
overflowJobs: []
|
||||
|
||||
Reference in New Issue
Block a user