mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
Client-, shared-, and server-side ConfigurationManager (#3477)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using Robust.Client.Configuration;
|
||||
using Robust.Client.Debugging;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.GameStates;
|
||||
@@ -25,7 +26,7 @@ namespace Robust.Client
|
||||
{
|
||||
[Dependency] private readonly IClientNetManager _net = default!;
|
||||
[Dependency] private readonly IPlayerManager _playMan = default!;
|
||||
[Dependency] private readonly INetConfigurationManager _configManager = default!;
|
||||
[Dependency] private readonly IClientNetConfigurationManager _configManager = default!;
|
||||
[Dependency] private readonly IClientEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IDiscordRichPresence _discord = default!;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Robust.Client.Audio.Midi;
|
||||
using Robust.Client.Configuration;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.Debugging;
|
||||
using Robust.Client.GameObjects;
|
||||
@@ -23,6 +24,7 @@ using Robust.Client.UserInterface.Themes;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Client.ViewVariables;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -123,6 +125,11 @@ namespace Robust.Client
|
||||
deps.Register<IClientViewVariablesManagerInternal, ClientViewVariablesManager>();
|
||||
deps.Register<IClientConGroupController, ClientConGroupController>();
|
||||
deps.Register<IScriptClient, ScriptClient>();
|
||||
deps.Register<IConfigurationManager, ClientNetConfigurationManager>();
|
||||
deps.Register<INetConfigurationManager, ClientNetConfigurationManager>();
|
||||
deps.Register<IConfigurationManagerInternal, ClientNetConfigurationManager>();
|
||||
deps.Register<IClientNetConfigurationManager, ClientNetConfigurationManager>();
|
||||
deps.Register<INetConfigurationManagerInternal, ClientNetConfigurationManager>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Threading.Tasks;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Resources;
|
||||
using SixLabors.ImageSharp;
|
||||
|
||||
namespace Robust.Client;
|
||||
|
||||
@@ -18,7 +17,7 @@ internal static class ClientWarmup
|
||||
private static void WarmupCore()
|
||||
{
|
||||
// Get ImageSharp loaded.
|
||||
_ = Configuration.Default;
|
||||
_ = SixLabors.ImageSharp.Configuration.Default;
|
||||
|
||||
SharedWarmup.WarmupCore();
|
||||
|
||||
|
||||
130
Robust.Client/Configuration/ClientNetConfigurationManager.cs
Normal file
130
Robust.Client/Configuration/ClientNetConfigurationManager.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.Configuration;
|
||||
|
||||
internal sealed class ClientNetConfigurationManager : NetConfigurationManager, IClientNetConfigurationManager
|
||||
{
|
||||
[Dependency] private readonly IBaseClient _client = default!;
|
||||
|
||||
private bool _receivedInitialNwVars = false;
|
||||
|
||||
public event EventHandler? ReceivedInitialNwVars;
|
||||
|
||||
public void SyncWithServer()
|
||||
{
|
||||
DebugTools.Assert(NetManager.IsConnected);
|
||||
|
||||
Sawmill.Info("Sending client info...");
|
||||
|
||||
var msg = new MsgConVars();
|
||||
msg.Tick = default;
|
||||
msg.NetworkedVars = GetReplicatedVars();
|
||||
NetManager.ClientSendMessage(msg);
|
||||
}
|
||||
|
||||
public void ClearReceivedInitialNwVars()
|
||||
{
|
||||
_receivedInitialNwVars = false;
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
ReceivedInitialNwVars = null;
|
||||
_receivedInitialNwVars = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void SetCVar(string name, object value, bool force = false)
|
||||
{
|
||||
CVar flags;
|
||||
using (Lock.ReadGuard())
|
||||
{
|
||||
if (!_configVars.TryGetValue(name, out var cVar) || !cVar.Registered)
|
||||
throw new InvalidConfigurationException($"Trying to set unregistered variable '{name}'");
|
||||
|
||||
flags = cVar.Flags;
|
||||
if (!force && NetManager.IsConnected && (cVar.Flags & CVar.NOT_CONNECTED) != 0)
|
||||
{
|
||||
Sawmill.Warning($"'{name}' can only be changed when not connected to a server.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!force && ((cVar.Flags & CVar.SERVER) != 0) && _client.RunLevel != ClientRunLevel.SinglePlayerGame)
|
||||
{
|
||||
Sawmill.Warning($"Only the server can change '{name}'.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Actually set the CVar
|
||||
base.SetCVar(name, value, force);
|
||||
|
||||
if ((flags & CVar.REPLICATED) == 0)
|
||||
return;
|
||||
|
||||
var msg = new MsgConVars();
|
||||
msg.Tick = Timing.CurTick;
|
||||
msg.NetworkedVars = new List<(string name, object value)>
|
||||
{
|
||||
(name, value)
|
||||
};
|
||||
NetManager.ClientSendMessage(msg);
|
||||
}
|
||||
|
||||
protected override void HandleNetVarMessage(MsgConVars message)
|
||||
{
|
||||
if (!_receivedInitialNwVars)
|
||||
ApplyClientNetVarChange(message.NetworkedVars, message.Tick);
|
||||
else
|
||||
base.HandleNetVarMessage(message);
|
||||
}
|
||||
|
||||
protected override void ApplyNetVarChange(
|
||||
INetChannel msgChannel,
|
||||
List<(string name, object value)> networkedVars,
|
||||
GameTick tick)
|
||||
{
|
||||
ApplyClientNetVarChange(networkedVars, tick);
|
||||
}
|
||||
|
||||
private void ApplyClientNetVarChange(List<(string name, object value)> networkedVars, GameTick tick)
|
||||
{
|
||||
// Server sent us a CVar update.
|
||||
Sawmill.Debug($"Handling replicated cvars...");
|
||||
|
||||
foreach (var (name, value) in networkedVars)
|
||||
{
|
||||
if (!_configVars.TryGetValue(name, out var cVar))
|
||||
{
|
||||
Sawmill.Warning($"Server sent an unknown replicated CVar '{name}.'");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((cVar.Flags & CVar.CLIENT) != 0)
|
||||
continue; // ignore the server specified value.
|
||||
|
||||
// Actually set the CVar
|
||||
SetCVarInternal(name, value, tick);
|
||||
|
||||
Sawmill.Debug($"name={name}, val={value}");
|
||||
}
|
||||
|
||||
if (!_receivedInitialNwVars)
|
||||
{
|
||||
_receivedInitialNwVars = true;
|
||||
ReceivedInitialNwVars?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override T GetClientCVar<T>(INetChannel channel, string name) => GetCVar<T>(name);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Timing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Robust.Client.Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// A networked configuration manager that controls the replication of
|
||||
/// console variables between client and server.
|
||||
/// </summary>
|
||||
public interface IClientNetConfigurationManager : INetConfigurationManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Synchronize the CVars marked with <see cref="CVar.REPLICATED"/> with the server.
|
||||
/// This needs to be called once when connecting.
|
||||
/// </summary>
|
||||
void SyncWithServer();
|
||||
|
||||
/// <summary>
|
||||
/// Clears internal flag for <see cref="ReceivedInitialNwVars"/>.
|
||||
/// Must be called upon disconnect.
|
||||
/// </summary>
|
||||
void ClearReceivedInitialNwVars();
|
||||
|
||||
public event EventHandler ReceivedInitialNwVars;
|
||||
}
|
||||
@@ -77,7 +77,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
_currentBoundRenderTarget = default!;
|
||||
_currentRenderTarget = default!;
|
||||
Configuration.Default.PreferContiguousImageBuffers = true;
|
||||
SixLabors.ImageSharp.Configuration.Default.PreferContiguousImageBuffers = true;
|
||||
}
|
||||
|
||||
public bool InitializePreWindowing()
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
public ClydeHeadless()
|
||||
{
|
||||
Configuration.Default.PreferContiguousImageBuffers = true;
|
||||
SixLabors.ImageSharp.Configuration.Default.PreferContiguousImageBuffers = true;
|
||||
|
||||
var mainRt = new DummyRenderWindow(this);
|
||||
var window = new DummyWindow(mainRt) {Id = new WindowId(1)};
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Robust.Server.Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// A networked configuration manager that controls the replication of
|
||||
/// console variables between client and server.
|
||||
/// </summary>
|
||||
public interface IServerNetConfigurationManager : INetConfigurationManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Synchronize the CVars marked with <see cref="CVar.REPLICATED"/> with the client.
|
||||
/// This needs to be called once during the client connection.
|
||||
/// </summary>
|
||||
/// <param name="client">Client's NetChannel to sync replicated CVars with.</param>
|
||||
void SyncConnectingClient(INetChannel client);
|
||||
}
|
||||
127
Robust.Server/Configuration/ServerNetConfigurationManager.cs
Normal file
127
Robust.Server/Configuration/ServerNetConfigurationManager.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Robust.Server.Configuration;
|
||||
|
||||
internal sealed class ServerNetConfigurationManager : NetConfigurationManager, IServerNetConfigurationManager
|
||||
{
|
||||
private readonly Dictionary<INetChannel, Dictionary<string, object>> _replicatedCVars = new();
|
||||
|
||||
public override void SetupNetworking()
|
||||
{
|
||||
base.SetupNetworking();
|
||||
NetManager.Connected += PeerConnected;
|
||||
NetManager.Disconnect += PeerDisconnected;
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
_replicatedCVars.Clear();
|
||||
}
|
||||
|
||||
private void PeerConnected(object? sender, NetChannelArgs e)
|
||||
{
|
||||
_replicatedCVars.Add(e.Channel, new Dictionary<string, object>());
|
||||
}
|
||||
|
||||
private void PeerDisconnected(object? sender, NetDisconnectedArgs e)
|
||||
{
|
||||
_replicatedCVars.Remove(e.Channel);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override T GetClientCVar<T>(INetChannel channel, string name)
|
||||
{
|
||||
using var _ = Lock.ReadGuard();
|
||||
|
||||
if (!_configVars.TryGetValue(name, out var cVar) || !cVar.Registered)
|
||||
throw new InvalidConfigurationException($"Trying to get unregistered variable '{name}'");
|
||||
|
||||
if (_replicatedCVars.TryGetValue(channel, out var clientCVars) && clientCVars.TryGetValue(name, out var value))
|
||||
{
|
||||
return (T)value;
|
||||
}
|
||||
|
||||
return (T)(cVar.DefaultValue!);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void SetCVar(string name, object value, bool force)
|
||||
{
|
||||
CVar flags;
|
||||
using (Lock.ReadGuard())
|
||||
{
|
||||
if (!_configVars.TryGetValue(name, out var cVar) || !cVar.Registered)
|
||||
throw new InvalidConfigurationException($"Trying to set unregistered variable '{name}'");
|
||||
|
||||
flags = cVar.Flags;
|
||||
}
|
||||
|
||||
if (!force && (flags & CVar.CLIENT) != 0)
|
||||
{
|
||||
Sawmill.Warning($"Only clients can change the '{name}' cvar.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Actually set the CVar
|
||||
base.SetCVar(name, value, force);
|
||||
|
||||
if ((flags & CVar.REPLICATED) == 0)
|
||||
return;
|
||||
|
||||
var msg = new MsgConVars();
|
||||
msg.Tick = Timing.CurTick;
|
||||
msg.NetworkedVars = new List<(string name, object value)>{ (name, value) };
|
||||
|
||||
// TODO REPLAYS: send cvar changes after the initial cvars were set
|
||||
NetManager.ServerSendToAll(msg);
|
||||
}
|
||||
|
||||
protected override void ApplyNetVarChange(
|
||||
INetChannel msgChannel,
|
||||
List<(string name, object value)> networkedVars,
|
||||
GameTick tick)
|
||||
{
|
||||
Sawmill.Debug($"{msgChannel} Handling replicated cvars...");
|
||||
|
||||
// Client sent us a CVar update
|
||||
if (!_replicatedCVars.TryGetValue(msgChannel, out var clientCVars))
|
||||
{
|
||||
Sawmill.Warning($"{msgChannel} tried to replicate CVars but is not in _replicatedCVars.");
|
||||
return;
|
||||
}
|
||||
|
||||
using var _ = Lock.ReadGuard();
|
||||
|
||||
foreach (var (name, value) in networkedVars)
|
||||
{
|
||||
if (!_configVars.TryGetValue(name, out var cVar))
|
||||
{
|
||||
Sawmill.Warning($"{msgChannel} tried to replicate an unknown CVar '{name}.'");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!cVar.Registered)
|
||||
{
|
||||
Sawmill.Warning($"{msgChannel} tried to replicate an unregistered CVar '{name}.'");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((cVar.Flags & CVar.REPLICATED) != 0)
|
||||
{
|
||||
clientCVars[name] = value;
|
||||
Sawmill.Debug($"name={name}, val={value}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Sawmill.Warning($"{msgChannel} tried to replicate an un-replicated CVar '{name}.'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using Robust.Server.Configuration;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared;
|
||||
@@ -28,7 +29,7 @@ internal sealed partial class PVSSystem : EntitySystem
|
||||
[Shared.IoC.Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Shared.IoC.Dependency] private readonly IConfigurationManager _configManager = default!;
|
||||
[Shared.IoC.Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Shared.IoC.Dependency] private readonly INetConfigurationManager _netConfigManager = default!;
|
||||
[Shared.IoC.Dependency] private readonly IServerNetConfigurationManager _netConfigManager = default!;
|
||||
[Shared.IoC.Dependency] private readonly IServerGameStateManager _serverGameStateManager = default!;
|
||||
|
||||
public const float ChunkSize = 8;
|
||||
|
||||
@@ -5,8 +5,8 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Prometheus;
|
||||
using Robust.Server.Configuration;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
@@ -37,7 +37,7 @@ namespace Robust.Server.Player
|
||||
[Dependency] private readonly IServerNetManager _network = default!;
|
||||
[Dependency] private readonly IReflectionManager _reflectionManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly INetConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly IServerNetConfigurationManager _cfg = default!;
|
||||
|
||||
public BoundKeyMap KeyMap { get; private set; } = default!;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Robust.Server.Bql;
|
||||
using Robust.Server.Configuration;
|
||||
using Robust.Server.Console;
|
||||
using Robust.Server.DataMetrics;
|
||||
using Robust.Server.Debugging;
|
||||
@@ -15,6 +16,7 @@ using Robust.Server.ServerHub;
|
||||
using Robust.Server.ServerStatus;
|
||||
using Robust.Server.ViewVariables;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -80,6 +82,11 @@ namespace Robust.Server
|
||||
deps.Register<IPhysicsManager, PhysicsManager>();
|
||||
deps.Register<IBqlQueryManager, BqlQueryManager>();
|
||||
deps.Register<HubManager, HubManager>();
|
||||
deps.Register<IConfigurationManager, ServerNetConfigurationManager>();
|
||||
deps.Register<INetConfigurationManager, ServerNetConfigurationManager>();
|
||||
deps.Register<IConfigurationManagerInternal, ServerNetConfigurationManager>();
|
||||
deps.Register<IServerNetConfigurationManager, ServerNetConfigurationManager>();
|
||||
deps.Register<INetConfigurationManagerInternal, ServerNetConfigurationManager>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,7 @@ namespace Robust.Shared.Configuration
|
||||
/// <summary>
|
||||
/// Stores and manages global configuration variables.
|
||||
/// </summary>
|
||||
[Virtual]
|
||||
internal class ConfigurationManager : IConfigurationManagerInternal
|
||||
internal abstract class ConfigurationManager : IConfigurationManagerInternal
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
@@ -448,7 +447,7 @@ namespace Robust.Shared.Configuration
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void SetCVar(string name, object value)
|
||||
public virtual void SetCVar(string name, object value, bool force = false)
|
||||
{
|
||||
SetCVarInternal(name, value, _gameTiming.CurTick);
|
||||
}
|
||||
@@ -480,9 +479,9 @@ namespace Robust.Shared.Configuration
|
||||
InvokeValueChanged(invoke.Value);
|
||||
}
|
||||
|
||||
public void SetCVar<T>(CVarDef<T> def, T value) where T : notnull
|
||||
public void SetCVar<T>(CVarDef<T> def, T value, bool force = false) where T : notnull
|
||||
{
|
||||
SetCVar(def.Name, value);
|
||||
SetCVar(def.Name, value, force);
|
||||
}
|
||||
|
||||
public void OverrideDefault(string name, object value)
|
||||
|
||||
@@ -96,9 +96,11 @@ namespace Robust.Shared.Configuration
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the CVar.</param>
|
||||
/// <param name="value">The value to set.</param>
|
||||
void SetCVar(string name, object value);
|
||||
/// <param name="force">If true, this will set the cvar even if it should not be settable (e.g., server
|
||||
/// authoritative cvars being set by clients).</param>
|
||||
void SetCVar(string name, object value, bool force = false);
|
||||
|
||||
void SetCVar<T>(CVarDef<T> def, T value) where T : notnull;
|
||||
void SetCVar<T>(CVarDef<T> def, T value, bool force = false) where T : notnull;
|
||||
|
||||
/// <summary>
|
||||
/// Change the default value for a CVar.
|
||||
|
||||
@@ -22,36 +22,9 @@ namespace Robust.Shared.Configuration
|
||||
void SetupNetworking();
|
||||
|
||||
/// <summary>
|
||||
/// Get a replicated client CVar for a specific client.
|
||||
/// Gets the list of networked cvars.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">CVar type.</typeparam>
|
||||
/// <param name="channel">channel of the connected client.</param>
|
||||
/// <param name="definition">The CVar.</param>
|
||||
/// <returns>Replicated CVar of the client.</returns>
|
||||
public T GetClientCVar<T>(INetChannel channel, CVarDef<T> definition) where T : notnull =>
|
||||
GetClientCVar<T>(channel, definition.Name);
|
||||
|
||||
/// <summary>
|
||||
/// Get a replicated client CVar for a specific client.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">CVar type.</typeparam>
|
||||
/// <param name="channel">channel of the connected client.</param>
|
||||
/// <param name="name">Name of the CVar.</param>
|
||||
/// <returns>Replicated CVar of the client.</returns>
|
||||
T GetClientCVar<T>(INetChannel channel, string name);
|
||||
|
||||
/// <summary>
|
||||
/// Synchronize the CVars marked with <see cref="CVar.REPLICATED"/> with the client.
|
||||
/// This needs to be called once during the client connection.
|
||||
/// </summary>
|
||||
/// <param name="client">Client's NetChannel to sync replicated CVars with.</param>
|
||||
void SyncConnectingClient(INetChannel client);
|
||||
|
||||
/// <summary>
|
||||
/// Synchronize the CVars marked with <see cref="CVar.REPLICATED"/> with the server.
|
||||
/// This needs to be called once when connecting.
|
||||
/// </summary>
|
||||
void SyncWithServer();
|
||||
List<(string name, object value)> GetReplicatedVars();
|
||||
|
||||
/// <summary>
|
||||
/// Called every tick to process any incoming network messages.
|
||||
@@ -64,12 +37,23 @@ namespace Robust.Shared.Configuration
|
||||
void FlushMessages();
|
||||
|
||||
/// <summary>
|
||||
/// Clears internal flag for <see cref="ReceivedInitialNwVars"/>.
|
||||
/// Must be called upon disconnect.
|
||||
/// Get a replicated client CVar for a specific client. When used client-side, this simply returns the local cvar.
|
||||
/// </summary>
|
||||
void ClearReceivedInitialNwVars();
|
||||
/// <typeparam name="T">CVar type.</typeparam>
|
||||
/// <param name="channel">channel of the connected client.</param>
|
||||
/// <param name="name">Name of the CVar.</param>
|
||||
/// <returns>Replicated CVar of the client.</returns>
|
||||
T GetClientCVar<T>(INetChannel channel, string name);
|
||||
|
||||
public event EventHandler ReceivedInitialNwVars;
|
||||
/// <summary>
|
||||
/// Get a replicated client CVar for a specific client.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">CVar type.</typeparam>
|
||||
/// <param name="channel">channel of the connected client.</param>
|
||||
/// <param name="definition">The CVar.</param>
|
||||
/// <returns>Replicated CVar of the client.</returns>
|
||||
T GetClientCVar<T>(INetChannel channel, CVarDef<T> definition) where T : notnull
|
||||
=> GetClientCVar<T>(channel, definition.Name);
|
||||
}
|
||||
|
||||
internal interface INetConfigurationManagerInternal : INetConfigurationManager, IConfigurationManagerInternal
|
||||
@@ -78,73 +62,38 @@ namespace Robust.Shared.Configuration
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="INetConfigurationManager"/>
|
||||
internal sealed class NetConfigurationManager : ConfigurationManager, INetConfigurationManagerInternal
|
||||
internal abstract class NetConfigurationManager : ConfigurationManager, INetConfigurationManagerInternal
|
||||
{
|
||||
[Dependency] private readonly INetManager _netManager = null!;
|
||||
[Dependency] private readonly IGameTiming _timing = null!;
|
||||
[Dependency] protected readonly INetManager NetManager = null!;
|
||||
[Dependency] protected readonly IGameTiming Timing = null!;
|
||||
|
||||
private readonly Dictionary<INetChannel, Dictionary<string, object>> _replicatedCVars = new();
|
||||
private readonly List<MsgConVars> _netVarsMessages = new();
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
public event EventHandler? ReceivedInitialNwVars;
|
||||
private bool _receivedInitialNwVars;
|
||||
protected ISawmill Sawmill = default!;
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
FlushMessages();
|
||||
_replicatedCVars.Clear();
|
||||
ReceivedInitialNwVars = null;
|
||||
_receivedInitialNwVars = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetupNetworking()
|
||||
public virtual void SetupNetworking()
|
||||
{
|
||||
_sawmill = Logger.GetSawmill("cfg");
|
||||
_sawmill.Level = LogLevel.Info;
|
||||
|
||||
if(_isServer)
|
||||
{
|
||||
_netManager.Connected += PeerConnected;
|
||||
_netManager.Disconnect += PeerDisconnected;
|
||||
}
|
||||
|
||||
_netManager.RegisterNetMessage<MsgConVars>(HandleNetVarMessage);
|
||||
Sawmill = Logger.GetSawmill("cfg");
|
||||
Sawmill.Level = LogLevel.Info;
|
||||
NetManager.RegisterNetMessage<MsgConVars>(HandleNetVarMessage);
|
||||
}
|
||||
|
||||
private void PeerConnected(object? sender, NetChannelArgs e)
|
||||
protected virtual void HandleNetVarMessage(MsgConVars message)
|
||||
{
|
||||
_replicatedCVars.Add(e.Channel, new Dictionary<string, object>());
|
||||
}
|
||||
|
||||
private void PeerDisconnected(object? sender, NetDisconnectedArgs e)
|
||||
{
|
||||
_replicatedCVars.Remove(e.Channel);
|
||||
}
|
||||
|
||||
private void HandleNetVarMessage(MsgConVars message)
|
||||
{
|
||||
if (_netManager.IsClient && !_receivedInitialNwVars)
|
||||
{
|
||||
_receivedInitialNwVars = true;
|
||||
|
||||
// apply the initial set immediately, so that they are available to
|
||||
// for the rest of connection building
|
||||
ApplyNetVarChange(message.MsgChannel, message.NetworkedVars, message.Tick);
|
||||
ReceivedInitialNwVars?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
else
|
||||
_netVarsMessages.Add(message);
|
||||
_netVarsMessages.Add(message);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void TickProcessMessages()
|
||||
{
|
||||
if (!_timing.InSimulation || _timing.InPrediction)
|
||||
if (!Timing.InSimulation || Timing.InPrediction)
|
||||
return;
|
||||
|
||||
// _netVarsMessages is not in any particular ordering.
|
||||
@@ -155,7 +104,7 @@ namespace Robust.Shared.Configuration
|
||||
{
|
||||
var msg = _netVarsMessages[i];
|
||||
|
||||
if (msg.Tick > _timing.CurTick)
|
||||
if (msg.Tick > Timing.CurTick)
|
||||
continue;
|
||||
|
||||
toApply.Add(msg);
|
||||
@@ -173,8 +122,8 @@ namespace Robust.Shared.Configuration
|
||||
{
|
||||
ApplyNetVarChange(msg.MsgChannel, msg.NetworkedVars, msg.Tick);
|
||||
|
||||
if(msg.Tick != default && msg.Tick < _timing.CurTick)
|
||||
_sawmill.Warning($"{msg.MsgChannel}: Received late nwVar message ({msg.Tick} < {_timing.CurTick} ).");
|
||||
if(msg.Tick != default && msg.Tick < Timing.CurTick)
|
||||
Sawmill.Warning($"{msg.MsgChannel}: Received late nwVar message ({msg.Tick} < {Timing.CurTick} ).");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,191 +140,26 @@ namespace Robust.Shared.Configuration
|
||||
_netVarsMessages.Clear();
|
||||
}
|
||||
|
||||
private void ApplyNetVarChange(
|
||||
protected abstract void ApplyNetVarChange(
|
||||
INetChannel msgChannel,
|
||||
List<(string name, object value)> networkedVars,
|
||||
GameTick tick)
|
||||
{
|
||||
_sawmill.Debug($"{msgChannel} Handling replicated cvars...");
|
||||
|
||||
if (_netManager.IsClient)
|
||||
{
|
||||
// Server sent us a CVar update.
|
||||
foreach (var (name, value) in networkedVars)
|
||||
{
|
||||
if (!_configVars.TryGetValue(name, out var cVar))
|
||||
{
|
||||
_sawmill.Warning($"{msgChannel} tried to replicate an unknown CVar '{name}.'");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((cVar.Flags & CVar.CLIENT) != 0)
|
||||
continue; // ignore the server specified value.
|
||||
|
||||
// Actually set the CVar
|
||||
SetCVarInternal(name, value, tick);
|
||||
|
||||
_sawmill.Debug($"name={name}, val={value}");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Client sent us a CVar update
|
||||
if (!_replicatedCVars.TryGetValue(msgChannel, out var clientCVars))
|
||||
{
|
||||
_sawmill.Warning($"{msgChannel} tried to replicate CVars but is not in _replicatedCVars.");
|
||||
return;
|
||||
}
|
||||
|
||||
using var _ = Lock.ReadGuard();
|
||||
|
||||
foreach (var (name, value) in networkedVars)
|
||||
{
|
||||
if (!_configVars.TryGetValue(name, out var cVar))
|
||||
{
|
||||
_sawmill.Warning($"{msgChannel} tried to replicate an unknown CVar '{name}.'");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!cVar.Registered)
|
||||
{
|
||||
_sawmill.Warning($"{msgChannel} tried to replicate an unregistered CVar '{name}.'");
|
||||
continue;
|
||||
}
|
||||
|
||||
if((cVar.Flags & CVar.REPLICATED) != 0)
|
||||
{
|
||||
clientCVars[name] = value;
|
||||
_sawmill.Debug($"name={name}, val={value}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_sawmill.Warning($"{msgChannel} tried to replicate an un-replicated CVar '{name}.'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public T GetClientCVar<T>(INetChannel channel, string name)
|
||||
{
|
||||
using var _ = Lock.ReadGuard();
|
||||
|
||||
if (!_configVars.TryGetValue(name, out var cVar) || !cVar.Registered)
|
||||
throw new InvalidConfigurationException($"Trying to get unregistered variable '{name}'");
|
||||
|
||||
if (_replicatedCVars.TryGetValue(channel, out var clientCVars) && clientCVars.TryGetValue(name, out var value))
|
||||
{
|
||||
return (T)value;
|
||||
}
|
||||
|
||||
return (T)(cVar.DefaultValue!);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void SetCVar(string name, object value)
|
||||
{
|
||||
CVar flags;
|
||||
using (Lock.ReadGuard())
|
||||
{
|
||||
if (_configVars.TryGetValue(name, out var cVar) && cVar.Registered)
|
||||
{
|
||||
flags = cVar.Flags;
|
||||
if (_netManager.IsClient)
|
||||
{
|
||||
if (_netManager.IsConnected)
|
||||
{
|
||||
if ((cVar.Flags & CVar.NOT_CONNECTED) != 0)
|
||||
{
|
||||
_sawmill.Warning($"'{name}' can only be changed when not connected to a server.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((cVar.Flags & CVar.SERVER) != 0)
|
||||
{
|
||||
_sawmill.Warning($"Only the server can change '{name}'.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((cVar.Flags & CVar.CLIENT) != 0)
|
||||
{
|
||||
_sawmill.Warning($"Only clients can change '{name}'.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidConfigurationException($"Trying to set unregistered variable '{name}'");
|
||||
}
|
||||
}
|
||||
|
||||
// Actually set the CVar
|
||||
base.SetCVar(name, value);
|
||||
|
||||
if ((flags & CVar.REPLICATED) == 0)
|
||||
return;
|
||||
|
||||
// replicate if needed
|
||||
if (_netManager.IsClient)
|
||||
{
|
||||
var msg = new MsgConVars();
|
||||
msg.Tick = _timing.CurTick;
|
||||
msg.NetworkedVars = new List<(string name, object value)>
|
||||
{
|
||||
(name, value)
|
||||
};
|
||||
_netManager.ClientSendMessage(msg);
|
||||
}
|
||||
else // Server
|
||||
{
|
||||
var msg = new MsgConVars();
|
||||
msg.Tick = _timing.CurTick;
|
||||
msg.NetworkedVars = new List<(string name, object value)>
|
||||
{
|
||||
(name, value)
|
||||
};
|
||||
_netManager.ServerSendToAll(msg);
|
||||
}
|
||||
}
|
||||
GameTick tick);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SyncConnectingClient(INetChannel client)
|
||||
{
|
||||
DebugTools.Assert(_netManager.IsConnected);
|
||||
DebugTools.Assert(_netManager.IsServer);
|
||||
DebugTools.Assert(NetManager.IsConnected);
|
||||
DebugTools.Assert(NetManager.IsServer);
|
||||
|
||||
_sawmill.Info($"{client}: Sending server info...");
|
||||
Sawmill.Info($"{client}: Sending server info...");
|
||||
|
||||
var msg = new MsgConVars();
|
||||
msg.Tick = _timing.CurTick;
|
||||
msg.Tick = Timing.CurTick;
|
||||
msg.NetworkedVars = GetReplicatedVars();
|
||||
_netManager.ServerSendMessage(msg, client);
|
||||
NetManager.ServerSendMessage(msg, client);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SyncWithServer()
|
||||
{
|
||||
DebugTools.Assert(_netManager.IsConnected);
|
||||
DebugTools.Assert(_netManager.IsClient);
|
||||
|
||||
_sawmill.Info("Sending client info...");
|
||||
|
||||
var msg = new MsgConVars();
|
||||
msg.Tick = default;
|
||||
msg.NetworkedVars = GetReplicatedVars();
|
||||
_netManager.ClientSendMessage(msg);
|
||||
}
|
||||
|
||||
public void ClearReceivedInitialNwVars()
|
||||
{
|
||||
_receivedInitialNwVars = false;
|
||||
}
|
||||
|
||||
private List<(string name, object value)> GetReplicatedVars()
|
||||
public List<(string name, object value)> GetReplicatedVars()
|
||||
{
|
||||
using var _ = Lock.ReadGuard();
|
||||
|
||||
@@ -389,15 +173,26 @@ namespace Robust.Shared.Configuration
|
||||
if ((cVar.Flags & CVar.REPLICATED) == 0)
|
||||
continue;
|
||||
|
||||
if (_netManager.IsClient && (cVar.Flags & CVar.SERVER) != 0)
|
||||
continue;
|
||||
if (NetManager.IsClient)
|
||||
{
|
||||
if ((cVar.Flags & CVar.SERVER) != 0)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((cVar.Flags & CVar.CLIENT) != 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
nwVars.Add((cVar.Name, GetConfigVarValue(cVar)));
|
||||
|
||||
_sawmill.Debug($"name={cVar.Name}, val={(cVar.Value ?? cVar.DefaultValue)}");
|
||||
Sawmill.Debug($"name={cVar.Name}, val={(cVar.Value ?? cVar.DefaultValue)}");
|
||||
}
|
||||
|
||||
return nwVars;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract T GetClientCVar<T>(INetChannel channel, string name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,6 @@ namespace Robust.Shared
|
||||
public static void RegisterIoC(IDependencyCollection deps)
|
||||
{
|
||||
deps.Register<ISerializationManager, SerializationManager>();
|
||||
deps.Register<IConfigurationManager, NetConfigurationManager>();
|
||||
deps.Register<INetConfigurationManager, NetConfigurationManager>();
|
||||
deps.Register<IConfigurationManagerInternal, NetConfigurationManager>();
|
||||
deps.Register<INetConfigurationManagerInternal, NetConfigurationManager>();
|
||||
deps.Register<IDynamicTypeFactory, DynamicTypeFactory>();
|
||||
deps.Register<IDynamicTypeFactoryInternal, DynamicTypeFactory>();
|
||||
deps.Register<IEntitySystemManager, EntitySystemManager>();
|
||||
|
||||
@@ -4,14 +4,16 @@ using System.Reflection;
|
||||
using JetBrains.Annotations;
|
||||
using Moq;
|
||||
using Robust.Server;
|
||||
using Robust.Server.Configuration;
|
||||
using Robust.Server.Console;
|
||||
using Robust.Server.Debugging;
|
||||
using Robust.Server.Containers;
|
||||
using Robust.Server.Debugging;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameStates;
|
||||
using Robust.Server.Physics;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Server.Reflection;
|
||||
using Robust.Server.Replays;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Asynchronous;
|
||||
using Robust.Shared.Configuration;
|
||||
@@ -29,19 +31,18 @@ using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Collision;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Dynamics;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Profiling;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Replays;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Threading;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Server.Replays;
|
||||
using Robust.Shared.Physics.Dynamics;
|
||||
using Robust.Shared.Replays;
|
||||
using Robust.Shared.Players;
|
||||
|
||||
namespace Robust.UnitTesting.Server
|
||||
{
|
||||
@@ -163,8 +164,11 @@ namespace Robust.UnitTesting.Server
|
||||
//Tier 1: System
|
||||
container.Register<ILogManager, LogManager>();
|
||||
container.Register<IRuntimeLog, RuntimeLog>();
|
||||
container.Register<IConfigurationManager, ConfigurationManager>();
|
||||
container.Register<IConfigurationManagerInternal, ConfigurationManager>();
|
||||
container.Register<IConfigurationManager, ServerNetConfigurationManager>();
|
||||
container.Register<INetConfigurationManager, ServerNetConfigurationManager>();
|
||||
container.Register<IConfigurationManagerInternal, ServerNetConfigurationManager>();
|
||||
container.Register<IServerNetConfigurationManager, ServerNetConfigurationManager>();
|
||||
container.Register<INetConfigurationManagerInternal, ServerNetConfigurationManager>();
|
||||
container.Register<IDynamicTypeFactory, DynamicTypeFactory>();
|
||||
container.Register<IDynamicTypeFactoryInternal, DynamicTypeFactory>();
|
||||
container.Register<ILocalizationManager, LocalizationManager>();
|
||||
@@ -231,7 +235,6 @@ namespace Robust.UnitTesting.Server
|
||||
|
||||
// I just wanted to load pvs system
|
||||
container.Register<IServerEntityManager, ServerEntityManager>();
|
||||
container.Register<INetConfigurationManager, NetConfigurationManager>();
|
||||
container.Register<IServerNetManager, NetManager>();
|
||||
// god help you if you actually need to test pvs functions
|
||||
container.RegisterInstance<IPlayerManager>(new Mock<IPlayerManager>().Object);
|
||||
@@ -257,7 +260,7 @@ namespace Robust.UnitTesting.Server
|
||||
|
||||
var compFactory = container.Resolve<IComponentFactory>();
|
||||
|
||||
// if only we had some sort of attribute for autmatically registering components.
|
||||
// if only we had some sort of attribute for automatically registering components.
|
||||
compFactory.RegisterClass<MetaDataComponent>();
|
||||
compFactory.RegisterClass<TransformComponent>();
|
||||
compFactory.RegisterClass<MapGridComponent>();
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using NUnit.Framework;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Robust.Server.Configuration;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Robust.UnitTesting.Shared.Configuration
|
||||
@@ -70,7 +73,9 @@ namespace Robust.UnitTesting.Shared.Configuration
|
||||
private ConfigurationManager MakeCfg()
|
||||
{
|
||||
var collection = new DependencyCollection();
|
||||
collection.Register<ConfigurationManager, ConfigurationManager>();
|
||||
collection.RegisterInstance<INetManager>(new Mock<INetManager>().Object);
|
||||
collection.Register<ConfigurationManager, ServerNetConfigurationManager>();
|
||||
collection.Register<IServerNetConfigurationManager, ServerNetConfigurationManager>();
|
||||
collection.Register<IGameTiming, GameTiming>();
|
||||
collection.Register<ILogManager, LogManager>();
|
||||
collection.BuildGraph();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using Robust.Server.Configuration;
|
||||
using Robust.Server.Reflection;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
@@ -29,8 +30,8 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
{
|
||||
var container = new DependencyCollection();
|
||||
container.Register<ILogManager, LogManager>();
|
||||
container.Register<IConfigurationManager, ConfigurationManager>();
|
||||
container.Register<IConfigurationManagerInternal, ConfigurationManager>();
|
||||
container.Register<IConfigurationManager, ServerNetConfigurationManager>();
|
||||
container.Register<IConfigurationManagerInternal, ServerNetConfigurationManager>();
|
||||
container.Register<INetManager, NetManager>();
|
||||
container.Register<IReflectionManager, ServerReflectionManager>();
|
||||
container.Register<IRobustSerializer, RobustSerializer>();
|
||||
|
||||
@@ -3,12 +3,14 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Robust.Server.Configuration;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Exceptions;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Profiling;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -72,7 +74,9 @@ namespace Robust.UnitTesting.Shared.GameObjects
|
||||
deps.Register<IRuntimeLog, RuntimeLog>();
|
||||
deps.Register<ILogManager, LogManager>();
|
||||
deps.Register<IGameTiming, GameTiming>();
|
||||
deps.Register<IConfigurationManager, ConfigurationManager>();
|
||||
deps.RegisterInstance<INetManager>(new Mock<INetManager>().Object);
|
||||
deps.Register<IConfigurationManager, ServerNetConfigurationManager>();
|
||||
deps.Register<IServerNetConfigurationManager, ServerNetConfigurationManager>();
|
||||
deps.Register<ProfManager, ProfManager>();
|
||||
deps.Register<IDynamicTypeFactory, DynamicTypeFactory>();
|
||||
deps.Register<IDynamicTypeFactoryInternal, DynamicTypeFactory>();
|
||||
|
||||
Reference in New Issue
Block a user