Refactor GameSpeed setting

*Remove internal GameSpeed defaults
 Enforce setting values explicitly all the time
 Require definition of a DefaultSpeed

*Remove Global.Timestep default

*Remove the hacky Timestep/OrderLatency setting via LobbyInfo

*Fix shellmaps ignoring mod-defined gamespeeds

*Make DateTimeGlobal use the MapOptions gamespeed
This commit is contained in:
reaperrr
2021-04-02 14:11:45 +02:00
committed by Paul Chote
parent fe129956bb
commit 1a9dfc0893
22 changed files with 214 additions and 205 deletions

View File

@@ -162,8 +162,12 @@ namespace OpenRA
using (new PerfTimer("PrepareMap"))
map = ModData.PrepareMap(mapUID);
using (new PerfTimer("NewWorld"))
{
OrderManager.World = new World(ModData, map, OrderManager, type);
OrderManager.FramesAhead = OrderManager.World.OrderLatency;
}
OrderManager.World.GameOver += FinishBenchmark;
@@ -581,7 +585,11 @@ namespace OpenRA
Cursor.Tick();
}
var worldTimestep = world == null ? Ui.Timestep : world.IsLoadingGameSave ? 1 : world.Timestep;
var worldTimestep = world == null ? Ui.Timestep :
world.IsLoadingGameSave ? 1 :
world.IsReplay ? world.ReplayTimestep :
world.Timestep;
var worldTickDelta = tick - orderManager.LastTickTime;
if (worldTimestep != 0 && worldTickDelta >= worldTimestep)
{
@@ -776,9 +784,14 @@ namespace OpenRA
while (state == RunStatus.Running)
{
// Ideal time between logic updates. Timestep = 0 means the game is paused
// but we still call LogicTick() because it handles pausing internally.
var logicInterval = worldRenderer != null && worldRenderer.World.Timestep != 0 ? worldRenderer.World.Timestep : Ui.Timestep;
var logicInterval = Ui.Timestep;
var logicWorld = worldRenderer?.World;
// ReplayTimestep = 0 means the replay is paused: we need to keep logicInterval as UI.Timestep to avoid breakage
if (logicWorld != null && !(logicWorld.IsReplay && logicWorld.ReplayTimestep == 0))
logicInterval = logicWorld.IsLoadingGameSave ? 1 :
logicWorld.IsReplay ? logicWorld.ReplayTimestep :
logicWorld.Timestep;
// Ideal time between screen updates
var maxFramerate = Settings.Graphics.CapFramerate ? Settings.Graphics.MaxFramerate.Clamp(1, 1000) : 1000;

View File

@@ -10,26 +10,49 @@
#endregion
using System.Collections.Generic;
using System.Linq;
namespace OpenRA
{
public class GameSpeed
{
public readonly string Name = "Default";
public readonly int Timestep = 40;
public readonly int OrderLatency = 3;
[FieldLoader.Require]
public readonly string Name;
[FieldLoader.Require]
public readonly int Timestep;
[FieldLoader.Require]
public readonly int OrderLatency;
}
public class GameSpeeds : IGlobalModData
{
[FieldLoader.Require]
public readonly string DefaultSpeed;
[FieldLoader.LoadUsing(nameof(LoadSpeeds))]
public readonly Dictionary<string, GameSpeed> Speeds;
static object LoadSpeeds(MiniYaml y)
{
var ret = new Dictionary<string, GameSpeed>();
foreach (var node in y.Nodes)
ret.Add(node.Key, FieldLoader.Load<GameSpeed>(node.Value));
var speedsNode = y.Nodes.FirstOrDefault(n => n.Key == "Speeds");
if (speedsNode == null)
throw new YamlException("Error parsing GameSpeeds: Missing Speeds node!");
foreach (var node in speedsNode.Value.Nodes)
{
try
{
ret.Add(node.Key, FieldLoader.Load<GameSpeed>(node.Value));
}
catch (FieldLoader.MissingFieldsException e)
{
var label = e.Missing.Length > 1 ? "Required properties missing" : "Required property missing";
throw new YamlException("Error parsing GameSpeed {0}: {1}: {2}".F(node.Key, label, e.Missing.JoinWith(", ")));
}
}
return ret;
}

View File

@@ -27,7 +27,10 @@ namespace OpenRA.Network
Queue<Chunk> chunks = new Queue<Chunk>();
List<byte[]> sync = new List<byte[]>();
readonly int orderLatency;
int ordersFrame;
Dictionary<int, int> lastClientsFrame = new Dictionary<int, int>();
public int LocalClientId => -1;
@@ -122,7 +125,10 @@ namespace OpenRA.Network
}
}
ordersFrame = LobbyInfo.GlobalSettings.OrderLatency;
var gameSpeeds = Game.ModData.Manifest.Get<GameSpeeds>();
var gameSpeedName = LobbyInfo.GlobalSettings.OptionOrDefault("gamespeed", gameSpeeds.DefaultSpeed);
orderLatency = gameSpeeds.Speeds[gameSpeedName].OrderLatency;
ordersFrame = orderLatency;
}
// Do nothing: ignore locally generated orders
@@ -137,7 +143,7 @@ namespace OpenRA.Network
sync.Add(ms.GetBuffer());
// Store the current frame so Receive() can return the next chunk of orders.
ordersFrame = frame + LobbyInfo.GlobalSettings.OrderLatency;
ordersFrame = frame + orderLatency;
}
public void Receive(Action<int, byte[]> packetFn)

View File

@@ -222,8 +222,6 @@ namespace OpenRA.Network
{
public string ServerName;
public string Map;
public int Timestep = 40;
public int OrderLatency = 3; // net tick frames (x 120 = ms)
public int RandomSeed = 0;
public bool AllowSpectators = true;
public string GameUid;

View File

@@ -254,7 +254,6 @@ namespace OpenRA.Network
case "SyncInfo":
{
orderManager.LobbyInfo = Session.Deserialize(order.TargetString);
SetOrderLag(orderManager);
Game.SyncLobbyInfo();
break;
}
@@ -304,7 +303,6 @@ namespace OpenRA.Network
orderManager.LobbyInfo.GlobalSettings = Session.Global.Deserialize(node.Value);
}
SetOrderLag(orderManager);
Game.SyncLobbyInfo();
break;
}
@@ -354,14 +352,5 @@ namespace OpenRA.Network
if (world.OrderValidators.All(vo => vo.OrderValidation(orderManager, world, clientId, order)))
order.Subject.ResolveOrder(order);
}
static void SetOrderLag(OrderManager o)
{
if (o.FramesAhead != o.LobbyInfo.GlobalSettings.OrderLatency && !o.GameStarted)
{
o.FramesAhead = o.LobbyInfo.GlobalSettings.OrderLatency;
Log.Write("server", "Order lag is now {0} frames.", o.LobbyInfo.GlobalSettings.OrderLatency);
}
}
}
}

View File

@@ -1200,10 +1200,6 @@ namespace OpenRA.Server
DropClient(c);
}
// HACK: Turn down the latency if there is only one real player
if (LobbyInfo.NonBotClients.Count() == 1)
LobbyInfo.GlobalSettings.OrderLatency = 1;
// Enable game saves for singleplayer missions only
// TODO: Enable for multiplayer (non-dedicated servers only) once the lobby UI has been created
LobbyInfo.GlobalSettings.GameSavesEnabled = Type != ServerType.Dedicated && LobbyInfo.NonBotClients.Count() == 1;

View File

@@ -36,7 +36,12 @@ namespace OpenRA
readonly Queue<Action<World>> frameEndActions = new Queue<Action<World>>();
public int Timestep;
public readonly GameSpeed GameSpeed;
public readonly int Timestep;
public readonly int OrderLatency;
public int ReplayTimestep;
internal readonly OrderManager OrderManager;
public Session LobbyInfo => OrderManager.LobbyInfo;
@@ -180,7 +185,18 @@ namespace OpenRA
OrderManager = orderManager;
orderGenerator = new UnitOrderGenerator();
Map = map;
Timestep = orderManager.LobbyInfo.GlobalSettings.Timestep;
var gameSpeeds = modData.Manifest.Get<GameSpeeds>();
var gameSpeedName = orderManager.LobbyInfo.GlobalSettings.OptionOrDefault("gamespeed", gameSpeeds.DefaultSpeed);
GameSpeed = gameSpeeds.Speeds[gameSpeedName];
Timestep = ReplayTimestep = GameSpeed.Timestep;
OrderLatency = GameSpeed.OrderLatency;
// HACK: Turn down the latency if there is only one real player/spectator
if (orderManager.LobbyInfo.NonBotClients.Count() == 1)
OrderLatency = 1;
SharedRandom = new MersenneTwister(orderManager.LobbyInfo.GlobalSettings.RandomSeed);
LocalRandom = new MersenneTwister();