Compare commits

...

8 Commits

Author SHA1 Message Date
PJB3005
40b10f0dcc Version: 271.1.0 2026-01-20 19:45:58 +01:00
PJB3005
5885549c78 Release notes 2026-01-20 19:45:51 +01:00
PJB3005
89e16d5ba9 Fix Reset() not getting called if client channel disconnects unprompted.
Fixes https://github.com/space-wizards/RobustToolbox/issues/6390
Fixes https://github.com/space-wizards/RobustToolbox/issues/6388
2026-01-20 19:03:32 +01:00
PJB3005
2afef1480e Add debug code to slow down transfer connections 2026-01-20 19:01:56 +01:00
PJB3005
76189579c7 Remove dead code from transfer 2026-01-20 19:01:39 +01:00
PJB3005
114c2bee62 Fix transfer being entirely nonfunctional
Oops
2026-01-20 19:01:32 +01:00
PJB3005
ce96331ec4 Add completions to launchauth command 2026-01-20 01:14:56 +01:00
Ataman
14b17aff6d Add events on animation starts (#6382)
* added AnimationStartedEvent

* added AnimationStarted event to Control

* reordered Control.AnimationStarted above Control.AnimationCompleted

* fixed comment

* switched to internal constructor and proxy method
2026-01-19 23:29:22 +01:00
11 changed files with 135 additions and 29 deletions

View File

@@ -1,4 +1,4 @@
<Project>
<!-- This file automatically reset by Tools/version.py -->
<!-- This file automatically reset by Tools/version.py -->

View File

@@ -54,6 +54,22 @@ END TEMPLATE-->
*None yet*
## 271.1.0
### New features
* Added `AnimationStartedEvent` and `Control.AnimationStarted` events.
### Bugfixes
* Fixed the new transfer system not working.
* Fixed `NetManager` client state not getting reset properly when disconnected without call to `ClientDisconnect()`.
### Other
* The `launchauth` command now displays completions.
## 271.0.0
### Breaking changes

View File

@@ -1,6 +1,9 @@
#if TOOLS
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Data.Sqlite;
using Robust.Client.Utility;
using Robust.Shared.Console;
@@ -20,15 +23,7 @@ namespace Robust.Client.Console.Commands
{
var wantName = args.Length > 0 ? args[0] : null;
var basePath = UserDataDir.GetRootUserDataDir(_gameController);
var launcherDirName = Environment.GetEnvironmentVariable("SS14_LAUNCHER_APPDATA_NAME") ?? "launcher";
var dbPath = Path.Combine(basePath, launcherDirName, "settings.db");
#if USE_SYSTEM_SQLITE
SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3());
#endif
using var con = new SqliteConnection($"Data Source={dbPath};Mode=ReadOnly");
con.Open();
using var con = GetDb();
using var cmd = con.CreateCommand();
cmd.CommandText = "SELECT UserId, UserName, Token FROM Login WHERE Expires > datetime('NOW')";
@@ -57,6 +52,51 @@ namespace Robust.Client.Console.Commands
shell.WriteLine($"Logged into account {userName}");
}
public override async ValueTask<CompletionResult> GetCompletionAsync(
IConsoleShell shell,
string[] args,
string argStr,
CancellationToken cancel)
{
if (args.Length != 1)
return CompletionResult.Empty;
return await Task.Run(() =>
{
using var con = GetDb();
using var cmd = con.CreateCommand();
cmd.CommandText = "SELECT UserName FROM Login WHERE Expires > datetime('NOW')";
var options = new List<CompletionOption>();
using var reader = cmd.ExecuteReader();
while (reader.Read())
{
var name = reader.GetString(0);
options.Add(new CompletionOption(name));
}
return CompletionResult.FromOptions(options);
},
cancel);
}
private SqliteConnection GetDb()
{
var basePath = UserDataDir.GetRootUserDataDir(_gameController);
var launcherDirName = Environment.GetEnvironmentVariable("SS14_LAUNCHER_APPDATA_NAME") ?? "launcher";
var dbPath = Path.Combine(basePath, launcherDirName, "settings.db");
#if USE_SYSTEM_SQLITE
SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3());
#endif
var con = new SqliteConnection($"Data Source={dbPath};Mode=ReadOnly");
con.Open();
return con;
}
}
}

View File

@@ -154,6 +154,9 @@ namespace Robust.Client.GameObjects
}
ent.Comp.PlayingAnimations.Add(key, playback);
var startedEvent = new AnimationStartedEvent(ent.Owner, ent.Comp, key);
RaiseLocalEvent(ent.Owner, startedEvent, true);
}
public bool HasRunningAnimation(EntityUid uid, string key)
@@ -199,6 +202,34 @@ namespace Robust.Client.GameObjects
}
}
/// <summary>
/// Raised whenever an animation started playing.
/// </summary>
public sealed class AnimationStartedEvent : EntityEventArgs
{
/// <summary>
/// The entity associated with the event.
/// </summary>
public EntityUid Uid { get; init; }
/// <summary>
/// The animation player component associated with the entity this event was raised on.
/// </summary>
public AnimationPlayerComponent AnimationPlayer { get; init; }
/// <summary>
/// The key associated with the animation that was started.
/// </summary>
public string Key { get; init; } = string.Empty;
internal AnimationStartedEvent(EntityUid uid, AnimationPlayerComponent animationPlayer, string key)
{
Uid = uid;
AnimationPlayer = animationPlayer;
Key = key;
}
}
/// <summary>
/// Raised whenever an animation stops, either due to running its course or being stopped manually.
/// </summary>

View File

@@ -11,15 +11,18 @@ namespace Robust.Client.Network.Transfer;
internal sealed class ClientTransferImplWebSocket : TransferImplWebSocket
{
private readonly (string EndpointUrl, byte[] Key) _info;
private readonly bool _slow;
public ClientTransferImplWebSocket(
(string EndpointUrl, byte[] Key) info,
ISawmill sawmill,
BaseTransferManager parent,
INetChannel channel)
INetChannel channel,
bool slow)
: base(sawmill, parent, channel)
{
_info = info;
_slow = slow;
}
public override async Task ClientInit(CancellationToken cancel)
@@ -28,6 +31,9 @@ internal sealed class ClientTransferImplWebSocket : TransferImplWebSocket
clientWs.Options.SetRequestHeader(KeyHeaderName, Convert.ToBase64String(_info.Key));
clientWs.Options.SetRequestHeader(UserIdHeaderName, Channel.UserId.ToString());
if (_slow)
await Task.Delay(2000, cancel);
await clientWs.ConnectAsync(new Uri(_info.EndpointUrl), cancel);
WebSocket = clientWs;

View File

@@ -1,7 +1,9 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Robust.Shared;
using Robust.Shared.Asynchronous;
using Robust.Shared.Configuration;
using Robust.Shared.Log;
using Robust.Shared.Network;
using Robust.Shared.Network.Messages.Transfer;
@@ -12,6 +14,7 @@ namespace Robust.Client.Network.Transfer;
internal sealed class ClientTransferManager : BaseTransferManager, ITransferManager
{
private readonly IClientNetManager _netManager;
private readonly IConfigurationManager _cfg;
private BaseTransferImpl? _transferImpl;
public event Action? ClientHandshakeComplete;
@@ -19,10 +22,12 @@ internal sealed class ClientTransferManager : BaseTransferManager, ITransferMana
internal ClientTransferManager(
IClientNetManager netManager,
ILogManager logManager,
ITaskManager taskManager)
ITaskManager taskManager,
IConfigurationManager cfg)
: base(logManager, NetMessageAccept.Client, taskManager)
{
_netManager = netManager;
_cfg = cfg;
}
public Stream StartTransfer(INetChannel channel, TransferStartInfo startInfo)
@@ -48,7 +53,12 @@ internal sealed class ClientTransferManager : BaseTransferManager, ITransferMana
BaseTransferImpl impl;
if (message.HttpInfo is { } httpInfo)
{
impl = new ClientTransferImplWebSocket(httpInfo, Sawmill, this, message.MsgChannel);
impl = new ClientTransferImplWebSocket(
httpInfo,
Sawmill,
this,
message.MsgChannel,
_cfg.GetCVar(CVars.TransferArtificialDelay));
}
else
{

View File

@@ -12,6 +12,7 @@ namespace Robust.Client.UserInterface
{
private Dictionary<string, AnimationPlayback>? _playingAnimations;
public Action<string>? AnimationStarted;
public Action<string>? AnimationCompleted;
/// <summary>
@@ -27,6 +28,7 @@ namespace Robust.Client.UserInterface
_playingAnimations ??= new Dictionary<string, AnimationPlayback>();
_playingAnimations.Add(key, playback);
AnimationStarted?.Invoke(key);
}
public bool HasRunningAnimation(string key)

View File

@@ -441,6 +441,12 @@ namespace Robust.Shared
public static readonly CVarDef<int> TransferStreamLimit =
CVarDef.Create("transfer.stream_limit", 10, CVar.SERVERONLY);
/// <summary>
/// Artificially delay transfer operations to simulate slow network. Debug option.
/// </summary>
internal static readonly CVarDef<bool> TransferArtificialDelay =
CVarDef.Create("transfer.artificial_delay", false);
/**
* SUS
*/

View File

@@ -144,6 +144,7 @@ namespace Robust.Shared.Network
private bool _clientSerializerComplete;
private bool _clientTransferComplete;
private bool _clientResetPending;
/// <inheritdoc />
public int Port => _config.GetCVar(CVars.NetPort);
@@ -420,6 +421,10 @@ namespace Robust.Shared.Network
public void Reset(string reason)
{
_logger.Info($"Resetting NetManager: {reason}");
_clientResetPending = false;
foreach (var kvChannel in _channels)
{
DisconnectChannel(kvChannel.Value, reason);
@@ -606,6 +611,9 @@ namespace Robust.Shared.Network
MessagesUnsentMetrics.Set(unsent);
MessagesStoredMetrics.Set(stored);
*/
if (_clientResetPending)
Reset("Channel closed");
}
/// <inheritdoc />
@@ -875,14 +883,7 @@ namespace Robust.Shared.Network
#endif
if (IsClient)
{
connection.Peer.Shutdown(reason);
_toCleanNetPeers.Add(connection.Peer);
_strings.Reset();
_cancelConnectTokenSource?.Cancel();
ClientConnectState = ClientConnectionState.NotConnecting;
}
_clientResetPending = true;
}
/// <inheritdoc />

View File

@@ -56,8 +56,8 @@ internal abstract class BaseTransferImpl(ISawmill sawmill, BaseTransferManager p
return;
}
// var stream = new ReceiveStream(reader);
// Parent.TransferReceived(key, Channel, stream);
var stream = new ReceiveStream(reader);
Parent.TransferReceived(key, Channel, stream);
}
protected void HandleHeaderReceived(

View File

@@ -66,12 +66,6 @@ internal abstract partial class BaseTransferManager
});
}
protected void CheckRegistered(TransferStartInfo info)
{
if (!RegisteredKeys.ContainsKey(info.MessageKey))
throw new ArgumentException($"Key is not registered: {info.MessageKey}");
}
protected sealed class RegisteredKey
{
public Action<TransferReceivedEvent>? Callback;