fix antag selection being evil (#28197)

* fix antag selection being evil

* fix test

* untroll the other tests

* remove role timer troll

* Allow tests to modify antag preferences

* Fix antag selection

* Misc test fixes

* Add AntagPreferenceTest

* Fix lazy mistakes

* Test cleanup

* Try stop players in lobbies from being assigned mid-round antags

* ranting

* I am going insane

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
This commit is contained in:
deltanedas
2024-05-26 05:14:29 +00:00
committed by GitHub
parent af10de61d3
commit 492ccc93d0
13 changed files with 182 additions and 61 deletions

View File

@@ -2,6 +2,9 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.Preferences.Managers;
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
@@ -128,4 +131,29 @@ public sealed partial class TestPair
return list;
}
/// <summary>
/// Helper method for enabling or disabling a antag role
/// </summary>
public async Task SetAntagPref(ProtoId<AntagPrototype> id, bool value)
{
var prefMan = Server.ResolveDependency<IServerPreferencesManager>();
var prefs = prefMan.GetPreferences(Client.User!.Value);
// what even is the point of ICharacterProfile if we always cast it to HumanoidCharacterProfile to make it usable?
var profile = (HumanoidCharacterProfile) prefs.SelectedCharacter;
Assert.That(profile.AntagPreferences.Contains(id), Is.EqualTo(!value));
var newProfile = profile.WithAntagPreference(id, value);
await Server.WaitPost(() =>
{
prefMan.SetProfile(Client.User.Value, prefs.SelectedCharacterIndex, newProfile).Wait();
});
// And why the fuck does it always create a new preference and profile object instead of just reusing them?
var newPrefs = prefMan.GetPreferences(Client.User.Value);
var newProf = (HumanoidCharacterProfile) newPrefs.SelectedCharacter;
Assert.That(newProf.AntagPreferences.Contains(id), Is.EqualTo(value));
}
}

View File

@@ -65,11 +65,11 @@ public static partial class PoolManager
options.BeforeStart += () =>
{
// Server-only systems (i.e., systems that subscribe to events with server-only components)
var entSysMan = IoCManager.Resolve<IEntitySystemManager>();
entSysMan.LoadExtraSystemType<ResettingEntitySystemTests.TestRoundRestartCleanupEvent>();
entSysMan.LoadExtraSystemType<InteractionSystemTests.TestInteractionSystem>();
entSysMan.LoadExtraSystemType<DeviceNetworkTestSystem>();
entSysMan.LoadExtraSystemType<TestDestructibleListenerSystem>();
IoCManager.Resolve<ILogManager>().GetSawmill("loc").Level = LogLevel.Error;
IoCManager.Resolve<IConfigurationManager>()
.OnValueChanged(RTCVars.FailureLogLevel, value => logHandler.FailureLevel = value, true);

View File

@@ -0,0 +1,76 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
using Content.Server.Antag;
using Content.Server.Antag.Components;
using Content.Server.GameTicking;
using Content.Shared.GameTicking;
using Robust.Shared.GameObjects;
using Robust.Shared.Player;
using Robust.Shared.Random;
namespace Content.IntegrationTests.Tests.GameRules;
// Once upon a time, players in the lobby weren't ever considered eligible for antag roles.
// Lets not let that happen again.
[TestFixture]
public sealed class AntagPreferenceTest
{
[Test]
public async Task TestLobbyPlayersValid()
{
await using var pair = await PoolManager.GetServerClient(new PoolSettings
{
DummyTicker = false,
Connected = true,
InLobby = true
});
var server = pair.Server;
var client = pair.Client;
var ticker = server.System<GameTicker>();
var sys = server.System<AntagSelectionSystem>();
// Initially in the lobby
Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby));
Assert.That(client.AttachedEntity, Is.Null);
Assert.That(ticker.PlayerGameStatuses[client.User!.Value], Is.EqualTo(PlayerGameStatus.NotReadyToPlay));
EntityUid uid = default;
await server.WaitPost(() => uid = server.EntMan.Spawn("Traitor"));
var rule = new Entity<AntagSelectionComponent>(uid, server.EntMan.GetComponent<AntagSelectionComponent>(uid));
var def = rule.Comp.Definitions.Single();
// IsSessionValid & IsEntityValid are preference agnostic and should always be true for players in the lobby.
// Though maybe that will change in the future, but then GetPlayerPool() needs to be updated to reflect that.
Assert.That(sys.IsSessionValid(rule, pair.Player, def), Is.True);
Assert.That(sys.IsEntityValid(client.AttachedEntity, def), Is.True);
// By default, traitor/antag preferences are disabled, so the pool should be empty.
var sessions = new List<ICommonSession>{pair.Player!};
var pool = sys.GetPlayerPool(rule, sessions, def);
Assert.That(pool.Count, Is.EqualTo(0));
// Opt into the traitor role.
await pair.SetAntagPref("Traitor", true);
Assert.That(sys.IsSessionValid(rule, pair.Player, def), Is.True);
Assert.That(sys.IsEntityValid(client.AttachedEntity, def), Is.True);
pool = sys.GetPlayerPool(rule, sessions, def);
Assert.That(pool.Count, Is.EqualTo(1));
pool.TryPickAndTake(pair.Server.ResolveDependency<IRobustRandom>(), out var picked);
Assert.That(picked, Is.EqualTo(pair.Player));
Assert.That(sessions.Count, Is.EqualTo(1));
// opt back out
await pair.SetAntagPref("Traitor", false);
Assert.That(sys.IsSessionValid(rule, pair.Player, def), Is.True);
Assert.That(sys.IsEntityValid(client.AttachedEntity, def), Is.True);
pool = sys.GetPlayerPool(rule, sessions, def);
Assert.That(pool.Count, Is.EqualTo(0));
await server.WaitPost(() => server.EntMan.DeleteEntity(uid));
await pair.CleanReturnAsync();
}
}

View File

@@ -58,6 +58,9 @@ public sealed class NukeOpsTest
Assert.That(client.AttachedEntity, Is.Null);
Assert.That(ticker.PlayerGameStatuses[client.User!.Value], Is.EqualTo(PlayerGameStatus.NotReadyToPlay));
// Opt into the nukies role.
await pair.SetAntagPref("NukeopsCommander", true);
// There are no grids or maps
Assert.That(entMan.Count<MapComponent>(), Is.Zero);
Assert.That(entMan.Count<MapGridComponent>(), Is.Zero);
@@ -198,6 +201,7 @@ public sealed class NukeOpsTest
ticker.SetGamePreset((GamePresetPrototype?)null);
server.CfgMan.SetCVar(CCVars.GridFill, false);
await pair.SetAntagPref("NukeopsCommander", false);
await pair.CleanReturnAsync();
}
}

View File

@@ -407,7 +407,6 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
await pair.CleanReturnAsync();
}
[Reflect(false)]
public sealed class TestInteractionSystem : EntitySystem
{
public EntityEventHandler<InteractUsingEvent>? InteractUsingEvent;

View File

@@ -9,7 +9,6 @@ namespace Content.IntegrationTests.Tests
[TestOf(typeof(RoundRestartCleanupEvent))]
public sealed class ResettingEntitySystemTests
{
[Reflect(false)]
public sealed class TestRoundRestartCleanupEvent : EntitySystem
{
public bool HasBeenReset { get; set; }
@@ -49,8 +48,6 @@ namespace Content.IntegrationTests.Tests
system.HasBeenReset = false;
Assert.That(system.HasBeenReset, Is.False);
gameTicker.RestartRound();
Assert.That(system.HasBeenReset);