#nullable enable
using System;
-using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Content.IntegrationTests;
using Content.IntegrationTests.Pair;
+using Content.Server.Mind;
using Content.Server.Warps;
using Robust.Server.GameObjects;
using Robust.Shared;
using Robust.Shared.Analyzers;
-using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
-using Robust.Shared.GameStates;
using Robust.Shared.Map;
-using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Random;
_pair.Server.CfgMan.SetCVar(CVars.NetPvsAsync, false);
_sys = _entMan.System<SharedTransformSystem>();
+ SetupAsync().Wait();
+ }
+
+ private async Task SetupAsync()
+ {
// Spawn the map
_pair.Server.ResolveDependency<IRobustRandom>().SetSeed(42);
- _pair.Server.WaitPost(() =>
+ await _pair.Server.WaitPost(() =>
{
var success = _entMan.System<MapLoaderSystem>().TryLoad(_mapId, Map, out _);
if (!success)
throw new Exception("Map load failed");
_pair.Server.MapMan.DoMapInitialize(_mapId);
- }).Wait();
+ });
// Get list of ghost warp positions
_spawns = _entMan.AllComponentsList<WarpPointComponent>()
Array.Resize(ref _players, PlayerCount);
- // Spawn "Players".
- _pair.Server.WaitPost(() =>
+ // Spawn "Players"
+ _players = await _pair.Server.AddDummySessions(PlayerCount);
+ await _pair.Server.WaitPost(() =>
{
+ var mind = _pair.Server.System<MindSystem>();
for (var i = 0; i < PlayerCount; i++)
{
var pos = _spawns[i % _spawns.Length];
var uid =_entMan.SpawnEntity("MobHuman", pos);
_pair.Server.ConsoleHost.ExecuteCommand($"setoutfit {_entMan.GetNetEntity(uid)} CaptainGear");
- _players[i] = new DummySession{AttachedEntity = uid};
+ mind.ControlMob(_players[i].UserId, uid);
}
- }).Wait();
+ });
// Repeatedly move players around so that they "explore" the map and see lots of entities.
// This will populate their PVS data with out-of-view entities.
}).Wait();
_pair.Server.PvsTick(_players);
}
-
- private sealed class DummySession : ICommonSession
- {
- public SessionStatus Status => SessionStatus.InGame;
- public EntityUid? AttachedEntity {get; set; }
- public NetUserId UserId => default;
- public string Name => string.Empty;
- public short Ping => default;
- public INetChannel Channel { get; set; } = default!;
- public LoginType AuthType => default;
- public HashSet<EntityUid> ViewSubscriptions { get; } = new();
- public DateTime ConnectedTime { get; set; }
- public SessionState State => default!;
- public SessionData Data => default!;
- public bool ClientSide { get; set; }
- }
}
using Content.Shared.Roles;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
+using Robust.Shared.Network;
+using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.UnitTesting;
/// Helper method for enabling or disabling a antag role
/// </summary>
public async Task SetAntagPref(ProtoId<AntagPrototype> id, bool value)
+ {
+ await SetAntagPref(Client.User!.Value, id, value);
+ }
+
+ public async Task SetAntagPref(NetUserId user, ProtoId<AntagPrototype> id, bool value)
{
var prefMan = Server.ResolveDependency<IServerPreferencesManager>();
- var prefs = prefMan.GetPreferences(Client.User!.Value);
+ var prefs = prefMan.GetPreferences(user);
// what even is the point of ICharacterProfile if we always cast it to HumanoidCharacterProfile to make it usable?
var profile = (HumanoidCharacterProfile) prefs.SelectedCharacter;
await Server.WaitPost(() =>
{
- prefMan.SetProfile(Client.User.Value, prefs.SelectedCharacterIndex, newProfile).Wait();
+ prefMan.SetProfile(user, 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 newPrefs = prefMan.GetPreferences(user);
var newProf = (HumanoidCharacterProfile) newPrefs.SelectedCharacter;
Assert.That(newProf.AntagPreferences.Contains(id), Is.EqualTo(value));
}
Assert.That(client.AttachedEntity, Is.Null);
Assert.That(ticker.PlayerGameStatuses[client.User!.Value], Is.EqualTo(PlayerGameStatus.NotReadyToPlay));
+ // Add several dummy players
+ var dummies = await pair.Server.AddDummySessions(3);
+ await pair.RunTicksSync(5);
+
// Opt into the nukies role.
await pair.SetAntagPref("NukeopsCommander", true);
+ await pair.SetAntagPref(dummies[1].UserId, "NukeopsMedic", true);
+
+ // Initially, the players have no attached entities
+ Assert.That(pair.Player?.AttachedEntity, Is.Null);
+ Assert.That(dummies.All(x => x.AttachedEntity == null));
// There are no grids or maps
Assert.That(entMan.Count<MapComponent>(), Is.Zero);
Assert.That(entMan.Count<NukeOperativeSpawnerComponent>(), Is.Zero);
// Ready up and start nukeops
- await pair.WaitClientCommand("toggleready True");
- Assert.That(ticker.PlayerGameStatuses[client.User!.Value], Is.EqualTo(PlayerGameStatus.ReadyToPlay));
+ ticker.ToggleReadyAll(true);
+ Assert.That(ticker.PlayerGameStatuses.Values.All(x => x == PlayerGameStatus.ReadyToPlay));
await pair.WaitCommand("forcepreset Nukeops");
await pair.RunTicksSync(10);
// Game should have started
Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.InRound));
- Assert.That(ticker.PlayerGameStatuses[client.User!.Value], Is.EqualTo(PlayerGameStatus.JoinedGame));
+ Assert.That(ticker.PlayerGameStatuses.Values.All(x => x == PlayerGameStatus.JoinedGame));
Assert.That(client.EntMan.EntityExists(client.AttachedEntity));
+
+ var dummyEnts = dummies.Select(x => x.AttachedEntity ?? default).ToArray();
var player = pair.Player!.AttachedEntity!.Value;
Assert.That(entMan.EntityExists(player));
+ Assert.That(dummyEnts.All(e => entMan.EntityExists(e)));
// Maps now exist
Assert.That(entMan.Count<MapComponent>(), Is.GreaterThan(0));
// And we now have nukie related components
Assert.That(entMan.Count<NukeopsRuleComponent>(), Is.EqualTo(1));
- Assert.That(entMan.Count<NukeopsRoleComponent>(), Is.EqualTo(1));
- Assert.That(entMan.Count<NukeOperativeComponent>(), Is.EqualTo(1));
+ Assert.That(entMan.Count<NukeopsRoleComponent>(), Is.EqualTo(2));
+ Assert.That(entMan.Count<NukeOperativeComponent>(), Is.EqualTo(2));
Assert.That(entMan.Count<NukeOpsShuttleComponent>(), Is.EqualTo(1));
// The player entity should be the nukie commander
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mind));
Assert.That(factionSys.IsMember(player, "Syndicate"), Is.True);
Assert.That(factionSys.IsMember(player, "NanoTrasen"), Is.False);
-
var roles = roleSys.MindGetAllRoles(mind);
var cmdRoles = roles.Where(x => x.Prototype == "NukeopsCommander" && x.Component is NukeopsRoleComponent);
Assert.That(cmdRoles.Count(), Is.EqualTo(1));
+ // The second dummy player should be a medic
+ var dummyMind = mindSys.GetMind(dummyEnts[1])!.Value;
+ Assert.That(entMan.HasComponent<NukeOperativeComponent>(dummyEnts[1]));
+ Assert.That(roleSys.MindIsAntagonist(dummyMind));
+ Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(dummyMind));
+ Assert.That(factionSys.IsMember(dummyEnts[1], "Syndicate"), Is.True);
+ Assert.That(factionSys.IsMember(dummyEnts[1], "NanoTrasen"), Is.False);
+ roles = roleSys.MindGetAllRoles(dummyMind);
+ cmdRoles = roles.Where(x => x.Prototype == "NukeopsMedic" && x.Component is NukeopsRoleComponent);
+ Assert.That(cmdRoles.Count(), Is.EqualTo(1));
+
+ // The other two players should have just spawned in as normal.
+ CheckDummy(0);
+ CheckDummy(2);
+ void CheckDummy(int i)
+ {
+ var ent = dummyEnts[i];
+ var mind = mindSys.GetMind(ent)!.Value;
+ Assert.That(entMan.HasComponent<NukeOperativeComponent>(ent), Is.False);
+ Assert.That(roleSys.MindIsAntagonist(mind), Is.False);
+ Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mind), Is.False);
+ Assert.That(factionSys.IsMember(ent, "Syndicate"), Is.False);
+ Assert.That(factionSys.IsMember(ent, "NanoTrasen"), Is.True);
+ Assert.That(roleSys.MindGetAllRoles(mind).Any(x => x.Component is NukeopsRoleComponent), Is.False);
+ }
+
// The game rule exists, and all the stations/shuttles/maps are properly initialized
var rule = entMan.AllComponents<NukeopsRuleComponent>().Single().Component;
var gridsRule = entMan.AllComponents<RuleGridsComponent>().Single().Component;
// While we're at it, lets make sure they aren't naked. I don't know how many inventory slots all mobs will be
// likely to have in the future. But nukies should probably have at least 3 slots with something in them.
var enumerator = invSys.GetSlotEnumerator(player);
- int total = 0;
+ var total = 0;
while (enumerator.NextItem(out _))
{
total++;
ticker.SetGamePreset((GamePresetPrototype?)null);
await pair.SetAntagPref("NukeopsCommander", false);
+ await pair.SetAntagPref(dummies[1].UserId, "NukeopsMedic", false);
await pair.CleanReturnAsync();
}
}