Skip to content

Commit

Permalink
Add dummy sessions for integration tests (space-wizards#5202)
Browse files Browse the repository at this point in the history
* Add dummy sessions

* if FULL_RELEASE
  • Loading branch information
ElectroJr committed Jun 5, 2024
1 parent 3e3cd0e commit 75626a8
Show file tree
Hide file tree
Showing 12 changed files with 286 additions and 32 deletions.
6 changes: 3 additions & 3 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ END TEMPLATE-->

### New features

*None yet*
* `ServerIntegrationInstance` has new methods for adding dummy player sessions for tests that require multiple players.

### Bugfixes

Expand All @@ -51,8 +51,8 @@ END TEMPLATE-->

### Internal

*None yet*

* Added `DummySession` and `DummyChannel` classes for use in integration tests and benchmarks to fool the server into thinking that there are multiple players connected.
* Added `ICommonSessionInternal` and updated `CommonSession` so that the internal setters now go through that interface.

## 224.0.1

Expand Down
10 changes: 5 additions & 5 deletions Robust.Client/Player/PlayerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,8 @@ private bool UpdatePlayerList(IEnumerable<SessionState> remotePlayers, bool full
{
// This is a new userid, so we create a new session.
DebugTools.Assert(state.UserId != LocalPlayer?.UserId);
var newSession = (CommonSession) CreateAndAddSession(state.UserId, state.Name);
newSession.Ping = state.Ping;
var newSession = (ICommonSessionInternal)CreateAndAddSession(state.UserId, state.Name);
newSession.SetPing(state.Ping);
SetStatus(newSession, state.Status);
SetAttachedEntity(newSession, controlled, out _, true);
dirty = true;
Expand All @@ -279,9 +279,9 @@ private bool UpdatePlayerList(IEnumerable<SessionState> remotePlayers, bool full
}

dirty = true;
var local = (CommonSession) session;
local.Name = state.Name;
local.Ping = state.Ping;
var local = (ICommonSessionInternal)session;
local.SetName(state.Name);
local.SetPing(state.Ping);
SetStatus(local, state.Status);
SetAttachedEntity(local, controlled, out _, true);
}
Expand Down
3 changes: 2 additions & 1 deletion Robust.Server/GameStates/PvsSystem.Session.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Network.Messages;
using Robust.Shared.Player;
using Robust.Shared.Timing;
Expand Down Expand Up @@ -42,7 +43,7 @@ private void SendStateUpdate(ICommonSession session, PvsThreadResources resource

// PVS benchmarks use dummy sessions.
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
if (session.Channel != null)
if (session.Channel is not DummyChannel)
{
_netMan.ServerSendMessage(msg, session.Channel);
if (msg.ShouldSendReliably())
Expand Down
41 changes: 34 additions & 7 deletions Robust.Server/Player/PlayerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,18 +90,18 @@ private void NewSession(object? sender, NetChannelArgs args)
_cfg.SyncConnectingClient(args.Channel);
}

private void EndSession(object? sender, NetChannelArgs args)
{
EndSession(args.Channel.UserId);
}

/// <summary>
/// Ends a clients session, and disconnects them.
/// </summary>
private void EndSession(object? sender, NetChannelArgs args)
internal void EndSession(NetUserId user)
{
if (!TryGetSessionByChannel(args.Channel, out var session))
{
if (!TryGetSessionById(user, out var session))
return;
}

// make sure nothing got messed up during the life of the session
DebugTools.Assert(session.Channel == args.Channel);

SetStatus(session, SessionStatus.Disconnected);
SetAttachedEntity(session, null, out _, true);
Expand Down Expand Up @@ -159,5 +159,32 @@ public override bool TryGetSessionByEntity(EntityUid uid, [NotNullWhen(true)] ou
session = actor.PlayerSession;
return true;
}

internal ICommonSession AddDummySession(NetUserId user, string name)
{
#if FULL_RELEASE
// Lets not make it completely trivial to fake player counts.
throw new NotSupportedException();
#endif
Lock.EnterWriteLock();
DummySession session;
try
{
UserIdMap[name] = user;
if (!PlayerData.TryGetValue(user, out var data))
PlayerData[user] = data = new(user, name);

session = new DummySession(user, name, data);
InternalSessions.Add(user, session);
}
finally
{
Lock.ExitWriteLock();
}

UpdateState(session);

return session;
}
}
}
1 change: 1 addition & 0 deletions Robust.Shared/Network/NetManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Robust.Shared.Configuration;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Player;
using Robust.Shared.Profiling;
using Robust.Shared.Serialization;
using Robust.Shared.Timing;
Expand Down
34 changes: 28 additions & 6 deletions Robust.Shared/Player/CommonSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Robust.Shared.Player;

internal sealed class CommonSession : ICommonSession
internal sealed class CommonSession : ICommonSessionInternal
{
[ViewVariables]
public EntityUid? AttachedEntity { get; set; }
Expand All @@ -17,10 +17,10 @@ internal sealed class CommonSession : ICommonSession
public NetUserId UserId { get; }

[ViewVariables]
public string Name { get; internal set; } = "<Unknown>";
public string Name { get; set; } = "<Unknown>";

[ViewVariables]
public short Ping { get; internal set; }
public short Ping { get; set; }

[ViewVariables]
public DateTime ConnectedTime { get; set; }
Expand All @@ -42,9 +42,6 @@ internal sealed class CommonSession : ICommonSession
[ViewVariables]
public HashSet<EntityUid> ViewSubscriptions { get; } = new();

[ViewVariables]
public int VisibilityMask { get; set; } = 1;

[ViewVariables]
public LoginType AuthType => Channel?.AuthType ?? default;

Expand All @@ -56,4 +53,29 @@ public CommonSession(NetUserId user, string name, SessionData data)
Name = name;
Data = data;
}

public void SetStatus(SessionStatus status)
{
Status = status;
}

public void SetAttachedEntity(EntityUid? uid)
{
AttachedEntity = uid;
}

public void SetPing(short ping)
{
Ping = ping;
}

public void SetName(string name)
{
Name = name;
}

public void SetChannel(INetChannel channel)
{
Channel = channel;
}
}
127 changes: 127 additions & 0 deletions Robust.Shared/Player/DummySession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Net;
using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.Network;

namespace Robust.Shared.Player;

/// <summary>
/// This is a mock session for use with integration tests and benchmarks. It uses a <see cref="DummyChannel"/> as
/// its <see cref="INetChannel"/>, which doesn't support actually sending any messages.
/// </summary>
internal sealed class DummySession : ICommonSessionInternal
{
public EntityUid? AttachedEntity {get; set; }
public SessionStatus Status { get; set; } = SessionStatus.Connecting;
public NetUserId UserId => UserData.UserId;
public string Name => UserData.UserName;

public short Ping { get; set; }

public INetChannel Channel
{
get => DummyChannel;
[Obsolete]
set => throw new NotSupportedException();
}

public LoginType AuthType { get; set; } = LoginType.GuestAssigned;
public HashSet<EntityUid> ViewSubscriptions { get; } = new();
public DateTime ConnectedTime { get; set; }
public SessionState State { get; set; } = new();
public SessionData Data { get; set; }
public bool ClientSide { get; set; }
public NetUserData UserData { get; set; }

public DummyChannel DummyChannel;

public DummySession(NetUserId userId, string userName, SessionData data)
{
Data = data;
UserData = new(userId, userName)
{
HWId = ImmutableArray<byte>.Empty
};
DummyChannel = new(this);
}

public void SetStatus(SessionStatus status)
{
Status = status;
}

public void SetAttachedEntity(EntityUid? uid)
{
AttachedEntity = uid;
}

public void SetPing(short ping)
{
Ping = ping;
}

public void SetName(string name)
{
UserData = new(UserData.UserId, name)
{
HWId = UserData.HWId
};
}

public void SetChannel(INetChannel channel)
{
throw new NotSupportedException();
}
}

/// <summary>
/// A mock NetChannel for use in integration tests and benchmarks.
/// </summary>
internal sealed class DummyChannel(DummySession session) : INetChannel
{
public readonly DummySession Session = session;
public NetUserData UserData => Session.UserData;
public short Ping => Session.Ping;
public string UserName => Session.Name;
public LoginType AuthType => Session.AuthType;
public NetUserId UserId => Session.UserId;

public int CurrentMtu { get; set; } = default;
public long ConnectionId { get; set; } = default;
public TimeSpan RemoteTimeOffset { get; set; } = default;
public TimeSpan RemoteTime { get; set; } = default;
public bool IsConnected { get; set; } = true;
public bool IsHandshakeComplete { get; set; } = true;

// This is just pilfered from IntegrationNetChannel
public IPEndPoint RemoteEndPoint { get; } = new(IPAddress.Loopback, 1212);

// Only used on server, contains the encryption to use for this channel.
public NetEncryption? Encryption { get; set; }

public INetManager NetPeer => throw new NotImplementedException();

public T CreateNetMessage<T>() where T : NetMessage, new()
{
throw new NotImplementedException();
}

public void SendMessage(NetMessage message)
{
throw new NotImplementedException();
}

public void Disconnect(string reason)
{
throw new NotImplementedException();
}

public void Disconnect(string reason, bool sendBye)
{
throw new NotImplementedException();
}
}
12 changes: 10 additions & 2 deletions Robust.Shared/Player/ICommonSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,8 @@ public interface ICommonSession
/// <remarks>
/// On the Server every player has a network channel,
/// on the Client only the LocalPlayer has a network channel, and that channel points to the server.
/// Unless you know what you are doing, you shouldn't be modifying this directly.
/// </remarks>
INetChannel Channel { get; set; }
INetChannel Channel { get; [Obsolete] set; }

LoginType AuthType { get; }

Expand Down Expand Up @@ -75,3 +74,12 @@ public interface ICommonSession
/// </summary>
bool ClientSide { get; set; }
}

internal interface ICommonSessionInternal : ICommonSession
{
public void SetStatus(SessionStatus status);
public void SetAttachedEntity(EntityUid? uid);
public void SetPing(short ping);
public void SetName(string name);
void SetChannel(INetChannel channel);
}
14 changes: 7 additions & 7 deletions Robust.Shared/Player/SharedPlayerManager.Sessions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ protected virtual CommonSession CreateSession(NetUserId user, string name, Sessi

public ICommonSession CreateAndAddSession(INetChannel channel)
{
var session = CreateAndAddSession(channel.UserId, channel.UserName);
session.Channel = channel;
var session = (ICommonSessionInternal)CreateAndAddSession(channel.UserId, channel.UserName);
session.SetChannel(channel);
return session;
}

Expand Down Expand Up @@ -176,7 +176,7 @@ private void Detach(ICommonSession session)
if (session.AttachedEntity is not {} uid)
return;

((CommonSession) session).AttachedEntity = null;
((ICommonSessionInternal) session).SetAttachedEntity(null);
UpdateState(session);

if (EntManager.TryGetComponent(uid, out ActorComponent? actor) && actor.LifeStage <= ComponentLifeStage.Running)
Expand Down Expand Up @@ -215,7 +215,7 @@ private bool Attach(ICommonSession session, EntityUid uid, out ICommonSession? k
if (session.AttachedEntity != null)
Detach(session);

((CommonSession) session).AttachedEntity = uid;
((ICommonSessionInternal) session).SetAttachedEntity(uid);
actor.PlayerSession = session;
UpdateState(session);
EntManager.EventBus.RaiseLocalEvent(uid, new PlayerAttachedEvent(uid, session), true);
Expand All @@ -228,21 +228,21 @@ public void SetStatus(ICommonSession session, SessionStatus status)
return;

var old = session.Status;
((CommonSession) session).Status = status;
((ICommonSessionInternal) session).SetStatus(status);

UpdateState(session);
PlayerStatusChanged?.Invoke(this, new SessionStatusEventArgs(session, old, status));
}

public void SetPing(ICommonSession session, short ping)
{
((CommonSession) session).Ping = ping;
((ICommonSessionInternal) session).SetPing(ping);
UpdateState(session);
}

public void SetName(ICommonSession session, string name)
{
((CommonSession) session).Name = name;
((ICommonSessionInternal) session).SetName(name);
UpdateState(session);
}

Expand Down
Loading

0 comments on commit 75626a8

Please sign in to comment.