using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Player;
+using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.UnitTesting;
public TestMapData? TestMap;
private List<NetUserId> _modifiedProfiles = new();
+ private int _nextServerSeed;
+ private int _nextClientSeed;
+
+ public int ServerSeed;
+ public int ClientSeed;
+
public RobustIntegrationTest.ServerIntegrationInstance Server { get; private set; } = default!;
public RobustIntegrationTest.ClientIntegrationInstance Client { get; private set; } = default!;
await Server.WaitPost(() => gameTicker.RestartRound());
}
- if (settings.ShouldBeConnected)
+ // Always initially connect clients to generate an initial random set of preferences/profiles.
+ // This is to try and prevent issues where if the first test that connects the client is consistently some test
+ // that uses a fixed seed, it would effectively prevent it from beingrandomized.
+
+ Client.SetConnectTarget(Server);
+ await Client.WaitIdleAsync();
+ var netMgr = Client.ResolveDependency<IClientNetManager>();
+ await Client.WaitPost(() => netMgr.ClientConnect(null!, 0, null!));
+ await ReallyBeIdle(10);
+ await Client.WaitRunTicks(1);
+
+ if (!settings.ShouldBeConnected)
{
- Client.SetConnectTarget(Server);
- await Client.WaitIdleAsync();
- var netMgr = Client.ResolveDependency<IClientNetManager>();
-
- await Client.WaitPost(() =>
- {
- if (!netMgr.IsConnected)
- {
- netMgr.ClientConnect(null!, 0, null!);
- }
- });
+ await Client.WaitPost(() => netMgr.ClientDisconnect("Initial disconnect"));
await ReallyBeIdle(10);
- await Client.WaitRunTicks(1);
}
+
+ var cRand = Client.ResolveDependency<IRobustRandom>();
+ var sRand = Server.ResolveDependency<IRobustRandom>();
+ _nextClientSeed = cRand.Next();
+ _nextServerSeed = sRand.Next();
}
public void Kill()
CleanDisposed = 2,
Dead = 3,
}
+
+ public void SetupSeed()
+ {
+ var sRand = Server.ResolveDependency<IRobustRandom>();
+ if (Settings.ServerSeed is { } severSeed)
+ {
+ ServerSeed = severSeed;
+ sRand.SetSeed(ServerSeed);
+ }
+ else
+ {
+ ServerSeed = _nextServerSeed;
+ sRand.SetSeed(ServerSeed);
+ _nextServerSeed = sRand.Next();
+ }
+
+ var cRand = Client.ResolveDependency<IRobustRandom>();
+ if (Settings.ClientSeed is { } clientSeed)
+ {
+ ClientSeed = clientSeed;
+ cRand.SetSeed(ClientSeed);
+ }
+ else
+ {
+ ClientSeed = _nextClientSeed;
+ cRand.SetSeed(ClientSeed);
+ _nextClientSeed = cRand.Next();
+ }
+ }
}
}
finally
{
- if (pair != null && pair.TestHistory.Count > 1)
+ if (pair != null && pair.TestHistory.Count > 0)
{
await testOut.WriteLineAsync($"{nameof(GetServerClientPair)}: Pair {pair.Id} Test History Start");
for (var i = 0; i < pair.TestHistory.Count; i++)
var poolRetrieveTime = poolRetrieveTimeWatch.Elapsed;
await testOut.WriteLineAsync(
$"{nameof(GetServerClientPair)}: Retrieving pair {pair.Id} from pool took {poolRetrieveTime.TotalMilliseconds} ms");
- await testOut.WriteLineAsync(
- $"{nameof(GetServerClientPair)}: Returning pair {pair.Id}");
pair.ClearModifiedCvars();
pair.Settings = poolSettings;
pair.TestHistory.Add(currentTestName);
+ pair.SetupSeed();
+ await testOut.WriteLineAsync(
+ $"{nameof(GetServerClientPair)}: Returning pair {pair.Id} with client/server seeds: {pair.ClientSeed}/{pair.ServerSeed}");
+
pair.Watch.Restart();
return pair;
}
#nullable enable
+using Robust.Shared.Random;
+
namespace Content.IntegrationTests;
/// <summary>
/// </summary>
public sealed class PoolSettings
{
- /// <summary>
- /// If the returned pair must not be reused
- /// </summary>
- public bool MustNotBeReused => Destructive || NoLoadContent || NoLoadTestPrototypes;
-
- /// <summary>
- /// If the given pair must be brand new
- /// </summary>
- public bool MustBeNew => Fresh || NoLoadContent || NoLoadTestPrototypes;
-
/// <summary>
/// Set to true if the test will ruin the server/client pair.
/// </summary>
/// </summary>
public bool DummyTicker { get; init; } = true;
- public bool UseDummyTicker => !InLobby && DummyTicker;
-
/// <summary>
/// If true, this enables the creation of admin logs during the test.
/// </summary>
/// </summary>
public bool Connected { get; init; }
- public bool ShouldBeConnected => InLobby || Connected;
-
/// <summary>
/// Set to true if the given server/client pair should be in the lobby.
/// If the pair is not in the lobby at the end of the test, this test must be marked as dirty.
/// </summary>
public string? TestName { get; set; }
+ /// <summary>
+ /// If set, this will be used to call <see cref="IRobustRandom.SetSeed"/>
+ /// </summary>
+ public int? ServerSeed { get; set; }
+
+ /// <summary>
+ /// If set, this will be used to call <see cref="IRobustRandom.SetSeed"/>
+ /// </summary>
+ public int? ClientSeed { get; set; }
+
+ #region Inferred Properties
+
+ /// <summary>
+ /// If the returned pair must not be reused
+ /// </summary>
+ public bool MustNotBeReused => Destructive || NoLoadContent || NoLoadTestPrototypes;
+
+ /// <summary>
+ /// If the given pair must be brand new
+ /// </summary>
+ public bool MustBeNew => Fresh || NoLoadContent || NoLoadTestPrototypes;
+
+ public bool UseDummyTicker => !InLobby && DummyTicker;
+
+ public bool ShouldBeConnected => InLobby || Connected;
+
+ #endregion
+
/// <summary>
/// Tries to guess if we can skip recycling the server/client pair.
/// </summary>
&& Map == nextSettings.Map
&& InLobby == nextSettings.InLobby;
}
-}
\ No newline at end of file
+}