Compare commits

..

1 Commits

Author SHA1 Message Date
PJB3005
927f05fd3b Robust native, compiled with ogg, opus, and vorbis 2026-01-10 23:22:13 +01:00
179 changed files with 7436 additions and 3988 deletions

View File

@@ -59,7 +59,7 @@
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.12" />
<PackageVersion Include="SpaceWizards.HttpListener" Version="0.2.0" />
<PackageVersion Include="SpaceWizards.NFluidsynth" Version="0.2.2" />
<PackageVersion Include="SpaceWizards.Sdl" Version="1.1.1" />
<PackageVersion Include="SpaceWizards.Sdl" Version="1.0.0" />
<PackageVersion Include="SpaceWizards.SharpFont" Version="1.1.0" />
<PackageVersion Include="SpaceWizards.Sodium" Version="0.3.0" />
<PackageVersion Include="SpaceWizards.Fontconfig.Interop" Version="1.0.0" />

View File

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

View File

@@ -11,7 +11,7 @@
<Target Name="_RTCheckForDirectReferences" BeforeTargets="BeforeResolveReferences"
Condition="'$(AllowDirectRobustReferences)' != 'true'">
<Error File="%(ProjectReference.DefiningProjectFullPath)"
Text="Direct reference to %(Filename) is not allowed. Use RobustToolbox/Imports/*.props instead (e.g., Shared.props, Client.props, Server.props)"
Text="Content may not reference %(Filename) directly"
Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('%(Identity)', 'RobustToolbox')) and !$([System.Text.RegularExpressions.Regex]::IsMatch('%(DefiningProjectFullPath)', '([Mm]icrosoft|RobustToolbox)'))" />
</Target>
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
#nullable enable
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using Robust.Roslyn.Shared;
@@ -27,15 +29,16 @@ public sealed class ValidateMemberAnalyzer : DiagnosticAnalyzer
{
context.EnableConcurrentExecution();
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
context.RegisterOperationAction(AnalyzeOperation, OperationKind.Invocation);
context.RegisterSyntaxNodeAction(AnalyzeExpression, SyntaxKind.InvocationExpression);
}
private void AnalyzeOperation(OperationAnalysisContext context)
private void AnalyzeExpression(SyntaxNodeAnalysisContext context)
{
if (context.Operation is not IInvocationOperation node)
if (context.Node is not InvocationExpressionSyntax node)
return;
var methodSymbol = node.TargetMethod;
if (context.SemanticModel.GetSymbolInfo(node.Expression).Symbol is not IMethodSymbol methodSymbol)
return;
// We need at least one type argument for context
if (methodSymbol.TypeArguments.Length < 1)
@@ -45,12 +48,16 @@ public sealed class ValidateMemberAnalyzer : DiagnosticAnalyzer
if (methodSymbol.TypeArguments[0] is not INamedTypeSymbol targetType)
return;
// Check each parameter of the method
foreach (var op in node.Arguments)
{
if (op.Parameter is null)
continue;
// We defer building this set until we need it later, so we don't have to build it for every single method invocation!
ImmutableHashSet<ISymbol>? members = null;
// Check each parameter of the method
foreach (var parameterContext in node.ArgumentList.Arguments)
{
// Get the symbol for this parameter
if (context.SemanticModel.GetOperation(parameterContext) is not IArgumentOperation op || op.Parameter is null)
continue;
var parameterSymbol = op.Parameter.OriginalDefinition;
// Make sure the parameter has the ValidateMember attribute
@@ -59,12 +66,15 @@ public sealed class ValidateMemberAnalyzer : DiagnosticAnalyzer
// Find the value passed for this parameter.
// We use GetConstantValue to resolve compile-time values - i.e. the result of nameof()
if (op.Value.ConstantValue is not { HasValue: true, Value: string fieldName})
if (context.SemanticModel.GetConstantValue(parameterContext.Expression).Value is not string fieldName)
continue;
// Get a set containing all the members of the target type and its ancestors
members ??= targetType.GetBaseTypesAndThis().SelectMany(n => n.GetMembers()).ToImmutableHashSet(SymbolEqualityComparer.Default);
// Check each member of the target type to see if it matches our passed in value
var found = false;
foreach (var member in targetType.GetMembers())
foreach (var member in members)
{
if (member.Name == fieldName)
{
@@ -74,14 +84,12 @@ public sealed class ValidateMemberAnalyzer : DiagnosticAnalyzer
}
// If we didn't find it, report the violation
if (!found)
{
context.ReportDiagnostic(Diagnostic.Create(
ValidateMemberDescriptor,
op.Syntax.GetLocation(),
parameterContext.GetLocation(),
fieldName,
targetType.Name
));
}
));
}
}
}

View File

@@ -16,11 +16,7 @@
<ProjectReference Include="..\Robust.UnitTesting\Robust.UnitTesting.csproj" />
</ItemGroup>
<ItemGroup>
<!-- BenchmarkDotNet autogenerates files that attempt to reference BenchmarkDotNet through Robust.Benchmarks.
By default the RT project privates these files, so we have to explicitly state that these files should be made available
to the BenchmarkDotNet project so it can build the runner that executes the benchmark. -->
<PackageReference Include="BenchmarkDotNet" PrivateAssets="none" />
<PackageReference Include="BenchmarkDotNet" />
<PackageReference Include="JetBrains.Annotations" />
<PackageReference Include="YamlDotNet" />
<PackageReference Include="prometheus-net" />

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using JetBrains.Annotations;
using OpenTK.Audio.OpenAL;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
@@ -16,6 +17,7 @@ using Robust.Shared.Exceptions;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
@@ -180,16 +182,14 @@ public sealed partial class AudioSystem : SharedAudioSystem
}
// If playback position changed then update it.
var totalLen = GetAudioLengthImpl(entity.Comp.FileName).TotalSeconds;
var position = CalculateAudioPosition(entity, (float) totalLen);
var position = (float) ((entity.Comp.PauseTime ?? Timing.CurTime) - entity.Comp.AudioStart).TotalSeconds;
var currentPosition = entity.Comp.Source.PlaybackPosition;
var diff = Math.Abs(position - currentPosition);
// Don't try to set the audio too far ahead.
if (!string.IsNullOrEmpty(entity.Comp.FileName))
{
if (position > totalLen - _audioEndBuffer)
if (position > GetAudioLengthImpl(entity.Comp.FileName).TotalSeconds - _audioEndBuffer)
{
entity.Comp.StopPlaying();
return;
@@ -251,7 +251,7 @@ public sealed partial class AudioSystem : SharedAudioSystem
length ??= GetAudioLength(component.FileName);
// If audio came into range then start playback at the correct position.
var offset = CalculateAudioPosition(entity, (float) length.Value.TotalSeconds);
var offset = ((entity.Comp.PauseTime ?? Timing.CurTime) - component.AudioStart).TotalSeconds;
if (TryAudioLimit(component.FileName))
{
@@ -289,7 +289,7 @@ public sealed partial class AudioSystem : SharedAudioSystem
if (offset > 0)
{
component.PlaybackPosition = offset;
component.PlaybackPosition = (float) offset;
}
}
@@ -755,7 +755,10 @@ public sealed partial class AudioSystem : SharedAudioSystem
var comp = entity.Comp;
var source = comp.Source;
var offset = CalculateAudioPosition(entity, (float)stream.Length.TotalSeconds, audioP.PlayOffsetSeconds);
// TODO clamp the offset inside of SetPlaybackPosition() itself.
var offset = audioP.PlayOffsetSeconds;
var maxOffset = Math.Max((float) stream.Length.TotalSeconds - 0.01f, 0f);
offset = Math.Clamp(offset, 0f, maxOffset);
source.PlaybackPosition = offset;
source.StartPlaying();

View File

@@ -13,7 +13,6 @@ using Robust.Client.HWId;
using Robust.Client.Input;
using Robust.Client.Localization;
using Robust.Client.Map;
using Robust.Client.Network.Transfer;
using Robust.Client.Placement;
using Robust.Client.Player;
using Robust.Client.Profiling;
@@ -42,7 +41,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Network.Transfer;
using Robust.Shared.Physics;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
@@ -176,8 +174,6 @@ namespace Robust.Client
deps.Register<IXamlProxyHelper, XamlProxyHelper>();
deps.Register<MarkupTagManager>();
deps.Register<IHWId, BasicHWId>();
deps.Register<ITransferManager, ClientTransferManager>();
deps.Register<ClientTransferTestManager>();
}
}
}

View File

@@ -1,9 +1,6 @@
#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;
@@ -23,7 +20,15 @@ namespace Robust.Client.Console.Commands
{
var wantName = args.Length > 0 ? args[0] : null;
using var con = 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
using var con = new SqliteConnection($"Data Source={dbPath};Mode=ReadOnly");
con.Open();
using var cmd = con.CreateCommand();
cmd.CommandText = "SELECT UserId, UserName, Token FROM Login WHERE Expires > datetime('NOW')";
@@ -52,51 +57,6 @@ 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

@@ -11,7 +11,6 @@ using Robust.Client.GameObjects;
using Robust.Client.GameStates;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.Network.Transfer;
using Robust.Client.Placement;
using Robust.Client.Replays.Loading;
using Robust.Client.Replays.Playback;
@@ -36,7 +35,6 @@ using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Network.Transfer;
using Robust.Shared.Profiling;
using Robust.Shared.Prototypes;
using Robust.Shared.Reflection;
@@ -100,8 +98,6 @@ namespace Robust.Client
[Dependency] private readonly ILocalizationManager _loc = default!;
[Dependency] private readonly ISystemFontManagerInternal _systemFontManager = default!;
[Dependency] private readonly LoadingScreenManager _loadscr = default!;
[Dependency] private readonly ITransferManager _transfer = default!;
[Dependency] private readonly ClientTransferTestManager _transferTest = default!;
private IWebViewManagerHook? _webViewHook;
@@ -205,14 +201,7 @@ namespace Robust.Client
_logManager.GetSawmill("res"));
_loadscr.LoadingStep(_resourceCache.PreloadTextures, "Texture preload");
_loadscr.LoadingStep(() =>
{
_networkManager.Initialize(false);
_transfer.Initialize();
_transferTest.Initialize();
},
_networkManager);
_loadscr.LoadingStep(() => { _networkManager.Initialize(false); }, _networkManager);
_loadscr.LoadingStep(_configurationManager.SetupNetworking, _configurationManager);
_loadscr.LoadingStep(_serializer.Initialize, _serializer);
_loadscr.LoadingStep(_inputManager.Initialize, _inputManager);
@@ -696,11 +685,6 @@ namespace Robust.Client
_modLoader.BroadcastUpdate(ModUpdateLevel.FramePostEngine, frameEventArgs);
}
using (_prof.Group("Transfer"))
{
_transfer.FrameUpdate();
}
_audio.FlushALDisposeQueues();
}

View File

@@ -1336,10 +1336,11 @@ namespace Robust.Client.GameObjects
public Layer(Layer toClone, SpriteComponent parent) : this(parent)
{
if (toClone.Shader != null)
{
Shader = toClone.Shader.Mutable ? toClone.Shader.Duplicate() : toClone.Shader;
UnShaded = toClone.UnShaded;
ShaderPrototype = toClone.ShaderPrototype;
UnShaded = toClone.UnShaded;
ShaderPrototype = toClone.ShaderPrototype;
}
Texture = toClone.Texture;
RSI = toClone.RSI;
State = toClone.State;

View File

@@ -14,9 +14,9 @@ namespace Robust.Client.GameObjects
private EntityQuery<AnimationPlayerComponent> _playerQuery;
private EntityQuery<MetaDataComponent> _metaQuery;
#if DEBUG
#pragma warning disable CS0414
[Dependency] private readonly IComponentFactory _compFact = default!;
#endif
#pragma warning restore CS0414
public override void Initialize()
{
@@ -154,9 +154,6 @@ 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)
@@ -202,34 +199,6 @@ 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

@@ -493,9 +493,6 @@ namespace Robust.Client.Graphics.Clyde
{
if (viewport.Eye == null || viewport.Eye.Position.MapId == MapId.Nullspace)
{
if (viewport.ClearWhenMissingEye)
RenderInRenderTarget(viewport.RenderTarget, () => { }, viewport.ClearColor);
return;
}

View File

@@ -138,7 +138,6 @@ namespace Robust.Client.Graphics.Clyde
public Vector2i Size { get; set; }
public event Action<ClearCachedViewportResourcesEvent>? ClearCachedResources;
public Color? ClearColor { get; set; } = Color.Black;
public bool ClearWhenMissingEye { get; set; }
public Vector2 RenderScale { get; set; } = Vector2.One;
public bool AutomaticRender { get; set; }
public long Id { get; }

View File

@@ -601,11 +601,6 @@ namespace Robust.Client.Graphics.Clyde
_clyde._windowing!.TextInputStop(Reg);
}
public void SetWindowProgress(WindowProgressState state, float value)
{
_clyde._windowing!.WindowSetProgress(Reg, state, value);
}
public nint? WindowsHWnd => _clyde._windowing!.WindowGetWin32Window(Reg);
}

View File

@@ -91,8 +91,6 @@ namespace Robust.Client.Graphics.Clyde
private bool _earlyGLInit;
private bool _threadWindowApi;
public bool IsInitialized { get; private set; }
public Clyde()
{
_currentBoundRenderTarget = default!;
@@ -185,8 +183,6 @@ namespace Robust.Client.Graphics.Clyde
if (!InitMainWindowAndRenderer())
return false;
IsInitialized = true;
return true;
}

View File

@@ -27,7 +27,6 @@ namespace Robust.Client.Graphics.Clyde
internal sealed class ClydeHeadless : IClydeInternal
{
// Would it make sense to report a fake resolution like 720p here so code doesn't break? idk.
public bool IsInitialized { get; private set; }
public IClydeWindow MainWindow { get; }
public Vector2i ScreenSize => (1280, 720);
public IEnumerable<IClydeWindow> AllWindows => _windows;
@@ -173,7 +172,6 @@ namespace Robust.Client.Graphics.Clyde
public bool InitializePostWindowing()
{
IsInitialized = true;
return true;
}
@@ -526,7 +524,6 @@ namespace Robust.Client.Graphics.Clyde
public Vector2i Size { get; }
public event Action<ClearCachedViewportResourcesEvent>? ClearCachedResources;
public Color? ClearColor { get; set; } = Color.Black;
public bool ClearWhenMissingEye { get; set; }
public Vector2 RenderScale { get; set; }
public bool AutomaticRender { get; set; }
@@ -585,11 +582,6 @@ namespace Robust.Client.Graphics.Clyde
public event Action<WindowDestroyedEventArgs>? Destroyed;
public event Action<WindowResizedEventArgs>? Resized { add { } remove { } }
public void SetWindowProgress(WindowProgressState state, float value)
{
// Nop.
}
public void TextInputSetRect(UIBox2i rect, int cursor)
{
// Nop.

View File

@@ -42,7 +42,6 @@ namespace Robust.Client.Graphics.Clyde
void WindowSetSize(WindowReg window, Vector2i size);
void WindowSetVisible(WindowReg window, bool visible);
void WindowRequestAttention(WindowReg window);
void WindowSetProgress(WindowReg reg, WindowProgressState state, float value);
void WindowSwapBuffers(WindowReg window);
uint? WindowGetX11Id(WindowReg window);
nint? WindowGetX11Display(WindowReg window);

View File

@@ -38,7 +38,7 @@ internal partial class Clyde
fixed (Rgba32* pixPtr = img.GetPixelSpan())
{
var surface = (nint) SDL.SDL_CreateSurfaceFrom(
var surface = SDL.SDL_CreateSurfaceFrom(
img.Width,
img.Height,
SDL.SDL_PixelFormat.SDL_PIXELFORMAT_ABGR8888,

View File

@@ -21,7 +21,6 @@ internal partial class Clyde
private sealed partial class Sdl3WindowingImpl
{
private int _nextWindowId = 1;
private bool _progressUnavailable;
public (WindowReg?, string? error) WindowCreate(
GLContextSpec? spec,
@@ -439,8 +438,7 @@ internal partial class Clyde
private static void WinThreadWinSetSize(CmdWinSetSize cmd)
{
var density = SDL.SDL_GetWindowPixelDensity(cmd.Window);
SDL.SDL_SetWindowSize(cmd.Window, (int)(cmd.W / density), (int)(cmd.H / density));
SDL.SDL_SetWindowSize(cmd.Window, cmd.W, cmd.H);
}
private static void WinThreadWinSetVisible(CmdWinSetVisible cmd)
@@ -463,42 +461,6 @@ internal partial class Clyde
_sawmill.Error("Failed to flash window: {error}", SDL.SDL_GetError());
}
public void WindowSetProgress(WindowReg window, WindowProgressState state, float value)
{
SendCmd(new CmdWinSetProgress
{
Window = WinPtr(window),
State = (SDL.SDL_ProgressState)state,
Value = value
});
}
private void WinThreadWinSetProgress(CmdWinSetProgress cmd)
{
if (_progressUnavailable)
return;
try
{
var res = SDL.SDL_SetWindowProgressState(cmd.Window, cmd.State);
if (!res)
{
_sawmill.Error("Failed to set window progress state: {error}", SDL.SDL_GetError());
return;
}
res = SDL.SDL_SetWindowProgressValue(cmd.Window, cmd.Value);
if (!res)
_sawmill.Error("Failed to set window progress value: {error}", SDL.SDL_GetError());
}
catch (EntryPointNotFoundException)
{
// Allowing it to fail means I don't have to update the launcher immediately :)
_progressUnavailable = true;
_sawmill.Debug("SDL3 progress APIs unavailable");
}
}
public unsafe void WindowSwapBuffers(WindowReg window)
{
var reg = (Sdl3WindowReg)window;

View File

@@ -75,7 +75,7 @@ internal partial class Clyde
IntPtr surface;
fixed (byte* ptr = copied)
{
surface = (nint) SDL.SDL_CreateSurfaceFrom(
surface = SDL.SDL_CreateSurfaceFrom(
img.Width,
img.Height,
SDL.SDL_PixelFormat.SDL_PIXELFORMAT_ABGR8888,

View File

@@ -93,10 +93,6 @@ internal partial class Clyde
WinThreadWinRequestAttention(cmd);
break;
case CmdWinSetProgress cmd:
WinThreadWinSetProgress(cmd);
break;
case CmdWinSetSize cmd:
WinThreadWinSetSize(cmd);
break;
@@ -265,13 +261,6 @@ internal partial class Clyde
public nint Window;
}
private sealed class CmdWinSetProgress : CmdBase
{
public nint Window;
public SDL.SDL_ProgressState State;
public float Value;
}
private sealed class CmdWinSetSize : CmdBase
{
public nint Window;

View File

@@ -18,8 +18,6 @@ namespace Robust.Client.Graphics
[NotContentImplementable]
public interface IClyde
{
internal bool IsInitialized { get; }
IClydeWindow MainWindow { get; }
IRenderTarget MainWindowRenderTarget => MainWindow.RenderTarget;

View File

@@ -43,11 +43,6 @@ namespace Robust.Client.Graphics
/// </summary>
Color? ClearColor { get; set; }
/// <summary>
/// On frames where Eye is null or in nullspace, whether the viewport may clear.
/// </summary>
bool ClearWhenMissingEye { get; set; }
/// <summary>
/// This is, effectively, a multiplier to the eye's zoom.
/// </summary>

View File

@@ -2,7 +2,6 @@
using System.Numerics;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using SDL3;
namespace Robust.Client.Graphics
{
@@ -44,8 +43,6 @@ namespace Robust.Client.Graphics
/// </summary>
event Action<WindowResizedEventArgs> Resized;
internal void SetWindowProgress(WindowProgressState state, float value);
/// <summary>
/// Set the active text input area in window pixel coordinates.
/// </summary>
@@ -71,15 +68,6 @@ namespace Robust.Client.Graphics
void TextInputStop();
}
internal enum WindowProgressState : byte
{
None = SDL.SDL_ProgressState.SDL_PROGRESS_STATE_NONE,
Indeterminate = SDL.SDL_ProgressState.SDL_PROGRESS_STATE_INDETERMINATE,
Normal = SDL.SDL_ProgressState.SDL_PROGRESS_STATE_NORMAL,
Paused = SDL.SDL_ProgressState.SDL_PROGRESS_STATE_PAUSED,
Error = SDL.SDL_ProgressState.SDL_PROGRESS_STATE_ERROR
}
[NotContentImplementable]
internal interface IClydeWindowInternal : IClydeWindow
{

View File

@@ -118,13 +118,6 @@ internal sealed class LoadingScreenManager : ILoadingScreenManager
_currentSectionName = sectionName;
if (_clyde.IsInitialized)
{
_clyde.MainWindow.SetWindowProgress(
WindowProgressState.Normal,
_currentSection / (float)_numberOfLoadingSections);
}
if (!dontRender)
{
// This ensures that if the screen was resized or something the new size is properly updated to clyde.
@@ -183,8 +176,6 @@ internal sealed class LoadingScreenManager : ILoadingScreenManager
if (_currentSection != _numberOfLoadingSections)
_sawmill.Error($"The number of seen loading sections isn't equal to the total number of loading sections! Seen: {_currentSection}, Total: {_numberOfLoadingSections}");
_clyde.MainWindow.SetWindowProgress(WindowProgressState.None, 1);
_finished = true;
}

View File

@@ -0,0 +1,13 @@
using System.Runtime.CompilerServices;
using Robust.Shared.Interop.RobustNative;
namespace Robust.Client;
internal static class ModuleInit
{
[ModuleInitializer]
public static void Initialize()
{
RobustNativeDll.IsClientProcess = true;
}
}

View File

@@ -1,48 +0,0 @@
using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using Robust.Shared.Log;
using Robust.Shared.Network;
using Robust.Shared.Network.Transfer;
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,
bool slow)
: base(sawmill, parent, channel)
{
_info = info;
_slow = slow;
}
public override async Task ClientInit(CancellationToken cancel)
{
var clientWs = new ClientWebSocket();
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;
ReadThread();
}
public override Task ServerInit()
{
throw new NotSupportedException();
}
}

View File

@@ -1,89 +0,0 @@
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;
using Robust.Shared.Network.Transfer;
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;
internal ClientTransferManager(
IClientNetManager netManager,
ILogManager logManager,
ITaskManager taskManager,
IConfigurationManager cfg)
: base(logManager, NetMessageAccept.Client, taskManager)
{
_netManager = netManager;
_cfg = cfg;
}
public Stream StartTransfer(INetChannel channel, TransferStartInfo startInfo)
{
if (_transferImpl == null)
throw new InvalidOperationException("Not connected yet!");
if (channel != _netManager.ServerChannel)
throw new InvalidOperationException("Invalid channel!");
return _transferImpl.StartTransfer(startInfo);
}
public void Initialize()
{
_netManager.RegisterNetMessage<MsgTransferInit>(RxTransferInit, NetMessageAccept.Client | NetMessageAccept.Handshake);
_netManager.RegisterNetMessage<MsgTransferAckInit>();
_netManager.RegisterNetMessage<MsgTransferData>(RxTransferData, NetMessageAccept.Client | NetMessageAccept.Handshake);
}
private async void RxTransferInit(MsgTransferInit message)
{
BaseTransferImpl impl;
if (message.HttpInfo is { } httpInfo)
{
impl = new ClientTransferImplWebSocket(
httpInfo,
Sawmill,
this,
message.MsgChannel,
_cfg.GetCVar(CVars.TransferArtificialDelay));
}
else
{
impl = new TransferImplLidgren(Sawmill, message.MsgChannel, this, _netManager);
}
_transferImpl = impl;
await _transferImpl.ClientInit(default);
ClientHandshakeComplete?.Invoke();
}
private void RxTransferData(MsgTransferData message)
{
if (_transferImpl is not TransferImplLidgren lidgren)
{
message.MsgChannel.Disconnect("Not lidgren");
return;
}
lidgren.ReceiveData(message);
}
public Task ServerHandshake(INetChannel channel)
{
throw new NotSupportedException();
}
}

View File

@@ -1,14 +0,0 @@
using Robust.Shared.Log;
using Robust.Shared.Network;
using Robust.Shared.Network.Transfer;
namespace Robust.Client.Network.Transfer;
internal sealed class ClientTransferTestManager(ITransferManager manager, ILogManager logManager)
: TransferTestManager(manager, logManager)
{
protected override bool PermissionCheck(INetChannel channel)
{
return true;
}
}

View File

@@ -13,9 +13,9 @@ namespace Robust.Client.Prototypes
public sealed class ClientPrototypeManager : PrototypeManager
{
[Dependency] private readonly INetManager _netManager = default!;
#if TOOLS
#pragma warning disable CS0414
[Dependency] private readonly IClientGameTiming _timing = default!;
#endif
#pragma warning restore CS0414
[Dependency] private readonly IGameControllerInternal _controller = default!;
[Dependency] private readonly IReloadManager _reload = default!;

View File

@@ -279,7 +279,10 @@ public sealed partial class ReplayLoadManager
var path = resUpload.RelativePath.Clean().ToRelativePath();
if (uploadedFiles.Add(path) && !_netResMan.FileExists(path))
{
_netResMan.StoreFile(path, resUpload.Data);
_netMan.DispatchLocalNetMessage(new NetworkResourceUploadMessage
{
RelativePath = path, Data = resUpload.Data
});
message.Messages.RemoveSwap(i);
break;
}

View File

@@ -21,6 +21,7 @@ public sealed partial class ReplayLoadManager : IReplayLoadManager
[Dependency] private readonly IBaseClient _client = default!;
[Dependency] private readonly EntityManager _entMan = default!;
[Dependency] private readonly IClientGameTiming _timing = default!;
[Dependency] private readonly IClientNetManager _netMan = default!;
[Dependency] private readonly IComponentFactory _factory = default!;
[Dependency] private readonly IPrototypeManager _protoMan = default!;
[Dependency] private readonly ILocalizationManager _locMan = default!;

View File

@@ -48,6 +48,7 @@
<ProjectReference Include="..\Lidgren.Network\Lidgren.Network.csproj" />
<ProjectReference Include="..\NetSerializer\NetSerializer\NetSerializer.csproj" />
<ProjectReference Include="..\Robust.LoaderApi\Robust.LoaderApi\Robust.LoaderApi.csproj" />
<ProjectReference Include="..\Robust.Shared.Interop.RobustNative\Robust.Shared.Interop.RobustNative.csproj" />
<ProjectReference Include="..\Robust.Shared.Maths\Robust.Shared.Maths.csproj" />
<ProjectReference Include="..\Robust.Shared\Robust.Shared.csproj" />
</ItemGroup>

View File

@@ -4,6 +4,7 @@ using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Upload;
using Robust.Shared.Utility;
@@ -13,7 +14,7 @@ public sealed class UploadFileCommand : IConsoleCommand
{
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
[Dependency] private readonly IFileDialogManager _dialog = default!;
[Dependency] private readonly NetworkResourceManager _netRes = default!;
[Dependency] private readonly INetManager _netManager = default!;
public string Command => "uploadfile";
public string Description => "Uploads a resource to the server.";
@@ -54,6 +55,12 @@ public sealed class UploadFileCommand : IConsoleCommand
var data = file.CopyToArray();
_netRes.UploadResources([(path, data)]);
var msg = new NetworkResourceUploadMessage
{
RelativePath = path,
Data = data
};
_netManager.ClientSendMessage(msg);
}
}

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System;
using System.IO;
using Robust.Shared;
using Robust.Shared.Configuration;
@@ -6,6 +6,7 @@ using Robust.Shared.Console;
using Robust.Shared.ContentPack;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Network;
using Robust.Shared.Upload;
using Robust.Shared.Utility;
@@ -13,9 +14,9 @@ namespace Robust.Client.Upload.Commands;
public sealed class UploadFolderCommand : IConsoleCommand
{
[Dependency] private readonly IResourceManager _resourceManager = default!;
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly NetworkResourceManager _netRes = default!;
[Dependency] private IResourceManager _resourceManager = default!;
[Dependency] private IConfigurationManager _configManager = default!;
[Dependency] private INetManager _netMan = default!;
public string Command => "uploadfolder";
public string Description => Loc.GetString("uploadfolder-command-description");
@@ -49,7 +50,6 @@ public sealed class UploadFolderCommand : IConsoleCommand
}
//Grab all files in specified folder and upload them
var files = new List<(ResPath Relative, byte[] Data)>();
foreach (var filepath in _resourceManager.UserData.Find($"{folderPath.ToRelativePath()}/").files )
{
await using var filestream = _resourceManager.UserData.Open(filepath, FileMode.Open);
@@ -63,14 +63,17 @@ public sealed class UploadFolderCommand : IConsoleCommand
var data = filestream.CopyToArray();
files.Add((filepath.RelativeTo(BaseUploadFolderPath), data));
var msg = new NetworkResourceUploadMessage
{
RelativePath = filepath.RelativeTo(BaseUploadFolderPath),
Data = data
};
_netMan.ClientSendMessage(msg);
fileCount++;
}
}
_netRes.UploadResources(files);
shell.WriteLine( Loc.GetString("uploadfolder-command-success",("fileCount",fileCount)));
}
}

View File

@@ -1,11 +1,5 @@
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Network.Transfer;
using Robust.Shared.Upload;
using Robust.Shared.Utility;
namespace Robust.Client.Upload;
@@ -13,44 +7,10 @@ public sealed class NetworkResourceManager : SharedNetworkResourceManager
{
[Dependency] private readonly IBaseClient _client = default!;
internal override void Initialize()
public override void Initialize()
{
base.Initialize();
_client.RunLevelChanged += OnLevelChanged;
TransferManager.RegisterTransferMessage(TransferKeyNetworkUpload);
TransferManager.RegisterTransferMessage(TransferKeyNetworkDownload, ReceiveDownload);
NetManager.RegisterNetMessage<NetworkResourceAckMessage>();
}
private async void ReceiveDownload(TransferReceivedEvent transfer)
{
Sawmill.Debug("Receiving file download transfer!");
await using var stream = transfer.DataStream;
try
{
var ackKeyBytes = new byte[4];
await stream.ReadExactlyAsync(ackKeyBytes);
var ackKey = BinaryPrimitives.ReadInt32LittleEndian(ackKeyBytes);
await IngestFileStream(stream);
if (ackKey != 0)
{
NetManager.ClientSendMessage(new NetworkResourceAckMessage
{
Key = ackKey
});
}
}
catch (Exception e)
{
Sawmill.Error($"Error while downloading transfer resources: {e}");
}
}
private void OnLevelChanged(object? sender, RunLevelChangedEventArgs e)
@@ -67,20 +27,4 @@ public sealed class NetworkResourceManager : SharedNetworkResourceManager
{
ContentRoot.Clear();
}
internal async void UploadResources(List<(ResPath Relative, byte[] Data)> files)
{
var clientNet = (IClientNetManager)NetManager;
if (clientNet.ServerChannel is not { } channel)
throw new InvalidOperationException("Not connected to server!");
await using var transfer = TransferManager.StartTransfer(
channel,
new TransferStartInfo
{
MessageKey = TransferKeyNetworkUpload,
});
await WriteFileStream(transfer, files);
}
}

View File

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

View File

@@ -2,7 +2,6 @@ using System;
using System.Numerics;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Animations;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.ViewVariables;
@@ -356,7 +355,6 @@ namespace Robust.Client.UserInterface
/// </remarks>
/// <seealso cref="MinWidth"/>
/// <seealso cref="MinHeight"/>
[Animatable]
public Vector2 MinSize
{
get => new(_minWidth, _minHeight);
@@ -380,7 +378,6 @@ namespace Robust.Client.UserInterface
/// </remarks>
/// <seealso cref="SetWidth"/>
/// <seealso cref="SetHeight"/>
[Animatable]
public Vector2 SetSize
{
get => new(_setWidth, _setHeight);
@@ -437,7 +434,6 @@ namespace Robust.Client.UserInterface
/// Width component of <see cref="SetSize"/>.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[Animatable]
public float SetWidth
{
get => _setWidth;
@@ -453,7 +449,6 @@ namespace Robust.Client.UserInterface
/// Height component of <see cref="SetSize"/>.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[Animatable]
public float SetHeight
{
get => _setHeight;

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Text;
@@ -44,7 +44,6 @@ namespace Robust.Client.UserInterface.Controls
/// Thrown if <see cref="TextMemory"/> was set directly and there is no backing string instance to fetch.
/// </exception>
[ViewVariables]
[Animatable]
public string? Text
{
get => _text ?? (_textMemory.Length > 0 ? throw new InvalidOperationException("Label uses TextMemory, cannot fetch string text.") : null);

View File

@@ -144,7 +144,7 @@ namespace Robust.Client.UserInterface.Controls
SetPositionFirst();
// Resize the window by our UIScale
ClydeWindow.Size = new((int)(parameters.Width * UIScale), (int)(parameters.Height * UIScale));
ClydeWindow.Size = new((int)(ClydeWindow.Size.X * UIScale), (int)(ClydeWindow.Size.Y * UIScale));
return ClydeWindow;
}

View File

@@ -22,10 +22,8 @@ namespace Robust.Client.UserInterface.Controls
private int _currentTab;
private bool _tabsVisible = true;
// the laid out tabs
private List<TabBox> _tabBoxes = new();
private float _enclosingTabHeight;
// The right-most coordinate of each tab header
private List<float> _tabRight = new();
public int CurrentTab
{
@@ -148,66 +146,41 @@ namespace Robust.Client.UserInterface.Controls
base.Draw(handle);
// First, draw panel.
var headerSize = _enclosingTabHeight;
var headerSize = _getHeaderSize();
var panel = _getPanel();
var panelBox = new UIBox2(0, headerSize, PixelWidth, PixelHeight);
panel?.Draw(handle, panelBox, UIScale);
var font = _getFont();
var boxActive = _getTabBoxActive();
var boxInactive = _getTabBoxInactive();
var fontColorActive = _getTabFontColorActive();
var fontColorInactive = _getTabFontColorInactive();
// Then draw the tabs
foreach (var tabBox in _tabBoxes)
{
if (tabBox.Box is { } styleBox)
{
styleBox.Draw(handle, tabBox.Bounding, UIScale);
}
var headerOffset = 0f;
var baseLine = new Vector2(0, font.GetAscent(UIScale)) + tabBox.Content.TopLeft;
foreach (var rune in tabBox.Title.EnumerateRunes())
{
if (!font.TryGetCharMetrics(rune, UIScale, out var metrics))
continue;
font.DrawChar(handle, rune, baseLine, UIScale, tabBox.Index == _currentTab ? fontColorActive : fontColorInactive);
baseLine += new Vector2(metrics.Advance, 0);
}
}
}
private readonly record struct TabBox(UIBox2 Bounding, UIBox2 Content, StyleBox? Box, string Title, int Index);
private void CalculateTabBoxes(Vector2 availableSize)
{
availableSize *= UIScale;
var tabLeft = 0f;
var tabTop = 0f;
var tabHeight = 0f;
var font = _getFont();
var boxActive = _getTabBoxActive();
var boxInactive = _getTabBoxInactive();
_tabBoxes.Clear();
if (!_tabsVisible)
return;
_tabRight.Clear();
// Then, draw the tabs.
for (var i = 0; i < ChildCount; i++)
{
if (!GetTabVisible(i))
{
_tabRight.Add(headerOffset);
continue;
}
var title = GetActualTabTitle(i);
var titleLength = 0;
// Get string length.
foreach (var rune in title.EnumerateRunes())
{
if (!font.TryGetCharMetrics(rune, UIScale, out var metrics))
{
continue;
}
titleLength += metrics.Advance;
}
@@ -215,57 +188,50 @@ namespace Robust.Client.UserInterface.Controls
var active = _currentTab == i;
var box = active ? boxActive : boxInactive;
var topLeft = new Vector2(tabLeft, tabTop);
var size = new Vector2(titleLength, font.GetHeight(UIScale));
if (box != null)
{
size = box.GetEnvelopBox(topLeft, size, UIScale).Size;
}
if (tabLeft + size.X > availableSize.X)
{
tabLeft = 0;
tabTop += tabHeight;
tabHeight = 0;
}
topLeft = new(tabLeft, tabTop);
size = new(titleLength, font.GetHeight(UIScale));
UIBox2 boundingBox;
UIBox2 contentBox;
var topLeft = new Vector2(headerOffset, 0);
var size = new Vector2(titleLength, font.GetHeight(UIScale));
float boxAdvance;
if (box != null)
{
boundingBox = box.GetEnvelopBox(topLeft, size, UIScale);
contentBox = box.GetContentBox(boundingBox, UIScale);
var drawBox = box.GetEnvelopBox(topLeft, size, UIScale);
boxAdvance = drawBox.Width;
box.Draw(handle, drawBox, UIScale);
contentBox = box.GetContentBox(drawBox, UIScale);
}
else
{
boxAdvance = size.X;
contentBox = UIBox2.FromDimensions(topLeft, size);
boundingBox = contentBox;
}
tabLeft += boundingBox.Size.X;
tabHeight = Math.Max(tabHeight, boundingBox.Size.Y);
_tabBoxes.Add(new(boundingBox, contentBox, box, title, i));
}
var baseLine = new Vector2(0, font.GetAscent(UIScale)) + contentBox.TopLeft;
if (Math.Abs(_enclosingTabHeight - (tabTop + tabHeight)) >= 0.1)
{
InvalidateArrange();
foreach (var rune in title.EnumerateRunes())
{
if (!font.TryGetCharMetrics(rune, UIScale, out var metrics))
{
continue;
}
font.DrawChar(handle, rune, baseLine, UIScale, active ? fontColorActive : fontColorInactive);
baseLine += new Vector2(metrics.Advance, 0);
}
headerOffset += boxAdvance;
// Remember the right-most point of this tab, for testing clicked areas
_tabRight.Add(headerOffset);
}
_enclosingTabHeight = tabTop + tabHeight;
}
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
CalculateTabBoxes(availableSize);
var headerSize = Vector2.Zero;
if (TabsVisible)
{
headerSize = new Vector2(0, _enclosingTabHeight / UIScale);
headerSize = new Vector2(0, _getHeaderSize() / UIScale);
}
var panel = _getPanel();
@@ -288,13 +254,12 @@ namespace Robust.Client.UserInterface.Controls
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
CalculateTabBoxes(finalSize);
if (ChildCount == 0 || _currentTab >= ChildCount)
{
return finalSize;
}
var headerSize = (int)_enclosingTabHeight;
var headerSize = _getHeaderSize();
var panel = _getPanel();
var contentBox = new UIBox2i(0, headerSize, (int) (finalSize.X * UIScale), (int) (finalSize.Y * UIScale));
if (panel != null)
@@ -318,23 +283,50 @@ namespace Robust.Client.UserInterface.Controls
}
// Outside of header size, ignore.
if (args.RelativePixelPosition.Y < 0 || args.RelativePixelPosition.Y > _enclosingTabHeight)
if (args.RelativePixelPosition.Y < 0 || args.RelativePixelPosition.Y > _getHeaderSize())
{
return;
}
args.Handle();
foreach (var box in _tabBoxes)
var relX = args.RelativePixelPosition.X;
float tabLeft = 0;
for (var i = 0; i < ChildCount; i++)
{
if (box.Bounding.Contains(args.RelativePixelPosition))
if (relX > tabLeft && relX <= _tabRight[i])
{
CurrentTab = box.Index;
CurrentTab = i;
return;
}
// Next tab starts here
tabLeft = _tabRight[i];
}
}
// Returns the size of the header, in real pixels
[System.Diagnostics.Contracts.Pure]
private int _getHeaderSize()
{
var headerSize = 0;
if (TabsVisible)
{
var active = _getTabBoxActive();
var inactive = _getTabBoxInactive();
var font = _getFont();
var activeSize = (active?.MinimumSize ?? Vector2.Zero) * UIScale;
var inactiveSize = (inactive?.MinimumSize ?? Vector2.Zero) * UIScale;
headerSize = (int) MathF.Max(activeSize.Y, inactiveSize.Y);
headerSize += font.GetHeight(UIScale);
}
return headerSize;
}
[System.Diagnostics.Contracts.Pure]
private StyleBox? _getTabBoxActive()
{

View File

@@ -14,6 +14,15 @@ namespace Robust.Client.Utility
{
NativeLibrary.SetDllImportResolver(typeof(ClientDllMap).Assembly, (name, assembly, path) =>
{
if (name == "swnfd.dll")
{
#if LINUX || FREEBSD
return NativeLibrary.Load("libswnfd.so", assembly, path);
#elif MACOS
return NativeLibrary.Load("libswnfd.dylib", assembly, path);
#endif
}
if (name == "libEGL.dll")
{
#if LINUX || FREEBSD

View File

@@ -20,9 +20,9 @@ internal sealed class ReloadManager : IReloadManager
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly ILogManager _logMan = default!;
[Dependency] private readonly IResourceManagerInternal _res = default!;
#if TOOLS
#pragma warning disable CS0414
[Dependency] private readonly ITaskManager _tasks = default!;
#endif
#pragma warning restore CS0414
private readonly TimeSpan _reloadDelay = TimeSpan.FromMilliseconds(10);
private CancellationTokenSource _reloadToken = new();

View File

@@ -56,7 +56,7 @@ internal sealed class ViewVariableControlFactory : IViewVariableControlFactory
RegisterForType<TimeSpan>(_ => new VVPropEditorTimeSpan());
RegisterWithCondition(
type => type != typeof(ViewVariablesBlobMembers.ServerValueTypeToken),
type => type != typeof(ViewVariablesBlobMembers.ServerValueTypeToken) && !type.IsValueType,
_ => new VVPropEditorReference()
);
RegisterWithCondition(

View File

@@ -9,13 +9,11 @@ using Robust.Server.Debugging;
using Robust.Server.GameObjects;
using Robust.Server.GameStates;
using Robust.Server.Localization;
using Robust.Server.Network.Transfer;
using Robust.Server.Physics;
using Robust.Server.Player;
using Robust.Server.Prototypes;
using Robust.Server.Reflection;
using Robust.Server.Replays;
using Robust.Server.ServerStatus;
using Robust.Shared;
using Robust.Shared.Asynchronous;
using Robust.Shared.Configuration;
@@ -30,7 +28,6 @@ using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Network;
using Robust.Shared.Network.Transfer;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision;
using Robust.Shared.Physics.Components;
@@ -201,9 +198,6 @@ namespace Robust.UnitTesting.Server
container.Register<HttpClientHolder>();
container.Register<IHttpClientHolder, HttpClientHolder>();
container.Register<IHWId, DummyHWId>();
container.Register<IServerNetManager, NetManager>();
container.Register<IStatusHost, StatusHost>();
container.Register<ITransferManager, ServerTransferManager>();
var realReflection = new ServerReflectionManager();
realReflection.LoadAssemblies(new List<Assembly>(2)
@@ -268,6 +262,7 @@ namespace Robust.UnitTesting.Server
// I just wanted to load pvs system
container.Register<IServerEntityManager, ServerEntityManager>();
container.Register<IServerNetManager, NetManager>();
// god help you if you actually need to test pvs functions
container.RegisterInstance<IPlayerManager>(new Mock<IPlayerManager>().Object);
container.RegisterInstance<ISharedPlayerManager>(new Mock<ISharedPlayerManager>().Object);

View File

@@ -9,7 +9,6 @@ using Robust.Server.DataMetrics;
using Robust.Server.GameObjects;
using Robust.Server.GameStates;
using Robust.Server.Log;
using Robust.Server.Network.Transfer;
using Robust.Server.Placement;
using Robust.Server.Player;
using Robust.Server.Scripting;
@@ -30,7 +29,6 @@ using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Network.Transfer;
using Robust.Shared.Player;
using Robust.Shared.Profiling;
using Robust.Shared.Prototypes;
@@ -109,8 +107,6 @@ namespace Robust.Server
[Dependency] private readonly UploadedContentManager _uploadedContMan = default!;
[Dependency] private readonly NetworkResourceManager _netResMan = default!;
[Dependency] private readonly IReflectionManager _refMan = default!;
[Dependency] private readonly ITransferManager _transfer = default!;
[Dependency] private readonly ServerTransferTestManager _transferTest = default!;
private readonly Stopwatch _uptimeStopwatch = new();
@@ -279,7 +275,6 @@ namespace Robust.Server
// Load metrics really early so that we can profile startup times in the future maybe.
_metricsManager.Initialize();
_prof.Initialize();
try
{
@@ -298,9 +293,6 @@ namespace Robust.Server
return true;
}
_transfer.Initialize();
_transferTest.Initialize();
var dataDir = Options.LoadConfigAndUserData
? _commandLineArgs?.DataDir ?? PathHelpers.ExecutableRelativeFile("data")
: null;
@@ -781,8 +773,6 @@ namespace Robust.Server
_modLoader.BroadcastUpdate(ModUpdateLevel.FramePostEngine, frameEventArgs);
_transfer.FrameUpdate();
_metricsManager.FrameUpdate();
}

View File

@@ -9,7 +9,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Network.Messages;
using Robust.Shared.Player;
using Robust.Shared.Profiling;
using Robust.Shared.Toolshed;
using Robust.Shared.Utility;
@@ -23,7 +22,6 @@ namespace Robust.Server.Console
[Dependency] private readonly IPlayerManager _players = default!;
[Dependency] private readonly ISystemConsoleManager _systemConsole = default!;
[Dependency] private readonly ToolshedManager _toolshed = default!;
[Dependency] private readonly ProfManager _prof = default!;
public ServerConsoleHost() : base(isServer: true) {}
@@ -110,8 +108,7 @@ namespace Robust.Server.Console
if (args.Count == 0)
return;
var cmdName = args[0];
using var _ = _prof.Group(cmdName);
string? cmdName = args[0];
if (RegisteredCommands.TryGetValue(cmdName, out var conCmd)) // command registered
{

View File

@@ -0,0 +1,13 @@
using System.Runtime.CompilerServices;
using Robust.Shared.Interop.RobustNative;
namespace Robust.Server;
internal static class ModuleInit
{
[ModuleInitializer]
public static void Initialize()
{
RobustNativeDll.IsServerProcess = true;
}
}

View File

@@ -1,122 +0,0 @@
using System;
using System.Net;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using Robust.Server.ServerStatus;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.Log;
using Robust.Shared.Network;
using Robust.Shared.Network.Messages.Transfer;
using Robust.Shared.Network.Transfer;
using Robust.Shared.Utility;
namespace Robust.Server.Network.Transfer;
internal sealed class ServerTransferImplWebSocket : TransferImplWebSocket
{
private readonly IConfigurationManager _cfg;
private readonly INetManager _netManager;
private readonly SemaphoreSlim _apiLock = new(1, 1);
private readonly TaskCompletionSource _connectTcs = new();
// To authenticate the client doing the HTTP request,
// we ask that they provide a key we gave them via Lidgren traffic.
public byte[]? Key;
public ServerTransferImplWebSocket(
ISawmill sawmill,
BaseTransferManager parent,
IConfigurationManager cfg,
INetManager netManager,
INetChannel channel)
: base(sawmill, parent, channel)
{
_cfg = cfg;
_netManager = netManager;
}
public override Task ServerInit()
{
Key = RandomNumberGenerator.GetBytes(RandomKeyBytes);
var uriBuilder = new UriBuilder(string.Concat(
_cfg.GetCVar(CVars.TransferHttpEndpoint).TrimEnd("/"),
ServerTransferManager.TransferApiUrl));
uriBuilder.Scheme = uriBuilder.Scheme switch
{
"http" => "ws",
"https" => "wss",
_ => throw new InvalidOperationException($"Invalid API endpoint scheme: {uriBuilder.Scheme}")
};
var url = uriBuilder.ToString();
Sawmill.Verbose($"Transfer API URL is '{url}'");
var initMsg = new MsgTransferInit();
initMsg.HttpInfo = (url, Key);
_netManager.ServerSendMessage(initMsg, Channel);
return _connectTcs.Task;
}
public override Task ClientInit(CancellationToken cancel)
{
throw new NotSupportedException();
}
public async Task HandleApiRequest(NetUserId userId, IStatusHandlerContext context)
{
using var _ = await _apiLock.WaitGuardAsync();
if (Key == null)
{
Sawmill.Warning($"HTTP request failed: UserID '{userId}' tried to connect twice");
await context.RespondErrorAsync(HttpStatusCode.BadRequest);
return;
}
if (!context.RequestHeaders.TryGetValue(KeyHeaderName, out var keyValue) || keyValue is not [{ } keyValueStr])
{
await context.RespondErrorAsync(HttpStatusCode.BadRequest);
return;
}
var buf = new byte[RandomKeyBytes];
if (!Convert.TryFromBase64String(keyValueStr, buf, out var written) || written != RandomKeyBytes)
{
Sawmill.Verbose("HTTP request failed: key is not valid base64 or wrong length");
await context.RespondErrorAsync(HttpStatusCode.BadRequest);
return;
}
if (!CryptographicOperations.FixedTimeEquals(buf, Key))
{
Sawmill.Warning("HTTP request failed: key is wrong");
await context.RespondErrorAsync(HttpStatusCode.Unauthorized);
return;
}
Sawmill.Debug("Client connect to transfer WS channel: {UserId}", userId);
WebSocket = await context.AcceptWebSocketAsync();
// We've connected.
// Clear key so this can't be reconnected to.
Key = null;
_connectTcs.TrySetResult();
ReadThread();
}
public override void Dispose()
{
_connectTcs.TrySetCanceled();
}
}

View File

@@ -1,171 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using Robust.Server.ServerStatus;
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;
using Robust.Shared.Network.Transfer;
namespace Robust.Server.Network.Transfer;
internal sealed class ServerTransferManager : BaseTransferManager, ITransferManager
{
internal const string TransferApiUrl = "/rt_transfer_init";
private readonly IConfigurationManager _cfg;
private readonly IStatusHost _statusHost;
private readonly IServerNetManager _netManager;
private readonly Dictionary<NetUserId, Player> _onlinePlayers = new();
internal ServerTransferManager(IConfigurationManager cfg, IStatusHost statusHost, IServerNetManager netManager, ILogManager logManager, ITaskManager taskManager)
: base(logManager, NetMessageAccept.Server, taskManager)
{
_cfg = cfg;
_statusHost = statusHost;
_netManager = netManager;
}
public void Initialize()
{
_netManager.RegisterNetMessage<MsgTransferInit>();
_netManager.RegisterNetMessage<MsgTransferData>(RxTransferData, NetMessageAccept.Server | NetMessageAccept.Handshake);
_netManager.RegisterNetMessage<MsgTransferAckInit>(RxTransferAckInit, NetMessageAccept.Server | NetMessageAccept.Handshake);
_statusHost.AddHandler(HandleRequest);
_netManager.Disconnect += NetManagerOnDisconnect;
}
private void RxTransferData(MsgTransferData message)
{
if (!_onlinePlayers.TryGetValue(message.MsgChannel.UserId, out var player)
|| player.Impl is not TransferImplLidgren lidgren)
{
message.MsgChannel.Disconnect("Not lidgren");
return;
}
lidgren.ReceiveData(message);
}
private void RxTransferAckInit(MsgTransferAckInit message)
{
if (!_onlinePlayers.TryGetValue(message.MsgChannel.UserId, out var player)
|| player.Impl is not TransferImplLidgren lidgren)
{
message.MsgChannel.Disconnect("Not lidgren");
return;
}
lidgren.ReceiveInitAck();
}
public Stream StartTransfer(INetChannel channel, TransferStartInfo startInfo)
{
if (!_onlinePlayers.TryGetValue(channel.UserId, out var player))
throw new InvalidOperationException("Player is not connected yet!");
return player.Impl.StartTransfer(startInfo);
}
private async Task<bool> HandleRequest(IStatusHandlerContext context)
{
if (context.Url.AbsolutePath != TransferApiUrl)
return false;
if (!context.IsWebSocketRequest)
{
Sawmill.Verbose("HTTP request failed: not a websocket request");
await context.RespondErrorAsync(HttpStatusCode.BadRequest);
return true;
}
if (!context.RequestHeaders.TryGetValue(TransferImplWebSocket.UserIdHeaderName, out var userIdValue)
|| userIdValue.Count != 1)
{
Sawmill.Verbose("HTTP request failed: missing RT-UserId");
await context.RespondErrorAsync(HttpStatusCode.BadRequest);
return true;
}
if (!Guid.TryParse(userIdValue[0], out var userId))
{
Sawmill.Verbose($"HTTP request failed: UserID '{userId}' invalid");
await context.RespondErrorAsync(HttpStatusCode.BadRequest);
return true;
}
if (!_onlinePlayers.TryGetValue(new NetUserId(userId), out var player))
{
Sawmill.Warning($"HTTP request failed: UserID '{userId}' not online");
await context.RespondErrorAsync(HttpStatusCode.BadRequest);
return true;
}
if (player.Impl is not ServerTransferImplWebSocket serverWs)
{
Sawmill.Warning($"HTTP request failed: UserID '{userId}' is not using websocket transfer");
await context.RespondErrorAsync(HttpStatusCode.Unauthorized);
return true;
}
await serverWs.HandleApiRequest(new NetUserId(userId), context);
return true;
}
public async Task ServerHandshake(INetChannel channel)
{
if (_onlinePlayers.ContainsKey(channel.UserId))
throw new InvalidOperationException("We already have data for this user??");
var transferHttpEnabled = _cfg.GetCVar(CVars.TransferHttp);
BaseTransferImpl impl;
if (transferHttpEnabled)
{
impl = new ServerTransferImplWebSocket(Sawmill, this, _cfg, _netManager, channel);
}
else
{
impl = new TransferImplLidgren(Sawmill, channel, this, _netManager);
}
impl.MaxChannelCount = _cfg.GetCVar(CVars.TransferStreamLimit);
var datum = new Player
{
Impl = impl,
};
_onlinePlayers.Add(channel.UserId, datum);
await impl.ServerInit();
}
public event Action ClientHandshakeComplete
{
add { }
remove { }
}
private void NetManagerOnDisconnect(object? sender, NetDisconnectedArgs e)
{
if (!_onlinePlayers.Remove(e.Channel.UserId, out var player))
return;
Sawmill.Debug("Cleaning up connection for channel {Player} that disconnected", e.Channel);
player.Impl.Dispose();
}
private sealed class Player
{
public required BaseTransferImpl Impl;
}
}

View File

@@ -1,23 +0,0 @@
using Robust.Server.Console;
using Robust.Server.Player;
using Robust.Shared.Log;
using Robust.Shared.Network;
using Robust.Shared.Network.Transfer;
namespace Robust.Server.Network.Transfer;
internal sealed class ServerTransferTestManager(
ITransferManager manager,
ILogManager logManager,
IConGroupController controller,
IPlayerManager playerManager)
: TransferTestManager(manager, logManager)
{
protected override bool PermissionCheck(INetChannel channel)
{
if (!playerManager.TryGetSessionByChannel(channel, out var session))
return false;
return controller.CanCommand(session, TransferTestCommand.CommandKey);
}
}

View File

@@ -217,10 +217,6 @@ namespace Robust.Server.Placement
}
}
/// <summary>
/// Deletes any existing entity.
/// </summary>
/// <param name="msg"></param>
private void HandleEntRemoveReq(MsgPlacement msg)
{
//TODO: Some form of admin check
@@ -229,61 +225,26 @@ namespace Robust.Server.Placement
if (!_entityManager.EntityExists(entity))
return;
var placementEraseEvent = new PlacementEntityEvent(entity,
_entityManager.GetComponent<TransformComponent>(entity).Coordinates,
PlacementEventAction.Erase,
msg.MsgChannel.UserId);
var placementEraseEvent = new PlacementEntityEvent(entity, _entityManager.GetComponent<TransformComponent>(entity).Coordinates, PlacementEventAction.Erase, msg.MsgChannel.UserId);
_entityManager.EventBus.RaiseEvent(EventSource.Local, placementEraseEvent);
_entityManager.DeleteEntity(entity);
}
/// <summary>
/// Deletes almost any existing entity within a selection box.
/// </summary>
/// <param name="msg"></param>
private void HandleRectRemoveReq(MsgPlacement msg)
{
var start = _entityManager.GetCoordinates(msg.NetCoordinates);
var rectSize = msg.RectSize;
foreach (var entity in _lookup.GetEntitiesIntersecting(_xformSystem.GetMapId(start), new Box2(start.Position, start.Position + rectSize)))
EntityCoordinates start = _entityManager.GetCoordinates(msg.NetCoordinates);
Vector2 rectSize = msg.RectSize;
foreach (var entity in _lookup.GetEntitiesIntersecting(_xformSystem.GetMapId(start),
new Box2(start.Position, start.Position + rectSize)))
{
if (_entityManager.Deleted(entity)
|| _entityManager.HasComponent<MapGridComponent>(entity)
|| _entityManager.HasComponent<ActorComponent>(entity))
continue;
var xform = _entityManager.GetComponent<TransformComponent>(entity);
var parent = xform.ParentUid;
var isChildOfActor = false;
while (parent.IsValid())
if (_entityManager.Deleted(entity) ||
_entityManager.HasComponent<MapGridComponent>(entity) ||
_entityManager.HasComponent<ActorComponent>(entity))
{
if (_entityManager.HasComponent<ActorComponent>(parent))
{
isChildOfActor = true;
break;
}
if (_entityManager.TryGetComponent<TransformComponent>(parent, out var parentXform))
{
parent = parentXform.ParentUid;
}
else
{
break;
}
continue;
}
if (isChildOfActor)
continue;
var placementEraseEvent = new PlacementEntityEvent(entity,
_entityManager.GetComponent<TransformComponent>(entity).Coordinates,
PlacementEventAction.Erase,
msg.MsgChannel.UserId);
var placementEraseEvent = new PlacementEntityEvent(entity, _entityManager.GetComponent<TransformComponent>(entity).Coordinates, PlacementEventAction.Erase, msg.MsgChannel.UserId);
_entityManager.EventBus.RaiseEvent(EventSource.Local, placementEraseEvent);
_entityManager.DeleteEntity(entity);
}

View File

@@ -1,5 +1,4 @@
using Robust.Shared.Input;
using Robust.Shared.Network;
using Robust.Shared.Player;
namespace Robust.Server.Player;
@@ -11,6 +10,4 @@ namespace Robust.Server.Player;
public interface IPlayerManager : ISharedPlayerManager
{
BoundKeyMap KeyMap { get; }
internal void MarkPlayerResourcesSent(INetChannel channel);
}

View File

@@ -120,34 +120,13 @@ namespace Robust.Server.Player
private void HandlePlayerListReq(MsgPlayerListReq message)
{
var channel = message.MsgChannel;
var session = (CommonSession) GetSessionByChannel(channel);
session.InitialPlayerListReqDone = true;
if (!session.InitialResourcesDone)
return;
SendPlayerList(channel, session);
}
public void MarkPlayerResourcesSent(INetChannel channel)
{
var session = (CommonSession) GetSessionByChannel(channel);
session.InitialResourcesDone = true;
if (!session.InitialPlayerListReqDone)
return;
SendPlayerList(channel, session);
}
private void SendPlayerList(INetChannel channel, CommonSession session)
{
var players = Sessions;
var netMsg = new MsgPlayerList();
// client session is complete, set their status accordingly.
// This is done before the packet is built, so that the client
// can see themselves Connected.
var session = GetSessionByChannel(channel);
session.ConnectedTime = DateTime.UtcNow;
SetStatus(session, SessionStatus.Connected);

View File

@@ -13,10 +13,10 @@ namespace Robust.Server.Prototypes
{
public sealed class ServerPrototypeManager : PrototypeManager
{
#if TOOLS
#pragma warning disable CS0414
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IConGroupController _conGroups = default!;
#endif
#pragma warning restore CS0414
[Dependency] private readonly INetManager _netManager = default!;
[Dependency] private readonly IBaseServerInternal _server = default!;

View File

@@ -44,6 +44,7 @@
<ItemGroup>
<ProjectReference Include="..\Lidgren.Network\Lidgren.Network.csproj" />
<ProjectReference Include="..\NetSerializer\NetSerializer\NetSerializer.csproj" />
<ProjectReference Include="..\Robust.Shared.Interop.RobustNative\Robust.Shared.Interop.RobustNative.csproj" />
<ProjectReference Include="..\Robust.Shared.Maths\Robust.Shared.Maths.csproj" />
<ProjectReference Include="..\Robust.Shared.Scripting\Robust.Shared.Scripting.csproj" />
<ProjectReference Include="..\Robust.Shared\Robust.Shared.csproj" />

View File

@@ -5,7 +5,6 @@ using Robust.Server.DataMetrics;
using Robust.Server.GameObjects;
using Robust.Server.GameStates;
using Robust.Server.Localization;
using Robust.Server.Network.Transfer;
using Robust.Server.Placement;
using Robust.Server.Player;
using Robust.Server.Prototypes;
@@ -26,7 +25,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Network.Transfer;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Reflection;
@@ -104,8 +102,6 @@ namespace Robust.Server
deps.Register<IHWId, DummyHWId>();
deps.Register<ILocalizationManager, ServerLocalizationManager>();
deps.Register<ILocalizationManagerInternal, ServerLocalizationManager>();
deps.Register<ITransferManager, ServerTransferManager>();
deps.Register<ServerTransferTestManager>();
}
}
}

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.WebSockets;
using System.Threading.Tasks;
using Microsoft.Extensions.Primitives;
@@ -26,8 +25,6 @@ namespace Robust.Server.ServerStatus
IDictionary<string, string> ResponseHeaders { get; }
bool KeepAlive { get; set; }
bool IsWebSocketRequest { get; }
Task<T?> RequestBodyJsonAsync<T>();
Task RespondNoContentAsync();
@@ -57,7 +54,5 @@ namespace Robust.Server.ServerStatus
Task RespondJsonAsync(object jsonData, HttpStatusCode code = HttpStatusCode.OK);
Task<Stream> RespondStreamAsync(HttpStatusCode code = HttpStatusCode.OK);
Task<WebSocket> AcceptWebSocketAsync();
}
}

View File

@@ -14,7 +14,6 @@ using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Mime;
using System.Net.WebSockets;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
@@ -243,7 +242,6 @@ namespace Robust.Server.ServerStatus
public Uri Url => _context.Request.Url!;
public bool IsGetLike => RequestMethod == HttpMethod.Head || RequestMethod == HttpMethod.Get;
public IReadOnlyDictionary<string, StringValues> RequestHeaders { get; }
public bool IsWebSocketRequest => _context.Request.IsWebSocketRequest;
public bool KeepAlive
{
@@ -355,12 +353,6 @@ namespace Robust.Server.ServerStatus
return Task.FromResult(_context.Response.OutputStream);
}
public async Task<WebSocket> AcceptWebSocketAsync()
{
var context = await _context.AcceptWebSocketAsync(null);
return context.WebSocket;
}
private void RespondShared()
{
foreach (var (header, value) in _responseHeaders)

View File

@@ -1,153 +1,77 @@
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Robust.Server.Console;
using Robust.Server.Player;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Network.Transfer;
using Robust.Shared.Player;
using Robust.Shared.Upload;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
namespace Robust.Server.Upload;
public sealed class NetworkResourcesUploadedEvent
{
public ICommonSession Session { get; }
public ImmutableArray<(ResPath Relative, byte[] Data)> Files { get; }
internal NetworkResourcesUploadedEvent(ICommonSession session, ImmutableArray<(ResPath, byte[])> files)
{
Session = session;
Files = files;
}
}
public sealed class NetworkResourceManager : SharedNetworkResourceManager
{
internal const int AckInitial = 1;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IServerNetManager _serverNetManager = default!;
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
[Dependency] private readonly IConGroupController _controller = default!;
[Obsolete("Use ResourcesUploaded instead")]
public event Action<ICommonSession, NetworkResourceUploadMessage>? OnResourceUploaded;
public event Action<NetworkResourcesUploadedEvent>? ResourcesUploaded;
[ViewVariables] public bool Enabled { get; private set; } = true;
[ViewVariables] public float SizeLimit { get; private set; }
internal event Action<INetChannel, int>? AckReceived;
internal override void Initialize()
public override void Initialize()
{
base.Initialize();
TransferManager.RegisterTransferMessage(TransferKeyNetworkDownload);
TransferManager.RegisterTransferMessage(TransferKeyNetworkUpload, ReceiveUpload);
_cfgManager.OnValueChanged(CVars.ResourceUploadingEnabled, value => Enabled = value, true);
_cfgManager.OnValueChanged(CVars.ResourceUploadingLimitMb, value => SizeLimit = value, true);
_serverNetManager.RegisterNetMessage<NetworkResourceAckMessage>(RxAck);
}
private void RxAck(NetworkResourceAckMessage message)
{
AckReceived?.Invoke(message.MsgChannel, message.Key);
}
private async void ReceiveUpload(TransferReceivedEvent transfer)
/// <summary>
/// Callback for when a client attempts to upload a resource.
/// </summary>
/// <param name="msg"></param>
/// <exception cref="NotImplementedException"></exception>
protected override void ResourceUploadMsg(NetworkResourceUploadMessage msg)
{
// Do not allow uploading any new resources if it has been disabled.
// Note: Any resources uploaded before being disabled will still be kept and sent.
if (!Enabled)
{
transfer.Channel.Disconnect("Resource upload not enabled.");
return;
}
if (!_playerManager.TryGetSessionByChannel(transfer.Channel, out var session))
{
transfer.Channel.Disconnect("Not in-game");
if (!_playerManager.TryGetSessionByChannel(msg.MsgChannel, out var session))
return;
}
if (!_controller.CanCommand(session, "uploadfile"))
{
transfer.Channel.Disconnect("Not authorized");
return;
}
Sawmill.Verbose("Ingesting file uploads from {Session}", session);
// Ensure the data is under the current size limit, if it's currently enabled.
if (SizeLimit > 0f && msg.Data.Length * BytesToMegabytes > SizeLimit)
return;
List<(ResPath Relative, byte[] Data)> ingested;
await using (var stream = transfer.DataStream)
{
ingested = await IngestFileStream(stream);
}
Sawmill.Verbose("Ingesting file uploads complete, distributing...");
base.ResourceUploadMsg(msg);
// Now we broadcast the message!
foreach (var channel in _serverNetManager.Channels)
{
SendToPlayer(channel, ingested);
channel.SendMessage(msg);
}
#pragma warning disable CS0618 // Type or member is obsolete
if (OnResourceUploaded != null)
OnResourceUploaded?.Invoke(session, msg);
}
internal void SendToNewUser(INetChannel channel)
{
foreach (var (path, data) in ContentRoot.GetAllFiles())
{
foreach (var (relative, data) in ingested)
{
OnResourceUploaded?.Invoke(session, new NetworkResourceUploadMessage
{
MsgChannel = session.Channel,
Data = data,
RelativePath = relative
});
}
var msg = new NetworkResourceUploadMessage();
msg.RelativePath = path;
msg.Data = data;
channel.SendMessage(msg);
}
#pragma warning restore CS0618 // Type or member is obsolete
ResourcesUploaded?.Invoke(new NetworkResourcesUploadedEvent(session, [..ingested]));
}
protected override void ValidateUpload(uint size)
{
if (SizeLimit > 0f && size * BytesToMegabytes > SizeLimit)
throw new Exception("File upload too large!");
}
internal bool SendToNewUser(INetChannel channel)
{
var allFiles = ContentRoot.GetAllFiles().ToList();
if (allFiles.Count == 0)
return false;
SendToPlayer(channel, allFiles, AckInitial);
return true;
}
private async void SendToPlayer(INetChannel channel, List<(ResPath Relative, byte[] Data)> files, int ack = 0)
{
await using var stream = TransferManager.StartTransfer(channel,
new TransferStartInfo
{
MessageKey = TransferKeyNetworkDownload
});
var ackBytes = new byte[4];
BinaryPrimitives.WriteInt32LittleEndian(ackBytes, ack);
await stream.WriteAsync(ackBytes);
await WriteFileStream(stream, files);
}
}

View File

@@ -1,5 +1,4 @@
using Robust.Server.Player;
using Robust.Shared.IoC;
using Robust.Shared.IoC;
using Robust.Shared.Network;
namespace Robust.Server.Upload;
@@ -10,36 +9,20 @@ namespace Robust.Server.Upload;
internal sealed class UploadedContentManager
{
[Dependency] private readonly IServerNetManager _netManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly GamePrototypeLoadManager _prototypeLoadManager = default!;
[Dependency] private readonly NetworkResourceManager _networkResourceManager = default!;
public void Initialize()
{
_netManager.Connected += NetManagerOnConnected;
_networkResourceManager.AckReceived += OnAckReceived;
}
private void OnAckReceived(INetChannel channel, int ack)
{
if (ack != NetworkResourceManager.AckInitial)
return;
ResourcesReady(channel);
}
private void NetManagerOnConnected(object? sender, NetChannelArgs e)
{
// This just shells out to the other managers, ensuring they are ordered properly.
// Resources must be done before prototypes.
var sentAny = _networkResourceManager.SendToNewUser(e.Channel);
if (!sentAny)
ResourcesReady(e.Channel);
}
private void ResourcesReady(INetChannel channel)
{
_prototypeLoadManager.SendToNewUser(channel);
_playerManager.MarkPlayerResourcesSent(channel);
// Note: both net messages sent here are on the same group and are therefore ordered.
_networkResourceManager.SendToNewUser(e.Channel);
_prototypeLoadManager.SendToNewUser(e.Channel);
}
}

View File

@@ -12,6 +12,5 @@ namespace Robust.Server.ViewVariables
object Object { get; }
uint SessionId { get; }
Type ObjectType { get; }
Action<object>? ObjectChangeDelegate { get; }
}
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Robust.Server.Console;
using Robust.Server.Player;
using Robust.Shared.Audio;
using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -137,7 +138,6 @@ namespace Robust.Server.ViewVariables
}
object theObject;
Action<object>? objectChangeDelegate = null;
switch (message.Selector)
{
@@ -200,14 +200,13 @@ namespace Robust.Server.ViewVariables
return;
}
if (value == null)
if (value == null || value.GetType().IsValueType)
{
Deny(ViewVariablesResponseCode.NoObject);
return;
}
theObject = value;
objectChangeDelegate = obj => relSession.Modify(sessionRelativeSelector.PropertyIndex, obj);
break;
}
case ViewVariablesIoCSelector ioCSelector:
@@ -251,7 +250,7 @@ namespace Robust.Server.ViewVariables
}
var sessionId = _nextSessionId++;
var session = new ViewVariablesSession(message.MsgChannel.UserId, theObject, objectChangeDelegate, sessionId, this,
var session = new ViewVariablesSession(message.MsgChannel.UserId, theObject, sessionId, this,
_robustSerializer, _entityManager, Sawmill);
_sessions.Add(sessionId, session);

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Prototypes;
@@ -197,8 +198,6 @@ namespace Robust.Server.ViewVariables.Traits
try
{
field.SetValue(Session.Object, value);
Session.ObjectChangeDelegate?.Invoke(Session.Object);
return true;
}
catch (Exception e)

View File

@@ -22,7 +22,6 @@ namespace Robust.Server.ViewVariables
public object Object { get; }
public uint SessionId { get; }
public Type ObjectType { get; }
public Action<object>? ObjectChangeDelegate { get; }
/// <param name="playerUser">The session ID of the player who opened this session.</param>
/// <param name="o">The object we represent.</param>
@@ -30,14 +29,13 @@ namespace Robust.Server.ViewVariables
/// The session ID for this session. This is what the server and client use to talk about this session.
/// </param>
/// <param name="host">The view variables host owning this session.</param>
public ViewVariablesSession(NetUserId playerUser, object o, Action<object>? objectChangeDelegate, uint sessionId, IServerViewVariablesInternal host,
public ViewVariablesSession(NetUserId playerUser, object o, uint sessionId, IServerViewVariablesInternal host,
IRobustSerializer robustSerializer, IEntityManager entMan, ISawmill logger)
{
PlayerUser = playerUser;
Object = o;
SessionId = sessionId;
ObjectType = o.GetType();
ObjectChangeDelegate = objectChangeDelegate;
Host = host;
RobustSerializer = robustSerializer;
EntityManager = entMan;

View File

@@ -2,14 +2,9 @@ using System;
using System.IO;
using Moq;
using NUnit.Framework;
using Robust.Server;
using Robust.Server.Configuration;
using Robust.Server.Network.Transfer;
using Robust.Server.Player;
using Robust.Server.Reflection;
using Robust.Server.Serialization;
using Robust.Server.ServerStatus;
using Robust.Shared.Asynchronous;
using Robust.Shared.Configuration;
using Robust.Shared.ContentPack;
using Robust.Shared.GameObjects;
@@ -18,7 +13,6 @@ using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Network;
using Robust.Shared.Network.Transfer;
using Robust.Shared.Profiling;
using Robust.Shared.Reflection;
using Robust.Shared.Replays;
@@ -49,7 +43,6 @@ namespace Robust.UnitTesting.Shared.GameObjects
container.Register<IAuthManager, AuthManager>();
container.Register<IGameTiming, GameTiming>();
container.Register<ProfManager, ProfManager>();
container.RegisterInstance<ITransferManager>(Mock.Of<ITransferManager>());
container.Register<HttpClientHolder>();
container.RegisterInstance<IReplayRecordingManager>(new Mock<IReplayRecordingManager>().Object);
container.BuildGraph();

View File

@@ -1,3 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Moq;
using NUnit.Framework;
using Robust.Server.Configuration;
@@ -85,6 +88,7 @@ namespace Robust.UnitTesting.Shared.GameObjects
deps.Register<IDynamicTypeFactoryInternal, DynamicTypeFactory>();
deps.RegisterInstance<IModLoader>(new Mock<IModLoader>().Object);
deps.Register<IEntitySystemManager, EntitySystemManager>();
deps.RegisterInstance<IEntityManager>(new Mock<IEntityManager>().Object);
// WHEN WILL THE SUFFERING END
deps.RegisterInstance<IReplayRecordingManager>(new Mock<IReplayRecordingManager>().Object);
@@ -100,15 +104,6 @@ namespace Robust.UnitTesting.Shared.GameObjects
deps.RegisterInstance<IReflectionManager>(reflectionMock.Object);
// Never
var componentFactoryMock = new Mock<IComponentFactory>();
componentFactoryMock.Setup(p => p.AllRegisteredTypes).Returns(Enumerable.Empty<Type>());
deps.RegisterInstance<IComponentFactory>(componentFactoryMock.Object);
var entityManagerMock = new Mock<IEntityManager>();
entityManagerMock.Setup(p => p.ComponentFactory).Returns(componentFactoryMock.Object);
deps.RegisterInstance<IEntityManager>(entityManagerMock.Object);
deps.BuildGraph();
IoCManager.InitThread(deps, true);

View File

@@ -1,10 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Robust.Shared.Analyzers;
using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.IoC.Exceptions;
using Robust.Shared.Physics.Components;
namespace Robust.UnitTesting.Shared.GameObjects
{
@@ -38,14 +39,6 @@ namespace Robust.UnitTesting.Shared.GameObjects
[Dependency] public readonly ESystemDepA ESystemDepA = default!;
}
internal sealed class ESystemDepAll : EntitySystem
{
[Dependency] public readonly ESystemDepA ESystemDepA = default!;
[Dependency] public readonly IConfigurationManager Config = default!;
[Dependency] public readonly EntityQuery<TransformComponent> TransformQuery = default!;
[Dependency] public readonly EntityQuery<PhysicsComponent> PhysicsQuery = default!;
}
/*
ESystemBase (Abstract)
- ESystemA
@@ -65,7 +58,6 @@ namespace Robust.UnitTesting.Shared.GameObjects
syssy.LoadExtraSystemType<ESystemC>();
syssy.LoadExtraSystemType<ESystemDepA>();
syssy.LoadExtraSystemType<ESystemDepB>();
syssy.LoadExtraSystemType<ESystemDepAll>();
syssy.Initialize(false);
}
@@ -111,16 +103,5 @@ namespace Robust.UnitTesting.Shared.GameObjects
Assert.That(sysB.ESystemDepA, Is.EqualTo(sysA));
}
[Test]
public void DependencyInjectionTest()
{
var esm = IoCManager.Resolve<IEntitySystemManager>();
var sys = esm.GetEntitySystem<ESystemDepAll>();
Assert.That(sys.ESystemDepA, Is.Not.Null);
Assert.That(sys.Config, Is.Not.Null);
Assert.That(sys.TransformQuery, Is.Not.Default);
Assert.That(sys.PhysicsQuery, Is.Not.Default);
}
}
}

View File

@@ -1,203 +0,0 @@
using JetBrains.Annotations;
using NUnit.Framework;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using Robust.UnitTesting.Shared;
namespace Robust.Shared.IntegrationTests.Serialization;
[Serializable, NetSerializable]
[UsedImplicitly(Reason = "Needed so RobustSerializer is guaranteed to pick up on the unsafe types.")]
internal sealed class MakeTheseSerializable
{
public UnsafeFloat Single;
public UnsafeDouble Double;
public UnsafeHalf Half;
public Half SafeHalf;
}
/// <summary>
/// Tests the serialization behavior of float types when <see cref="IRobustSerializer"/> is *not* set to do anything special.
/// Tests both primitives and Robust's "Unsafe" variants.
/// </summary>
[TestFixture, TestOf(typeof(RobustSerializer)), TestOf(typeof(NetUnsafeFloatSerializer))]
internal sealed class NetSerializerDefaultFloatTest : OurRobustUnitTest
{
private IRobustSerializer _serializer = null!;
[OneTimeSetUp]
public void Setup()
{
_serializer = IoCManager.Resolve<IRobustSerializer>();
_serializer.Initialize();
}
internal static readonly TestCaseData[] PassThroughFloatTests =
[
new TestCaseData(0.0).Returns(0.0),
new TestCaseData(1.0).Returns(1.0),
new TestCaseData(double.NaN).Returns(double.NaN),
new TestCaseData(double.PositiveInfinity).Returns(double.PositiveInfinity),
];
[TestCaseSource(nameof(PassThroughFloatTests))]
public double TestSingle(double input)
{
var ms = new MemoryStream();
_serializer.Serialize(ms, (float)input);
ms.Position = 0;
return _serializer.Deserialize<float>(ms);
}
[TestCaseSource(nameof(PassThroughFloatTests))]
public double TestUnsafeSingle(double input)
{
var ms = new MemoryStream();
_serializer.Serialize(ms, (UnsafeFloat)input);
ms.Position = 0;
return _serializer.Deserialize<UnsafeFloat>(ms);
}
[TestCaseSource(nameof(PassThroughFloatTests))]
public double TestDouble(double input)
{
var ms = new MemoryStream();
_serializer.Serialize(ms, input);
ms.Position = 0;
return _serializer.Deserialize<double>(ms);
}
[TestCaseSource(nameof(PassThroughFloatTests))]
public double TestUnsafeDouble(double input)
{
var ms = new MemoryStream();
_serializer.Serialize(ms, (UnsafeDouble)input);
ms.Position = 0;
return _serializer.Deserialize<UnsafeDouble>(ms);
}
[TestCaseSource(nameof(PassThroughFloatTests))]
public double TestHalf(double input)
{
var ms = new MemoryStream();
_serializer.Serialize(ms, (Half)input);
ms.Position = 0;
return (double)_serializer.Deserialize<Half>(ms);
}
[TestCaseSource(nameof(PassThroughFloatTests))]
public double TestUnsafeHalf(double input)
{
var ms = new MemoryStream();
_serializer.Serialize(ms, (UnsafeHalf)(Half)input);
ms.Position = 0;
return (double)(Half)_serializer.Deserialize<UnsafeHalf>(ms);
}
}
/// <summary>
/// Tests the serialization behavior of float types when <see cref="IRobustSerializer"/> is set to remove NaNs on read.
/// Tests both primitives and Robust's "Unsafe" variants.
/// </summary>
[TestFixture]
[TestOf(typeof(RobustSerializer)), TestOf(typeof(NetUnsafeFloatSerializer)), TestOf(typeof(NetSafeFloatSerializer))]
internal sealed class NetSerializerSafeFloatTest : OurRobustUnitTest
{
private IRobustSerializer _serializer = default!;
[OneTimeSetUp]
public void Setup()
{
_serializer = IoCManager.Resolve<IRobustSerializer>();
_serializer.FloatFlags = SerializerFloatFlags.RemoveReadNan;
_serializer.Initialize();
}
internal static readonly TestCaseData[] SafeFloatTests =
[
new TestCaseData(0.0).Returns(0.0),
new TestCaseData(1.0).Returns(1.0),
new TestCaseData(double.NaN).Returns(0.0),
new TestCaseData(double.PositiveInfinity).Returns(double.PositiveInfinity),
];
[TestCaseSource(nameof(SafeFloatTests))]
public double TestSingle(double input)
{
var ms = new MemoryStream();
_serializer.Serialize(ms, (float)input);
ms.Position = 0;
return _serializer.Deserialize<float>(ms);
}
[TestCaseSource(typeof(NetSerializerDefaultFloatTest), nameof(NetSerializerDefaultFloatTest.PassThroughFloatTests))]
public double TestUnsafeSingle(double input)
{
var ms = new MemoryStream();
_serializer.Serialize(ms, (UnsafeFloat)input);
ms.Position = 0;
return _serializer.Deserialize<UnsafeFloat>(ms);
}
[TestCaseSource(nameof(SafeFloatTests))]
public double TestDouble(double input)
{
var ms = new MemoryStream();
_serializer.Serialize(ms, input);
ms.Position = 0;
return _serializer.Deserialize<double>(ms);
}
[TestCaseSource(typeof(NetSerializerDefaultFloatTest), nameof(NetSerializerDefaultFloatTest.PassThroughFloatTests))]
public double TestUnsafeDouble(double input)
{
var ms = new MemoryStream();
_serializer.Serialize(ms, (UnsafeDouble)input);
ms.Position = 0;
return _serializer.Deserialize<UnsafeDouble>(ms);
}
[TestCaseSource(nameof(SafeFloatTests))]
public double TestHalf(double input)
{
var ms = new MemoryStream();
_serializer.Serialize(ms, (Half)input);
ms.Position = 0;
return (double)_serializer.Deserialize<Half>(ms);
}
[TestCaseSource(typeof(NetSerializerDefaultFloatTest), nameof(NetSerializerDefaultFloatTest.PassThroughFloatTests))]
public double TestUnsafeHalf(double input)
{
var ms = new MemoryStream();
_serializer.Serialize(ms, (UnsafeHalf)(Half)input);
ms.Position = 0;
return (double)(Half)_serializer.Deserialize<UnsafeHalf>(ms);
}
}

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Robust.Shared")]
[assembly: InternalsVisibleTo("Robust.Client")]
[assembly: InternalsVisibleTo("Robust.Server")]

View File

@@ -0,0 +1,2 @@
global using System.Runtime.InteropServices;
global using Robust.Shared.Interop.RobustNative.Ogg;

View File

@@ -1,9 +1,9 @@
using System;
using System.Runtime.InteropServices;
// ReSharper disable IdentifierTypo
// ReSharper disable InconsistentNaming
namespace Robust.Shared.Native;
namespace Robust.Shared.Interop.RobustNative;
internal static class Libc
internal static partial class Libc
{
public const int RTLD_LAZY = 0x00001;
public const int RTLD_NOW = 0x00002;
@@ -14,6 +14,6 @@ internal static class Libc
public const int RTLD_LOCAL = 0;
public const int RTLD_NODELETE = 0x01000;
[DllImport("libdl.so.2")]
public static extern IntPtr dlopen([MarshalAs(UnmanagedType.LPUTF8Str)] string name, int flags);
[LibraryImport("dl", StringMarshalling = StringMarshalling.Utf8)]
public static partial IntPtr dlopen(string name, int flags);
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Diagnostics;
namespace Robust.Shared.Interop.RobustNative.Ogg;
/// <summary>Defines the annotation found in a native declaration.</summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
[Conditional("DEBUG")]
internal sealed partial class NativeAnnotationAttribute : Attribute
{
private readonly string _annotation;
/// <summary>Initializes a new instance of the <see cref="NativeAnnotationAttribute" /> class.</summary>
/// <param name="annotation">The annotation that was used in the native declaration.</param>
public NativeAnnotationAttribute(string annotation)
{
_annotation = annotation;
}
/// <summary>Gets the annotation that was used in the native declaration.</summary>
public string Annotation => _annotation;
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Diagnostics;
namespace Robust.Shared.Interop.RobustNative.Ogg;
/// <summary>Defines the type of a member as it was used in the native signature.</summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = false, Inherited = true)]
[Conditional("DEBUG")]
internal sealed partial class NativeTypeNameAttribute : Attribute
{
private readonly string _name;
/// <summary>Initializes a new instance of the <see cref="NativeTypeNameAttribute" /> class.</summary>
/// <param name="name">The name of the type that was used in the native signature.</param>
public NativeTypeNameAttribute(string name)
{
_name = name;
}
/// <summary>Gets the name of the type that was used in the native signature.</summary>
public string Name => _name;
}

View File

@@ -0,0 +1,237 @@
using System.Runtime.InteropServices;
namespace Robust.Shared.Interop.RobustNative.Ogg;
internal static unsafe partial class Ogg
{
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpack_writeinit(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int oggpack_writecheck(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpack_writetrunc(oggpack_buffer* b, [NativeTypeName("long")] CLong bits);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpack_writealign(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpack_writecopy(oggpack_buffer* b, void* source, [NativeTypeName("long")] CLong bits);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpack_reset(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpack_writeclear(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpack_readinit(oggpack_buffer* b, [NativeTypeName("unsigned char *")] byte* buf, int bytes);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpack_write(oggpack_buffer* b, [NativeTypeName("unsigned long")] CULong value, int bits);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong oggpack_look(oggpack_buffer* b, int bits);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong oggpack_look1(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpack_adv(oggpack_buffer* b, int bits);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpack_adv1(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong oggpack_read(oggpack_buffer* b, int bits);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong oggpack_read1(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong oggpack_bytes(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong oggpack_bits(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("unsigned char *")]
public static extern byte* oggpack_get_buffer(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpackB_writeinit(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int oggpackB_writecheck(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpackB_writetrunc(oggpack_buffer* b, [NativeTypeName("long")] CLong bits);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpackB_writealign(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpackB_writecopy(oggpack_buffer* b, void* source, [NativeTypeName("long")] CLong bits);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpackB_reset(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpackB_writeclear(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpackB_readinit(oggpack_buffer* b, [NativeTypeName("unsigned char *")] byte* buf, int bytes);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpackB_write(oggpack_buffer* b, [NativeTypeName("unsigned long")] CULong value, int bits);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong oggpackB_look(oggpack_buffer* b, int bits);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong oggpackB_look1(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpackB_adv(oggpack_buffer* b, int bits);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void oggpackB_adv1(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong oggpackB_read(oggpack_buffer* b, int bits);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong oggpackB_read1(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong oggpackB_bytes(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong oggpackB_bits(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("unsigned char *")]
public static extern byte* oggpackB_get_buffer(oggpack_buffer* b);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_packetin(ogg_stream_state* os, ogg_packet* op);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_iovecin(ogg_stream_state* os, ogg_iovec_t* iov, int count, [NativeTypeName("long")] CLong e_o_s, [NativeTypeName("ogg_int64_t")] CLong granulepos);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_pageout(ogg_stream_state* os, ogg_page* og);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_pageout_fill(ogg_stream_state* os, ogg_page* og, int nfill);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_flush(ogg_stream_state* os, ogg_page* og);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_flush_fill(ogg_stream_state* os, ogg_page* og, int nfill);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_sync_init(ogg_sync_state* oy);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_sync_clear(ogg_sync_state* oy);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_sync_reset(ogg_sync_state* oy);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_sync_destroy(ogg_sync_state* oy);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_sync_check(ogg_sync_state* oy);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("char *")]
public static extern sbyte* ogg_sync_buffer(ogg_sync_state* oy, [NativeTypeName("long")] CLong size);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_sync_wrote(ogg_sync_state* oy, [NativeTypeName("long")] CLong bytes);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong ogg_sync_pageseek(ogg_sync_state* oy, ogg_page* og);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_sync_pageout(ogg_sync_state* oy, ogg_page* og);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_pagein(ogg_stream_state* os, ogg_page* og);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_packetout(ogg_stream_state* os, ogg_packet* op);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_packetpeek(ogg_stream_state* os, ogg_packet* op);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_init(ogg_stream_state* os, int serialno);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_clear(ogg_stream_state* os);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_reset(ogg_stream_state* os);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_reset_serialno(ogg_stream_state* os, int serialno);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_destroy(ogg_stream_state* os);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_check(ogg_stream_state* os);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_stream_eos(ogg_stream_state* os);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void ogg_page_checksum_set(ogg_page* og);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_page_version([NativeTypeName("const ogg_page *")] ogg_page* og);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_page_continued([NativeTypeName("const ogg_page *")] ogg_page* og);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_page_bos([NativeTypeName("const ogg_page *")] ogg_page* og);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_page_eos([NativeTypeName("const ogg_page *")] ogg_page* og);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("ogg_int64_t")]
public static extern CLong ogg_page_granulepos([NativeTypeName("const ogg_page *")] ogg_page* og);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_page_serialno([NativeTypeName("const ogg_page *")] ogg_page* og);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong ogg_page_pageno([NativeTypeName("const ogg_page *")] ogg_page* og);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int ogg_page_packets([NativeTypeName("const ogg_page *")] ogg_page* og);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void ogg_packet_clear(ogg_packet* op);
}

View File

@@ -0,0 +1,9 @@
namespace Robust.Shared.Interop.RobustNative.Ogg;
internal unsafe partial struct ogg_iovec_t
{
public void* iov_base;
[NativeTypeName("size_t")]
public nuint iov_len;
}

View File

@@ -0,0 +1,22 @@
namespace Robust.Shared.Interop.RobustNative.Ogg;
internal unsafe partial struct ogg_packet
{
[NativeTypeName("unsigned char *")]
public byte* packet;
[NativeTypeName("long")]
public CLong bytes;
[NativeTypeName("long")]
public CLong b_o_s;
[NativeTypeName("long")]
public CLong e_o_s;
[NativeTypeName("ogg_int64_t")]
public CLong granulepos;
[NativeTypeName("ogg_int64_t")]
public CLong packetno;
}

View File

@@ -0,0 +1,16 @@
namespace Robust.Shared.Interop.RobustNative.Ogg;
internal unsafe partial struct ogg_page
{
[NativeTypeName("unsigned char *")]
public byte* header;
[NativeTypeName("long")]
public CLong header_len;
[NativeTypeName("unsigned char *")]
public byte* body;
[NativeTypeName("long")]
public CLong body_len;
}

View File

@@ -0,0 +1,54 @@
namespace Robust.Shared.Interop.RobustNative.Ogg;
internal unsafe partial struct ogg_stream_state
{
[NativeTypeName("unsigned char *")]
public byte* body_data;
[NativeTypeName("long")]
public CLong body_storage;
[NativeTypeName("long")]
public CLong body_fill;
[NativeTypeName("long")]
public CLong body_returned;
public int* lacing_vals;
[NativeTypeName("ogg_int64_t *")]
public CLong* granule_vals;
[NativeTypeName("long")]
public CLong lacing_storage;
[NativeTypeName("long")]
public CLong lacing_fill;
[NativeTypeName("long")]
public CLong lacing_packet;
[NativeTypeName("long")]
public CLong lacing_returned;
[NativeTypeName("unsigned char[282]")]
public fixed byte header[282];
public int header_fill;
public int e_o_s;
public int b_o_s;
[NativeTypeName("long")]
public CLong serialno;
[NativeTypeName("long")]
public CLong pageno;
[NativeTypeName("ogg_int64_t")]
public CLong packetno;
[NativeTypeName("ogg_int64_t")]
public CLong granulepos;
}

View File

@@ -0,0 +1,19 @@
namespace Robust.Shared.Interop.RobustNative.Ogg;
internal unsafe partial struct ogg_sync_state
{
[NativeTypeName("unsigned char *")]
public byte* data;
public int storage;
public int fill;
public int returned;
public int unsynced;
public int headerbytes;
public int bodybytes;
}

View File

@@ -0,0 +1,18 @@
namespace Robust.Shared.Interop.RobustNative.Ogg;
internal unsafe partial struct oggpack_buffer
{
[NativeTypeName("long")]
public CLong endbyte;
public int endbit;
[NativeTypeName("unsigned char *")]
public byte* buffer;
[NativeTypeName("unsigned char *")]
public byte* ptr;
[NativeTypeName("long")]
public CLong storage;
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Diagnostics;
namespace Robust.Shared.Interop.RobustNative.Opus;
/// <summary>Defines the annotation found in a native declaration.</summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
[Conditional("DEBUG")]
internal sealed partial class NativeAnnotationAttribute : Attribute
{
private readonly string _annotation;
/// <summary>Initializes a new instance of the <see cref="NativeAnnotationAttribute" /> class.</summary>
/// <param name="annotation">The annotation that was used in the native declaration.</param>
public NativeAnnotationAttribute(string annotation)
{
_annotation = annotation;
}
/// <summary>Gets the annotation that was used in the native declaration.</summary>
public string Annotation => _annotation;
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Diagnostics;
namespace Robust.Shared.Interop.RobustNative.Opus;
/// <summary>Defines the type of a member as it was used in the native signature.</summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = false, Inherited = true)]
[Conditional("DEBUG")]
internal sealed partial class NativeTypeNameAttribute : Attribute
{
private readonly string _name;
/// <summary>Initializes a new instance of the <see cref="NativeTypeNameAttribute" /> class.</summary>
/// <param name="name">The name of the type that was used in the native signature.</param>
public NativeTypeNameAttribute(string name)
{
_name = name;
}
/// <summary>Gets the name of the type that was used in the native signature.</summary>
public string Name => _name;
}

View File

@@ -0,0 +1,161 @@
using System.Runtime.InteropServices;
namespace Robust.Shared.Interop.RobustNative.Opus;
internal static unsafe partial class Opus
{
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("const char *")]
public static extern sbyte* opus_strerror(int error);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("const char *")]
public static extern sbyte* opus_get_version_string();
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_encoder_get_size(int channels);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern OpusEncoder* opus_encoder_create([NativeTypeName("opus_int32")] int Fs, int channels, int application, int* error);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_encoder_init(OpusEncoder* st, [NativeTypeName("opus_int32")] int Fs, int channels, int application);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("opus_int32")]
public static extern int opus_encode(OpusEncoder* st, [NativeTypeName("const opus_int16 *")] short* pcm, int frame_size, [NativeTypeName("unsigned char *")] byte* data, [NativeTypeName("opus_int32")] int max_data_bytes);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("opus_int32")]
public static extern int opus_encode_float(OpusEncoder* st, [NativeTypeName("const float *")] float* pcm, int frame_size, [NativeTypeName("unsigned char *")] byte* data, [NativeTypeName("opus_int32")] int max_data_bytes);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void opus_encoder_destroy(OpusEncoder* st);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_encoder_ctl(OpusEncoder* st, int request, __arglist);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_decoder_get_size(int channels);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern OpusDecoder* opus_decoder_create([NativeTypeName("opus_int32")] int Fs, int channels, int* error);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_decoder_init(OpusDecoder* st, [NativeTypeName("opus_int32")] int Fs, int channels);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_decode(OpusDecoder* st, [NativeTypeName("const unsigned char *")] byte* data, [NativeTypeName("opus_int32")] int len, [NativeTypeName("opus_int16 *")] short* pcm, int frame_size, int decode_fec);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_decode_float(OpusDecoder* st, [NativeTypeName("const unsigned char *")] byte* data, [NativeTypeName("opus_int32")] int len, float* pcm, int frame_size, int decode_fec);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_decoder_ctl(OpusDecoder* st, int request, __arglist);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void opus_decoder_destroy(OpusDecoder* st);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_dred_decoder_get_size();
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern OpusDREDDecoder* opus_dred_decoder_create(int* error);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_dred_decoder_init(OpusDREDDecoder* dec);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void opus_dred_decoder_destroy(OpusDREDDecoder* dec);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_dred_decoder_ctl(OpusDREDDecoder* dred_dec, int request, __arglist);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_dred_get_size();
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern OpusDRED* opus_dred_alloc(int* error);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void opus_dred_free(OpusDRED* dec);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_dred_parse(OpusDREDDecoder* dred_dec, OpusDRED* dred, [NativeTypeName("const unsigned char *")] byte* data, [NativeTypeName("opus_int32")] int len, [NativeTypeName("opus_int32")] int max_dred_samples, [NativeTypeName("opus_int32")] int sampling_rate, int* dred_end, int defer_processing);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_dred_process(OpusDREDDecoder* dred_dec, [NativeTypeName("const OpusDRED *")] OpusDRED* src, OpusDRED* dst);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_decoder_dred_decode(OpusDecoder* st, [NativeTypeName("const OpusDRED *")] OpusDRED* dred, [NativeTypeName("opus_int32")] int dred_offset, [NativeTypeName("opus_int16 *")] short* pcm, [NativeTypeName("opus_int32")] int frame_size);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_decoder_dred_decode_float(OpusDecoder* st, [NativeTypeName("const OpusDRED *")] OpusDRED* dred, [NativeTypeName("opus_int32")] int dred_offset, float* pcm, [NativeTypeName("opus_int32")] int frame_size);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_packet_parse([NativeTypeName("const unsigned char *")] byte* data, [NativeTypeName("opus_int32")] int len, [NativeTypeName("unsigned char *")] byte* out_toc, [NativeTypeName("const unsigned char *[48]")] byte** frames, [NativeTypeName("opus_int16[48]")] short* size, int* payload_offset);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_packet_get_bandwidth([NativeTypeName("const unsigned char *")] byte* data);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_packet_get_samples_per_frame([NativeTypeName("const unsigned char *")] byte* data, [NativeTypeName("opus_int32")] int Fs);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_packet_get_nb_channels([NativeTypeName("const unsigned char *")] byte* data);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_packet_get_nb_frames([NativeTypeName("const unsigned char[]")] byte* packet, [NativeTypeName("opus_int32")] int len);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_packet_get_nb_samples([NativeTypeName("const unsigned char[]")] byte* packet, [NativeTypeName("opus_int32")] int len, [NativeTypeName("opus_int32")] int Fs);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_packet_has_lbrr([NativeTypeName("const unsigned char[]")] byte* packet, [NativeTypeName("opus_int32")] int len);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_decoder_get_nb_samples([NativeTypeName("const OpusDecoder *")] OpusDecoder* dec, [NativeTypeName("const unsigned char[]")] byte* packet, [NativeTypeName("opus_int32")] int len);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void opus_pcm_soft_clip(float* pcm, int frame_size, int channels, float* softclip_mem);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_repacketizer_get_size();
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern OpusRepacketizer* opus_repacketizer_init(OpusRepacketizer* rp);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern OpusRepacketizer* opus_repacketizer_create();
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void opus_repacketizer_destroy(OpusRepacketizer* rp);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_repacketizer_cat(OpusRepacketizer* rp, [NativeTypeName("const unsigned char *")] byte* data, [NativeTypeName("opus_int32")] int len);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("opus_int32")]
public static extern int opus_repacketizer_out_range(OpusRepacketizer* rp, int begin, int end, [NativeTypeName("unsigned char *")] byte* data, [NativeTypeName("opus_int32")] int maxlen);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_repacketizer_get_nb_frames(OpusRepacketizer* rp);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("opus_int32")]
public static extern int opus_repacketizer_out(OpusRepacketizer* rp, [NativeTypeName("unsigned char *")] byte* data, [NativeTypeName("opus_int32")] int maxlen);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_packet_pad([NativeTypeName("unsigned char *")] byte* data, [NativeTypeName("opus_int32")] int len, [NativeTypeName("opus_int32")] int new_len);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("opus_int32")]
public static extern int opus_packet_unpad([NativeTypeName("unsigned char *")] byte* data, [NativeTypeName("opus_int32")] int len);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int opus_multistream_packet_pad([NativeTypeName("unsigned char *")] byte* data, [NativeTypeName("opus_int32")] int len, [NativeTypeName("opus_int32")] int new_len, int nb_streams);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("opus_int32")]
public static extern int opus_multistream_packet_unpad([NativeTypeName("unsigned char *")] byte* data, [NativeTypeName("opus_int32")] int len, int nb_streams);
}

View File

@@ -0,0 +1,5 @@
namespace Robust.Shared.Interop.RobustNative.Opus;
internal partial struct OpusDRED
{
}

View File

@@ -0,0 +1,5 @@
namespace Robust.Shared.Interop.RobustNative.Opus;
internal partial struct OpusDREDDecoder
{
}

View File

@@ -0,0 +1,5 @@
namespace Robust.Shared.Interop.RobustNative.Opus;
internal partial struct OpusDecoder
{
}

View File

@@ -0,0 +1,5 @@
namespace Robust.Shared.Interop.RobustNative.Opus;
internal partial struct OpusEncoder
{
}

View File

@@ -0,0 +1,5 @@
namespace Robust.Shared.Interop.RobustNative.Opus;
internal partial struct OpusRepacketizer
{
}

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\MSBuild\Robust.Engine.props" />
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" PrivateAssets="All" />
</ItemGroup>
<Import Project="..\MSBuild\Robust.Properties.targets" />
</Project>

View File

@@ -0,0 +1,95 @@
namespace Robust.Shared.Interop.RobustNative;
internal static class RobustNativeDll
{
private const string DllName = "robust-native";
private static readonly Lock LoadLock = new();
public static bool IsClientProcess;
public static bool IsServerProcess;
private static nint _robustNativeHandle;
private static Exception? _loadFailed;
static RobustNativeDll()
{
NativeLibrary.SetDllImportResolver(typeof(RobustNativeDll).Assembly,
(name, _, _) =>
{
if (name == DllName)
return LoadRobustNative();
return 0;
});
}
public static nint LoadRobustNative()
{
using var _ = LoadLock.EnterScope();
if (_robustNativeHandle != 0)
return _robustNativeHandle;
if (_loadFailed != null)
throw _loadFailed;
try
{
_robustNativeHandle = LoadCore();
return _robustNativeHandle;
}
catch (Exception e)
{
_loadFailed = e;
throw _loadFailed;
}
}
private static nint LoadCore()
{
var dllName = GetDllName();
#if WINDOWS
return NativeLibrary.Load(dllName, typeof(RobustNativeDll).Assembly, DllImportSearchPath.SafeDirectories);
#elif UNIX
#if MACOS
dllName = $"lib{dllName}.dylib";
#else
dllName = $"lib{dllName}.so";
#endif
// On Unix platforms we *need* to load the native lib with RTLD_DEEPBIND | RTLD_LOCAL
// To avoid issues with symbol collisions.
var searchDirectories = (string?)AppContext.GetData("NATIVE_DLL_SEARCH_DIRECTORIES");
foreach (var dir in searchDirectories?.Split(':') ?? Array.Empty<string>()) {
var libraryPath = Path.Combine(dir, dllName);
var attempt = Libc.dlopen(libraryPath, Libc.RTLD_LAZY | Libc.RTLD_DEEPBIND | Libc.RTLD_LOCAL);
if (attempt != 0)
return attempt;
}
throw new DllNotFoundException($"Unable to locatee {dllName}");
#endif
}
private static string GetDllName()
{
#if DEVELOPMENT
// Always load universal on dev builds to avoid issues with test processes.
return "robust_native_universal";
#else
if (IsClientProcess && IsServerProcess)
return "robust_native_universal";
if (IsClientProcess)
return "robust_native_client";
if (IsServerProcess)
return "robust_native_server";
throw new InvalidOperationException("Is neither server or client process???");
#endif
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Diagnostics;
namespace Robust.Shared.Interop.RobustNative.Vorbis;
/// <summary>Defines the annotation found in a native declaration.</summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
[Conditional("DEBUG")]
internal sealed partial class NativeAnnotationAttribute : Attribute
{
private readonly string _annotation;
/// <summary>Initializes a new instance of the <see cref="NativeAnnotationAttribute" /> class.</summary>
/// <param name="annotation">The annotation that was used in the native declaration.</param>
public NativeAnnotationAttribute(string annotation)
{
_annotation = annotation;
}
/// <summary>Gets the annotation that was used in the native declaration.</summary>
public string Annotation => _annotation;
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Diagnostics;
namespace Robust.Shared.Interop.RobustNative.Vorbis;
/// <summary>Defines the type of a member as it was used in the native signature.</summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = false, Inherited = true)]
[Conditional("DEBUG")]
internal sealed partial class NativeTypeNameAttribute : Attribute
{
private readonly string _name;
/// <summary>Initializes a new instance of the <see cref="NativeTypeNameAttribute" /> class.</summary>
/// <param name="name">The name of the type that was used in the native signature.</param>
public NativeTypeNameAttribute(string name)
{
_name = name;
}
/// <summary>Gets the name of the type that was used in the native signature.</summary>
public string Name => _name;
}

View File

@@ -0,0 +1,117 @@
using System.Runtime.InteropServices;
namespace Robust.Shared.Interop.RobustNative.Vorbis;
internal static unsafe partial class Vorbis
{
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void vorbis_info_init(vorbis_info* vi);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void vorbis_info_clear(vorbis_info* vi);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_info_blocksize(vorbis_info* vi, int zo);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void vorbis_comment_init(vorbis_comment* vc);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void vorbis_comment_add(vorbis_comment* vc, [NativeTypeName("const char *")] sbyte* comment);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void vorbis_comment_add_tag(vorbis_comment* vc, [NativeTypeName("const char *")] sbyte* tag, [NativeTypeName("const char *")] sbyte* contents);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("char *")]
public static extern sbyte* vorbis_comment_query(vorbis_comment* vc, [NativeTypeName("const char *")] sbyte* tag, int count);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_comment_query_count(vorbis_comment* vc, [NativeTypeName("const char *")] sbyte* tag);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void vorbis_comment_clear(vorbis_comment* vc);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_block_init(vorbis_dsp_state* v, vorbis_block* vb);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_block_clear(vorbis_block* vb);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void vorbis_dsp_clear(vorbis_dsp_state* v);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern double vorbis_granule_time(vorbis_dsp_state* v, [NativeTypeName("ogg_int64_t")] CLong granulepos);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("const char *")]
public static extern sbyte* vorbis_version_string();
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_analysis_init(vorbis_dsp_state* v, vorbis_info* vi);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_commentheader_out(vorbis_comment* vc, ogg_packet* op);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_analysis_headerout(vorbis_dsp_state* v, vorbis_comment* vc, ogg_packet* op, ogg_packet* op_comm, ogg_packet* op_code);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern float** vorbis_analysis_buffer(vorbis_dsp_state* v, int vals);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_analysis_wrote(vorbis_dsp_state* v, int vals);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_analysis_blockout(vorbis_dsp_state* v, vorbis_block* vb);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_analysis(vorbis_block* vb, ogg_packet* op);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_bitrate_addblock(vorbis_block* vb);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_bitrate_flushpacket(vorbis_dsp_state* vd, ogg_packet* op);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_synthesis_idheader(ogg_packet* op);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_synthesis_headerin(vorbis_info* vi, vorbis_comment* vc, ogg_packet* op);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_synthesis_init(vorbis_dsp_state* v, vorbis_info* vi);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_synthesis_restart(vorbis_dsp_state* v);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_synthesis(vorbis_block* vb, ogg_packet* op);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_synthesis_trackonly(vorbis_block* vb, ogg_packet* op);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_synthesis_blockin(vorbis_dsp_state* v, vorbis_block* vb);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_synthesis_pcmout(vorbis_dsp_state* v, float*** pcm);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_synthesis_lapout(vorbis_dsp_state* v, float*** pcm);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_synthesis_read(vorbis_dsp_state* v, int samples);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
[return: NativeTypeName("long")]
public static extern CLong vorbis_packet_blocksize(vorbis_info* vi, ogg_packet* op);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_synthesis_halfrate(vorbis_info* v, int flag);
[DllImport("robust-native", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern int vorbis_synthesis_halfrate_p(vorbis_info* v);
}

View File

@@ -0,0 +1,9 @@
namespace Robust.Shared.Interop.RobustNative.Vorbis;
internal unsafe partial struct alloc_chain
{
public void* ptr;
[NativeTypeName("struct alloc_chain *")]
public alloc_chain* next;
}

View File

@@ -0,0 +1,59 @@
namespace Robust.Shared.Interop.RobustNative.Vorbis;
internal unsafe partial struct vorbis_block
{
public float** pcm;
public oggpack_buffer opb;
[NativeTypeName("long")]
public CLong lW;
[NativeTypeName("long")]
public CLong W;
[NativeTypeName("long")]
public CLong nW;
public int pcmend;
public int mode;
public int eofflag;
[NativeTypeName("ogg_int64_t")]
public CLong granulepos;
[NativeTypeName("ogg_int64_t")]
public CLong sequence;
public vorbis_dsp_state* vd;
public void* localstore;
[NativeTypeName("long")]
public CLong localtop;
[NativeTypeName("long")]
public CLong localalloc;
[NativeTypeName("long")]
public CLong totaluse;
[NativeTypeName("struct alloc_chain *")]
public alloc_chain* reap;
[NativeTypeName("long")]
public CLong glue_bits;
[NativeTypeName("long")]
public CLong time_bits;
[NativeTypeName("long")]
public CLong floor_bits;
[NativeTypeName("long")]
public CLong res_bits;
public void* @internal;
}

View File

@@ -0,0 +1,14 @@
namespace Robust.Shared.Interop.RobustNative.Vorbis;
internal unsafe partial struct vorbis_comment
{
[NativeTypeName("char **")]
public sbyte** user_comments;
public int* comment_lengths;
public int comments;
[NativeTypeName("char *")]
public sbyte* vendor;
}

View File

@@ -0,0 +1,54 @@
namespace Robust.Shared.Interop.RobustNative.Vorbis;
internal unsafe partial struct vorbis_dsp_state
{
public int analysisp;
public vorbis_info* vi;
public float** pcm;
public float** pcmret;
public int pcm_storage;
public int pcm_current;
public int pcm_returned;
public int preextrapolate;
public int eofflag;
[NativeTypeName("long")]
public CLong lW;
[NativeTypeName("long")]
public CLong W;
[NativeTypeName("long")]
public CLong nW;
[NativeTypeName("long")]
public CLong centerW;
[NativeTypeName("ogg_int64_t")]
public CLong granulepos;
[NativeTypeName("ogg_int64_t")]
public CLong sequence;
[NativeTypeName("ogg_int64_t")]
public CLong glue_bits;
[NativeTypeName("ogg_int64_t")]
public CLong time_bits;
[NativeTypeName("ogg_int64_t")]
public CLong floor_bits;
[NativeTypeName("ogg_int64_t")]
public CLong res_bits;
public void* backend_state;
}

View File

@@ -0,0 +1,25 @@
namespace Robust.Shared.Interop.RobustNative.Vorbis;
internal unsafe partial struct vorbis_info
{
public int version;
public int channels;
[NativeTypeName("long")]
public CLong rate;
[NativeTypeName("long")]
public CLong bitrate_upper;
[NativeTypeName("long")]
public CLong bitrate_nominal;
[NativeTypeName("long")]
public CLong bitrate_lower;
[NativeTypeName("long")]
public CLong bitrate_window;
public void* codec_setup;
}

Some files were not shown because too many files have changed in this diff Show More