Compare commits

...

25 Commits

Author SHA1 Message Date
Pieter-Jan Briers
950ceb235a Version: 228.0.2 2024-08-11 19:54:40 +02:00
Pieter-Jan Briers
38ab4b729e Use absolute path for explorer.exe
frick me

(cherry picked from commit 0284eb0430)
2024-08-11 19:54:40 +02:00
Pieter-Jan Briers
634ba59316 Version: 228.0.1 2024-08-11 17:52:24 +02:00
Pieter-Jan Briers
01b60240d5 Security updates (#5353)
* Fix security bug in WritableDirProvider.OpenOsWindow()

Reported by @NarryG and @nyeogmi

* Sandbox updates

* Update ImageSharp again

(cherry picked from commit 7d778248ee)
2024-08-11 17:52:24 +02:00
metalgearsloth
fc1cca4f48 Version: 228.0.0 2024-07-12 21:50:15 +10:00
Pieter-Jan Briers
3657b0a424 Strongly order network prototypes and resources. (#5293)
* Strongly order network prototypes and resources.

When a new client connects, both the uploaded prototypes and resources get sent at once. There was no ordering here, which means that prototypes could easily load before resources. This would then obviously give load errors at runtime. In practice though this seemed fine because the RSI or something would just load fine after when spawned or something.

This was then broken by ae1051e813, which made ResourceCache start caching "that RSI doesn't exist" so it never really tried again.

I originally tried to fix this by adding an API to IResourceManager that allows content to invalidate the aforementioned cache (commit 316a7e4ac10100593202ff7f53dc2992611bbd1e, for however GitHub will track that) but then realized resource uploading isn't part of content like I first thought. Lol whoops. That API might still be useful for other dynamic content use cases, but I'm not committing it for now. That fix still caused errors to be spammed if the prototype was loaded before the resources were ready.

The new fix is to just load resources before prototypes. This is done by making them both ordered relative to each other, and running resources first.

Fixes #5291

* Release notes
2024-07-12 09:12:58 +02:00
Tayrtahn
c3d8080a8e Add PreferNonGenericVariantFor attribute and analyzer (#5190)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2024-07-10 12:33:56 +02:00
Tayrtahn
8e50924607 Add analyzer/fixer for DataFields with ReadWrite VV (#5164)
* Add analyzer/fixer for datafields with ReadWrite VV

* Nothing to see here
2024-07-10 02:04:55 +02:00
Leon Friedrich
7fdd5c9d1c Make color equality exact (#5253) 2024-07-10 01:43:12 +02:00
Pieter-Jan Briers
7fbcfeaa8f Warning fixes (#5275)
* Warning fixes in Robust.Shared

* Robust.Client warning fixes

* Fix test failure

Test failures were due to broken system registrations for the client RobustUnitTest. It was accidentally registering some server systems, which means DebugPhysicsSystem wasn't gettings its dependencies properly.

Fixing this meant pulling half a dozen extra dependencies that client ContainerSystem and TransformSystem are supposed to have, but didn't.
2024-07-10 01:38:32 +02:00
eoineoineoin
b82bc258db Add styleclass to OptionsButton popup background widget (#5290)
* Add styleclass to OptionsButton popup background widget

* Update Robust.Client/UserInterface/Controls/OptionButton.cs

Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>

---------

Co-authored-by: Eoin Mcloughlin <helloworld@eoinrul.es>
Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
2024-07-09 23:33:16 +02:00
metalgearsloth
7ad2925f2c Add TryQueueDeleteEntity (#5281)
Having to check deleted by hand up front is annoying.
2024-07-09 23:32:17 +02:00
CaasGit
4091ad4837 Fixes two moderate security issues in ImageSharp (#5257)
Two moderate issues were fixed in ImageSharp 3.1.4:
* https://github.com/SixLabors/ImageSharp/security/advisories/GHSA-g85r-6x2q-45w7
* https://github.com/SixLabors/ImageSharp/security/advisories/GHSA-5x7m-6737-26cr
2024-07-09 23:31:49 +02:00
metalgearsloth
35881d7a6a Add SpriteSystem.IsVisible (#5283)
So content doesn't need to manually check in the rare case we update this.
2024-07-09 22:37:35 +02:00
Pieter-Jan Briers
2d28ac35d8 Interpolated string handler for AudioManager.LogALError
This reduces a decent chunk of useless log allocations.
2024-07-09 17:12:06 +02:00
Pieter-Jan Briers
8b5ad938d5 Fix a closure allocation in physics
Makes InternalParallel a static function. This makes the sort delegate on line 609 statically cacheable by the compiler as it has no state.
2024-07-09 17:00:17 +02:00
Pieter-Jan Briers
723f936a33 Add full caps doc comment about VisibilityComponent
Brought to you by "why does disabling PVS make ghosts visible in SS14"
2024-07-07 20:37:12 +02:00
ShadowCommander
2636879860 ViewVariables UI for Flags Enum and fixes enums with duplicate values (#5287)
* Add editor dropdown for large enums

* Add enum flag selection buttons

* Cleanup
2024-07-07 16:27:17 +10:00
ShadowCommander
dad1da507c Toolshed command help usage (#5274)
* Add usage to toolshed help

* Add name to toolshed usage help

* Better formatting

* Localize toolshed command usage

* Remove unnecessary call

* Cleanup

* Add release notes

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2024-07-07 16:19:56 +10:00
DrSmugleaf
145c190800 Add cvar to limit nearby command range (#5282)
* Add cvar to limit nearby command range

* Release notes

* More comment

* Fix release note

* Update Robust.Shared/CVars.cs
2024-07-07 13:54:34 +10:00
TemporalOroboros
b7cc0ec629 Adds event for mass and angular inertia changes. (#5286)
* Adds MassDataChangedEvent to physics
This event is raised in response to changes to an entities innate mass/angular inertia/center of mass

* Use properties to fetch data from component

* Comp1

* Vector2

* I sure love an analyzer that doesn't work half the time
2024-07-06 17:34:50 +10:00
Amy
ad329a6b58 whitelist (#5285)
Co-authored-by: amylizzle <amylizzle@users.noreply.github.com>
2024-07-04 15:29:03 +02:00
Guillaume E
4deba4b866 Darken SnapgridCenter placement grid (#5279)
In SS14, the bright blue placement grid was making other game objects
difficult to see in low lighting conditions.
2024-07-04 09:55:46 +10:00
deathride58
4c31083186 Replaces the entity spawn window's bespoke method of object icon rendering with entityprototypeview (#5277) 2024-07-03 21:37:18 +10:00
DrSmugleaf
d31e7ccb55 Add Text property to RichTextLabel (#5280) 2024-07-03 13:02:41 +02:00
85 changed files with 1194 additions and 284 deletions

View File

@@ -55,7 +55,7 @@
<PackageVersion Include="Serilog" Version="3.1.1" />
<PackageVersion Include="Serilog.Sinks.Loki" Version="4.0.0-beta3" />
<PackageVersion Include="SharpZstd.Interop" Version="1.5.2-beta2" />
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.3" />
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.5" />
<PackageVersion Include="SpaceWizards.HttpListener" Version="0.1.1" />
<PackageVersion Include="SpaceWizards.NFluidsynth" Version="0.1.1" />
<PackageVersion Include="SpaceWizards.SharpFont" Version="1.0.2" />

View File

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

View File

@@ -54,6 +54,33 @@ END TEMPLATE-->
*None yet*
## 228.0.2
## 228.0.1
## 228.0.0
### Breaking changes
* The `Color` struct's equality methods now check for exact equality. Use `MathHelper.CloseToPercent(Color, Color)` for the previous functionality.
* Added a toolshed.nearby_limit cvar to limit the maximum range of the nearby command. Defaults to 200.
### New features
* Added command usage with types to Toolshed command help.
* Add Text property to RichTextLabel.
* Whitelist System.Net.IPEndPoint.
* Add event for mass & angular inertia changes.
* Add SpriteSystem.IsVisible for layers.
* Add TryQueueDeleteEntity that checks if the entity is already deleted / queuedeleted first.
### Bugfixes
* Clients connecting to a server now always load prototype uploads after resource uploads, fixing ordering bugs that could cause various errors.
## 227.0.0
### Breaking changes

View File

@@ -0,0 +1,91 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.CodeAnalysis.Testing.Verifiers;
using NUnit.Framework;
using VerifyCS =
Microsoft.CodeAnalysis.CSharp.Testing.NUnit.AnalyzerVerifier<Robust.Analyzers.DataDefinitionAnalyzer>;
namespace Robust.Analyzers.Tests;
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
[TestFixture]
public sealed class DataDefinitionAnalyzerTest
{
private static Task Verifier(string code, params DiagnosticResult[] expected)
{
var test = new CSharpAnalyzerTest<DataDefinitionAnalyzer, NUnitVerifier>()
{
TestState =
{
Sources = { code }
},
};
// ExpectedDiagnostics cannot be set, so we need to AddRange here...
test.TestState.ExpectedDiagnostics.AddRange(expected);
return test.RunAsync();
}
[Test]
public async Task Test()
{
const string code = """
using System;
using Robust.Shared.ViewVariables;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Robust.Shared.ViewVariables
{
public sealed class ViewVariablesAttribute : Attribute
{
public readonly VVAccess Access = VVAccess.ReadOnly;
public ViewVariablesAttribute() { }
public ViewVariablesAttribute(VVAccess access)
{
Access = access;
}
}
public enum VVAccess : byte
{
ReadOnly = 0,
ReadWrite = 1,
}
}
namespace Robust.Shared.Serialization.Manager.Attributes
{
public class DataFieldBaseAttribute : Attribute;
public class DataFieldAttribute : DataFieldBaseAttribute;
public sealed class DataDefinitionAttribute : Attribute;
}
[DataDefinition]
public sealed partial class Foo
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public int Bad;
[DataField]
public int Good;
[DataField, ViewVariables]
public int Good2;
[DataField, ViewVariables(VVAccess.ReadOnly)]
public int Good3;
[ViewVariables]
public int Good4;
}
""";
await Verifier(code,
// /0/Test0.cs(35,5): info RA0028: Data field Bad in data definition Foo has ViewVariables attribute with ReadWrite access, which is redundant
VerifyCS.Diagnostic(DataDefinitionAnalyzer.DataFieldNoVVReadWriteRule).WithSpan(35, 5, 36, 20).WithArguments("Bad", "Foo")
);
}
}

View File

@@ -0,0 +1,71 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.CodeAnalysis.Testing.Verifiers;
using NUnit.Framework;
using VerifyCS =
Microsoft.CodeAnalysis.CSharp.Testing.NUnit.AnalyzerVerifier<Robust.Analyzers.PreferNonGenericVariantForAnalyzer>;
namespace Robust.Analyzers.Tests;
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
[TestFixture]
public sealed class PreferNonGenericVariantForTest
{
private static Task Verifier(string code, params DiagnosticResult[] expected)
{
var test = new CSharpAnalyzerTest<PreferNonGenericVariantForAnalyzer, NUnitVerifier>()
{
TestState =
{
Sources = { code },
},
};
TestHelper.AddEmbeddedSources(
test.TestState,
"Robust.Shared.Analyzers.PreferNonGenericVariantForAttribute.cs"
);
// ExpectedDiagnostics cannot be set, so we need to AddRange here...
test.TestState.ExpectedDiagnostics.AddRange(expected);
return test.RunAsync();
}
[Test]
public async Task Test()
{
const string code = """
using Robust.Shared.Analyzers;
public class Bar { };
public class Baz { };
public class Okay { };
public static class Foo
{
[PreferNonGenericVariantFor(typeof(Bar), typeof(Baz))]
public static void DoFoo<T>() { }
}
public class Test
{
public void DoBad()
{
Foo.DoFoo<Bar>();
}
public void DoGood()
{
Foo.DoFoo<Okay>();
}
}
""";
await Verifier(code,
// /0/Test0.cs(17,9): warning RA0029: Use the non-generic variant of this method for type Bar
VerifyCS.Diagnostic().WithSpan(17, 9, 17, 25).WithArguments("Bar")
);
}
}

View File

@@ -11,6 +11,7 @@
<EmbeddedResource Include="..\Robust.Shared\Analyzers\AccessAttribute.cs" LogicalName="Robust.Shared.Analyzers.AccessAttribute.cs" LinkBase="Implementations" />
<EmbeddedResource Include="..\Robust.Shared\Analyzers\AccessPermissions.cs" LogicalName="Robust.Shared.Analyzers.AccessPermissions.cs" LinkBase="Implementations" />
<EmbeddedResource Include="..\Robust.Shared\Analyzers\MustCallBaseAttribute.cs" LogicalName="Robust.Shared.IoC.MustCallBaseAttribute.cs" LinkBase="Implementations" />
<EmbeddedResource Include="..\Robust.Shared\Analyzers\PreferNonGenericVariantForAttribute.cs" LogicalName="Robust.Shared.Analyzers.PreferNonGenericVariantForAttribute.cs" LinkBase="Implementations" />
<EmbeddedResource Include="..\Robust.Shared\IoC\DependencyAttribute.cs" LogicalName="Robust.Shared.IoC.DependencyAttribute.cs" LinkBase="Implementations" />
</ItemGroup>

View File

@@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Robust.Roslyn.Shared;
using Robust.Shared.Serialization.Manager.Definition;
using Robust.Shared.ViewVariables;
namespace Robust.Analyzers;
@@ -16,6 +17,7 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
private const string DataDefinitionNamespace = "Robust.Shared.Serialization.Manager.Attributes.DataDefinitionAttribute";
private const string ImplicitDataDefinitionNamespace = "Robust.Shared.Serialization.Manager.Attributes.ImplicitDataDefinitionForInheritorsAttribute";
private const string DataFieldBaseNamespace = "Robust.Shared.Serialization.Manager.Attributes.DataFieldBaseAttribute";
private const string ViewVariablesNamespace = "Robust.Shared.ViewVariables.ViewVariablesAttribute";
private static readonly DiagnosticDescriptor DataDefinitionPartialRule = new(
Diagnostics.IdDataDefinitionPartial,
@@ -66,9 +68,20 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
true,
"Make sure to remove the tag string from the data field attribute."
);
public static readonly DiagnosticDescriptor DataFieldNoVVReadWriteRule = new(
Diagnostics.IdDataFieldNoVVReadWrite,
"Data field has VV ReadWrite",
"Data field {0} in data definition {1} has ViewVariables attribute with ReadWrite access, which is redundant",
"Usage",
DiagnosticSeverity.Info,
true,
"Make sure to remove the ViewVariables attribute."
);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(
DataDefinitionPartialRule, NestedDataDefinitionPartialRule, DataFieldWritableRule, DataFieldPropertyWritableRule,
DataFieldRedundantTagRule
DataFieldRedundantTagRule, DataFieldNoVVReadWriteRule
);
public override void Initialize(AnalysisContext context)
@@ -141,6 +154,11 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
{
context.ReportDiagnostic(Diagnostic.Create(DataFieldRedundantTagRule, context.Node.GetLocation(), fieldSymbol.Name, type.Name));
}
if (HasVVReadWrite(fieldSymbol))
{
context.ReportDiagnostic(Diagnostic.Create(DataFieldNoVVReadWriteRule, context.Node.GetLocation(), fieldSymbol.Name, type.Name));
}
}
}
@@ -170,6 +188,11 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
{
context.ReportDiagnostic(Diagnostic.Create(DataFieldRedundantTagRule, context.Node.GetLocation(), propertySymbol.Name, type.Name));
}
if (HasVVReadWrite(propertySymbol))
{
context.ReportDiagnostic(Diagnostic.Create(DataFieldNoVVReadWriteRule, context.Node.GetLocation(), propertySymbol.Name, type.Name));
}
}
private static bool IsReadOnlyDataField(ITypeSymbol type, ISymbol field)
@@ -292,6 +315,34 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
return explicitName == automaticName;
}
private static bool HasVVReadWrite(ISymbol symbol)
{
if (!IsDataField(symbol, out _, out _))
return false;
// Make sure it has ViewVariablesAttribute
AttributeData? viewVariablesAttribute = null;
foreach (var attr in symbol.GetAttributes())
{
if (attr.AttributeClass?.ToDisplayString() == ViewVariablesNamespace)
{
viewVariablesAttribute = attr;
}
}
if (viewVariablesAttribute == null)
return false;
// Default is ReadOnly, which is fine
if (viewVariablesAttribute.ConstructorArguments.Length == 0)
return false;
var accessArgument = viewVariablesAttribute.ConstructorArguments[0];
if (accessArgument.Value is not byte accessByte)
return false;
return (VVAccess)accessByte == VVAccess.ReadWrite;
}
private static bool IsImplicitDataDefinition(ITypeSymbol type)
{
if (HasAttribute(type, ImplicitDataDefinitionNamespace))

View File

@@ -15,9 +15,11 @@ public sealed class DefinitionFixer : CodeFixProvider
{
private const string DataFieldAttributeName = "DataField";
private const string ViewVariablesAttributeName = "ViewVariables";
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(
IdDataDefinitionPartial, IdNestedDataDefinitionPartial, IdDataFieldWritable, IdDataFieldPropertyWritable,
IdDataFieldRedundantTag
IdDataFieldRedundantTag, IdDataFieldNoVVReadWrite
);
public override Task RegisterCodeFixesAsync(CodeFixContext context)
@@ -36,6 +38,8 @@ public sealed class DefinitionFixer : CodeFixProvider
return RegisterDataFieldPropertyFix(context, diagnostic);
case IdDataFieldRedundantTag:
return RegisterRedundantTagFix(context, diagnostic);
case IdDataFieldNoVVReadWrite:
return RegisterVVReadWriteFix(context, diagnostic);
}
}
@@ -136,6 +140,48 @@ public sealed class DefinitionFixer : CodeFixProvider
return document.WithSyntaxRoot(root);
}
private static async Task RegisterVVReadWriteFix(CodeFixContext context, Diagnostic diagnostic)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
var span = diagnostic.Location.SourceSpan;
var token = root?.FindToken(span.Start).Parent?.AncestorsAndSelf().OfType<MemberDeclarationSyntax>().First();
if (token == null)
return;
context.RegisterCodeFix(CodeAction.Create(
"Remove ViewVariables attribute",
c => RemoveVVAttribute(context.Document, token, c),
"Remove ViewVariables attribute"
), diagnostic);
}
private static async Task<Document> RemoveVVAttribute(Document document, MemberDeclarationSyntax syntax, CancellationToken cancellation)
{
var root = (CompilationUnitSyntax?) await document.GetSyntaxRootAsync(cancellation);
var newLists = new SyntaxList<AttributeListSyntax>();
foreach (var attributeList in syntax.AttributeLists)
{
var attributes = new SeparatedSyntaxList<AttributeSyntax>();
foreach (var attribute in attributeList.Attributes)
{
if (attribute.Name.ToString() != ViewVariablesAttributeName)
{
attributes = attributes.Add(attribute);
}
}
// Don't add empty lists []
if (attributes.Count > 0)
newLists = newLists.Add(attributeList.WithAttributes(attributes));
}
var newSyntax = syntax.WithAttributeLists(newLists);
root = root!.ReplaceNode(syntax, newSyntax);
return document.WithSyntaxRoot(root);
}
private static async Task RegisterDataFieldFix(CodeFixContext context, Diagnostic diagnostic)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);

View File

@@ -0,0 +1,65 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using Robust.Roslyn.Shared;
namespace Robust.Analyzers;
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class PreferNonGenericVariantForAnalyzer : DiagnosticAnalyzer
{
private const string AttributeType = "Robust.Shared.Analyzers.PreferNonGenericVariantForAttribute";
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(
UseNonGenericVariantDescriptor
);
private static readonly DiagnosticDescriptor UseNonGenericVariantDescriptor = new(
Diagnostics.IdUseNonGenericVariant,
"Consider using the non-generic variant of this method",
"Use the non-generic variant of this method for type {0}",
"Usage",
DiagnosticSeverity.Warning,
true,
"Use the generic variant of this method.");
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.ReportDiagnostics | GeneratedCodeAnalysisFlags.Analyze);
context.EnableConcurrentExecution();
context.RegisterOperationAction(CheckForNonGenericVariant, OperationKind.Invocation);
}
private void CheckForNonGenericVariant(OperationAnalysisContext obj)
{
if (obj.Operation is not IInvocationOperation invocationOperation) return;
var preferNonGenericAttribute = obj.Compilation.GetTypeByMetadataName(AttributeType);
HashSet<ITypeSymbol> forTypes = [];
foreach (var attribute in invocationOperation.TargetMethod.GetAttributes())
{
if (!SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, preferNonGenericAttribute))
continue;
foreach (var type in attribute.ConstructorArguments[0].Values)
forTypes.Add((ITypeSymbol)type.Value);
break;
}
if (forTypes == null)
return;
foreach (var typeArg in invocationOperation.TargetMethod.TypeArguments)
{
if (forTypes.Contains(typeArg))
{
obj.ReportDiagnostic(
Diagnostic.Create(UseNonGenericVariantDescriptor,
invocationOperation.Syntax.GetLocation(), typeArg.Name));
}
}
}
}

View File

@@ -16,9 +16,16 @@
<Compile Include="..\Robust.Shared\Analyzers\PreferGenericVariantAttribute.cs" LinkBase="Implementations" />
</ItemGroup>
<ItemGroup>
<!-- Needed for PreferNonGenericVariantAnalyzer. -->
<Compile Include="..\Robust.Shared\Analyzers\PreferNonGenericVariantForAttribute.cs" LinkBase="Implementations" />
</ItemGroup>
<ItemGroup>
<!-- Needed for DataDefinitionAnalyzer. -->
<Compile Include="..\Robust.Shared\Serialization\Manager\Definition\DataDefinitionUtility.cs" LinkBase="Implementations" />
<Compile Include="..\Robust.Shared\ViewVariables\ViewVariablesAttribute.cs" LinkBase="Implementations" />
<Compile Include="..\Robust.Shared\Serialization\NetSerializableAttribute.cs" LinkBase="Implementations" />
</ItemGroup>
<Import Project="../Robust.Roslyn.Shared/Robust.Roslyn.Shared.props" />

View File

@@ -302,7 +302,7 @@ internal partial class AudioManager
}
/// <inheritdoc/>
IBufferedAudioSource? IAudioInternal.CreateBufferedAudioSource(int buffers, bool floatAudio=false)
IBufferedAudioSource? IAudioInternal.CreateBufferedAudioSource(int buffers, bool floatAudio)
{
var source = AL.GenSource();

View File

@@ -143,12 +143,11 @@ internal sealed partial class AudioManager : IAudioInternal
/// <summary>
/// Like _checkAlError but allows custom data to be passed in as relevant.
/// </summary>
internal void LogALError(string message, [CallerMemberName] string callerMember = "", [CallerLineNumber] int callerLineNumber = -1)
internal void LogALError(ALErrorInterpolatedStringHandler message, [CallerMemberName] string callerMember = "", [CallerLineNumber] int callerLineNumber = -1)
{
var error = AL.GetError();
if (error != ALError.NoError)
if (message.Error != ALError.NoError)
{
OpenALSawmill.Error("[{0}:{1}] AL error: {2}, {3}. Stacktrace is {4}", callerMember, callerLineNumber, error, message, Environment.StackTrace);
OpenALSawmill.Error("[{0}:{1}] AL error: {2}, {3}. Stacktrace is {4}", callerMember, callerLineNumber, message.Error, message.ToStringAndClear(), Environment.StackTrace);
}
}
@@ -170,4 +169,32 @@ internal sealed partial class AudioManager : IAudioInternal
BufferHandle = bufferHandle;
}
}
[InterpolatedStringHandler]
internal ref struct ALErrorInterpolatedStringHandler
{
private DefaultInterpolatedStringHandler _handler;
public ALError Error;
public ALErrorInterpolatedStringHandler(int literalLength, int formattedCount, out bool shouldAppend)
{
Error = AL.GetError();
if (Error == ALError.NoError)
{
shouldAppend = false;
_handler = default;
}
else
{
shouldAppend = true;
_handler = new DefaultInterpolatedStringHandler(literalLength, formattedCount);
}
}
public string ToStringAndClear() => _handler.ToStringAndClear();
public override string ToString() => _handler.ToString();
public void AppendLiteral(string value) => _handler.AppendLiteral(value);
public void AppendFormatted<T>(T value) => _handler.AppendFormatted(value);
public void AppendFormatted<T>(T value, string? format) => _handler.AppendFormatted(value, format);
}
}

View File

@@ -46,7 +46,7 @@ public sealed class AudioOverlay : Overlay
var screenHandle = args.ScreenHandle;
var output = new StringBuilder();
var listenerPos = _entManager.GetComponent<TransformComponent>(localPlayer.Value).MapPosition;
var listenerPos = _transform.GetMapCoordinates(_entManager.GetComponent<TransformComponent>(localPlayer.Value));
if (listenerPos.MapId != args.MapId)
return;

View File

@@ -1,24 +1,18 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using OpenTK.Audio.OpenAL;
using OpenTK.Audio.OpenAL.Extensions.Creative.EFX;
using Robust.Client.Graphics;
using Robust.Shared.Audio.Sources;
using Robust.Shared.Maths;
namespace Robust.Client.Audio.Sources;
internal sealed class BufferedAudioSource : BaseAudioSource, IBufferedAudioSource
{
private int? SourceHandle = null;
private int[] BufferHandles;
private Dictionary<int, int> BufferMap = new();
private readonly AudioManager _master;
private bool _mono = true;
private bool _float = false;
private int FilterHandle;
public int SampleRate { get; set; } = 44100;
@@ -43,7 +37,7 @@ internal sealed class BufferedAudioSource : BaseAudioSource, IBufferedAudioSourc
get
{
_checkDisposed();
var state = AL.GetSourceState(SourceHandle!.Value);
var state = AL.GetSourceState(SourceHandle);
_master._checkAlError();
return state == ALSourceState.Playing;
}
@@ -53,7 +47,7 @@ internal sealed class BufferedAudioSource : BaseAudioSource, IBufferedAudioSourc
{
_checkDisposed();
// IDK why this stackallocs but gonna leave it for now.
AL.SourcePlay(stackalloc int[] {SourceHandle!.Value});
AL.SourcePlay(stackalloc int[] {SourceHandle});
_master._checkAlError();
}
else
@@ -61,7 +55,7 @@ internal sealed class BufferedAudioSource : BaseAudioSource, IBufferedAudioSourc
if (_isDisposed())
return;
AL.SourceStop(SourceHandle!.Value);
AL.SourceStop(SourceHandle);
_master._checkAlError();
}
}
@@ -74,13 +68,13 @@ internal sealed class BufferedAudioSource : BaseAudioSource, IBufferedAudioSourc
protected override void Dispose(bool disposing)
{
if (SourceHandle == null)
if (SourceHandle == -1)
return;
if (!_master.IsMainThread())
{
// We can't run this code inside another thread so tell Clyde to clear it up later.
_master.DeleteBufferedSourceOnMainThread(SourceHandle.Value, FilterHandle);
_master.DeleteBufferedSourceOnMainThread(SourceHandle, FilterHandle);
foreach (var handle in BufferHandles)
{
@@ -92,21 +86,21 @@ internal sealed class BufferedAudioSource : BaseAudioSource, IBufferedAudioSourc
if (FilterHandle != 0)
EFX.DeleteFilter(FilterHandle);
AL.DeleteSource(SourceHandle.Value);
AL.DeleteSource(SourceHandle);
AL.DeleteBuffers(BufferHandles);
_master.RemoveBufferedAudioSource(SourceHandle.Value);
_master.RemoveBufferedAudioSource(SourceHandle);
_master._checkAlError();
}
FilterHandle = 0;
SourceHandle = null;
SourceHandle = -1;
}
public int GetNumberOfBuffersProcessed()
{
_checkDisposed();
// ReSharper disable once PossibleInvalidOperationException
AL.GetSource(SourceHandle!.Value, ALGetSourcei.BuffersProcessed, out var buffersProcessed);
AL.GetSource(SourceHandle, ALGetSourcei.BuffersProcessed, out var buffersProcessed);
return buffersProcessed;
}
@@ -116,7 +110,7 @@ internal sealed class BufferedAudioSource : BaseAudioSource, IBufferedAudioSourc
var entries = Math.Min(Math.Min(handles.Length, BufferHandles.Length), GetNumberOfBuffersProcessed());
fixed (int* ptr = handles)
{
AL.SourceUnqueueBuffers(SourceHandle!.Value, entries, ptr);
AL.SourceUnqueueBuffers(SourceHandle, entries, ptr);
}
for (var i = 0; i < entries; i++)
@@ -183,7 +177,7 @@ internal sealed class BufferedAudioSource : BaseAudioSource, IBufferedAudioSourc
fixed (int* ptr = realHandles)
// ReSharper disable once PossibleInvalidOperationException
{
AL.SourceQueueBuffers(SourceHandle!.Value, handles.Length, ptr);
AL.SourceQueueBuffers(SourceHandle, handles.Length, ptr);
}
}

View File

@@ -291,9 +291,9 @@ namespace Robust.Client.Console.Commands
}
}
internal sealed class SnapGridGetCell : LocalizedCommands
internal sealed class SnapGridGetCell : LocalizedEntityCommands
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
public override string Command => "sggcell";
@@ -319,9 +319,10 @@ namespace Robust.Client.Console.Commands
return;
}
if (_entManager.TryGetComponent<MapGridComponent>(_entManager.GetEntity(gridNet), out var grid))
var gridEnt = EntityManager.GetEntity(gridNet);
if (EntityManager.TryGetComponent<MapGridComponent>(gridEnt, out var grid))
{
foreach (var entity in grid.GetAnchoredEntities(new Vector2i(
foreach (var entity in _map.GetAnchoredEntities(gridEnt, grid, new Vector2i(
int.Parse(indices.Split(',')[0], CultureInfo.InvariantCulture),
int.Parse(indices.Split(',')[1], CultureInfo.InvariantCulture))))
{
@@ -425,9 +426,9 @@ namespace Robust.Client.Console.Commands
}
}
internal sealed class GridTileCount : LocalizedCommands
internal sealed class GridTileCount : LocalizedEntityCommands
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
public override string Command => "gridtc";
@@ -440,15 +441,15 @@ namespace Robust.Client.Console.Commands
}
if (!NetEntity.TryParse(args[0], out var gridUidNet) ||
!_entManager.TryGetEntity(gridUidNet, out var gridUid))
!EntityManager.TryGetEntity(gridUidNet, out var gridUid))
{
shell.WriteLine($"{args[0]} is not a valid entity UID.");
return;
}
if (_entManager.TryGetComponent<MapGridComponent>(gridUid, out var grid))
if (EntityManager.TryGetComponent<MapGridComponent>(gridUid, out var grid))
{
shell.WriteLine(grid.GetAllTiles().Count().ToString());
shell.WriteLine(_map.GetAllTiles(gridUid.Value, grid).Count().ToString());
}
else
{
@@ -680,12 +681,12 @@ namespace Robust.Client.Console.Commands
}
}
internal sealed class ChunkInfoCommand : LocalizedCommands
internal sealed class ChunkInfoCommand : LocalizedEntityCommands
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IMapManager _map = default!;
[Dependency] private readonly IEyeManager _eye = default!;
[Dependency] private readonly IInputManager _input = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
public override string Command => "chunkinfo";
@@ -699,8 +700,8 @@ namespace Robust.Client.Console.Commands
return;
}
var mapSystem = _entManager.System<SharedMapSystem>();
var chunkIndex = mapSystem.LocalToChunkIndices(gridUid, grid, grid.MapToGrid(mousePos));
var mapSystem = EntityManager.System<SharedMapSystem>();
var chunkIndex = mapSystem.LocalToChunkIndices(gridUid, grid, _mapSystem.MapToGrid(gridUid, mousePos));
var chunk = mapSystem.GetOrAddChunk(gridUid, grid, chunkIndex);
shell.WriteLine($"worldBounds: {mapSystem.CalcWorldAABB(gridUid, grid, chunk)} localBounds: {chunk.CachedBounds}");

View File

@@ -11,7 +11,7 @@ namespace Robust.Client.Console.Commands
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var type = Type.GetType(args[0]);
var type = GetType(args[0]);
if (type == null)
{
@@ -25,6 +25,17 @@ namespace Robust.Client.Console.Commands
shell.WriteLine(sig);
}
}
private Type? GetType(string name)
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
if (assembly.GetType(name) is { } type)
return type;
}
return null;
}
}
#endif
}

View File

@@ -1,16 +1,19 @@
using Robust.Client.GameObjects;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
namespace Robust.Client.Console.Commands
{
public sealed class GridChunkBBCommand : LocalizedCommands
public sealed class GridChunkBBCommand : LocalizedEntityCommands
{
[Dependency] private readonly GridChunkBoundsDebugSystem _system = default!;
public override string Command => "showchunkbb";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
EntitySystem.Get<GridChunkBoundsDebugSystem>().Enabled ^= true;
_system.Enabled ^= true;
}
}
}

View File

@@ -204,7 +204,7 @@ Suspendisse hendrerit blandit urna ut laoreet. Suspendisse ac elit at erat males
private Control TabRichText()
{
var label = new RichTextLabel();
label.SetMessage(FormattedMessage.FromMarkup(Lipsum));
label.SetMessage(FormattedMessage.FromMarkupOrThrow(Lipsum));
TabContainer.SetTabTitle(label, "RichText");
return label;

View File

@@ -1,4 +1,5 @@
using System.Numerics;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
@@ -14,6 +15,8 @@ namespace Robust.Client.Debugging
{
[Dependency] private readonly IOverlayManager _overlayManager = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly TransformSystem _transform = default!;
private bool _debugPositions;
private bool _debugRotations;
@@ -35,7 +38,7 @@ namespace Robust.Client.Debugging
if (value && !_overlayManager.HasOverlay<EntityPositionOverlay>())
{
_overlayManager.AddOverlay(new EntityPositionOverlay(_lookup, EntityManager));
_overlayManager.AddOverlay(new EntityPositionOverlay(_lookup, EntityManager, _transform));
}
else
{
@@ -74,13 +77,15 @@ namespace Robust.Client.Debugging
{
private readonly EntityLookupSystem _lookup;
private readonly IEntityManager _entityManager;
private readonly SharedTransformSystem _transform;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
public EntityPositionOverlay(EntityLookupSystem lookup, IEntityManager entityManager)
public EntityPositionOverlay(EntityLookupSystem lookup, IEntityManager entityManager, SharedTransformSystem transform)
{
_lookup = lookup;
_entityManager = entityManager;
_transform = transform;
}
protected internal override void Draw(in OverlayDrawArgs args)
@@ -88,11 +93,10 @@ namespace Robust.Client.Debugging
const float stubLength = 0.25f;
var worldHandle = (DrawingHandleWorld) args.DrawingHandle;
var xformQuery = _entityManager.GetEntityQuery<TransformComponent>();
foreach (var entity in _lookup.GetEntitiesIntersecting(args.MapId, args.WorldBounds))
{
var (center, worldRotation) = xformQuery.GetComponent(entity).GetWorldPositionRotation();
var (center, worldRotation) = _transform.GetWorldPositionRotation(entity);
var xLine = worldRotation.RotateVec(Vector2.UnitX);
var yLine = worldRotation.RotateVec(Vector2.UnitY);

View File

@@ -47,6 +47,7 @@
using System;
using System.Collections.Generic;
using System.Numerics;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.Player;
@@ -78,6 +79,14 @@ namespace Robust.Client.Debugging
internal int PointCount;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly IOverlayManager _overlay = default!;
[Dependency] private readonly IEyeManager _eye = default!;
[Dependency] private readonly IInputManager _input = default!;
[Dependency] private readonly IMapManager _map = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
internal ContactPoint[] Points = new ContactPoint[MaxContactPoints];
@@ -89,20 +98,21 @@ namespace Robust.Client.Debugging
if (value == _flags) return;
if (_flags == PhysicsDebugFlags.None)
IoCManager.Resolve<IOverlayManager>().AddOverlay(
_overlay.AddOverlay(
new PhysicsDebugOverlay(
EntityManager,
IoCManager.Resolve<IEyeManager>(),
IoCManager.Resolve<IInputManager>(),
IoCManager.Resolve<IMapManager>(),
IoCManager.Resolve<IPlayerManager>(),
IoCManager.Resolve<IResourceCache>(),
_eye,
_input,
_map,
_player,
_resourceCache,
this,
Get<EntityLookupSystem>(),
Get<SharedPhysicsSystem>()));
_entityLookup,
_physics,
_transform));
if (value == PhysicsDebugFlags.None)
IoCManager.Resolve<IOverlayManager>().RemoveOverlay(typeof(PhysicsDebugOverlay));
_overlay.RemoveOverlay(typeof(PhysicsDebugOverlay));
_flags = value;
}
@@ -198,6 +208,7 @@ namespace Robust.Client.Debugging
private readonly DebugPhysicsSystem _debugPhysicsSystem;
private readonly EntityLookupSystem _lookup;
private readonly SharedPhysicsSystem _physicsSystem;
private readonly SharedTransformSystem _transformSystem;
public override OverlaySpace Space => OverlaySpace.WorldSpace | OverlaySpace.ScreenSpace;
@@ -208,7 +219,7 @@ namespace Robust.Client.Debugging
private HashSet<Joint> _drawnJoints = new();
private List<Entity<MapGridComponent>> _grids = new();
public PhysicsDebugOverlay(IEntityManager entityManager, IEyeManager eyeManager, IInputManager inputManager, IMapManager mapManager, IPlayerManager playerManager, IResourceCache cache, DebugPhysicsSystem system, EntityLookupSystem lookup, SharedPhysicsSystem physicsSystem)
public PhysicsDebugOverlay(IEntityManager entityManager, IEyeManager eyeManager, IInputManager inputManager, IMapManager mapManager, IPlayerManager playerManager, IResourceCache cache, DebugPhysicsSystem system, EntityLookupSystem lookup, SharedPhysicsSystem physicsSystem, SharedTransformSystem transformSystem)
{
_entityManager = entityManager;
_eyeManager = eyeManager;
@@ -218,6 +229,7 @@ namespace Robust.Client.Debugging
_debugPhysicsSystem = system;
_lookup = lookup;
_physicsSystem = physicsSystem;
_transformSystem = transformSystem;
_font = new VectorFont(cache.GetResource<FontResource>("/EngineFonts/NotoSans/NotoSans-Regular.ttf"), 10);
}
@@ -327,7 +339,7 @@ namespace Robust.Client.Debugging
{
if (jointComponent.JointCount == 0 ||
!_entityManager.TryGetComponent(uid, out TransformComponent? xf1) ||
!viewAABB.Contains(xf1.WorldPosition)) continue;
!viewAABB.Contains(_transformSystem.GetWorldPosition(xf1))) continue;
foreach (var (_, joint) in jointComponent.Joints)
{
@@ -517,8 +529,8 @@ namespace Robust.Client.Debugging
if (!_entityManager.TryGetComponent(joint.BodyAUid, out TransformComponent? xform1) ||
!_entityManager.TryGetComponent(joint.BodyBUid, out TransformComponent? xform2)) return;
var matrix1 = xform1.WorldMatrix;
var matrix2 = xform2.WorldMatrix;
var matrix1 = _transformSystem.GetWorldMatrix(xform1);
var matrix2 = _transformSystem.GetWorldMatrix(xform2);
var xf1 = new Vector2(matrix1.M31, matrix1.M32);
var xf2 = new Vector2(matrix2.M31, matrix2.M32);
@@ -526,8 +538,8 @@ namespace Robust.Client.Debugging
var p1 = Vector2.Transform(joint.LocalAnchorA, matrix1);
var p2 = Vector2.Transform(joint.LocalAnchorB, matrix2);
var xfa = new Transform(xf1, xform1.WorldRotation);
var xfb = new Transform(xf2, xform2.WorldRotation);
var xfa = new Transform(xf1, _transformSystem.GetWorldRotation(xform1));
var xfb = new Transform(xf2, _transformSystem.GetWorldRotation(xform2));
switch (joint)
{

View File

@@ -48,16 +48,6 @@ namespace Robust.Client.GameObjects
return base.CreateEntity(prototypeName, out metadata);
}
void IClientEntityManagerInternal.InitializeEntity(EntityUid entity, MetaDataComponent? meta)
{
base.InitializeEntity(entity, meta);
}
void IClientEntityManagerInternal.StartEntity(EntityUid entity)
{
base.StartEntity(entity);
}
/// <inheritdoc />
public override void DirtyEntity(EntityUid uid, MetaDataComponent? meta = null)
{

View File

@@ -18,6 +18,8 @@ namespace Robust.Client.GameObjects
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IOverlayManager _overlayManager = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
private GridChunkBoundsOverlay? _overlay;
@@ -36,7 +38,9 @@ namespace Robust.Client.GameObjects
_overlay = new GridChunkBoundsOverlay(
EntityManager,
_eyeManager,
_mapManager);
_mapManager,
_transform,
_map);
_overlayManager.AddOverlay(_overlay);
}
@@ -56,16 +60,20 @@ namespace Robust.Client.GameObjects
private readonly IEntityManager _entityManager;
private readonly IEyeManager _eyeManager;
private readonly IMapManager _mapManager;
private readonly SharedTransformSystem _transformSystem;
private readonly SharedMapSystem _mapSystem;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
private List<Entity<MapGridComponent>> _grids = new();
public GridChunkBoundsOverlay(IEntityManager entManager, IEyeManager eyeManager, IMapManager mapManager)
public GridChunkBoundsOverlay(IEntityManager entManager, IEyeManager eyeManager, IMapManager mapManager, SharedTransformSystem transformSystem, SharedMapSystem mapSystem)
{
_entityManager = entManager;
_eyeManager = eyeManager;
_mapManager = mapManager;
_transformSystem = transformSystem;
_mapSystem = mapSystem;
}
protected internal override void Draw(in OverlayDrawArgs args)
@@ -78,11 +86,11 @@ namespace Robust.Client.GameObjects
_mapManager.FindGridsIntersecting(currentMap, viewport, ref _grids);
foreach (var grid in _grids)
{
var worldMatrix = _entityManager.GetComponent<TransformComponent>(grid).WorldMatrix;
var worldMatrix = _transformSystem.GetWorldMatrix(grid);
worldHandle.SetTransform(worldMatrix);
var transform = new Transform(Vector2.Zero, Angle.Zero);
var chunkEnumerator = grid.Comp.GetMapChunks(viewport);
var chunkEnumerator = _mapSystem.GetMapChunks(grid.Owner, grid.Comp, viewport);
while (chunkEnumerator.MoveNext(out var chunk))
{

View File

@@ -196,7 +196,7 @@ namespace Robust.Client.GameObjects
wOffset = new Vector2(wX, wY);
}
var coords = EntityCoordinates.FromMap(pent, _transform.GetMapCoordinates(pent).Offset(wOffset), _transform, EntityManager);
var coords = _transform.ToCoordinates(pent, _transform.GetMapCoordinates(pent).Offset(wOffset));
var funcId = _inputManager.NetworkBindMap.KeyFunctionID(keyFunction);
var message = new ClientFullInputCmdMessage(_timing.CurTick,

View File

@@ -66,6 +66,11 @@ namespace Robust.Client.GameObjects
_sawmill = _logManager.GetSawmill("sprite");
}
public bool IsVisible(Layer layer)
{
return layer.Visible && layer.CopyToShaderParameters == null;
}
private void OnInit(EntityUid uid, SpriteComponent component, ComponentInit args)
{
// I'm not 100% this is needed, but I CBF with this ATM. Somebody kill server sprite component please.

View File

@@ -14,6 +14,7 @@ namespace Robust.Client.GameObjects
{
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly TransformSystem _transform = default!;
internal bool Enabled { get; set; }
@@ -43,7 +44,7 @@ namespace Robust.Client.GameObjects
return;
}
var screenPos = _eyeManager.WorldToScreen(EntityManager.GetComponent<TransformComponent>(player.Value).WorldPosition);
var screenPos = _eyeManager.WorldToScreen(_transform.GetWorldPosition(Transform(player.Value)));
LayoutContainer.SetPosition(_label, screenPos + new Vector2(0, 50));
_label.Visible = true;

View File

@@ -7,9 +7,5 @@ namespace Robust.Client.GameObjects
// These methods are used by the Game State Manager.
EntityUid CreateEntity(string? prototypeName, out MetaDataComponent metadata);
void InitializeEntity(EntityUid entity, MetaDataComponent? meta = null);
void StartEntity(EntityUid entity);
}
}

View File

@@ -34,13 +34,13 @@ namespace Robust.Client.Placement.Modes
{
var from = ScreenToWorld(new Vector2(a, 0));
var to = ScreenToWorld(new Vector2(a, viewportSize.Y));
args.WorldHandle.DrawLine(from, to, new Color(0, 0, 1f));
args.WorldHandle.DrawLine(from, to, new Color(0, 0, 0.3f));
}
for (var a = gridstart.Y; a < viewportSize.Y; a += SnapSize * EyeManager.PixelsPerMeter)
{
var from = ScreenToWorld(new Vector2(0, a));
var to = ScreenToWorld(new Vector2(viewportSize.X, a));
args.WorldHandle.DrawLine(from, to, new Color(0, 0, 1f));
args.WorldHandle.DrawLine(from, to, new Color(0, 0, 0.3f));
}
}

View File

@@ -327,8 +327,7 @@ public sealed class EntitySpawningUIController : UIController
if (_window == null || _window.Disposed)
return;
var textures = SpriteComponent.GetPrototypeTextures(prototype, _resources).Select(o => o.Default).ToList();
var button = _window.InsertEntityButton(prototype, insertFirst, index, textures);
var button = _window.InsertEntityButton(prototype, insertFirst, index);
button.ActualButton.OnToggled += OnEntityButtonToggled;
}

View File

@@ -33,10 +33,7 @@ public class EntityPrototypeView : SpriteView
_currentPrototype = entProto;
SetEntity(null);
if (_ourEntity != null)
{
EntMan.DeleteEntity(_ourEntity);
}
EntMan.DeleteEntity(_ourEntity);
if (_currentPrototype != null)
{
@@ -57,8 +54,6 @@ public class EntityPrototypeView : SpriteView
protected override void ExitedTree()
{
base.ExitedTree();
if (!EntMan.Deleted(_ourEntity))
EntMan.QueueDeleteEntity(_ourEntity);
EntMan.TryQueueDeleteEntity(_ourEntity);
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Numerics;
using Robust.Client.Graphics;
@@ -14,6 +14,7 @@ namespace Robust.Client.UserInterface.Controls
public const string StyleClassOptionButton = "optionButton";
public const string StyleClassPopup = "optionButtonPopup";
public const string StyleClassOptionTriangle = "optionTriangle";
public const string StyleClassOptionsBackground = "optionButtonBackground";
public readonly ScrollContainer OptionsScroll;
private readonly List<ButtonData> _buttonData = new();
@@ -75,7 +76,12 @@ namespace Robust.Client.UserInterface.Controls
_popup = new Popup()
{
Children = { new PanelContainer(), OptionsScroll },
Children = {
new PanelContainer {
StyleClasses = { StyleClassOptionsBackground }
},
OptionsScroll
},
StyleClasses = { StyleClassPopup }
};
_popup.OnPopupHide += OnPopupHide;

View File

@@ -38,6 +38,18 @@ namespace Robust.Client.UserInterface.Controls
}
}
public string? Text
{
get => _message?.ToMarkup();
set
{
if (value == null)
_message?.Clear();
else
_message?.AddMarkupPermissive(value);
}
}
public RichTextLabel()
{
IoCManager.InjectDependencies(this);

View File

@@ -12,7 +12,7 @@ public sealed class EntitySpawnButton : Control
public EntityPrototype Prototype { get; set; } = default!;
public Button ActualButton { get; private set; }
public Label EntityLabel { get; private set; }
public LayeredTextureRect EntityTextureRects { get; private set; }
public EntityPrototypeView EntityTextureRects {get; private set; }
public int Index { get; set; }
public EntitySpawnButton()
@@ -27,13 +27,12 @@ public sealed class EntitySpawnButton : Control
Orientation = BoxContainer.LayoutOrientation.Horizontal,
Children =
{
(EntityTextureRects = new LayeredTextureRect
(EntityTextureRects = new EntityPrototypeView
{
MinSize = new Vector2(32, 32),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
Stretch = TextureRect.StretchMode.KeepAspectCentered,
CanShrink = true
Stretch = SpriteView.StretchMode.Fill
}),
(EntityLabel = new Label
{

View File

@@ -44,7 +44,7 @@ namespace Robust.Client.UserInterface.CustomControls
}
// Create a spawn button and insert it into the start or end of the list.
public EntitySpawnButton InsertEntityButton(EntityPrototype prototype, bool insertFirst, int index, List<Texture> textures)
public EntitySpawnButton InsertEntityButton(EntityPrototype prototype, bool insertFirst, int index)
{
var button = new EntitySpawnButton
{
@@ -67,7 +67,7 @@ namespace Robust.Client.UserInterface.CustomControls
}
var rect = button.EntityTextureRects;
rect.Textures = textures;
rect.SetPrototype(prototype.ID);
PrototypeList.AddChild(button);
if (insertFirst)

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Utility;
@@ -7,41 +8,135 @@ namespace Robust.Client.ViewVariables.Editors
{
sealed class VVPropEditorEnum : VVPropEditor
{
private readonly Dictionary<int, int> _idToValue = new();
private readonly Dictionary<int, int> _valueToId = new();
private readonly Dictionary<int, Button> _buttons = new();
private int _invalidOptionId;
private int _value;
private bool _flagEnum;
protected override Control MakeUI(object? value)
{
DebugTools.Assert(value!.GetType().IsEnum);
var enumType = value.GetType();
var enumList = Enum.GetValues(enumType);
var enumNames = Enum.GetNames(enumType);
var underlyingType = Enum.GetUnderlyingType(enumType);
var convertedValue = Convert.ToInt32(value);
var hBoxContainer = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
};
var optionButton = new OptionButton();
bool hasValue = false;
hBoxContainer.AddChild(optionButton);
var hasValue = false;
var selectedId = 0;
var i = 0;
foreach (var val in enumList)
{
var label = val?.ToString();
if (label == null)
continue;
optionButton.AddItem(label, Convert.ToInt32(val));
hasValue |= Convert.ToInt32(val) == Convert.ToInt32(value);
var label = enumNames[i];
var entry = Convert.ToInt32(val);
_idToValue.Add(i, entry);
_valueToId.TryAdd(entry, i);
optionButton.AddItem(label, i);
if (entry == convertedValue)
{
hasValue = true;
selectedId = i;
}
i += 1;
}
// TODO properly support enum flags
if (!hasValue)
optionButton.AddItem(value.ToString() ?? string.Empty, Convert.ToInt32(value));
var isFlags = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
optionButton.SelectId(Convert.ToInt32(value));
// Handle unnamed enum values.
if (!hasValue || isFlags)
{
_invalidOptionId = i;
_idToValue.Add(_invalidOptionId, convertedValue);
optionButton.AddItem(string.Empty, _invalidOptionId);
if (!hasValue)
selectedId = _invalidOptionId;
}
optionButton.SelectId(selectedId);
optionButton.Disabled = ReadOnly;
// Flags
if (isFlags)
{
_flagEnum = true;
var flags = 0;
foreach (var val in enumList)
{
var entry = Convert.ToInt32(val);
if ((entry & flags) != 0 || entry == 0)
continue;
flags |= entry;
var button = new Button
{
Text = enumNames[_valueToId[entry]],
};
_buttons.Add(entry, button);
hBoxContainer.AddChild(button);
button.ToggleMode = true;
if (!ReadOnly)
{
button.OnToggled += args =>
{
if (args.Pressed)
SelectButtons(_value | entry);
else
SelectButtons(_value & ~entry);
};
}
}
}
if (!ReadOnly)
{
var underlyingType = Enum.GetUnderlyingType(value.GetType());
optionButton.OnItemSelected += e =>
{
optionButton.SelectId(e.Id);
ValueChanged(Convert.ChangeType(e.Id, underlyingType));
if (e.Id == _invalidOptionId)
{
optionButton.SelectId(_invalidOptionId);
return;
}
SelectButtons(_idToValue[e.Id]);
};
}
return optionButton;
SelectButtons(convertedValue, false);
return hBoxContainer;
void SelectButtons(int flags, bool changeValue = true)
{
_value = flags;
if (_flagEnum)
{
foreach (var (buttonFlags, button) in _buttons)
{
button.Pressed = (buttonFlags & flags) != 0;
}
}
if (!_valueToId.TryGetValue(flags, out var id)
|| !optionButton.TrySelectId(id))
optionButton.SelectId(_invalidOptionId);
if (changeValue)
ValueChanged(Convert.ChangeType(flags, underlyingType));
}
}
}
}

View File

@@ -77,7 +77,7 @@ namespace Robust.Client.ViewVariables.Editors
{
var protoMan = IoCManager.Resolve<IPrototypeManager>();
if (!protoMan.TryGetVariantFrom(typeof(T), out var variant)) return;
if (!protoMan.TryGetKindFrom(typeof(T), out var variant)) return;
var list = new List<string>();

View File

@@ -32,6 +32,8 @@ public static class Diagnostics
public const string IdUncachedRegex = "RA0026";
public const string IdDataFieldRedundantTag = "RA0027";
public const string IdMustCallBase = "RA0028";
public const string IdDataFieldNoVVReadWrite = "RA0029";
public const string IdUseNonGenericVariant = "RA0030";
public static SuppressionDescriptor MeansImplicitAssignment =>
new SuppressionDescriptor("RADC1000", "CS0649", "Marked as implicitly assigned.");

View File

@@ -3,6 +3,10 @@ using Robust.Shared.Serialization.Manager.Attributes;
namespace Robust.Server.GameObjects
{
/// <summary>
/// Controls PVS visibility of entities. THIS COMPONENT CONTROLS WHETHER ENTITIES ARE NETWORKED TO PLAYERS
/// AND SHOULD NOT BE USED AS THE SOLE WAY TO HIDE AN ENTITY FROM A PLAYER.
/// </summary>
[RegisterComponent]
[Access(typeof(VisibilitySystem))]
public sealed partial class VisibilityComponent : Component

View File

@@ -93,8 +93,10 @@ namespace Robust.Server
deps.Register<IServerNetConfigurationManager, ServerNetConfigurationManager>();
deps.Register<INetConfigurationManagerInternal, ServerNetConfigurationManager>();
deps.Register<IGamePrototypeLoadManager, GamePrototypeLoadManager>();
deps.Register<GamePrototypeLoadManager>();
deps.Register<NetworkResourceManager>();
deps.Register<IHttpClientHolder, HttpClientHolder>();
deps.Register<UploadedContentManager>();
}
}
}

View File

@@ -24,8 +24,6 @@ public sealed class GamePrototypeLoadManager : SharedPrototypeLoadManager
base.Initialize();
_sawmill = _logManager.GetSawmill("adminbus");
_netManager.Connected += NetManagerOnConnected;
}
public override void SendGamePrototype(string prototype)
@@ -50,7 +48,7 @@ public sealed class GamePrototypeLoadManager : SharedPrototypeLoadManager
}
}
private void NetManagerOnConnected(object? sender, NetChannelArgs e)
internal void SendToNewUser(INetChannel channel)
{
// Just dump all the prototypes on connect, before them missing could be an issue.
foreach (var prototype in LoadedPrototypes)
@@ -59,7 +57,7 @@ public sealed class GamePrototypeLoadManager : SharedPrototypeLoadManager
{
PrototypeData = prototype
};
e.Channel.SendMessage(msg);
channel.SendMessage(msg);
}
}
}

View File

@@ -27,7 +27,6 @@ public sealed class NetworkResourceManager : SharedNetworkResourceManager
{
base.Initialize();
_serverNetManager.Connected += ServerNetManagerOnConnected;
_cfgManager.OnValueChanged(CVars.ResourceUploadingEnabled, value => Enabled = value, true);
_cfgManager.OnValueChanged(CVars.ResourceUploadingLimitMb, value => SizeLimit = value, true);
}
@@ -65,14 +64,14 @@ public sealed class NetworkResourceManager : SharedNetworkResourceManager
OnResourceUploaded?.Invoke(session, msg);
}
private void ServerNetManagerOnConnected(object? sender, NetChannelArgs e)
internal void SendToNewUser(INetChannel channel)
{
foreach (var (path, data) in ContentRoot.GetAllFiles())
{
var msg = new NetworkResourceUploadMessage();
msg.RelativePath = path;
msg.Data = data;
e.Channel.SendMessage(msg);
channel.SendMessage(msg);
}
}
}

View File

@@ -0,0 +1,28 @@
using Robust.Shared.IoC;
using Robust.Shared.Network;
namespace Robust.Server.Upload;
/// <summary>
/// Responsible for sending uploaded content to clients when they connect.
/// </summary>
internal sealed class UploadedContentManager
{
[Dependency] private readonly IServerNetManager _netManager = default!;
[Dependency] private readonly GamePrototypeLoadManager _prototypeLoadManager = default!;
[Dependency] private readonly NetworkResourceManager _networkResourceManager = default!;
public void Initialize()
{
_netManager.Connected += NetManagerOnConnected;
}
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.
// 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

@@ -997,12 +997,7 @@ namespace Robust.Shared.Maths
/// <param name="other">The Color structure to compare to.</param>
/// <returns>True if both Color structures contain the same components; false otherwise.</returns>
public readonly bool Equals(Color other)
{
// TODO COLOR why is this approximate
// This method literally doesn't do what its docstring says it does.
// If people wanted approximate equality, they can check that manually.
return MathHelper.CloseToPercent(this, other);
}
=> RGBA == other.RGBA;
[PublicAPI]
public enum BlendFactor : byte

View File

@@ -0,0 +1,18 @@
using System;
#if ROBUST_ANALYZERS_IMPL
namespace Robust.Shared.Analyzers.Implementation;
#else
namespace Robust.Shared.Analyzers;
#endif
[AttributeUsage(AttributeTargets.Method)]
public sealed class PreferNonGenericVariantForAttribute : Attribute
{
public readonly Type[] ForTypes;
public PreferNonGenericVariantForAttribute(params Type[] forTypes)
{
ForTypes = forTypes;
}
}

View File

@@ -18,6 +18,8 @@ namespace Robust.Shared.CPUJob.JobQueues
/// <typeparam name="T">The type of result this job generates</typeparam>
public abstract class Job<T> : IJob
{
private readonly ISawmill _sawmill = Logger.GetSawmill("job");
public JobStatus Status { get; private set; } = JobStatus.Pending;
/// <summary>
@@ -184,7 +186,7 @@ namespace Robust.Shared.CPUJob.JobQueues
{
// TODO: Should this be exposed differently?
// I feel that people might forget to check whether the job failed.
Logger.ErrorS("job", "Job failed on exception:\n{0}", e);
_sawmill.Error("Job failed on exception:\n{0}", e);
Exception = e;
_taskTcs.TrySetException(e);
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Runtime.InteropServices;
using System.Threading;
using Lidgren.Network;
using Robust.Shared.Audio;
@@ -1759,5 +1758,16 @@ namespace Robust.Shared
/// </summary>
public static readonly CVarDef<bool> LaunchContentBundle =
CVarDef.Create("launch.content_bundle", false, CVar.CLIENTONLY);
/*
* TOOLSHED
*/
/// <summary>
/// The max range that can be passed to the nearby toolshed command.
/// Any higher value will cause an exception.
/// </summary>
public static readonly CVarDef<int> ToolshedNearbyLimit =
CVarDef.Create("toolshed.nearby_limit", 200, CVar.SERVER | CVar.REPLICATED);
}
}

View File

@@ -24,6 +24,7 @@ public abstract class ComponentTreeSystem<TTreeComp, TComp> : EntitySystem
[Dependency] private readonly RecursiveMoveSystem _recursiveMoveSys = default!;
[Dependency] protected readonly SharedTransformSystem XformSystem = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
private readonly Queue<ComponentTreeEntry<TComp>> _updateQueue = new();
private readonly HashSet<EntityUid> _updated = new();
@@ -288,11 +289,9 @@ public abstract class ComponentTreeSystem<TTreeComp, TComp> : EntitySystem
return true;
}, includeMap: false);
var mapUid = _mapManager.GetMapEntityId(mapId);
if (TryComp(mapUid, out TTreeComp? mapTreeComp))
if (_mapSystem.TryGetMap(mapId, out var mapUid) && TryComp(mapUid, out TTreeComp? mapTreeComp))
{
state.trees.Add((mapUid, mapTreeComp));
state.trees.Add((mapUid.Value, mapTreeComp));
}
return state.trees;

View File

@@ -8,10 +8,9 @@ using Robust.Shared.Map.Components;
namespace Robust.Shared.Console.Commands;
sealed class AddMapCommand : LocalizedCommands
sealed class AddMapCommand : LocalizedEntityCommands
{
[Dependency] private readonly IMapManagerInternal _map = default!;
[Dependency] private readonly IEntityManager _entMan = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
public override string Command => "addmap";
public override bool RequireServerOrSingleplayer => true;
@@ -23,10 +22,10 @@ sealed class AddMapCommand : LocalizedCommands
var mapId = new MapId(int.Parse(args[0]));
if (!_map.MapExists(mapId))
if (!_mapSystem.MapExists(mapId))
{
var init = args.Length < 2 || !bool.Parse(args[1]);
_entMan.System<SharedMapSystem>().CreateMap(mapId, runMapInit: init);
EntityManager.System<SharedMapSystem>().CreateMap(mapId, runMapInit: init);
shell.WriteLine($"Map with ID {mapId} created.");
return;
@@ -64,11 +63,8 @@ sealed class RemoveMapCommand : LocalizedCommands
}
}
sealed class RemoveGridCommand : LocalizedCommands
sealed class RemoveGridCommand : LocalizedEntityCommands
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IMapManager _map = default!;
public override string Command => "rmgrid";
public override bool RequireServerOrSingleplayer => true;
@@ -82,20 +78,20 @@ sealed class RemoveGridCommand : LocalizedCommands
var gridIdNet = NetEntity.Parse(args[0]);
if (!_entManager.TryGetEntity(gridIdNet, out var gridId) || !_entManager.HasComponent<MapGridComponent>(gridId))
if (!EntityManager.TryGetEntity(gridIdNet, out var gridId) || !EntityManager.HasComponent<MapGridComponent>(gridId))
{
shell.WriteError($"Grid {gridId} does not exist.");
return;
}
_map.DeleteGrid(gridId.Value);
EntityManager.DeleteEntity(gridId);
shell.WriteLine($"Grid {gridId} was removed.");
}
}
internal sealed class RunMapInitCommand : LocalizedCommands
internal sealed class RunMapInitCommand : LocalizedEntityCommands
{
[Dependency] private readonly IMapManager _map = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
public override string Command => "mapinit";
public override bool RequireServerOrSingleplayer => true;
@@ -111,26 +107,27 @@ internal sealed class RunMapInitCommand : LocalizedCommands
var arg = args[0];
var mapId = new MapId(int.Parse(arg, CultureInfo.InvariantCulture));
if (!_map.MapExists(mapId))
if (!_mapSystem.MapExists(mapId))
{
shell.WriteError("Map does not exist!");
return;
}
if (_map.IsMapInitialized(mapId))
if (_mapSystem.IsInitialized(mapId))
{
shell.WriteError("Map is already initialized!");
return;
}
_map.DoMapInitialize(mapId);
_mapSystem.InitializeMap(mapId);
}
}
internal sealed class ListMapsCommand : LocalizedCommands
internal sealed class ListMapsCommand : LocalizedEntityCommands
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IMapManager _map = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
public override string Command => "lsmap";
@@ -143,13 +140,15 @@ internal sealed class ListMapsCommand : LocalizedCommands
foreach (var mapId in _map.GetAllMapIds().OrderBy(id => id.Value))
{
var mapUid = _map.GetMapEntityId(mapId);
if (!_mapSystem.TryGetMap(mapId, out var mapUid))
continue;
msg.AppendFormat("{0}: {1}, init: {2}, paused: {3}, nent: {4}, grids: {5}\n",
mapId, _entManager.GetComponent<MetaDataComponent>(mapUid).EntityName,
_map.IsMapInitialized(mapId),
_map.IsMapPaused(mapId),
_entManager.GetNetEntity(_map.GetMapEntityId(mapId)),
mapId,
_entManager.GetComponent<MetaDataComponent>(mapUid.Value).EntityName,
_mapSystem.IsInitialized(mapUid),
_mapSystem.IsPaused(mapId),
_entManager.GetNetEntity(mapUid),
string.Join(",", _map.GetAllGrids(mapId).Select(grid => grid.Owner)));
}
@@ -157,9 +156,10 @@ internal sealed class ListMapsCommand : LocalizedCommands
}
}
internal sealed class ListGridsCommand : LocalizedCommands
internal sealed class ListGridsCommand : LocalizedEntityCommands
{
[Dependency] private readonly IEntityManager _ent = default!;
[Dependency]
private readonly SharedTransformSystem _transformSystem = default!;
public override string Command => "lsgrid";
@@ -169,15 +169,14 @@ internal sealed class ListGridsCommand : LocalizedCommands
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var msg = new StringBuilder();
var xformSystem = _ent.System<SharedTransformSystem>();
var xformQuery = _ent.GetEntityQuery<TransformComponent>();
var grids = _ent.AllComponentsList<MapGridComponent>();
var xformQuery = EntityManager.GetEntityQuery<TransformComponent>();
var grids = EntityManager.AllComponentsList<MapGridComponent>();
grids.Sort((x, y) => x.Uid.CompareTo(y.Uid));
foreach (var (uid, grid) in grids)
foreach (var (uid, _) in grids)
{
var xform = xformQuery.GetComponent(uid);
var worldPos = xformSystem.GetWorldPosition(xform);
var worldPos = _transformSystem.GetWorldPosition(xform);
msg.AppendFormat("{0}: map: {1}, ent: {2}, pos: {3:0.0},{4:0.0} \n",
uid, xform.MapID, uid, worldPos.X, worldPos.Y);

View File

@@ -61,7 +61,7 @@ internal sealed class TeleportCommand : LocalizedEntityCommands
else
{
var mapEnt = _map.GetMapEntityIdOrThrow(mapId);
_transform.SetWorldPosition(transform, position);
_transform.SetWorldPosition((entity, transform), position);
_transform.SetParent(entity, transform, mapEnt);
}

View File

@@ -59,7 +59,7 @@ namespace Robust.Shared.Console
void WriteMarkup(string markup)
{
WriteLine(FormattedMessage.FromMarkup(markup));
WriteLine(FormattedMessage.FromMarkupPermissive(markup));
}
/// <summary>

View File

@@ -659,7 +659,9 @@ namespace Robust.Shared.Containers
if (!transform.Comp.ParentUid.IsValid()
|| !TryGetContainingContainer(transform.Comp.ParentUid, out var container)
|| !TryInsertIntoContainer(transform, container))
transform.Comp.AttachToGridOrMap();
{
_transform.AttachToGridOrMap(transform, transform.Comp);
}
}
private bool TryInsertIntoContainer(Entity<TransformComponent> transform, BaseContainer container)

View File

@@ -32,7 +32,7 @@ namespace Robust.Shared.ContentPack
String("short").ThenReturn(PrimitiveTypeCode.Int16);
private static readonly Parser<char, PrimitiveTypeCode> UInt16TypeParser =
String("ushort").ThenReturn(PrimitiveTypeCode.UInt32);
String("ushort").ThenReturn(PrimitiveTypeCode.UInt16);
private static readonly Parser<char, PrimitiveTypeCode> Int32TypeParser =
String("int").ThenReturn(PrimitiveTypeCode.Int32);

View File

@@ -84,12 +84,146 @@ Types:
- "bool get_HasContents()"
Lidgren.Network:
NetBuffer:
All: True
Methods:
- "byte[] get_Data()"
- "void set_Data(byte[])"
- "int get_LengthBytes()"
- "void set_LengthBytes(int)"
- "int get_LengthBits()"
- "void set_LengthBits(int)"
- "long get_Position()"
- "void set_Position(long)"
- "int get_PositionInBytes()"
- "byte[] PeekDataBuffer()"
- "bool PeekBoolean()"
- "byte PeekByte()"
- "sbyte PeekSByte()"
- "byte PeekByte(int)"
- "System.Span`1<byte> PeekBytes(System.Span`1<byte>)"
- "byte[] PeekBytes(int)"
- "void PeekBytes(byte[], int, int)"
- "short PeekInt16()"
- "ushort PeekUInt16()"
- "int PeekInt32()"
- "int PeekInt32(int)"
- "uint PeekUInt32()"
- "uint PeekUInt32(int)"
- "ulong PeekUInt64()"
- "long PeekInt64()"
- "ulong PeekUInt64(int)"
- "long PeekInt64(int)"
- "float PeekFloat()"
- "System.Half PeekHalf()"
- "float PeekSingle()"
- "double PeekDouble()"
- "string PeekString()"
- "int PeekStringSize()"
- "bool ReadBoolean()"
- "byte ReadByte()"
- "bool ReadByte(ref byte)"
- "sbyte ReadSByte()"
- "byte ReadByte(int)"
- "System.Span`1<byte> ReadBytes(System.Span`1<byte>)"
- "byte[] ReadBytes(int)"
- "bool ReadBytes(int, ref byte[])"
- "bool TryReadBytes(System.Span`1<byte>)"
- "void ReadBytes(byte[], int, int)"
- "void ReadBits(System.Span`1<byte>, int)"
- "void ReadBits(byte[], int, int)"
- "short ReadInt16()"
- "ushort ReadUInt16()"
- "int ReadInt32()"
- "bool ReadInt32(ref int)"
- "int ReadInt32(int)"
- "uint ReadUInt32()"
- "bool ReadUInt32(ref uint)"
- "uint ReadUInt32(int)"
- "ulong ReadUInt64()"
- "long ReadInt64()"
- "ulong ReadUInt64(int)"
- "long ReadInt64(int)"
- "float ReadFloat()"
- "System.Half ReadHalf()"
- "float ReadSingle()"
- "bool ReadSingle(ref float)"
- "double ReadDouble()"
- "uint ReadVariableUInt32()"
- "bool ReadVariableUInt32(ref uint)"
- "int ReadVariableInt32()"
- "long ReadVariableInt64()"
- "ulong ReadVariableUInt64()"
- "float ReadSignedSingle(int)"
- "float ReadUnitSingle(int)"
- "float ReadRangedSingle(float, float, int)"
- "int ReadRangedInteger(int, int)"
- "long ReadRangedInteger(long, long)"
- "string ReadString()"
- "bool ReadString(ref string)"
- "double ReadTime(Lidgren.Network.NetConnection, bool)"
- "System.Net.IPEndPoint ReadIPEndPoint()"
- "void SkipPadBits()"
- "void ReadPadBits()"
- "void SkipPadBits(int)"
- "void EnsureBufferSize(int)"
- "void Write(bool)"
- "void Write(byte)"
- "void WriteAt(int, byte)"
- "void Write(sbyte)"
- "void Write(byte, int)"
- "void Write(byte[])"
- "void Write(System.ReadOnlySpan`1<byte>)"
- "void Write(byte[], int, int)"
- "void Write(ushort)"
- "void WriteAt(int, ushort)"
- "void Write(ushort, int)"
- "void Write(short)"
- "void WriteAt(int, short)"
- "void Write(int)"
- "void WriteAt(int, int)"
- "void Write(uint)"
- "void WriteAt(int, uint)"
- "void Write(uint, int)"
- "void Write(int, int)"
- "void Write(ulong)"
- "void WriteAt(int, ulong)"
- "void Write(ulong, int)"
- "void Write(long)"
- "void Write(long, int)"
- "void Write(System.Half)"
- "void Write(float)"
- "void Write(double)"
- "int WriteVariableUInt32(uint)"
- "int WriteVariableInt32(int)"
- "int WriteVariableInt64(long)"
- "int WriteVariableUInt64(ulong)"
- "void WriteSignedSingle(float, int)"
- "void WriteUnitSingle(float, int)"
- "void WriteRangedSingle(float, float, float, int)"
- "int WriteRangedInteger(int, int, int)"
- "int WriteRangedInteger(long, long, long)"
- "void Write(string)"
- "void Write(System.Net.IPEndPoint)"
- "void WriteTime(bool)"
- "void WriteTime(double, bool)"
- "void WritePadBits()"
- "void WritePadBits(int)"
- "void Write(Lidgren.Network.NetBuffer)"
- "void Zero(int)"
- "void .ctor()"
NetDeliveryMethod: { }
NetIncomingMessage:
All: True
Methods:
- "Lidgren.Network.NetIncomingMessageType get_MessageType()"
- "Lidgren.Network.NetDeliveryMethod get_DeliveryMethod()"
- "int get_SequenceChannel()"
- "System.Net.IPEndPoint get_SenderEndPoint()"
- "Lidgren.Network.NetConnection get_SenderConnection()"
- "double get_ReceiveTime()"
- "double ReadTime(bool)"
- "string ToString()"
NetOutgoingMessage:
All: True
Methods:
- "string ToString()"
Nett:
CommentLocation: { } # Enum
Toml:
@@ -438,6 +572,7 @@ Types:
System.Net:
DnsEndPoint: { }
IPAddress: { All: True }
IPEndPoint: { All: True }
HttpStatusCode: { } # Enum
System.Net.Sockets:
AddressFamily: { }

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using Robust.Shared.Utility;
namespace Robust.Shared.ContentPack
@@ -135,11 +136,37 @@ namespace Robust.Shared.ContentPack
path = path.Directory;
var fullPath = GetFullPath(path);
Process.Start(new ProcessStartInfo
if (OperatingSystem.IsWindows())
{
UseShellExecute = true,
FileName = fullPath,
});
Process.Start(new ProcessStartInfo
{
FileName = $"{Environment.GetEnvironmentVariable("SystemRoot")}\\explorer.exe",
Arguments = ".",
WorkingDirectory = fullPath,
});
}
else if (OperatingSystem.IsMacOS())
{
Process.Start(new ProcessStartInfo
{
FileName = "open",
Arguments = ".",
WorkingDirectory = fullPath,
});
}
else if (OperatingSystem.IsLinux() || OperatingSystem.IsFreeBSD())
{
Process.Start(new ProcessStartInfo
{
FileName = "xdg-open",
Arguments = ".",
WorkingDirectory = fullPath,
});
}
else
{
throw new NotSupportedException("Opening OS windows not supported on this OS");
}
}
#endregion

View File

@@ -660,21 +660,25 @@ namespace Robust.Shared.GameObjects
/// Raised when the Anchor state of the transform is changed.
/// </summary>
[ByRefEvent]
public readonly struct AnchorStateChangedEvent
public readonly struct AnchorStateChangedEvent(
EntityUid entity,
TransformComponent transform,
bool detaching = false)
{
public readonly TransformComponent Transform;
public EntityUid Entity => Transform.Owner;
public readonly TransformComponent Transform = transform;
public EntityUid Entity { get; } = entity;
public bool Anchored => Transform.Anchored;
/// <summary>
/// If true, the entity is being detached to null-space
/// </summary>
public readonly bool Detaching;
public readonly bool Detaching = detaching;
[Obsolete("Use constructor that takes in EntityUid")]
public AnchorStateChangedEvent(TransformComponent transform, bool detaching = false)
: this(transform.Owner, transform, detaching)
{
Detaching = detaching;
Transform = transform;
}
}

View File

@@ -468,6 +468,21 @@ namespace Robust.Shared.GameObjects
ent.Comp4.LastModifiedTick = CurrentTick;
}
public bool TryQueueDeleteEntity(EntityUid? uid)
{
if (uid == null)
return false;
if (Deleted(uid.Value))
return false;
if (!QueuedDeletionsSet.Add(uid.Value))
return false;
QueueDeleteEntity(uid);
return true;
}
/// <summary>
/// Shuts-down and removes given Entity. This is also broadcast to all clients.
/// </summary>

View File

@@ -439,6 +439,7 @@ public partial class EntitySystem
/// <inheritdoc cref="IEntityManager.TryGetComponent&lt;T&gt;(EntityUid, out T)"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[PreferNonGenericVariantFor(typeof(TransformComponent), typeof(MetaDataComponent))]
protected bool TryComp<T>(EntityUid uid, [NotNullWhen(true)] out T? comp) where T : IComponent
{
return EntityManager.TryGetComponent(uid, out comp);
@@ -705,6 +706,13 @@ public partial class EntitySystem
EntityManager.QueueDeleteEntity(uid);
}
/// <inheritdoc cref="IEntityManager.TryQueueDeleteEntity(EntityUid?)" />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected bool TryQueueDel(EntityUid? uid)
{
return EntityManager.TryQueueDeleteEntity(uid);
}
#endregion
#region Entity Spawning

View File

@@ -23,7 +23,7 @@ namespace Robust.Shared.GameObjects
[Reflect(false), PublicAPI]
public abstract partial class EntitySystem : IEntitySystem, IPostInjectInit
{
[Dependency] protected readonly EntityManager EntityManager;
[Dependency] protected readonly EntityManager EntityManager = default!;
[Dependency] protected readonly ILogManager LogManager = default!;
[Dependency] private readonly ISharedPlayerManager _playerMan = default!;
[Dependency] private readonly IReplayRecordingManager _replayMan = default!;
@@ -65,11 +65,8 @@ namespace Robust.Shared.GameObjects
IEnumerable<Type> IEntitySystem.UpdatesAfter => UpdatesAfter;
IEnumerable<Type> IEntitySystem.UpdatesBefore => UpdatesBefore;
protected EntitySystem() : this(default!) { }
protected EntitySystem(IEntityManager entityManager)
protected EntitySystem()
{
EntityManager = (EntityManager)entityManager;
Subs = new Subscriptions(this);
}

View File

@@ -153,6 +153,11 @@ namespace Robust.Shared.GameObjects
where T3 : IComponent
where T4 : IComponent;
/// <summary>
/// Tries to QueueDeleteEntity if the entity is not already deleted.
/// </summary>
public bool TryQueueDeleteEntity(EntityUid? uid);
public void QueueDeleteEntity(EntityUid? uid);
public bool IsQueuedForDeletion(EntityUid uid);

View File

@@ -90,7 +90,7 @@ public abstract partial class SharedTransformSystem
if (!wasAnchored && xform.Running)
{
var ev = new AnchorStateChangedEvent(xform);
var ev = new AnchorStateChangedEvent(uid, xform);
RaiseLocalEvent(uid, ref ev, true);
}
@@ -150,7 +150,7 @@ public abstract partial class SharedTransformSystem
if (!xform.Running)
return;
var ev = new AnchorStateChangedEvent(xform);
var ev = new AnchorStateChangedEvent(uid, xform);
RaiseLocalEvent(uid, ref ev, true);
}
@@ -249,19 +249,20 @@ public abstract partial class SharedTransformSystem
if (!component._anchored)
return;
MapGridComponent? grid;
Entity<MapGridComponent>? grid = null;
// First try find grid via parent:
if (component.GridUid == component.ParentUid && TryComp(component.ParentUid, out MapGridComponent? gridComp))
{
grid = gridComp;
grid = (component.ParentUid, gridComp);
}
else
{
// Entity may not be directly parented to the grid (e.g., spawned using some relative entity coordinates)
// in that case, we attempt to attach to a grid.
var pos = new MapCoordinates(GetWorldPosition(component), component.MapID);
_mapManager.TryFindGridAt(pos, out _, out grid);
if (_mapManager.TryFindGridAt(pos, out var gridUid, out gridComp))
grid = (gridUid, gridComp);
}
if (grid == null)
@@ -270,7 +271,7 @@ public abstract partial class SharedTransformSystem
return;
}
if (!AnchorEntity(uid, component, grid))
if (!AnchorEntity((uid, component), grid))
component._anchored = false;
}
@@ -308,7 +309,7 @@ public abstract partial class SharedTransformSystem
if (xform.Anchored)
{
DebugTools.Assert(xform.ParentUid == xform.GridUid && xform.ParentUid.IsValid());
var anchorEv = new AnchorStateChangedEvent(xform);
var anchorEv = new AnchorStateChangedEvent(uid, xform);
RaiseLocalEvent(uid, ref anchorEv, true);
}
@@ -746,7 +747,7 @@ public abstract partial class SharedTransformSystem
if (oldAnchored != newState.Anchored && xform.Initialized)
{
var ev = new AnchorStateChangedEvent(xform);
var ev = new AnchorStateChangedEvent(uid, xform);
RaiseLocalEvent(uid, ref ev, true);
}
@@ -934,7 +935,7 @@ public abstract partial class SharedTransformSystem
// Entity was not actually in the transform hierarchy. This is probably a sign that something is wrong, or that the function is being misused.
Log.Warning($"Target entity ({ToPrettyString(relative)}) not in transform hierarchy while calling {nameof(GetRelativePositionRotation)}.");
var relXform = query.GetComponent(relative);
pos = Vector2.Transform(pos, relXform.InvWorldMatrix);
pos = Vector2.Transform(pos, GetInvWorldMatrix(relXform));
rot = rot - GetWorldRotation(relXform, query);
break;
}
@@ -976,10 +977,11 @@ public abstract partial class SharedTransformSystem
public void SetWorldPosition(EntityUid uid, Vector2 worldPos)
{
var xform = XformQuery.GetComponent(uid);
SetWorldPosition(xform, worldPos);
SetWorldPosition((uid, xform), worldPos);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Obsolete("Use overload that takes Entity<T> instead")]
public void SetWorldPosition(TransformComponent component, Vector2 worldPos)
{
SetWorldPosition((component.Owner, component), worldPos);
@@ -1313,10 +1315,9 @@ public abstract partial class SharedTransformSystem
{
newParent = gridUid;
}
else if (_mapManager.GetMapEntityId(xform.MapID) is { Valid: true } mapEnt
&& !TerminatingOrDeleted(mapEnt))
else if (_map.TryGetMap(xform.MapID, out var mapEnt) && !TerminatingOrDeleted(mapEnt))
{
newParent = mapEnt;
newParent = mapEnt.Value;
}
else
{
@@ -1446,7 +1447,7 @@ public abstract partial class SharedTransformSystem
var tileIndices = _map.TileIndicesFor(xform.GridUid.Value, grid, xform.Coordinates);
_map.RemoveFromSnapGridCell(xform.GridUid.Value, grid, tileIndices, uid);
xform._anchored = false;
var anchorStateChangedEvent = new AnchorStateChangedEvent(xform, true);
var anchorStateChangedEvent = new AnchorStateChangedEvent(uid, xform, true);
RaiseLocalEvent(uid, ref anchorStateChangedEvent, true);
}

View File

@@ -12,7 +12,8 @@ namespace Robust.Shared.Map
{
IoCManager.Resolve(ref entityManager, ref mapManager);
var gridId = coords.GetGridUid(entityManager);
var xform = entityManager.System<SharedTransformSystem>();
var gridId = xform.GetGrid(coords);
var mapSystem = entityManager.System<SharedMapSystem>();
if (entityManager.TryGetComponent<MapGridComponent>(gridId, out var mapGrid))
@@ -20,8 +21,7 @@ namespace Robust.Shared.Map
return mapSystem.GridTileToLocal(gridId.Value, mapGrid, mapSystem.CoordinatesToTile(gridId.Value, mapGrid, coords));
}
var transformSystem = entityManager.System<SharedTransformSystem>();
var mapCoords = coords.ToMap(entityManager, transformSystem);
var mapCoords = xform.ToMapCoordinates(coords);
if (mapManager.TryFindGridAt(mapCoords, out var gridUid, out mapGrid))
{
@@ -49,7 +49,8 @@ namespace Robust.Shared.Map
// TODO: Use CollisionManager to get nearest edge.
// figure out closest intersect
var gridIntersect = gridSearchBox.Intersect(gridXform.WorldMatrix.TransformBox(grid.Comp.LocalAABB));
var worldMatrix = xform.GetWorldMatrix(gridXform);
var gridIntersect = gridSearchBox.Intersect(worldMatrix.TransformBox(grid.Comp.LocalAABB));
var gridDist = (gridIntersect.Center - mapCoords.Position).LengthSquared();
if (gridDist >= distance)

View File

@@ -143,14 +143,14 @@ namespace Robust.Shared.Map
return new Vector2i();
var mapSystem = entityManager.System<SharedMapSystem>();
var gridIdOpt = GetGridUid(entityManager);
var gridIdOpt = transformSystem.GetGrid(this);
if (gridIdOpt is { } gridId && gridId.IsValid())
{
var grid = entityManager.GetComponent<MapGridComponent>(gridId);
return mapSystem.GetTileRef(gridId, grid, this).GridIndices;
}
var vec = ToMapPos(entityManager, transformSystem);
var vec = transformSystem.ToMapCoordinates(this);
return new Vector2i((int)MathF.Floor(vec.X), (int)MathF.Floor(vec.Y));
}
@@ -334,8 +334,8 @@ namespace Robust.Shared.Map
return true;
}
var mapCoordinates = ToMap(entityManager, transformSystem);
var otherMapCoordinates = otherCoordinates.ToMap(entityManager, transformSystem);
var mapCoordinates = transformSystem.ToMapCoordinates(this);
var otherMapCoordinates = transformSystem.ToMapCoordinates(otherCoordinates);
if (mapCoordinates.MapId != otherMapCoordinates.MapId)
return false;

View File

@@ -115,7 +115,7 @@ internal static class HappyEyeballsHttp
await socket.ConnectAsync(new IPEndPoint(address, port), cancel).ConfigureAwait(false);
return socket;
}
catch (Exception e)
catch (Exception)
{
// Log.Verbose(e, "Happy Eyeballs to {Address} [{Index}] failed", address, index);
socket.Dispose();

View File

@@ -1,6 +1,6 @@
using System;
using System.Buffers;
using System.Runtime.InteropServices;
using System.Buffers.Binary;
using System.Threading;
using Lidgren.Network;
using SpaceWizards.Sodium;
@@ -60,11 +60,10 @@ internal sealed class NetEncryption
ciphertext = message.Data = new byte[encryptedSize];
}
// TODO: this is probably broken for big-endian machines.
Span<byte> nonceData = stackalloc byte[CryptoAeadXChaCha20Poly1305Ietf.NoncePublicBytes];
nonceData.Fill(0);
MemoryMarshal.Write(nonceData, ref nonce);
MemoryMarshal.Write(ciphertext, ref nonce);
BinaryPrimitives.WriteUInt64LittleEndian(nonceData, nonce);
BinaryPrimitives.WriteUInt64LittleEndian(ciphertext, nonce);
CryptoAeadXChaCha20Poly1305Ietf.Encrypt(
// ciphertext
@@ -93,10 +92,9 @@ internal sealed class NetEncryption
var buffer = ArrayPool<byte>.Shared.Rent(cipherText.Length);
cipherText.CopyTo(buffer);
// TODO: this is probably broken for big-endian machines.
Span<byte> nonceData = stackalloc byte[CryptoAeadXChaCha20Poly1305Ietf.NoncePublicBytes];
nonceData.Fill(0);
MemoryMarshal.Write(nonceData, ref nonce);
BinaryPrimitives.WriteUInt64LittleEndian(nonceData, nonce);
var result = CryptoAeadXChaCha20Poly1305Ietf.Decrypt(
// plaintext

View File

@@ -17,8 +17,8 @@ namespace Robust.Shared.Physics.Controllers;
public sealed class Gravity2DController : VirtualController
{
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
private ISawmill _sawmill = default!;
@@ -72,7 +72,7 @@ public sealed class Gravity2DController : VirtualController
public void SetGravity(MapId mapId, Vector2 value)
{
var mapUid = _mapManager.GetMapEntityId(mapId);
var mapUid = _mapSystem.GetMap(mapId);
var gravity = EnsureComp<Gravity2DComponent>(mapUid);
if (gravity.Gravity.Equals(value))

View File

@@ -0,0 +1,28 @@
using Robust.Shared.GameObjects;
using Robust.Shared.Physics.Components;
using System.Numerics;
namespace Robust.Shared.Physics.Events;
/// <summary>
/// By-ref directed event raised when the mass or angular inertia or center of mass of a physics body changes.
/// </summary>
/// <param name="Entity">The physics body that changed.</param>
/// <param name="OldMass">The old mass of the physics body.</param>
/// <param name="OldInertia">The old angular inertia of the physics body.</param>
/// <param name="OldCenter">The old (local) center of mass of the physics body.</param>
[ByRefEvent]
public readonly record struct MassDataChangedEvent(
Entity<PhysicsComponent, FixturesComponent> Entity,
float OldMass,
float OldInertia,
Vector2 OldCenter
)
{
public float NewMass => Entity.Comp1._mass;
public float NewInertia => Entity.Comp1._inertia;
public Vector2 NewCenter => Entity.Comp1._localCenter;
public bool MassChanged => NewMass != OldMass;
public bool InertiaChanged => NewInertia != OldInertia;
public bool CenterChanged => NewCenter != OldCenter;
}

View File

@@ -53,7 +53,7 @@ public partial class SharedPhysicsSystem
{
if (component.BodyType != BodyType.Static)
{
SetAwake(uid, component, true);
SetAwake((uid, component), true);
}
}
@@ -256,6 +256,9 @@ public partial class SharedPhysicsSystem
if (!_fixturesQuery.Resolve(uid, ref manager))
return;
var oldMass = body._mass;
var oldInertia = body._inertia;
body._mass = 0.0f;
body._invMass = 0.0f;
body._inertia = 0.0f;
@@ -314,6 +317,12 @@ public partial class SharedPhysicsSystem
// Update center of mass velocity.
body.LinearVelocity += Vector2Helpers.Cross(body.AngularVelocity, localCenter - oldCenter);
Dirty(uid, body);
if (body._mass == oldMass && body._inertia == oldInertia && oldCenter == localCenter)
return;
var ev = new MassDataChangedEvent((uid, body, manager), oldMass, oldInertia, oldCenter);
RaiseLocalEvent(uid, ref ev);
}
public bool SetAngularVelocity(EntityUid uid, float value, bool dirty = true, FixturesComponent? manager = null, PhysicsComponent? body = null)
@@ -482,14 +491,14 @@ public partial class SharedPhysicsSystem
if (body.BodyType == BodyType.Static)
{
SetAwake(uid, body, false);
SetAwake((uid, body), false);
body.LinearVelocity = Vector2.Zero;
body.AngularVelocity = 0.0f;
}
// Even if it's dynamic if it can't collide then don't force it awake.
else if (body.CanCollide)
{
SetAwake(uid, body, true);
SetAwake((uid, body), true);
}
body.Force = Vector2.Zero;
@@ -562,7 +571,7 @@ public partial class SharedPhysicsSystem
body.CanCollide = value;
if (!value)
SetAwake(uid, body, false);
SetAwake((uid, body), false);
if (body.Initialized)
{
@@ -646,7 +655,7 @@ public partial class SharedPhysicsSystem
return;
if (!value)
SetAwake(uid, body, true);
SetAwake((uid, body), true);
body.SleepingAllowed = value;

View File

@@ -690,7 +690,7 @@ public abstract partial class SharedPhysicsSystem
/// </summary>
/// <param name="island"></param>
/// <returns></returns>
private bool InternalParallel(IslandData island)
private static bool InternalParallel(IslandData island)
{
// Should lone island most times as well.
return island.Bodies.Count > 128 || island.Contacts.Count > 128 || island.Joints.Count > 128;

View File

@@ -45,13 +45,15 @@ namespace Robust.Shared.Player
{
IoCManager.Resolve(ref entityManager, ref playerMan, ref cfgMan);
var transform = entityManager.GetComponent<TransformComponent>(origin);
return AddPlayersByPvs(transform.MapPosition, rangeMultiplier, entityManager, playerMan, cfgMan);
var transformSystem = entityManager.System<SharedTransformSystem>();
return AddPlayersByPvs(transformSystem.GetMapCoordinates(transform), rangeMultiplier, entityManager, playerMan, cfgMan);
}
/// <summary>
/// Adds all players inside an entity's PVS.
/// The current PVS range will be multiplied by <see cref="rangeMultiplier"/>.
/// </summary>
[Obsolete("Use overload that takes in managers")]
public Filter AddPlayersByPvs(TransformComponent origin, float rangeMultiplier = 2f)
{
return AddPlayersByPvs(origin.MapPosition, rangeMultiplier);
@@ -64,7 +66,8 @@ namespace Robust.Shared.Player
public Filter AddPlayersByPvs(EntityCoordinates origin, float rangeMultiplier = 2f, IEntityManager? entityMan = null, ISharedPlayerManager? playerMan = null)
{
IoCManager.Resolve(ref entityMan, ref playerMan);
return AddPlayersByPvs(origin.ToMap(entityMan, entityMan.System<SharedTransformSystem>()), rangeMultiplier, entityMan, playerMan);
var system = entityMan.System<SharedTransformSystem>();
return AddPlayersByPvs(system.ToMapCoordinates(origin), rangeMultiplier, entityMan, playerMan);
}
/// <summary>
@@ -168,12 +171,13 @@ namespace Robust.Shared.Player
{
IoCManager.Resolve(ref playerMan, ref entMan);
var xformQuery = entMan.GetEntityQuery<TransformComponent>();
var xformSystem = entMan.System<SharedTransformSystem>();
return AddWhere(session =>
session.AttachedEntity != null &&
xformQuery.TryGetComponent(session.AttachedEntity.Value, out var xform) &&
xform.MapID == position.MapId &&
(xform.WorldPosition - position.Position).Length() < range, playerMan);
(xformSystem.GetWorldPosition(xform) - position.Position).Length() < range, playerMan);
}
/// <summary>
@@ -211,7 +215,7 @@ namespace Robust.Shared.Player
/// <summary>
/// Removes players from the filter.
/// </summary>
public Filter RemovePlayers(params ICommonSession[] players) => RemovePlayers(players);
public Filter RemovePlayers(params ICommonSession[] players) => RemovePlayers((IEnumerable<ICommonSession>) players);
/// <summary>
/// Removes a single player from the filter, specified by the entity to which they are attached.
@@ -232,7 +236,7 @@ namespace Robust.Shared.Player
/// <summary>
/// Removes players from the filter, specified by the entities to which they are attached.
/// </summary>
public Filter RemovePlayersByAttachedEntity(params EntityUid[] uids) => RemovePlayersByAttachedEntity(uids);
public Filter RemovePlayersByAttachedEntity(params EntityUid[] uids) => RemovePlayersByAttachedEntity((IEnumerable<EntityUid>) uids);
/// <summary>
/// Removes all players from the filter that match a predicate.
@@ -260,12 +264,13 @@ namespace Robust.Shared.Player
{
IoCManager.Resolve(ref entMan);
var xformQuery = entMan.GetEntityQuery<TransformComponent>();
var xformSystem = entMan.System<SharedTransformSystem>();
return RemoveWhere(session =>
session.AttachedEntity != null &&
xformQuery.TryGetComponent(session.AttachedEntity.Value, out var xform) &&
xform.MapID == position.MapId &&
(xform.WorldPosition - position.Position).Length() < range);
(xformSystem.GetWorldPosition(xform) - position.Position).Length() < range);
}
/// <summary>
@@ -370,6 +375,7 @@ namespace Robust.Shared.Player
/// <summary>
/// A filter with every player whose PVS overlaps this point.
/// </summary>
[Obsolete("Use overload that takes in managers")]
public static Filter Pvs(TransformComponent origin, float rangeMultiplier = 2f)
{
return Empty().AddPlayersByPvs(origin, rangeMultiplier);

View File

@@ -18,7 +18,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
ISerializationContext? context = null,
ISerializationManager.InstantiationDelegate<FormattedMessage>? instanceProvider = null)
{
return FormattedMessage.FromMarkup(node.Value);
return FormattedMessage.FromMarkupOrThrow(node.Value);
}
public ValidationNode Validate(ISerializationManager serializationManager, ValueDataNode node,

View File

@@ -1,20 +1,30 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
namespace Robust.Shared.Toolshed.Commands.Entities;
[ToolshedCommand]
internal sealed class NearbyCommand : ToolshedCommand
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
private EntityLookupSystem? _lookup;
[CommandImplementation]
public IEnumerable<EntityUid> Nearby(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] IEnumerable<EntityUid> input,
[CommandArgument] float range
)
{
var limit = _cfg.GetCVar(CVars.ToolshedNearbyLimit);
if (range > limit)
throw new ArgumentException($"Tried to query too many entities with nearby ({range})! Limit: {limit}. Change the {CVars.ToolshedNearbyLimit.Name} cvar to increase this at your own risk.");
_lookup ??= GetSys<EntityLookupSystem>();
return input.SelectMany(x => _lookup.GetEntitiesInRange(x, range)).Distinct();
}

View File

@@ -16,12 +16,15 @@ internal sealed class BuildInfoCommand : ToolshedCommand
public void BuildInfo([CommandInvocationContext] IInvocationContext ctx)
{
var game = _cfg.GetCVar(CVars.BuildForkId);
ctx.WriteLine(FormattedMessage.FromMarkup($"[color={Gold}]Game:[/color] {game}"));
var buildCommit = _cfg.GetCVar(CVars.BuildHash);
ctx.WriteLine(FormattedMessage.FromMarkup($"[color={Gold}]Build commit:[/color] {buildCommit}"));
var buildManifest = _cfg.GetCVar(CVars.BuildManifestHash);
ctx.WriteLine(FormattedMessage.FromMarkup($"[color={Gold}]Manifest hash:[/color] {buildManifest}"));
var engine = _cfg.GetCVar(CVars.BuildEngineVersion);
ctx.WriteLine(FormattedMessage.FromMarkup($"[color={Gold}]Engine ver:[/color] {engine}"));
ctx.WriteLine(FormattedMessage.FromMarkupOrThrow($"""
[color={Gold}]Game:[/color] {game}
[color={Gold}]Build commit:[/color] {buildCommit}
[color={Gold}]Manifest hash:[/color] {buildManifest}
[color={Gold}]Engine ver:[/color] {engine}
"""));
}
}

View File

@@ -8,7 +8,7 @@ public sealed class NotForServerConsoleError : IConError
{
public FormattedMessage DescribeInner()
{
return FormattedMessage.FromMarkup(
return FormattedMessage.FromMarkupOrThrow(
"You must be logged in with a client to use this, the server console isn't workable.");
}

View File

@@ -9,7 +9,7 @@ public record SessionHasNoEntityError(ICommonSession Session) : IConError
{
public FormattedMessage DescribeInner()
{
return FormattedMessage.FromMarkup($"The user {Session.Name} has no attached entity.");
return FormattedMessage.FromMarkupOrThrow($"The user {Session.Name} has no attached entity.");
}
public string? Expression { get; set; }

View File

@@ -82,7 +82,7 @@ public interface IInvocationContext
/// </remarks>
public void WriteMarkup(string markup)
{
WriteLine(FormattedMessage.FromMarkup(markup));
WriteLine(FormattedMessage.FromMarkupPermissive(markup));
}
/// <summary>

View File

@@ -352,7 +352,7 @@ public record OutOfInputError : IConError
{
public FormattedMessage DescribeInner()
{
return FormattedMessage.FromMarkup("Ran out of input data when data was expected.");
return FormattedMessage.FromMarkupOrThrow("Ran out of input data when data was expected.");
}
public string? Expression { get; set; }

View File

@@ -103,7 +103,7 @@ public record BadVarTypeError(Type Got, Type Expected, string VarName) : IConErr
{
public FormattedMessage DescribeInner()
{
return FormattedMessage.FromMarkup(
return FormattedMessage.FromMarkupOrThrow(
$"Got unexpected type {Got.PrettyName()} in {VarName}, expected {Expected.PrettyName()}");
}

View File

@@ -1,5 +1,6 @@
using System.Linq;
using Robust.Shared.Localization;
using System;
using System.Linq;
using System.Text;
namespace Robust.Shared.Toolshed;
@@ -31,10 +32,37 @@ public abstract partial class ToolshedCommand
/// </summary>
public string GetHelp(string? subCommand)
{
if (subCommand is null)
return $"{Name}: {Description(null)}";
else
return $"{Name}:{subCommand}: {Description(subCommand)}";
// Description
var description = subCommand is null
? $"{Name}: {Description(null)}"
: $"{Name}:{subCommand}: {Description(subCommand)}";
// Usage
var usage = new StringBuilder();
usage.AppendLine();
usage.Append(Loc.GetString("command-description-usage"));
foreach (var (pipedType, parameters) in _readonlyParameters[subCommand ?? ""])
{
usage.Append(Environment.NewLine + " ");
// Piped type
if (pipedType != null)
{
usage.Append(Loc.GetString("command-description-usage-pipedtype",
("typeName", GetFriendlyName(pipedType))));
}
// Name
usage.Append(Name);
// Parameters
foreach (var param in parameters)
{
usage.Append($" <{GetFriendlyName(param)}>");
}
}
return description + usage;
}
/// <inheritdoc/>
@@ -42,4 +70,27 @@ public abstract partial class ToolshedCommand
{
return GetHelp(null);
}
public static string GetFriendlyName(Type type)
{
string friendlyName = type.Name;
if (type.IsGenericType)
{
int iBacktick = friendlyName.IndexOf('`');
if (iBacktick > 0)
{
friendlyName = friendlyName.Remove(iBacktick);
}
friendlyName += "<";
Type[] typeParameters = type.GetGenericArguments();
for (int i = 0; i < typeParameters.Length; ++i)
{
string typeParamName = GetFriendlyName(typeParameters[i]);
friendlyName += (i == 0 ? typeParamName : "," + typeParamName);
}
friendlyName += ">";
}
return friendlyName;
}
}

View File

@@ -12,6 +12,7 @@ using Robust.Shared.Reflection;
using Robust.Shared.Toolshed.Errors;
using Robust.Shared.Toolshed.Syntax;
using Robust.Shared.Toolshed.TypeParsers;
using Robust.Shared.Utility;
namespace Robust.Shared.Toolshed;
@@ -74,6 +75,12 @@ public abstract partial class ToolshedCommand
/// </summary>
public IEnumerable<string> Subcommands => _implementors.Keys.Where(x => x != "");
/// <summary>
/// List of parameters for this command and all sub commands. Used for command help usage.
/// Dictionary(subCommand, List(pipedType, List(parameterType)))
/// </summary>
private readonly Dictionary<string, List<(Type?, List<Type>)>> _readonlyParameters;
protected ToolshedCommand()
{
var name = GetType().GetCustomAttribute<ToolshedCommandAttribute>()!.Name;
@@ -103,9 +110,12 @@ public abstract partial class ToolshedCommand
var impls = GetGenericImplementations();
Dictionary<(string, Type?), SortedDictionary<string, Type>> parameters = new();
_readonlyParameters = new();
foreach (var impl in impls)
{
var myParams = new SortedDictionary<string, Type>();
var orderedParams = new List<Type>();
string? subCmd = null;
if (impl.GetCustomAttribute<CommandImplementationAttribute>() is {SubCommand: { } x})
{
@@ -123,7 +133,10 @@ public abstract partial class ToolshedCommand
foreach (var param in impl.GetParameters())
{
if (param.GetCustomAttribute<CommandArgumentAttribute>() is not null)
myParams.TryAdd(param.Name!, param.ParameterType);
{
if (myParams.TryAdd(param.Name!, param.ParameterType))
orderedParams.Add(param.ParameterType);
}
if (param.GetCustomAttribute<PipedArgumentAttribute>() is not null)
{
@@ -135,7 +148,11 @@ public abstract partial class ToolshedCommand
var key = (subCmd ?? "", pipedType);
if (parameters.TryAdd(key, myParams))
{
var readParam = _readonlyParameters.GetOrNew(subCmd ?? "");
readParam.Add((pipedType, orderedParams));
continue;
}
if (!parameters[key].SequenceEqual(myParams))
throw new NotImplementedException("All command implementations of a given subcommand with the same pipe type must share the same argument types");

View File

@@ -93,7 +93,7 @@ public record struct StringMustStartWithQuote : IConError
{
public FormattedMessage DescribeInner()
{
return FormattedMessage.FromMarkup("A string must start with a quote.");
return FormattedMessage.FromMarkupOrThrow("A string must start with a quote.");
}
public string? Expression { get; set; }

View File

@@ -8,8 +8,7 @@ namespace Robust.Shared.Upload;
public sealed class NetworkResourceUploadMessage : NetMessage
{
public override NetDeliveryMethod DeliveryMethod => NetDeliveryMethod.ReliableUnordered;
public override MsgGroups MsgGroup => MsgGroups.Command;
public override MsgGroups MsgGroup => MsgGroups.String;
public byte[] Data { get; set; } = Array.Empty<byte>();
public ResPath RelativePath { get; set; } = ResPath.Self;

View File

@@ -271,30 +271,34 @@ public sealed class ZStdDecompressStream : Stream
return 0;
}
unsafe
{
fixed (byte* inputPtr = _buffer)
fixed (byte* outputPtr = buffer.Span)
{
ZSTD_outBuffer outputBuf = default;
outputBuf.dst = outputPtr;
outputBuf.pos = 0;
outputBuf.size = (nuint)buffer.Length;
ZSTD_inBuffer inputBuf = default;
inputBuf.src = inputPtr;
inputBuf.pos = (nuint)_bufferPos;
inputBuf.size = (nuint)_bufferSize;
var ret = DecompressChunk(this, buffer.Span);
if (ret > 0)
return (int)ret;
var ret = ZSTD_decompressStream(_ctx, &outputBuf, &inputBuf);
_bufferPos = (int)inputBuf.pos;
ZStdException.ThrowIfError(ret);
if (outputBuf.pos > 0)
return (int)outputBuf.pos;
}
}
} while (true);
static unsafe nuint DecompressChunk(ZStdDecompressStream stream, Span<byte> buffer)
{
fixed (byte* inputPtr = stream._buffer)
fixed (byte* outputPtr = buffer)
{
ZSTD_outBuffer outputBuf = default;
outputBuf.dst = outputPtr;
outputBuf.pos = 0;
outputBuf.size = (nuint)buffer.Length;
ZSTD_inBuffer inputBuf = default;
inputBuf.src = inputPtr;
inputBuf.pos = (nuint)stream._bufferPos;
inputBuf.size = (nuint)stream._bufferSize;
var ret = ZSTD_decompressStream(stream._ctx, &outputBuf, &inputBuf);
stream._bufferPos = (int)inputBuf.pos;
ZStdException.ThrowIfError(ret);
return outputBuf.pos;
}
}
}
public override long Seek(long offset, SeekOrigin origin)

View File

@@ -14,7 +14,7 @@ internal abstract partial class ViewVariablesManager
if (_typeHandlers.TryGetValue(typeof(T), out var h))
return (ViewVariablesTypeHandler<T>)h;
var handler = new ViewVariablesTypeHandler<T>();
var handler = new ViewVariablesTypeHandler<T>(Sawmill);
_typeHandlers.Add(typeof(T), handler);
return handler;
}

View File

@@ -31,9 +31,11 @@ public sealed class ViewVariablesTypeHandler<T> : ViewVariablesTypeHandler
{
private readonly List<TypeHandlerData> _handlers = new();
private readonly Dictionary<string, PathHandler> _paths = new();
private readonly ISawmill _sawmill;
internal ViewVariablesTypeHandler()
internal ViewVariablesTypeHandler(ISawmill sawmill)
{
_sawmill = sawmill;
}
/// <summary>
@@ -210,7 +212,9 @@ public sealed class ViewVariablesTypeHandler<T> : ViewVariablesTypeHandler
}
catch (NullReferenceException e)
{
Logger.ErrorS(nameof(ViewVariablesManager), e,
_sawmill.Log(
LogLevel.Error,
e,
$"NRE caught in setter for path \"{path}\" for type \"{typeof(T).Name}\"...");
}
});

View File

@@ -8,6 +8,7 @@ using Robust.Server.Debugging;
using Robust.Server.GameObjects;
using Robust.Server.GameStates;
using Robust.Server.Physics;
using Robust.Shared.ComponentTrees;
using Robust.Shared.Configuration;
using Robust.Shared.Containers;
using Robust.Shared.ContentPack;
@@ -26,6 +27,7 @@ using Robust.Shared.Threading;
using Robust.Shared.Utility;
using InputSystem = Robust.Server.GameObjects.InputSystem;
using MapSystem = Robust.Server.GameObjects.MapSystem;
using PointLightComponent = Robust.Client.GameObjects.PointLightComponent;
namespace Robust.UnitTesting
{
@@ -126,8 +128,8 @@ namespace Robust.UnitTesting
if (Project == UnitTestProject.Client)
{
systems.LoadExtraSystemType<ClientMetaDataSystem>();
systems.LoadExtraSystemType<Robust.Server.Containers.ContainerSystem>();
systems.LoadExtraSystemType<Robust.Server.GameObjects.TransformSystem>();
systems.LoadExtraSystemType<ContainerSystem>();
systems.LoadExtraSystemType<Robust.Client.GameObjects.TransformSystem>();
systems.LoadExtraSystemType<Robust.Client.Physics.BroadPhaseSystem>();
systems.LoadExtraSystemType<Robust.Client.Physics.JointSystem>();
systems.LoadExtraSystemType<Robust.Client.Physics.PhysicsSystem>();
@@ -135,6 +137,12 @@ namespace Robust.UnitTesting
systems.LoadExtraSystemType<PrototypeReloadSystem>();
systems.LoadExtraSystemType<Robust.Client.Debugging.DebugPhysicsSystem>();
systems.LoadExtraSystemType<Robust.Client.GameObjects.MapSystem>();
systems.LoadExtraSystemType<Robust.Client.GameObjects.PointLightSystem>();
systems.LoadExtraSystemType<LightTreeSystem>();
systems.LoadExtraSystemType<RecursiveMoveSystem>();
systems.LoadExtraSystemType<SpriteSystem>();
systems.LoadExtraSystemType<SpriteTreeSystem>();
systems.LoadExtraSystemType<GridChunkBoundsDebugSystem>();
}
else
{
@@ -171,6 +179,11 @@ namespace Robust.UnitTesting
compFactory.RegisterClass<MapSaveTileMapComponent>();
compFactory.RegisterClass<MapSaveIdComponent>();
}
else
{
compFactory.RegisterClass<PointLightComponent>();
compFactory.RegisterClass<SpriteComponent>();
}
deps.Resolve<IParallelManagerInternal>().Initialize();

View File

@@ -344,7 +344,7 @@ namespace Robust.UnitTesting.Shared.Maths
var controlColor = new Color(rf, gf, bf, af);
var color = Color.FromSrgb(Color.ToSrgb(controlColor));
Assert.That(color, Is.EqualTo(controlColor));
Assert.That(MathHelper.CloseToPercent(color, controlColor));
}
[Test]
@@ -355,7 +355,7 @@ namespace Robust.UnitTesting.Shared.Maths
var controlColor = new Color(rf, gf, bf, af);
var color = Color.FromHsl(Color.ToHsl(controlColor));
Assert.That(color, Is.EqualTo(controlColor));
Assert.That(MathHelper.CloseToPercent(color, controlColor));
}
[Test]
@@ -366,7 +366,7 @@ namespace Robust.UnitTesting.Shared.Maths
var controlColor = new Color(rf, gf, bf, af);
var color = Color.FromHsv(Color.ToHsv(controlColor));
Assert.That(color, Is.EqualTo(controlColor));
Assert.That(MathHelper.CloseToPercent(color, controlColor));
}
[Test]
@@ -393,7 +393,7 @@ namespace Robust.UnitTesting.Shared.Maths
var controlColor = new Color(rf, gf, bf, af);
var color = Color.FromYcbcr(Color.ToYcbcr(controlColor));
Assert.That(color, Is.EqualTo(controlColor));
Assert.That(MathHelper.CloseToPercent(color, controlColor));
}
[Test]
@@ -404,7 +404,7 @@ namespace Robust.UnitTesting.Shared.Maths
var controlColor = new Color(rf, gf, bf, af);
var color = Color.FromHcy(Color.ToHcy(controlColor));
Assert.That(color, Is.EqualTo(controlColor));
Assert.That(MathHelper.CloseToPercent(color, controlColor));
}
static IEnumerable<float> InterpolationValues => new float[]
@@ -430,7 +430,7 @@ namespace Robust.UnitTesting.Shared.Maths
var interColor = Color.InterpolateBetween(color1, color2, interpolation);
var inverseInterColor = Color.InterpolateBetween(color2, color1, 1 - interpolation);
Assert.That(interColor, Is.EqualTo(inverseInterColor));
Assert.That(MathHelper.CloseToPercent(interColor, inverseInterColor));
}
[Test]