mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Compare commits
94 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac46a7845d | ||
|
|
60b526f653 | ||
|
|
d58e380dd9 | ||
|
|
96a098a0c2 | ||
|
|
c0d4e34089 | ||
|
|
e16e0f4bd0 | ||
|
|
d31ffd2794 | ||
|
|
04d94f87fc | ||
|
|
f809375389 | ||
|
|
530ea5f4e6 | ||
|
|
590a23d540 | ||
|
|
52351e8b11 | ||
|
|
f75a764ff3 | ||
|
|
d14f4f0ce3 | ||
|
|
5367570c7f | ||
|
|
e523a733c8 | ||
|
|
06af61106c | ||
|
|
2239c30924 | ||
|
|
f9f55b6862 | ||
|
|
83a5560850 | ||
|
|
9a8f139fb9 | ||
|
|
20dae60fd4 | ||
|
|
b4098668bb | ||
|
|
9397cc4a6b | ||
|
|
1601e75879 | ||
|
|
a7b9c87926 | ||
|
|
8fea42ff9a | ||
|
|
86d20a0ef1 | ||
|
|
09012ea4ff | ||
|
|
e68297eb93 | ||
|
|
c1a2e23ce2 | ||
|
|
f208f6bfa9 | ||
|
|
ae526e2e10 | ||
|
|
25549869b1 | ||
|
|
f71e81d204 | ||
|
|
e67812fdb4 | ||
|
|
aa44b1cb8a | ||
|
|
8ec75be244 | ||
|
|
48746b7bd3 | ||
|
|
a9791d2033 | ||
|
|
709f1f4284 | ||
|
|
907094a5c8 | ||
|
|
a35a5e1645 | ||
|
|
ad8a59a72f | ||
|
|
e93c0f76a9 | ||
|
|
7bac32d18e | ||
|
|
b6b1d46892 | ||
|
|
6f0bc3822e | ||
|
|
b7c8452285 | ||
|
|
8c1e075c91 | ||
|
|
b340e40c99 | ||
|
|
c4b124f48d | ||
|
|
7efae8fbc1 | ||
|
|
7feeeb2f6f | ||
|
|
f90462cf82 | ||
|
|
b19ae9e69e | ||
|
|
2132d6cbae | ||
|
|
d2d6f9d08e | ||
|
|
4b58fcbff2 | ||
|
|
f83f6a8cd6 | ||
|
|
dfd7711506 | ||
|
|
78f9d92c07 | ||
|
|
3a86c827ea | ||
|
|
325f25c547 | ||
|
|
be57b5d20b | ||
|
|
7124d86f94 | ||
|
|
229380a71d | ||
|
|
e9eb536df5 | ||
|
|
22297ef6d8 | ||
|
|
7f2e433087 | ||
|
|
18c32a0258 | ||
|
|
72314a102d | ||
|
|
719ea26a31 | ||
|
|
5cb8fe1897 | ||
|
|
f35a52fc24 | ||
|
|
6bdb0cef47 | ||
|
|
fe3c9fe28f | ||
|
|
6085671f22 | ||
|
|
a2398da324 | ||
|
|
b27304cc58 | ||
|
|
3bf851a6cf | ||
|
|
cef92efd0f | ||
|
|
c5961a5ab1 | ||
|
|
8ddd92993d | ||
|
|
da253a5f34 | ||
|
|
ca9400a1ff | ||
|
|
f232195ceb | ||
|
|
b54a803519 | ||
|
|
a0d3d2108f | ||
|
|
977e4a017b | ||
|
|
2d8b159016 | ||
|
|
9caa0dde4b | ||
|
|
7a5a8c5eb1 | ||
|
|
95ba58f0a4 |
2
Linguini
2
Linguini
Submodule Linguini updated: 62b0e75b91...26c2608f9b
107
Robust.Analyzers/FriendAnalyzer.cs
Normal file
107
Robust.Analyzers/FriendAnalyzer.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
|
||||
namespace Robust.Analyzers
|
||||
{
|
||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||
public class FriendAnalyzer : DiagnosticAnalyzer
|
||||
{
|
||||
const string FriendAttribute = "Robust.Shared.Analyzers.FriendAttribute";
|
||||
|
||||
public const string DiagnosticId = "RA0002";
|
||||
|
||||
private const string Title = "Tried to access friend-only member";
|
||||
private const string MessageFormat = "Tried to access member \"{0}\" in class \"{1}\" which can only be accessed by friend classes";
|
||||
private const string Description = "Make sure to specify the accessing class in the friends attribute.";
|
||||
private const string Category = "Usage";
|
||||
|
||||
[SuppressMessage("ReSharper", "RS2008")]
|
||||
private static readonly DiagnosticDescriptor Rule = new (DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, true, Description);
|
||||
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
|
||||
|
||||
public override void Initialize(AnalysisContext context)
|
||||
{
|
||||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
|
||||
context.EnableConcurrentExecution();
|
||||
context.RegisterSyntaxNodeAction(CheckFriendship, SyntaxKind.SimpleMemberAccessExpression);
|
||||
}
|
||||
|
||||
private void CheckFriendship(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
if (context.Node is not MemberAccessExpressionSyntax memberAccess)
|
||||
return;
|
||||
|
||||
// We only do something if our parent is one of a few types.
|
||||
switch (context.Node.Parent)
|
||||
{
|
||||
// If we're being assigned...
|
||||
case AssignmentExpressionSyntax assignParent:
|
||||
{
|
||||
if (assignParent.Left != memberAccess)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
// If we're being invoked...
|
||||
case InvocationExpressionSyntax:
|
||||
break;
|
||||
|
||||
// Otherwise, do nothing.
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the friend attribute
|
||||
var friendAttr = context.Compilation.GetTypeByMetadataName(FriendAttribute);
|
||||
|
||||
// Get the type that is containing this expression, or, the class where this is happening.
|
||||
if (context.ContainingSymbol?.ContainingType is not { } containingType)
|
||||
return;
|
||||
|
||||
// We check all of our children and get only the identifiers.
|
||||
foreach (var identifier in memberAccess.ChildNodes().Select(node => node as IdentifierNameSyntax))
|
||||
{
|
||||
if (identifier == null) continue;
|
||||
|
||||
// Get the type info of the identifier, so we can check the attributes...
|
||||
if (context.SemanticModel.GetTypeInfo(identifier).ConvertedType is not { } type)
|
||||
continue;
|
||||
|
||||
// Same-type access is always fine.
|
||||
if (SymbolEqualityComparer.Default.Equals(type, containingType))
|
||||
continue;
|
||||
|
||||
// Finally, get all attributes of the type, to check if we have any friend classes.
|
||||
foreach (var attribute in type.GetAttributes())
|
||||
{
|
||||
// If the attribute isn't the friend attribute, continue.
|
||||
if (!SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, friendAttr))
|
||||
continue;
|
||||
|
||||
// Check all types allowed in the friend attribute. (We assume there's only one constructor arg.)
|
||||
foreach (var constant in attribute.ConstructorArguments[0].Values)
|
||||
{
|
||||
// Check if the value is a type...
|
||||
if (constant.Value is not INamedTypeSymbol t)
|
||||
continue;
|
||||
|
||||
// If we find that the containing class is specified in the attribute, return! All is good.
|
||||
if (SymbolEqualityComparer.Default.Equals(containingType, t))
|
||||
return;
|
||||
}
|
||||
|
||||
// Not in a friend class! Report an error.
|
||||
context.ReportDiagnostic(
|
||||
Diagnostic.Create(Rule, context.Node.GetLocation(),
|
||||
$"{context.Node.ToString().Split('.').LastOrDefault()}", $"{type.Name}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>9</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
28
Robust.Benchmarks/NumericsHelpers/AddBenchmark.cs
Normal file
28
Robust.Benchmarks/NumericsHelpers/AddBenchmark.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
|
||||
namespace Robust.Benchmarks.NumericsHelpers
|
||||
{
|
||||
public class AddBenchmark
|
||||
{
|
||||
[Params(32, 128)]
|
||||
public int N { get; set; }
|
||||
|
||||
private float[] _inputA = default!;
|
||||
private float[] _inputB = default!;
|
||||
private float[] _output = default!;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
_inputA = new float[N];
|
||||
_inputB = new float[N];
|
||||
_output = new float[N];
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void Bench()
|
||||
{
|
||||
Shared.Maths.NumericsHelpers.Add(_inputA, _inputB, _output);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace Robust.Benchmarks
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run();
|
||||
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,26 +29,27 @@ namespace Robust.Build.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
//formatted according to https://github.com/dotnet/msbuild/blob/main/src/Shared/CanonicalError.cs#L57
|
||||
class ConsoleBuildEngine : IBuildEngine
|
||||
{
|
||||
public void LogErrorEvent(BuildErrorEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"ERROR: {e.Code} {e.Message} in {e.File} {e.LineNumber}:{e.ColumnNumber}-{e.EndLineNumber}:{e.EndColumnNumber}");
|
||||
Console.WriteLine($"{e.File} ({e.LineNumber},{e.ColumnNumber},{e.EndLineNumber},{e.EndColumnNumber}): XAMLIL ERROR {e.Code}: {e.Message}");
|
||||
}
|
||||
|
||||
public void LogWarningEvent(BuildWarningEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"WARNING: {e.Code} {e.Message} in {e.File} {e.LineNumber}:{e.ColumnNumber}-{e.EndLineNumber}:{e.EndColumnNumber}");
|
||||
Console.WriteLine($"{e.File} ({e.LineNumber},{e.ColumnNumber},{e.EndLineNumber},{e.EndColumnNumber}): XAMLIL WARNING {e.Code}: {e.Message}");
|
||||
}
|
||||
|
||||
public void LogMessageEvent(BuildMessageEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"MESSAGE: {e.Code} {e.Message} in {e.File} {e.LineNumber}:{e.ColumnNumber}-{e.EndLineNumber}:{e.EndColumnNumber}");
|
||||
Console.WriteLine($"{e.File} ({e.LineNumber},{e.ColumnNumber},{e.EndLineNumber},{e.EndColumnNumber}): XAMLIL MESSAGE {e.Code}: {e.Message}");
|
||||
}
|
||||
|
||||
public void LogCustomEvent(CustomBuildEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"CUSTOM: {e.Message}");
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
|
||||
public bool BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties,
|
||||
|
||||
@@ -280,8 +280,8 @@ namespace Robust.Build.Tasks
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
engine.LogWarningEvent(new BuildWarningEventArgs("XAMLIL", "", res.Uri, 0, 0, 0, 0,
|
||||
e.ToString(), "", "CompileRobustXaml"));
|
||||
engine.LogErrorEvent(new BuildErrorEventArgs("XAMLIL", "", res.FilePath, 0, 0, 0, 0,
|
||||
$"{res.FilePath}: {e.Message}", "", "CompileRobustXaml"));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Robust.Client.Audio.Midi
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfgMan = default!;
|
||||
|
||||
private SharedBroadPhaseSystem _broadPhaseSystem = default!;
|
||||
private SharedBroadphaseSystem _broadPhaseSystem = default!;
|
||||
|
||||
[ViewVariables]
|
||||
public bool IsAvailable
|
||||
@@ -175,7 +175,7 @@ namespace Robust.Client.Audio.Midi
|
||||
_midiThread = new Thread(ThreadUpdate);
|
||||
_midiThread.Start();
|
||||
|
||||
_broadPhaseSystem = EntitySystem.Get<SharedBroadPhaseSystem>();
|
||||
_broadPhaseSystem = EntitySystem.Get<SharedBroadphaseSystem>();
|
||||
FluidsynthInitialized = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Reflection;
|
||||
@@ -76,6 +77,7 @@ namespace Robust.Client
|
||||
IoCManager.Register<IDiscordRichPresence, DiscordRichPresence>();
|
||||
IoCManager.Register<IMidiManager, MidiManager>();
|
||||
IoCManager.Register<IAuthManager, AuthManager>();
|
||||
IoCManager.Register<IPhysicsManager, PhysicsManager>();
|
||||
switch (mode)
|
||||
{
|
||||
case GameController.DisplayMode.Headless:
|
||||
|
||||
@@ -83,6 +83,8 @@ namespace Robust.Client.Console
|
||||
OutputText(text, true, true);
|
||||
}
|
||||
|
||||
public override event ConAnyCommandCallback? AnyCommandExecuted;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ExecuteCommand(ICommonSession? session, string command)
|
||||
{
|
||||
@@ -103,7 +105,11 @@ namespace Robust.Client.Console
|
||||
{
|
||||
var command1 = AvailableCommands[commandName];
|
||||
args.RemoveAt(0);
|
||||
command1.Execute(new ConsoleShell(this, null), command, args.ToArray());
|
||||
var shell = new ConsoleShell(this, null);
|
||||
var cmdArgs = args.ToArray();
|
||||
|
||||
AnyCommandExecuted?.Invoke(shell, commandName, command, cmdArgs);
|
||||
command1.Execute(shell, command, cmdArgs);
|
||||
}
|
||||
else
|
||||
WriteError(null, "Unknown command: " + commandName);
|
||||
|
||||
@@ -27,6 +27,7 @@ using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
@@ -536,7 +537,10 @@ namespace Robust.Client.Console.Commands
|
||||
var scroll = new ScrollContainer();
|
||||
tabContainer.AddChild(scroll);
|
||||
//scroll.SetAnchorAndMarginPreset(Control.LayoutPreset.Wide);
|
||||
var vBox = new VBoxContainer();
|
||||
var vBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical
|
||||
};
|
||||
scroll.AddChild(vBox);
|
||||
|
||||
var progressBar = new ProgressBar { MaxValue = 10, Value = 5 };
|
||||
@@ -594,7 +598,10 @@ namespace Robust.Client.Console.Commands
|
||||
}
|
||||
|
||||
var group = new ButtonGroup();
|
||||
var vBoxRadioButtons = new VBoxContainer();
|
||||
var vBoxRadioButtons = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical
|
||||
};
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
vBoxRadioButtons.AddChild(new Button
|
||||
@@ -610,8 +617,9 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
TabContainer.SetTabTitle(vBoxRadioButtons, "Radio buttons!!");
|
||||
|
||||
tabContainer.AddChild(new VBoxContainer
|
||||
tabContainer.AddChild(new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
Name = "Slider",
|
||||
Children =
|
||||
{
|
||||
@@ -863,7 +871,7 @@ namespace Robust.Client.Console.Commands
|
||||
var chunkIndex = grid.LocalToChunkIndices(grid.MapToGrid(mousePos));
|
||||
var chunk = internalGrid.GetChunk(chunkIndex);
|
||||
|
||||
shell.WriteLine($"worldBounds: {chunk.CalcWorldBounds()} localBounds: {chunk.CalcLocalBounds()}");
|
||||
shell.WriteLine($"worldBounds: {chunk.CalcWorldAABB()} localBounds: {chunk.CalcLocalBounds()}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
17
Robust.Client/Console/Commands/GridChunkBBCommand.cs
Normal file
17
Robust.Client/Console/Commands/GridChunkBBCommand.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
public class GridChunkBBCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "showchunkbb";
|
||||
public string Description => "Displays chunk bounds for the purposes of rendering";
|
||||
public string Help => $"{Command}";
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
EntitySystem.Get<GridChunkBoundsDebugSystem>().Enabled ^= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ using Robust.Shared.IoC;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Scripting;
|
||||
using Robust.Shared.Timing;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.Console
|
||||
{
|
||||
@@ -18,7 +19,7 @@ namespace Robust.Client.Console
|
||||
{
|
||||
private readonly IReflectionManager _reflectionManager;
|
||||
|
||||
private readonly VBoxContainer _watchesVBox;
|
||||
private readonly BoxContainer _watchesVBox;
|
||||
private readonly LineEdit _addWatchEdit;
|
||||
private readonly Button _addWatchButton;
|
||||
|
||||
@@ -31,17 +32,20 @@ namespace Robust.Client.Console
|
||||
|
||||
Title = "Watch Window";
|
||||
|
||||
var mainVBox = new VBoxContainer
|
||||
var mainVBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
MinSize = (500, 300),
|
||||
Children =
|
||||
{
|
||||
(_watchesVBox = new VBoxContainer
|
||||
(_watchesVBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
VerticalExpand = true
|
||||
}),
|
||||
new HBoxContainer
|
||||
new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
Children =
|
||||
{
|
||||
(_addWatchEdit = new HistoryLineEdit
|
||||
@@ -105,8 +109,9 @@ namespace Robust.Client.Console
|
||||
Button delButton;
|
||||
_runner = runner;
|
||||
|
||||
AddChild(new HBoxContainer
|
||||
AddChild(new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
Children =
|
||||
{
|
||||
(_outputLabel = new Label
|
||||
@@ -166,8 +171,9 @@ namespace Robust.Client.Console
|
||||
public CompilationErrorControl(string message)
|
||||
{
|
||||
Button delButton;
|
||||
AddChild(new HBoxContainer
|
||||
AddChild(new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
Children =
|
||||
{
|
||||
new Label
|
||||
|
||||
@@ -162,12 +162,13 @@ namespace Robust.Client.Debugging
|
||||
if (viewport.IsEmpty()) return;
|
||||
|
||||
var mapId = _eyeManager.CurrentMap;
|
||||
var sleepThreshold = IoCManager.Resolve<IConfigurationManager>().GetCVar(CVars.TimeToSleep);
|
||||
var colorEdge = Color.Red.WithAlpha(0.33f);
|
||||
var drawnJoints = new HashSet<Joint>();
|
||||
|
||||
foreach (var physBody in EntitySystem.Get<SharedBroadPhaseSystem>().GetCollidingEntities(mapId, viewport))
|
||||
foreach (var physBody in EntitySystem.Get<SharedBroadphaseSystem>().GetCollidingEntities(mapId, viewport))
|
||||
{
|
||||
if (physBody.Owner.HasComponent<MapGridComponent>()) continue;
|
||||
|
||||
// all entities have a TransformComponent
|
||||
var transform = physBody.Owner.Transform;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Collision;
|
||||
using Robust.Shared.Physics.Dynamics;
|
||||
using Robust.Shared.Physics.Dynamics.Contacts;
|
||||
@@ -40,6 +41,8 @@ namespace Robust.Client.Debugging
|
||||
* Used for debugging shapes, controllers, joints, contacts
|
||||
*/
|
||||
|
||||
[Dependency] private readonly IPhysicsManager _physicsManager = default!;
|
||||
|
||||
private const int MaxContactPoints = 2048;
|
||||
internal int PointCount;
|
||||
|
||||
@@ -79,8 +82,7 @@ namespace Robust.Client.Debugging
|
||||
CollisionManager.GetPointStates(out state1, out state2, oldManifold, manifold);
|
||||
|
||||
Span<Vector2> points = stackalloc Vector2[2];
|
||||
Vector2 normal;
|
||||
contact.GetWorldManifold(out normal, points);
|
||||
contact.GetWorldManifold(_physicsManager, out var normal, points);
|
||||
|
||||
for (int i = 0; i < manifold.PointCount && PointCount < MaxContactPoints; ++i)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace Robust.Client.GameObjects
|
||||
RegisterClass<InputComponent>();
|
||||
RegisterClass<SpriteComponent>();
|
||||
RegisterClass<ClientOccluderComponent>();
|
||||
RegisterClass<OccluderTreeComponent>();
|
||||
RegisterClass<EyeComponent>();
|
||||
RegisterClass<AppearanceComponent>();
|
||||
RegisterClass<AppearanceTestComponent>();
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
@@ -10,7 +8,7 @@ namespace Robust.Client.GameObjects
|
||||
/// <summary>
|
||||
/// Defines data fields used in the <see cref="InputSystem"/>.
|
||||
/// </summary>
|
||||
class InputComponent : Component
|
||||
public class InputComponent : Component
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override string Name => "Input";
|
||||
|
||||
@@ -365,7 +365,7 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.ErrorS(LogCategory, "Unable to load RSI '{0}'. Trace:\n{1}", rsiPath);
|
||||
Logger.ErrorS(LogCategory, "Unable to load RSI '{0}'.", rsiPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,7 @@ namespace Robust.Client.GameObjects
|
||||
[Dependency] private readonly IClydeAudio _clyde = default!;
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
private SharedBroadPhaseSystem _broadPhaseSystem = default!;
|
||||
[Dependency] private readonly SharedBroadphaseSystem _broadPhaseSystem = default!;
|
||||
|
||||
private readonly List<PlayingStream> _playingClydeStreams = new();
|
||||
|
||||
@@ -38,7 +37,6 @@ namespace Robust.Client.GameObjects
|
||||
SubscribeNetworkEvent<StopAudioMessageClient>(StopAudioMessageHandler);
|
||||
|
||||
SubscribeLocalEvent<SoundSystem.QueryAudioSystem>((ev => ev.Audio = this));
|
||||
_broadPhaseSystem = Get<SharedBroadPhaseSystem>();
|
||||
}
|
||||
|
||||
private void StopAudioMessageHandler(StopAudioMessageClient ev)
|
||||
@@ -301,7 +299,7 @@ namespace Robust.Client.GameObjects
|
||||
if (!source.SetPosition(coordinates.ToMapPos(EntityManager)))
|
||||
{
|
||||
source.Dispose();
|
||||
Logger.Warning("Can't play positional audio \"{stream.Name}\", can't set position.");
|
||||
Logger.Warning($"Can't play positional audio \"{stream.Name}\", can't set position.");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public class ClientContainerSystem : ContainerSystem
|
||||
{
|
||||
private readonly HashSet<IEntity> _updateQueue = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<UpdateContainerOcclusionMessage>(UpdateContainerOcclusion);
|
||||
|
||||
UpdatesBefore.Add(typeof(SpriteSystem));
|
||||
}
|
||||
|
||||
private void UpdateContainerOcclusion(UpdateContainerOcclusionMessage ev)
|
||||
{
|
||||
_updateQueue.Add(ev.Entity);
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
base.FrameUpdate(frameTime);
|
||||
|
||||
foreach (var toUpdate in _updateQueue)
|
||||
{
|
||||
if (toUpdate.Deleted)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UpdateEntityRecursively(toUpdate);
|
||||
}
|
||||
|
||||
_updateQueue.Clear();
|
||||
}
|
||||
|
||||
private static void UpdateEntityRecursively(IEntity entity)
|
||||
{
|
||||
// TODO: Since we are recursing down,
|
||||
// we could cache ShowContents data here to speed it up for children.
|
||||
// Am lazy though.
|
||||
UpdateEntity(entity);
|
||||
|
||||
foreach (var child in entity.Transform.Children)
|
||||
{
|
||||
UpdateEntityRecursively(child.Owner);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateEntity(IEntity entity)
|
||||
{
|
||||
if (entity.TryGetComponent(out SpriteComponent? sprite))
|
||||
{
|
||||
sprite.ContainerOccluded = false;
|
||||
|
||||
// We have to recursively scan for containers upwards in case of nested containers.
|
||||
var tempParent = entity;
|
||||
while (tempParent.TryGetContainer(out var container))
|
||||
{
|
||||
if (!container.ShowContents)
|
||||
{
|
||||
sprite.ContainerOccluded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
tempParent = container.Owner;
|
||||
}
|
||||
}
|
||||
|
||||
if (entity.TryGetComponent(out PointLightComponent? light))
|
||||
{
|
||||
light.ContainerOccluded = false;
|
||||
|
||||
// We have to recursively scan for containers upwards in case of nested containers.
|
||||
var tempParent = entity;
|
||||
while (tempParent.TryGetContainer(out var container))
|
||||
{
|
||||
if (container.OccludesLight)
|
||||
{
|
||||
light.ContainerOccluded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
tempParent = container.Owner;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
237
Robust.Client/GameObjects/EntitySystems/ContainerSystem.cs
Normal file
237
Robust.Client/GameObjects/EntitySystems/ContainerSystem.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Serialization;
|
||||
using static Robust.Shared.Containers.ContainerManagerComponent;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public class ContainerSystem : SharedContainerSystem
|
||||
{
|
||||
[Dependency] private readonly IRobustSerializer _serializer = default!;
|
||||
[Dependency] private readonly IDynamicTypeFactoryInternal _dynFactory = default!;
|
||||
|
||||
private readonly HashSet<IEntity> _updateQueue = new();
|
||||
|
||||
public readonly Dictionary<EntityUid, IContainer> ExpectedEntities = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<UpdateContainerOcclusionMessage>(UpdateContainerOcclusion);
|
||||
SubscribeLocalEvent<EntityInitializedMessage>(HandleEntityInitialized);
|
||||
SubscribeLocalEvent<ContainerManagerComponent, ComponentHandleState>(HandleComponentState);
|
||||
|
||||
UpdatesBefore.Add(typeof(SpriteSystem));
|
||||
}
|
||||
|
||||
private void UpdateContainerOcclusion(UpdateContainerOcclusionMessage ev)
|
||||
{
|
||||
_updateQueue.Add(ev.Entity);
|
||||
}
|
||||
|
||||
private void HandleEntityInitialized(EntityInitializedMessage ev)
|
||||
{
|
||||
if (!ExpectedEntities.TryGetValue(ev.Entity.Uid, out var container))
|
||||
return;
|
||||
|
||||
RemoveExpectedEntity(ev.Entity.Uid);
|
||||
|
||||
if (container.Deleted)
|
||||
return;
|
||||
|
||||
container.Insert(ev.Entity);
|
||||
}
|
||||
|
||||
private void HandleComponentState(EntityUid uid, ContainerManagerComponent component, ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not ContainerManagerComponentState cast)
|
||||
return;
|
||||
|
||||
// Delete now-gone containers.
|
||||
List<string>? toDelete = null;
|
||||
foreach (var (id, container) in component.Containers)
|
||||
{
|
||||
if (!cast.ContainerSet.Any(data => data.Id == id))
|
||||
{
|
||||
container.Shutdown();
|
||||
toDelete ??= new List<string>();
|
||||
toDelete.Add(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (toDelete != null)
|
||||
{
|
||||
foreach (var dead in toDelete)
|
||||
{
|
||||
component.Containers.Remove(dead);
|
||||
}
|
||||
}
|
||||
|
||||
// Add new containers and update existing contents.
|
||||
|
||||
foreach (var (containerType, id, showEnts, occludesLight, entityUids) in cast.ContainerSet)
|
||||
{
|
||||
if (!component.Containers.TryGetValue(id, out var container))
|
||||
{
|
||||
container = ContainerFactory(component, containerType, id);
|
||||
component.Containers.Add(id, container);
|
||||
}
|
||||
|
||||
// sync show flag
|
||||
container.ShowContents = showEnts;
|
||||
container.OccludesLight = occludesLight;
|
||||
|
||||
// Remove gone entities.
|
||||
List<IEntity>? toRemove = null;
|
||||
foreach (var entity in container.ContainedEntities)
|
||||
{
|
||||
if (!entityUids.Contains(entity.Uid))
|
||||
{
|
||||
toRemove ??= new List<IEntity>();
|
||||
toRemove.Add(entity);
|
||||
}
|
||||
}
|
||||
|
||||
if (toRemove != null)
|
||||
{
|
||||
foreach (var goner in toRemove)
|
||||
container.Remove(goner);
|
||||
}
|
||||
|
||||
// Remove entities that were expected, but have been removed from the container.
|
||||
List<EntityUid>? removedExpected = null;
|
||||
foreach (var entityUid in container.ExpectedEntities)
|
||||
{
|
||||
if (!entityUids.Contains(entityUid))
|
||||
{
|
||||
removedExpected ??= new List<EntityUid>();
|
||||
removedExpected.Add(entityUid);
|
||||
}
|
||||
}
|
||||
|
||||
if (removedExpected != null)
|
||||
{
|
||||
foreach (var entityUid in removedExpected)
|
||||
RemoveExpectedEntity(entityUid);
|
||||
}
|
||||
|
||||
// Add new entities.
|
||||
foreach (var entityUid in entityUids)
|
||||
{
|
||||
if (!EntityManager.TryGetEntity(entityUid, out var entity))
|
||||
{
|
||||
AddExpectedEntity(entityUid, container);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!container.ContainedEntities.Contains(entity))
|
||||
container.Insert(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IContainer ContainerFactory(ContainerManagerComponent component, string containerType, string id)
|
||||
{
|
||||
var type = _serializer.FindSerializedType(typeof(IContainer), containerType);
|
||||
if (type is null) throw new ArgumentException($"Container of type {containerType} for id {id} cannot be found.");
|
||||
|
||||
var newContainer = _dynFactory.CreateInstanceUnchecked<BaseContainer>(type);
|
||||
newContainer.ID = id;
|
||||
newContainer.Manager = component;
|
||||
return newContainer;
|
||||
}
|
||||
|
||||
public void AddExpectedEntity(EntityUid uid, IContainer container)
|
||||
{
|
||||
if (ExpectedEntities.ContainsKey(uid))
|
||||
return;
|
||||
|
||||
ExpectedEntities.Add(uid, container);
|
||||
container.ExpectedEntities.Add(uid);
|
||||
}
|
||||
|
||||
public void RemoveExpectedEntity(EntityUid uid)
|
||||
{
|
||||
if (!ExpectedEntities.TryGetValue(uid, out var container))
|
||||
return;
|
||||
|
||||
ExpectedEntities.Remove(uid);
|
||||
container.ExpectedEntities.Remove(uid);
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
base.FrameUpdate(frameTime);
|
||||
|
||||
foreach (var toUpdate in _updateQueue)
|
||||
{
|
||||
if (toUpdate.Deleted)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UpdateEntityRecursively(toUpdate);
|
||||
}
|
||||
|
||||
_updateQueue.Clear();
|
||||
}
|
||||
|
||||
private static void UpdateEntityRecursively(IEntity entity)
|
||||
{
|
||||
// TODO: Since we are recursing down,
|
||||
// we could cache ShowContents data here to speed it up for children.
|
||||
// Am lazy though.
|
||||
UpdateEntity(entity);
|
||||
|
||||
foreach (var child in entity.Transform.Children)
|
||||
{
|
||||
UpdateEntityRecursively(child.Owner);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateEntity(IEntity entity)
|
||||
{
|
||||
if (entity.TryGetComponent(out SpriteComponent? sprite))
|
||||
{
|
||||
sprite.ContainerOccluded = false;
|
||||
|
||||
// We have to recursively scan for containers upwards in case of nested containers.
|
||||
var tempParent = entity;
|
||||
while (tempParent.TryGetContainer(out var container))
|
||||
{
|
||||
if (!container.ShowContents)
|
||||
{
|
||||
sprite.ContainerOccluded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
tempParent = container.Owner;
|
||||
}
|
||||
}
|
||||
|
||||
if (entity.TryGetComponent(out PointLightComponent? light))
|
||||
{
|
||||
light.ContainerOccluded = false;
|
||||
|
||||
// We have to recursively scan for containers upwards in case of nested containers.
|
||||
var tempParent = entity;
|
||||
while (tempParent.TryGetContainer(out var container))
|
||||
{
|
||||
if (container.OccludesLight)
|
||||
{
|
||||
light.ContainerOccluded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
tempParent = container.Owner;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public class GridChunkBoundsDebugSystem : EntitySystem
|
||||
{
|
||||
private GridChunkBoundsOverlay? _overlay;
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get => _enabled;
|
||||
set
|
||||
{
|
||||
if (_enabled == value) return;
|
||||
|
||||
_enabled = value;
|
||||
|
||||
if (_enabled)
|
||||
{
|
||||
DebugTools.Assert(_overlay == null);
|
||||
_overlay = new GridChunkBoundsOverlay(
|
||||
IoCManager.Resolve<IEntityManager>(),
|
||||
IoCManager.Resolve<IEyeManager>(),
|
||||
IoCManager.Resolve<IMapManager>());
|
||||
|
||||
IoCManager.Resolve<IOverlayManager>().AddOverlay(_overlay);
|
||||
}
|
||||
else
|
||||
{
|
||||
IoCManager.Resolve<IOverlayManager>().RemoveOverlay(_overlay!);
|
||||
_overlay = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _enabled;
|
||||
}
|
||||
|
||||
internal sealed class GridChunkBoundsOverlay : Overlay
|
||||
{
|
||||
private readonly IEntityManager _entityManager;
|
||||
private readonly IEyeManager _eyeManager;
|
||||
private readonly IMapManager _mapManager;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
|
||||
public GridChunkBoundsOverlay(IEntityManager entManager, IEyeManager eyeManager, IMapManager mapManager)
|
||||
{
|
||||
_entityManager = entManager;
|
||||
_eyeManager = eyeManager;
|
||||
_mapManager = mapManager;
|
||||
}
|
||||
|
||||
protected internal override void Draw(in OverlayDrawArgs args)
|
||||
{
|
||||
var currentMap = _eyeManager.CurrentMap;
|
||||
var viewport = _eyeManager.GetWorldViewport();
|
||||
|
||||
foreach (var grid in _mapManager.FindGridsIntersecting(currentMap, viewport))
|
||||
{
|
||||
var mapGrid = (IMapGridInternal) grid;
|
||||
var gridEnt = _entityManager.GetEntity(grid.GridEntityId);
|
||||
|
||||
var worldPos = gridEnt.Transform.WorldPosition;
|
||||
var worldRot = gridEnt.Transform.WorldRotation;
|
||||
|
||||
foreach (var (_, chunk) in mapGrid.GetMapChunks())
|
||||
{
|
||||
var chunkBounds = chunk.CalcWorldBounds(worldPos, worldRot);
|
||||
var aabb = chunkBounds.CalcBoundingBox();
|
||||
|
||||
// Calc world bounds for chunk.
|
||||
if (!aabb.Intersects(in viewport))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
args.WorldHandle.DrawRect(chunkBounds, Color.Green.WithAlpha(0.2f), true);
|
||||
args.WorldHandle.DrawRect(aabb, Color.Red, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,14 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly RenderingTreeSystem _treeSystem = default!;
|
||||
|
||||
private RenderingTreeSystem _treeSystem = default!;
|
||||
private readonly Queue<SpriteComponent> _inertUpdateQueue = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_treeSystem = Get<RenderingTreeSystem>();
|
||||
SubscribeLocalEvent<SpriteUpdateInertEvent>(QueueUpdateInert);
|
||||
}
|
||||
|
||||
|
||||
@@ -111,10 +111,11 @@ namespace Robust.Client.Graphics
|
||||
public MapCoordinates ScreenToMap(ScreenCoordinates point)
|
||||
{
|
||||
var (pos, window) = point;
|
||||
if (window != MainViewport.Window?.Id)
|
||||
|
||||
if (_uiManager.MouseGetControl(point) is not IViewportControl viewport)
|
||||
return default;
|
||||
|
||||
return MainViewport.ScreenToMap(pos);
|
||||
return viewport.ScreenToMap(pos);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Robust.Client.Graphics
|
||||
ScreenCoordinates CoordinatesToScreen(EntityCoordinates point);
|
||||
|
||||
/// <summary>
|
||||
/// Unprojects a point from UI screen space to world space using the current camera.
|
||||
/// Unprojects a point from UI screen space to world space using the viewport under the screen coordinates.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The game exists on the 2D X/Y plane, so this function returns a point o the plane
|
||||
@@ -64,7 +64,7 @@ namespace Robust.Client.Graphics
|
||||
MapCoordinates ScreenToMap(ScreenCoordinates point);
|
||||
|
||||
/// <summary>
|
||||
/// Unprojects a point from UI screen space to world space using the current camera.
|
||||
/// Unprojects a point from UI screen space to world space using the main viewport.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The game exists on the 2D X/Y plane, so this function returns a point o the plane
|
||||
|
||||
@@ -19,18 +19,17 @@ namespace Robust.Client.Graphics.Clyde
|
||||
private int _verticesPerChunk(IMapChunk chunk) => chunk.ChunkSize * chunk.ChunkSize * 4;
|
||||
private int _indicesPerChunk(IMapChunk chunk) => chunk.ChunkSize * chunk.ChunkSize * GetQuadBatchIndexCount();
|
||||
|
||||
private void _drawGrids(Box2 worldBounds)
|
||||
private void _drawGrids(Viewport viewport, Box2 worldBounds, IEye eye)
|
||||
{
|
||||
var mapId = _eyeManager.CurrentMap;
|
||||
var mapId = eye.Position.MapId;
|
||||
if (!_mapManager.MapExists(mapId))
|
||||
{
|
||||
// fall back to the default eye's map
|
||||
_eyeManager.ClearCurrentEye();
|
||||
mapId = _eyeManager.CurrentMap;
|
||||
// fall back to nullspace map
|
||||
mapId = MapId.Nullspace;
|
||||
}
|
||||
|
||||
SetTexture(TextureUnit.Texture0, _tileDefinitionManager.TileTextureAtlas);
|
||||
SetTexture(TextureUnit.Texture1, _lightingReady ? _currentViewport!.LightRenderTarget.Texture : _stockTextureWhite);
|
||||
SetTexture(TextureUnit.Texture1, _lightingReady ? viewport.LightRenderTarget.Texture : _stockTextureWhite);
|
||||
|
||||
var (gridProgram, _) = ActivateShaderInstance(_defaultShader.Handle);
|
||||
SetupGlobalUniformsImmediate(gridProgram, (ClydeTexture) _tileDefinitionManager.TileTextureAtlas);
|
||||
@@ -52,11 +51,13 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
var transform = compMan.GetComponent<ITransformComponent>(grid.GridEntityId);
|
||||
gridProgram.SetUniform(UniIModelMatrix, transform.WorldMatrix);
|
||||
var worldPos = transform.WorldPosition;
|
||||
var worldRot = transform.WorldRotation;
|
||||
|
||||
foreach (var (_, chunk) in grid.GetMapChunks())
|
||||
{
|
||||
// Calc world bounds for chunk.
|
||||
if (!chunk.CalcWorldBounds().Intersects(in worldBounds))
|
||||
if (!chunk.CalcWorldAABB(worldPos, worldRot).Intersects(in worldBounds))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -201,9 +201,10 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
|
||||
|
||||
private void DrawEntities(Viewport viewport, Box2 worldBounds)
|
||||
private void DrawEntities(Viewport viewport, Box2 worldBounds, IEye eye)
|
||||
{
|
||||
if (_eyeManager.CurrentMap == MapId.Nullspace || !_mapManager.HasMapEntity(_eyeManager.CurrentMap))
|
||||
var mapId = eye.Position.MapId;
|
||||
if (mapId == MapId.Nullspace || !_mapManager.HasMapEntity(mapId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -217,7 +218,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// TODO: Make this check more accurate.
|
||||
var widerBounds = worldBounds.Enlarged(5);
|
||||
|
||||
ProcessSpriteEntities(_eyeManager.CurrentMap, widerBounds, _drawingSpriteList);
|
||||
ProcessSpriteEntities(mapId, widerBounds, _drawingSpriteList);
|
||||
|
||||
var worldOverlays = new List<Overlay>();
|
||||
|
||||
@@ -291,6 +292,9 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// scale can be passed with PostShader as variable in future
|
||||
var postShadeScale = 1.25f;
|
||||
var screenSpriteSize = (Vector2i) ((screenRT - screenLB) * postShadeScale).Rounded();
|
||||
|
||||
// Rotate the vector by the eye angle, otherwise the bounding box will be incorrect
|
||||
screenSpriteSize = (Vector2i) eye.Rotation.RotateVec(screenSpriteSize).Rounded();
|
||||
screenSpriteSize.Y = -screenSpriteSize.Y;
|
||||
|
||||
// I'm not 100% sure why it works, but without it post-shader
|
||||
@@ -467,13 +471,13 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
using (DebugGroup("Grids"))
|
||||
{
|
||||
_drawGrids(worldBounds);
|
||||
_drawGrids(viewport, worldBounds, eye);
|
||||
}
|
||||
|
||||
// We will also render worldspace overlays here so we can do them under / above entities as necessary
|
||||
using (DebugGroup("Entities"))
|
||||
{
|
||||
DrawEntities(viewport, worldBounds);
|
||||
DrawEntities(viewport, worldBounds, eye);
|
||||
}
|
||||
|
||||
RenderOverlays(viewport, OverlaySpace.WorldSpaceBelowFOV, worldBounds);
|
||||
|
||||
@@ -5,6 +5,7 @@ using OpenToolkit.Graphics.OpenGL4;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -323,11 +324,17 @@ namespace Robust.Client.Graphics.Clyde
|
||||
return;
|
||||
}
|
||||
|
||||
var map = eye.Position.MapId;
|
||||
var mapId = eye.Position.MapId;
|
||||
|
||||
var (lights, count, expandedBounds) = GetLightsToRender(map, worldBounds);
|
||||
// If this map has lighting disabled, return
|
||||
if (!_mapManager.GetMapEntity(mapId).GetComponent<IMapComponent>().LightingEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateOcclusionGeometry(map, expandedBounds, eye.Position.Position);
|
||||
var (lights, count, expandedBounds) = GetLightsToRender(mapId, worldBounds);
|
||||
|
||||
UpdateOcclusionGeometry(mapId, expandedBounds, eye.Position.Position);
|
||||
|
||||
DrawFov(viewport, eye);
|
||||
|
||||
@@ -773,24 +780,13 @@ namespace Robust.Client.Graphics.Clyde
|
||||
var ii = 0;
|
||||
var imi = 0;
|
||||
|
||||
foreach (var gridId in _mapManager.FindGridIdsIntersecting(map, expandedBounds, true))
|
||||
foreach (var comp in occluderSystem.GetOccluderTrees(map, expandedBounds))
|
||||
{
|
||||
if (!occluderSystem.TryGetOccluderTreeForGrid(map, gridId, out var occluderTree)) continue;
|
||||
// TODO: I know this doesn't work with rotated grids but when I come back to these I'm adding tests
|
||||
// because rotation bugs are common.
|
||||
var treeBounds = expandedBounds.Translated(-comp.Owner.Transform.WorldPosition);
|
||||
|
||||
Box2 gridBounds;
|
||||
|
||||
if (gridId == GridId.Invalid)
|
||||
{
|
||||
gridBounds = expandedBounds;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Ideally this would clamp to the outer border of what we can see
|
||||
var grid = _mapManager.GetGrid(gridId);
|
||||
gridBounds = expandedBounds.Translated(-grid.WorldPosition);
|
||||
}
|
||||
|
||||
occluderTree.QueryAabb((in OccluderComponent sOccluder) =>
|
||||
comp.Tree.QueryAabb((in OccluderComponent sOccluder) =>
|
||||
{
|
||||
var occluder = (ClientOccluderComponent)sOccluder;
|
||||
var transform = occluder.Owner.Transform;
|
||||
@@ -919,7 +915,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
ami += 4;
|
||||
|
||||
return true;
|
||||
}, gridBounds);
|
||||
}, treeBounds);
|
||||
}
|
||||
|
||||
_occlusionDataLength = ii;
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
internal sealed partial class Clyde : IClydeInternal, IClydeAudio, IPostInjectInit
|
||||
{
|
||||
[Dependency] private readonly IClydeTileDefinitionManager _tileDefinitionManager = default!;
|
||||
[Dependency] private readonly IEntityLookup _lookup = default!;
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly ILightManager _lightManager = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
|
||||
@@ -20,6 +20,9 @@ namespace Robust.Client.Log
|
||||
|
||||
public void Log(string sawmillName, LogEvent message)
|
||||
{
|
||||
if (sawmillName == "CON")
|
||||
return;
|
||||
|
||||
var formatted = new FormattedMessage(8);
|
||||
var robustLevel = message.Level.ToRobust();
|
||||
formatted.PushColor(Color.DarkGray);
|
||||
|
||||
@@ -8,6 +8,7 @@ using Robust.Client.Utility;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
@@ -62,7 +63,7 @@ namespace Robust.Client.Map
|
||||
var row = i / dimensionX;
|
||||
|
||||
Image<Rgba32> image;
|
||||
using (var stream = _resourceCache.ContentFileRead(Path.Join(def.Path, $"{def.SpriteName}.png")))
|
||||
using (var stream = _resourceCache.ContentFileRead(new ResourcePath(def.Path) / $"{def.SpriteName}.png"))
|
||||
{
|
||||
image = Image.Load<Rgba32>(stream);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Robust.Shared.Physics.Broadphase;
|
||||
using Robust.Shared.Physics;
|
||||
|
||||
namespace Robust.Client.Physics
|
||||
{
|
||||
internal sealed class BroadPhaseSystem : SharedBroadPhaseSystem
|
||||
internal sealed class BroadPhaseSystem : SharedBroadphaseSystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
|
||||
@@ -16,8 +16,7 @@ namespace Robust.Client.Physics
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
_lastRem = _gameTiming.CurTime;
|
||||
|
||||
SimulateWorld(frameTime, !_gameTiming.InSimulation || !_gameTiming.IsFirstTimePredicted);
|
||||
SimulateWorld(frameTime, _gameTiming.InPrediction);
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
|
||||
@@ -504,8 +504,8 @@ namespace Robust.Client.Placement
|
||||
coordinates = new EntityCoordinates();
|
||||
return false;
|
||||
}
|
||||
coordinates = EntityCoordinates.FromMap(ent.EntityManager, MapManager,
|
||||
eyeManager.ScreenToMap(_inputManager.MouseScreenPosition));
|
||||
coordinates = EntityCoordinates.FromMap(MapManager,
|
||||
eyeManager.ScreenToMap(_inputManager.MouseScreenPosition));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Broadphase;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -232,7 +233,7 @@ namespace Robust.Client.Placement
|
||||
bounds.Width,
|
||||
bounds.Height);
|
||||
|
||||
return EntitySystem.Get<SharedBroadPhaseSystem>().TryCollideRect(collisionBox, mapCoords.MapId);
|
||||
return EntitySystem.Get<SharedBroadphaseSystem>().TryCollideRect(collisionBox, mapCoords.MapId);
|
||||
}
|
||||
|
||||
protected Vector2 ScreenToWorld(Vector2 point)
|
||||
@@ -250,7 +251,7 @@ namespace Robust.Client.Placement
|
||||
var mapCoords = pManager.eyeManager.ScreenToMap(coords.Position);
|
||||
if (!pManager.MapManager.TryFindGridAt(mapCoords, out var grid))
|
||||
{
|
||||
return EntityCoordinates.FromMap(pManager.EntityManager, pManager.MapManager, mapCoords);
|
||||
return EntityCoordinates.FromMap(pManager.MapManager, mapCoords);
|
||||
}
|
||||
|
||||
return EntityCoordinates.FromMap(pManager.EntityManager, grid.GridEntityId, mapCoords);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics;
|
||||
|
||||
|
||||
namespace Robust.Client.Placement
|
||||
|
||||
@@ -102,7 +102,9 @@ namespace Robust.Client.ResourceManagement
|
||||
|
||||
if (reg.Src.Width % frameSize.X != 0 || reg.Src.Height % frameSize.Y != 0)
|
||||
{
|
||||
throw new RSILoadException("State image size is not a multiple of the icon size.");
|
||||
var regDims = $"{reg.Src.Width}x{reg.Src.Height}";
|
||||
var iconDims = $"{frameSize.X}x{frameSize.Y}";
|
||||
throw new RSILoadException($"State '{stateObject.StateId}' image size ({regDims}) is not a multiple of the icon size ({iconDims}).");
|
||||
}
|
||||
|
||||
// Load all frames into a list so we can operate on it more sanely.
|
||||
@@ -250,7 +252,7 @@ namespace Robust.Client.ResourceManagement
|
||||
}
|
||||
|
||||
if (manifestJson == null)
|
||||
throw new RSILoadException("Manifest JSON was null!");
|
||||
throw new RSILoadException($"Manifest JSON failed to deserialize!");
|
||||
|
||||
var size = manifestJson.Size;
|
||||
var states = new StateMetadata[manifestJson.States.Length];
|
||||
@@ -270,7 +272,7 @@ namespace Robust.Client.ResourceManagement
|
||||
1 => RSI.State.DirectionType.Dir1,
|
||||
4 => RSI.State.DirectionType.Dir4,
|
||||
8 => RSI.State.DirectionType.Dir8,
|
||||
_ => throw new RSILoadException($"Invalid direction: {dirValue} expected 1, 4 or 8")
|
||||
_ => throw new RSILoadException($"Invalid direction for state '{stateName}': {dirValue}. Expected 1, 4 or 8")
|
||||
};
|
||||
}
|
||||
else
|
||||
@@ -291,7 +293,7 @@ namespace Robust.Client.ResourceManagement
|
||||
if (delays.Length != dirValue)
|
||||
{
|
||||
throw new RSILoadException(
|
||||
"DirectionsdirectionFramesList count does not match amount of delays specified.");
|
||||
$"Direction frames list count ({dirValue}) does not match amount of delays specified ({delays.Length}) for state '{stateName}'.");
|
||||
}
|
||||
|
||||
for (var i = 0; i < delays.Length; i++)
|
||||
|
||||
@@ -18,8 +18,9 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
ToggleMode = true;
|
||||
|
||||
var hBox = new HBoxContainer
|
||||
var hBox = new BoxContainer
|
||||
{
|
||||
Orientation = BoxContainer.LayoutOrientation.Horizontal,
|
||||
StyleClasses = { StyleClassCheckBox },
|
||||
};
|
||||
AddChild(hBox);
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Robust.Shared.Maths;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
@@ -13,9 +14,9 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
private readonly List<Menu> _menus = new();
|
||||
private readonly List<MenuBarTopButton> _buttons = new();
|
||||
private readonly HBoxContainer _hBox;
|
||||
private readonly BoxContainer _hBox;
|
||||
private readonly Popup _popup;
|
||||
private readonly VBoxContainer _popupVBox;
|
||||
private readonly BoxContainer _popupVBox;
|
||||
private bool _popupOpen;
|
||||
|
||||
public IList<Menu> Menus { get; }
|
||||
@@ -26,13 +27,21 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
Children =
|
||||
{
|
||||
(_popupVBox = new VBoxContainer {MinSize = (300, 0)})
|
||||
(_popupVBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
MinSize = (300, 0)
|
||||
})
|
||||
}
|
||||
};
|
||||
_popup.OnPopupHide += PopupHidden;
|
||||
UserInterfaceManager.ModalRoot.AddChild(_popup);
|
||||
Menus = new MenuCollection(this);
|
||||
AddChild(_hBox = new HBoxContainer {SeparationOverride = 8});
|
||||
AddChild(_hBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
SeparationOverride = 8
|
||||
});
|
||||
}
|
||||
|
||||
private void AddMenu(Menu menu)
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Maths;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
@@ -20,7 +21,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
// map from key to buttondata index
|
||||
private Dictionary<TKey, int> _keyMap = new();
|
||||
private readonly Popup _popup;
|
||||
private readonly VBoxContainer _popupVBox;
|
||||
private readonly BoxContainer _popupVBox;
|
||||
private readonly Label _label;
|
||||
|
||||
public event Action<ItemPressedEventArgs>? OnItemSelected;
|
||||
@@ -60,11 +61,17 @@ namespace Robust.Client.UserInterface.Controls
|
||||
AddStyleClass(StyleClassButton);
|
||||
OnPressed += OnPressedInternal;
|
||||
|
||||
var hBox = new HBoxContainer();
|
||||
var hBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal
|
||||
};
|
||||
AddChild(hBox);
|
||||
|
||||
_popup = new Popup();
|
||||
_popupVBox = new VBoxContainer();
|
||||
_popupVBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical
|
||||
};
|
||||
_popup.AddChild(_popupVBox);
|
||||
_popup.OnPopupHide += OnPopupHide;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Maths;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
@@ -13,7 +14,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
private readonly List<ButtonData> _buttonData = new();
|
||||
private readonly Dictionary<int, int> _idMap = new();
|
||||
private readonly Popup _popup;
|
||||
private readonly VBoxContainer _popupVBox;
|
||||
private readonly BoxContainer _popupVBox;
|
||||
private readonly Label _label;
|
||||
private readonly TextureRect _triangle;
|
||||
|
||||
@@ -49,11 +50,17 @@ namespace Robust.Client.UserInterface.Controls
|
||||
Prefix = "";
|
||||
OnPressed += OnPressedInternal;
|
||||
|
||||
var hBox = new HBoxContainer();
|
||||
var hBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal
|
||||
};
|
||||
AddChild(hBox);
|
||||
|
||||
_popup = new Popup();
|
||||
_popupVBox = new VBoxContainer();
|
||||
_popupVBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical
|
||||
};
|
||||
_popup.AddChild(_popupVBox);
|
||||
_popup.OnPopupHide += OnPopupHide;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using static Robust.Client.UserInterface.Controls.BaseButton;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
@@ -34,11 +35,17 @@ namespace Robust.Client.UserInterface.Controls
|
||||
switch (layout)
|
||||
{
|
||||
case RadioOptionsLayout.Vertical:
|
||||
_container = new VBoxContainer();
|
||||
_container = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical
|
||||
};
|
||||
break;
|
||||
case RadioOptionsLayout.Horizontal:
|
||||
default:
|
||||
_container = new HBoxContainer();
|
||||
_container = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Control xmlns="https://spacestation14.io"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics">
|
||||
<VBoxContainer>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<OutputPanel Name="Output" VerticalExpand="True">
|
||||
<OutputPanel.StyleBoxOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#25252add"
|
||||
@@ -9,5 +9,5 @@
|
||||
</OutputPanel.StyleBoxOverride>
|
||||
</OutputPanel>
|
||||
<HistoryLineEdit Name="CommandBar" PlaceHolder="{Loc 'console-line-edit-placeholder'}" />
|
||||
</VBoxContainer>
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
|
||||
@@ -12,6 +12,7 @@ using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
@@ -21,7 +22,7 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
private readonly IPrototypeManager prototypeManager;
|
||||
private readonly IResourceCache resourceCache;
|
||||
|
||||
private VBoxContainer MainVBox;
|
||||
private BoxContainer MainVBox;
|
||||
private PrototypeListContainer PrototypeList;
|
||||
private LineEdit SearchBar;
|
||||
private OptionButton OverrideMenu;
|
||||
@@ -71,13 +72,15 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
SetSize = (250, 300);
|
||||
MinSize = (250, 200);
|
||||
|
||||
Contents.AddChild(MainVBox = new VBoxContainer
|
||||
Contents.AddChild(MainVBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
Name = "AAAAAA",
|
||||
Children =
|
||||
{
|
||||
new HBoxContainer
|
||||
new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
Children =
|
||||
{
|
||||
(SearchBar = new LineEdit
|
||||
@@ -102,8 +105,9 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
(PrototypeList = new PrototypeListContainer())
|
||||
}
|
||||
},
|
||||
new HBoxContainer
|
||||
new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
Children =
|
||||
{
|
||||
(EraseButton = new Button
|
||||
@@ -472,8 +476,9 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
ToggleMode = true,
|
||||
});
|
||||
|
||||
AddChild(new HBoxContainer
|
||||
AddChild(new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
Children =
|
||||
{
|
||||
(EntityTextureRects = new LayeredTextureRect
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
}
|
||||
|
||||
var fps = _gameTiming.FramesPerSecondAvg;
|
||||
Text = $"FPS: {fps:N1}";
|
||||
Text = $"FPS: {fps:N0}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<SS14Window xmlns="https://spacestation14.io" MinWidth="100" MinHeight="50">
|
||||
<PanelContainer StyleClasses="windowPanel" />
|
||||
<VBoxContainer SeparationOverride="0">
|
||||
<BoxContainer Orientation="Vertical" SeparationOverride="0">
|
||||
<PanelContainer Name="WindowHeader" StyleClasses="windowHeader">
|
||||
<HBoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Margin="5 0 0 0" HorizontalExpand="true" Name="TitleLabel" StyleIdentifier="foo" ClipText="True"
|
||||
Text="{Loc 'ss14window-placeholder-title'}" VAlign="Center" StyleClasses="windowTitle" />
|
||||
<TextureButton Name="CloseButton" StyleClasses="windowCloseButton" VerticalAlignment="Center" />
|
||||
</HBoxContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
<Control Name="ContentsContainer" Margin="10" RectClipContent="True" VerticalExpand="true" />
|
||||
</VBoxContainer>
|
||||
</BoxContainer>
|
||||
</SS14Window>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
@@ -12,8 +13,9 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
|
||||
protected ScriptConsole()
|
||||
{
|
||||
Contents.AddChild(new VBoxContainer
|
||||
Contents.AddChild(new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
Children =
|
||||
{
|
||||
new PanelContainer
|
||||
@@ -29,8 +31,9 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
},
|
||||
VerticalExpand = true,
|
||||
},
|
||||
new HBoxContainer
|
||||
new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
Children =
|
||||
{
|
||||
(InputBar = new HistoryLineEdit
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
using Robust.Shared.Enums;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Placement;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
@@ -32,9 +35,15 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
_placementManager = placementManager;
|
||||
_resourceCache = resourceCache;
|
||||
|
||||
var vBox = new VBoxContainer();
|
||||
var vBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical
|
||||
};
|
||||
Contents.AddChild(vBox);
|
||||
var hBox = new HBoxContainer();
|
||||
var hBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal
|
||||
};
|
||||
vBox.AddChild(hBox);
|
||||
SearchBar = new LineEdit {PlaceHolder = "Search", HorizontalExpand = true};
|
||||
SearchBar.OnTextChanged += OnSearchBarTextChanged;
|
||||
@@ -105,7 +114,7 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
Texture? texture = null;
|
||||
if (!string.IsNullOrEmpty(entry.SpriteName))
|
||||
{
|
||||
texture = _resourceCache.GetResource<TextureResource>($"/Textures/Constructible/Tiles/{entry.SpriteName}.png");
|
||||
texture = _resourceCache.GetResource<TextureResource>(new ResourcePath(entry.Path) / $"{entry.SpriteName}.png");
|
||||
}
|
||||
TileList.AddItem(entry.DisplayName, texture);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Globalization;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.ViewVariables.Editors
|
||||
{
|
||||
@@ -9,8 +10,9 @@ namespace Robust.Client.ViewVariables.Editors
|
||||
{
|
||||
protected override Control MakeUI(object? value)
|
||||
{
|
||||
var hBox = new HBoxContainer
|
||||
var hBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
MinSize = new Vector2(200, 0)
|
||||
};
|
||||
var angle = (Angle) value!;
|
||||
|
||||
@@ -5,6 +5,7 @@ using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.ViewVariables.Editors
|
||||
{
|
||||
@@ -13,8 +14,9 @@ namespace Robust.Client.ViewVariables.Editors
|
||||
protected override Control MakeUI(object? value)
|
||||
{
|
||||
var coords = (EntityCoordinates) value!;
|
||||
var hBoxContainer = new HBoxContainer
|
||||
var hBoxContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
MinSize = new Vector2(240, 0),
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.ViewVariables.Editors
|
||||
{
|
||||
@@ -9,8 +10,9 @@ namespace Robust.Client.ViewVariables.Editors
|
||||
{
|
||||
protected override Control MakeUI(object? value)
|
||||
{
|
||||
var hBox = new HBoxContainer
|
||||
var hBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
MinSize = new Vector2(200, 0)
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.ViewVariables.Editors
|
||||
{
|
||||
@@ -20,7 +21,11 @@ namespace Robust.Client.ViewVariables.Editors
|
||||
{
|
||||
_localValue = value;
|
||||
|
||||
var hbox = new HBoxContainer() { HorizontalExpand = true };
|
||||
var hbox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
HorizontalExpand = true
|
||||
};
|
||||
|
||||
_lineEdit = new LineEdit()
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.ViewVariables.Editors
|
||||
{
|
||||
@@ -20,7 +21,10 @@ namespace Robust.Client.ViewVariables.Editors
|
||||
|
||||
protected override Control MakeUI(object? value)
|
||||
{
|
||||
var hBox = new HBoxContainer();
|
||||
var hBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal
|
||||
};
|
||||
|
||||
dynamic d = value!;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Globalization;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.ViewVariables.Editors
|
||||
{
|
||||
@@ -17,8 +18,9 @@ namespace Robust.Client.ViewVariables.Editors
|
||||
|
||||
protected override Control MakeUI(object? value)
|
||||
{
|
||||
var hBoxContainer = new HBoxContainer
|
||||
var hBoxContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
MinSize = new Vector2(200, 0),
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Globalization;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.ViewVariables.Editors
|
||||
{
|
||||
@@ -16,8 +17,9 @@ namespace Robust.Client.ViewVariables.Editors
|
||||
|
||||
protected override Control MakeUI(object? value)
|
||||
{
|
||||
var hBoxContainer = new HBoxContainer
|
||||
var hBoxContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
MinSize = new Vector2(240, 0),
|
||||
};
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Robust.Client.UserInterface.Control;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
using static Robust.Client.UserInterface.Controls.LineEdit;
|
||||
|
||||
namespace Robust.Client.ViewVariables.Instances
|
||||
@@ -48,10 +49,10 @@ namespace Robust.Client.ViewVariables.Instances
|
||||
|
||||
private ViewVariablesBlobMembers? _membersBlob;
|
||||
|
||||
private VBoxContainer _clientComponents = default!;
|
||||
private BoxContainer _clientComponents = default!;
|
||||
|
||||
private VBoxContainer _serverVariables = default!;
|
||||
private VBoxContainer _serverComponents = default!;
|
||||
private BoxContainer _serverVariables = default!;
|
||||
private BoxContainer _serverComponents = default!;
|
||||
|
||||
private Button _clientComponentsAddButton = default!;
|
||||
private Button _serverComponentsAddButton = default!;
|
||||
@@ -73,7 +74,10 @@ namespace Robust.Client.ViewVariables.Instances
|
||||
var scrollContainer = new ScrollContainer();
|
||||
//scrollContainer.SetAnchorPreset(Control.LayoutPreset.Wide, true);
|
||||
window.Contents.AddChild(scrollContainer);
|
||||
var vBoxContainer = new VBoxContainer();
|
||||
var vBoxContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical
|
||||
};
|
||||
scrollContainer.AddChild(vBoxContainer);
|
||||
|
||||
// Handle top bar displaying type and ToString().
|
||||
@@ -84,7 +88,11 @@ namespace Robust.Client.ViewVariables.Instances
|
||||
{
|
||||
//var smallFont = new VectorFont(_resourceCache.GetResource<FontResource>("/Fonts/CALIBRI.TTF"), 10);
|
||||
// Custom ToString() implementation.
|
||||
var headBox = new VBoxContainer {SeparationOverride = 0};
|
||||
var headBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
SeparationOverride = 0
|
||||
};
|
||||
headBox.AddChild(new Label {Text = stringified, ClipText = true});
|
||||
headBox.AddChild(new Label
|
||||
{
|
||||
@@ -102,7 +110,10 @@ namespace Robust.Client.ViewVariables.Instances
|
||||
|
||||
if (_entity.TryGetComponent(out ISpriteComponent? sprite))
|
||||
{
|
||||
var hBox = new HBoxContainer();
|
||||
var hBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal
|
||||
};
|
||||
top.HorizontalExpand = true;
|
||||
hBox.AddChild(top);
|
||||
hBox.AddChild(new SpriteView {Sprite = sprite});
|
||||
@@ -118,7 +129,11 @@ namespace Robust.Client.ViewVariables.Instances
|
||||
_tabs.OnTabChanged += _tabsOnTabChanged;
|
||||
vBoxContainer.AddChild(_tabs);
|
||||
|
||||
var clientVBox = new VBoxContainer {SeparationOverride = 0};
|
||||
var clientVBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
SeparationOverride = 0
|
||||
};
|
||||
_tabs.AddChild(clientVBox);
|
||||
_tabs.SetTabTitle(TabClientVars, Loc.GetString("view-variable-instance-entity-client-variables-tab-title"));
|
||||
|
||||
@@ -136,7 +151,11 @@ namespace Robust.Client.ViewVariables.Instances
|
||||
}
|
||||
}
|
||||
|
||||
_clientComponents = new VBoxContainer {SeparationOverride = 0};
|
||||
_clientComponents = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
SeparationOverride = 0
|
||||
};
|
||||
_tabs.AddChild(_clientComponents);
|
||||
_tabs.SetTabTitle(TabClientComponents, Loc.GetString("view-variable-instance-entity-client-components-tab-title"));
|
||||
|
||||
@@ -144,11 +163,19 @@ namespace Robust.Client.ViewVariables.Instances
|
||||
|
||||
if (!_entity.Uid.IsClientSide())
|
||||
{
|
||||
_serverVariables = new VBoxContainer {SeparationOverride = 0};
|
||||
_serverVariables = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
SeparationOverride = 0
|
||||
};
|
||||
_tabs.AddChild(_serverVariables);
|
||||
_tabs.SetTabTitle(TabServerVars, Loc.GetString("view-variable-instance-entity-server-variables-tab-title"));
|
||||
|
||||
_serverComponents = new VBoxContainer {SeparationOverride = 0};
|
||||
_serverComponents = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
SeparationOverride = 0
|
||||
};
|
||||
_tabs.AddChild(_serverComponents);
|
||||
_tabs.SetTabTitle(TabServerComponents, Loc.GetString("view-variable-instance-entity-server-components-tab-title"));
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ using Robust.Shared.Input;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Robust.Shared.Utility;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
using Timer = Robust.Shared.Timing.Timer;
|
||||
|
||||
namespace Robust.Client.ViewVariables.Instances
|
||||
@@ -64,8 +65,9 @@ namespace Robust.Client.ViewVariables.Instances
|
||||
var scrollContainer = new ScrollContainer();
|
||||
//scrollContainer.SetAnchorPreset(Control.LayoutPreset.Wide, true);
|
||||
window.Contents.AddChild(scrollContainer);
|
||||
var vBoxContainer = new VBoxContainer
|
||||
var vBoxContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
HorizontalExpand = true,
|
||||
VerticalExpand = true,
|
||||
};
|
||||
@@ -73,7 +75,10 @@ namespace Robust.Client.ViewVariables.Instances
|
||||
|
||||
// Handle top bar.
|
||||
{
|
||||
var headBox = new HBoxContainer();
|
||||
var headBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal
|
||||
};
|
||||
var name = MakeTopBar(top, bottom);
|
||||
name.HorizontalExpand = true;
|
||||
headBox.AddChild(name);
|
||||
|
||||
@@ -10,6 +10,7 @@ using Robust.Client.ViewVariables.Editors;
|
||||
using Robust.Client.ViewVariables.Instances;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.ViewVariables.Traits
|
||||
{
|
||||
@@ -25,8 +26,8 @@ namespace Robust.Client.ViewVariables.Traits
|
||||
private Button _leftButton = default!;
|
||||
private Button _rightButton = default!;
|
||||
private LineEdit _pageLabel = default!;
|
||||
private HBoxContainer _controlsHBox = default!;
|
||||
private VBoxContainer _elementsVBox = default!;
|
||||
private BoxContainer _controlsHBox = default!;
|
||||
private BoxContainer _elementsVBox = default!;
|
||||
|
||||
private int HighestKnownPage => Math.Max(0, ((_cache.Count + ElementsPerPage - 1) / ElementsPerPage) - 1);
|
||||
|
||||
@@ -47,9 +48,13 @@ namespace Robust.Client.ViewVariables.Traits
|
||||
_enumerator = enumerable.GetEnumerator();
|
||||
}
|
||||
|
||||
var outerVBox = new VBoxContainer();
|
||||
_controlsHBox = new HBoxContainer
|
||||
var outerVBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical
|
||||
};
|
||||
_controlsHBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
HorizontalAlignment = Control.HAlignment.Center
|
||||
};
|
||||
|
||||
@@ -70,7 +75,10 @@ namespace Robust.Client.ViewVariables.Traits
|
||||
|
||||
outerVBox.AddChild(_controlsHBox);
|
||||
|
||||
_elementsVBox = new VBoxContainer();
|
||||
_elementsVBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical
|
||||
};
|
||||
outerVBox.AddChild(_elementsVBox);
|
||||
|
||||
instance.AddTab("IEnumerable", outerVBox);
|
||||
|
||||
@@ -5,6 +5,7 @@ using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.ViewVariables.Traits
|
||||
{
|
||||
@@ -13,12 +14,16 @@ namespace Robust.Client.ViewVariables.Traits
|
||||
private readonly IViewVariablesManagerInternal _vvm;
|
||||
private readonly IRobustSerializer _robustSerializer;
|
||||
|
||||
private VBoxContainer _memberList = default!;
|
||||
private BoxContainer _memberList = default!;
|
||||
|
||||
public override void Initialize(ViewVariablesInstanceObject instance)
|
||||
{
|
||||
base.Initialize(instance);
|
||||
_memberList = new VBoxContainer {SeparationOverride = 0};
|
||||
_memberList = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
SeparationOverride = 0
|
||||
};
|
||||
instance.AddTab("Members", _memberList);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<cc:SS14Window xmlns:cc="clr-namespace:Robust.Client.UserInterface.CustomControls"
|
||||
xmlns:c="clr-namespace:Robust.Client.UserInterface.Controls">
|
||||
<c:VBoxContainer VerticalExpand="True">
|
||||
<c:BoxContainer Orientation="Vertical" VerticalExpand="True">
|
||||
<c:LineEdit Name="SearchLineEdit" PlaceHolder="Search..." HorizontalExpand="True" />
|
||||
<c:ItemList Name="EntryItemList" VerticalExpand="True" HorizontalExpand="True" SelectMode="Single" />
|
||||
<c:Button Name="AddButton" Text="Select" TextAlign="Center" HorizontalExpand="True"/>
|
||||
</c:VBoxContainer>
|
||||
</c:BoxContainer>
|
||||
</cc:SS14Window>
|
||||
|
||||
@@ -9,6 +9,7 @@ using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.ViewVariables
|
||||
{
|
||||
@@ -126,7 +127,11 @@ namespace Robust.Client.ViewVariables
|
||||
// 10);
|
||||
|
||||
// Custom ToString() implementation.
|
||||
var headBox = new VBoxContainer {SeparationOverride = 0};
|
||||
var headBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
SeparationOverride = 0
|
||||
};
|
||||
headBox.AddChild(new Label {Text = top, ClipText = true});
|
||||
headBox.AddChild(new Label
|
||||
{
|
||||
|
||||
@@ -8,14 +8,15 @@ using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.Client.ViewVariables
|
||||
{
|
||||
internal class ViewVariablesPropertyControl : PanelContainer
|
||||
{
|
||||
public VBoxContainer VBox { get; }
|
||||
public HBoxContainer TopContainer { get; }
|
||||
public HBoxContainer BottomContainer { get; }
|
||||
public BoxContainer VBox { get; }
|
||||
public BoxContainer TopContainer { get; }
|
||||
public BoxContainer BottomContainer { get; }
|
||||
public Label NameLabel { get; }
|
||||
|
||||
private readonly Label _bottomLabel;
|
||||
@@ -34,14 +35,23 @@ namespace Robust.Client.ViewVariables
|
||||
ToolTip = "Click to expand";
|
||||
MinHeight = 25;
|
||||
|
||||
VBox = new VBoxContainer {SeparationOverride = 0};
|
||||
VBox = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
SeparationOverride = 0
|
||||
};
|
||||
AddChild(VBox);
|
||||
|
||||
TopContainer = new HBoxContainer {VerticalExpand = true};
|
||||
TopContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
VerticalExpand = true
|
||||
};
|
||||
VBox.AddChild(TopContainer);
|
||||
|
||||
BottomContainer = new HBoxContainer
|
||||
BottomContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
Visible = false
|
||||
};
|
||||
VBox.AddChild(BottomContainer);
|
||||
|
||||
@@ -94,10 +94,6 @@ namespace Robust.Server
|
||||
private ILogHandler? _logHandler;
|
||||
private IGameLoop _mainLoop = default!;
|
||||
|
||||
private TimeSpan _lastTitleUpdate;
|
||||
private long _lastReceivedBytes;
|
||||
private long _lastSentBytes;
|
||||
|
||||
private string? _shutdownReason;
|
||||
|
||||
private readonly ManualResetEventSlim _shutdownEvent = new(false);
|
||||
@@ -515,28 +511,6 @@ namespace Robust.Server
|
||||
_mainLoop = gameLoop;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the console window title with performance statistics.
|
||||
/// </summary>
|
||||
private void UpdateTitle()
|
||||
{
|
||||
if (!Environment.UserInteractive || System.Console.IsInputRedirected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// every 1 second update stats in the console window title
|
||||
if ((_time.RealTime - _lastTitleUpdate).TotalSeconds < 1.0)
|
||||
return;
|
||||
|
||||
var netStats = UpdateBps();
|
||||
System.Console.Title = string.Format("FPS: {0:N2} SD: {1:N2}ms | Net: ({2}) | Memory: {3:N0} KiB",
|
||||
Math.Round(_time.FramesPerSecondAvg, 2),
|
||||
_time.RealFrameTimeStdDev.TotalMilliseconds,
|
||||
netStats,
|
||||
Process.GetCurrentProcess().PrivateMemorySize64 >> 10);
|
||||
_lastTitleUpdate = _time.RealTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the server settings from the ConfigurationManager.
|
||||
@@ -593,22 +567,9 @@ namespace Robust.Server
|
||||
}
|
||||
}
|
||||
|
||||
private string UpdateBps()
|
||||
{
|
||||
var stats = IoCManager.Resolve<IServerNetManager>().Statistics;
|
||||
|
||||
var bps =
|
||||
$"Send: {(stats.SentBytes - _lastSentBytes) >> 10:N0} KiB/s, Recv: {(stats.ReceivedBytes - _lastReceivedBytes) >> 10:N0} KiB/s";
|
||||
|
||||
_lastSentBytes = stats.SentBytes;
|
||||
_lastReceivedBytes = stats.ReceivedBytes;
|
||||
|
||||
return bps;
|
||||
}
|
||||
|
||||
private void Input(FrameEventArgs args)
|
||||
{
|
||||
_systemConsole.Update();
|
||||
_systemConsole.UpdateInput();
|
||||
|
||||
_network.ProcessPackets();
|
||||
_taskManager.ProcessPendingTasks();
|
||||
@@ -622,7 +583,7 @@ namespace Robust.Server
|
||||
// These are always the same on the server, there is no prediction.
|
||||
_time.LastRealTick = _time.CurTick;
|
||||
|
||||
UpdateTitle();
|
||||
_systemConsole.UpdateTick();
|
||||
|
||||
using (TickUsage.WithLabels("PreEngine").NewTimer())
|
||||
{
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
/// <summary>
|
||||
/// process input/output of the console. This needs to be called often.
|
||||
/// </summary>
|
||||
void Update();
|
||||
void UpdateInput();
|
||||
|
||||
/// <summary>
|
||||
/// Prints <paramref name="text" /> to the system console.
|
||||
/// </summary>
|
||||
/// <param name="text">Text to write to the system console.</param>
|
||||
void Print(string text);
|
||||
|
||||
void UpdateTick();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace Robust.Server.Console
|
||||
[Dependency] private readonly IPlayerManager _players = default!;
|
||||
[Dependency] private readonly ISystemConsoleManager _systemConsole = default!;
|
||||
|
||||
public override event ConAnyCommandCallback? AnyCommandExecuted;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ExecuteCommand(ICommonSession? session, string command)
|
||||
{
|
||||
@@ -87,20 +89,22 @@ namespace Robust.Server.Console
|
||||
|
||||
if (AvailableCommands.TryGetValue(cmdName, out var conCmd)) // command registered
|
||||
{
|
||||
args.RemoveAt(0);
|
||||
var cmdArgs = args.ToArray();
|
||||
if (shell.Player != null) // remote client
|
||||
{
|
||||
if (_groupController.CanCommand((IPlayerSession) shell.Player, cmdName)) // client has permission
|
||||
{
|
||||
args.RemoveAt(0);
|
||||
conCmd.Execute(shell, command, args.ToArray());
|
||||
AnyCommandExecuted?.Invoke(shell, cmdName, command, cmdArgs);
|
||||
conCmd.Execute(shell, command, cmdArgs);
|
||||
}
|
||||
else
|
||||
shell.WriteError($"Unknown command: '{cmdName}'");
|
||||
}
|
||||
else // system console
|
||||
{
|
||||
args.RemoveAt(0);
|
||||
conCmd.Execute(shell, command, args.ToArray());
|
||||
AnyCommandExecuted?.Invoke(shell, cmdName, command, cmdArgs);
|
||||
conCmd.Execute(shell, command, cmdArgs);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Robust.Shared.Asynchronous;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using Con = System.Console;
|
||||
|
||||
namespace Robust.Server.Console
|
||||
@@ -12,6 +16,12 @@ namespace Robust.Server.Console
|
||||
[Dependency] private readonly IServerConsoleHost _conShell = default!;
|
||||
[Dependency] private readonly ITaskManager _taskManager = default!;
|
||||
[Dependency] private readonly IBaseServer _baseServer = default!;
|
||||
[Dependency] private readonly IServerNetManager _netManager = default!;
|
||||
[Dependency] private readonly IGameTiming _time = default!;
|
||||
|
||||
//
|
||||
// Command entry stuff.
|
||||
//
|
||||
|
||||
private readonly Dictionary<int, string> commandHistory = new();
|
||||
private string currentBuffer = "";
|
||||
@@ -21,6 +31,20 @@ namespace Robust.Server.Console
|
||||
private int tabCompleteIndex;
|
||||
private ConsoleKey lastKeyPressed = ConsoleKey.NoName;
|
||||
|
||||
//
|
||||
// Title update stuff.
|
||||
//
|
||||
|
||||
// This is ridiculously expensive to fetch for some reason.
|
||||
// I'm gonna just assume that this can't change during the lifetime of the process. I hope.
|
||||
// I want this ridiculous 0.1% CPU usage off my profiler.
|
||||
private readonly bool _userInteractive = Environment.UserInteractive;
|
||||
|
||||
private TimeSpan _lastTitleUpdate;
|
||||
private long _lastReceivedBytes;
|
||||
private long _lastSentBytes;
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Environment.UserInteractive)
|
||||
@@ -37,7 +61,50 @@ namespace Robust.Server.Console
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
public void UpdateTick()
|
||||
{
|
||||
UpdateTitle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the console window title with performance statistics.
|
||||
/// </summary>
|
||||
private void UpdateTitle()
|
||||
{
|
||||
if (!_userInteractive || System.Console.IsInputRedirected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// every 1 second update stats in the console window title
|
||||
if ((_time.RealTime - _lastTitleUpdate).TotalSeconds < 1.0)
|
||||
return;
|
||||
|
||||
var netStats = UpdateBps();
|
||||
var privateSize = Process.GetCurrentProcess().GetPrivateMemorySize64NotSlowHolyFuckingShitMicrosoft();
|
||||
|
||||
System.Console.Title = string.Format("FPS: {0:N2} SD: {1:N2}ms | Net: ({2}) | Memory: {3:N0} KiB",
|
||||
Math.Round(_time.FramesPerSecondAvg, 2),
|
||||
_time.RealFrameTimeStdDev.TotalMilliseconds,
|
||||
netStats,
|
||||
privateSize >> 10);
|
||||
_lastTitleUpdate = _time.RealTime;
|
||||
}
|
||||
|
||||
private string UpdateBps()
|
||||
{
|
||||
var stats = _netManager.Statistics;
|
||||
|
||||
var bps =
|
||||
$"Send: {(stats.SentBytes - _lastSentBytes) >> 10:N0} KiB/s, Recv: {(stats.ReceivedBytes - _lastReceivedBytes) >> 10:N0} KiB/s";
|
||||
|
||||
_lastSentBytes = stats.SentBytes;
|
||||
_lastReceivedBytes = stats.ReceivedBytes;
|
||||
|
||||
return bps;
|
||||
}
|
||||
|
||||
public void UpdateInput()
|
||||
{
|
||||
if (Con.IsInputRedirected)
|
||||
{
|
||||
@@ -161,7 +228,7 @@ namespace Robust.Server.Console
|
||||
{
|
||||
var currentLineCursor = Con.CursorTop;
|
||||
Con.SetCursorPosition(0, Con.CursorTop);
|
||||
Con.Write(new string(' ', Con.WindowWidth-1));
|
||||
Con.Write(new string(' ', Con.WindowWidth - 1));
|
||||
Con.SetCursorPosition(0, currentLineCursor);
|
||||
}
|
||||
|
||||
@@ -174,7 +241,8 @@ namespace Robust.Server.Console
|
||||
|
||||
if (tabCompleteList.Count == 0)
|
||||
{
|
||||
tabCompleteList = _conShell.RegisteredCommands.Keys.Where(key => key.StartsWith(currentBuffer)).ToList();
|
||||
tabCompleteList = _conShell.RegisteredCommands.Keys.Where(key => key.StartsWith(currentBuffer))
|
||||
.ToList();
|
||||
if (tabCompleteList.Count == 0)
|
||||
{
|
||||
return String.Empty;
|
||||
|
||||
@@ -2,7 +2,7 @@ namespace Robust.Server.Console
|
||||
{
|
||||
internal sealed class SystemConsoleManagerDummy : ISystemConsoleManager
|
||||
{
|
||||
public void Update()
|
||||
public void UpdateInput()
|
||||
{
|
||||
// Nada.
|
||||
}
|
||||
@@ -11,5 +11,10 @@ namespace Robust.Server.Console
|
||||
{
|
||||
// Nada.
|
||||
}
|
||||
|
||||
public void UpdateTick()
|
||||
{
|
||||
// Nada.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
Robust.Server/Containers/ContainerSystem.cs
Normal file
10
Robust.Server/Containers/ContainerSystem.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
namespace Robust.Server.Containers
|
||||
{
|
||||
public class ContainerSystem : SharedContainerSystem
|
||||
{
|
||||
// Seems like shared EntitySystems aren't registered, so this is here to register it on the server.
|
||||
// Registering the SharedContainerSystem causes conflicts on client where two entity systems are registered.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
[RegisterComponent]
|
||||
internal class ViewSubscriberComponent : Component
|
||||
{
|
||||
public override string Name => "ViewSubscriber";
|
||||
|
||||
internal readonly HashSet<IPlayerSession> SubscribedSessions = new();
|
||||
}
|
||||
}
|
||||
@@ -141,7 +141,7 @@ namespace Robust.Server.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
public uint _renderOrder;
|
||||
private uint _renderOrder;
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public uint RenderOrder
|
||||
{
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity System that handles subscribing and unsubscribing to PVS views.
|
||||
/// </summary>
|
||||
public class ViewSubscriberSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ViewSubscriberComponent, ComponentShutdown>(OnViewSubscriberShutdown);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes the session to get PVS updates from the point of view of the specified entity.
|
||||
/// </summary>
|
||||
public void AddViewSubscriber(EntityUid uid, IPlayerSession session)
|
||||
{
|
||||
// This will throw if you pass in an invalid uid.
|
||||
var entity = EntityManager.GetEntity(uid);
|
||||
|
||||
// If the entity doesn't have the component, it will be added.
|
||||
var viewSubscriber = entity.EnsureComponent<ViewSubscriberComponent>();
|
||||
|
||||
if (viewSubscriber.SubscribedSessions.Contains(session))
|
||||
return; // Already subscribed, do nothing else.
|
||||
|
||||
viewSubscriber.SubscribedSessions.Add(session);
|
||||
session.AddViewSubscription(uid);
|
||||
|
||||
RaiseLocalEvent(uid, new ViewSubscriberAddedEvent(entity, session));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes the session from getting PVS updates from the point of view of the specified entity.
|
||||
/// </summary>
|
||||
public void RemoveViewSubscriber(EntityUid uid, IPlayerSession session)
|
||||
{
|
||||
if(!ComponentManager.TryGetComponent(uid, out ViewSubscriberComponent? viewSubscriber))
|
||||
return; // Entity didn't have any subscriptions, do nothing.
|
||||
|
||||
if (!viewSubscriber.SubscribedSessions.Remove(session))
|
||||
return; // Session wasn't subscribed, do nothing.
|
||||
|
||||
session.RemoveViewSubscription(uid);
|
||||
RaiseLocalEvent(uid, new ViewSubscriberRemovedEvent(EntityManager.GetEntity(uid), session));
|
||||
}
|
||||
|
||||
private void OnViewSubscriberShutdown(EntityUid uid, ViewSubscriberComponent component, ComponentShutdown _)
|
||||
{
|
||||
foreach (var session in component.SubscribedSessions)
|
||||
{
|
||||
session.RemoveViewSubscription(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a session subscribes to an entity's PVS view.
|
||||
/// </summary>
|
||||
public class ViewSubscriberAddedEvent : EntityEventArgs
|
||||
{
|
||||
public IEntity View { get; }
|
||||
public IPlayerSession Subscriber { get; }
|
||||
|
||||
public ViewSubscriberAddedEvent(IEntity view, IPlayerSession subscriber)
|
||||
{
|
||||
View = view;
|
||||
Subscriber = subscriber;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a session is unsubscribed from an entity's PVS view.
|
||||
/// Not raised when sessions are unsubscribed due to the component being removed.
|
||||
/// </summary>
|
||||
public class ViewSubscriberRemovedEvent : EntityEventArgs
|
||||
{
|
||||
public IEntity View { get; }
|
||||
public IPlayerSession Subscriber { get; }
|
||||
|
||||
public ViewSubscriberRemovedEvent(IEntity view, IPlayerSession subscriber)
|
||||
{
|
||||
View = view;
|
||||
Subscriber = subscriber;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ namespace Robust.Server.GameObjects
|
||||
RegisterClass<CollisionWakeComponent>();
|
||||
RegisterClass<ContainerManagerComponent>();
|
||||
RegisterClass<OccluderComponent>();
|
||||
RegisterClass<OccluderTreeComponent>();
|
||||
RegisterClass<SpriteComponent>();
|
||||
RegisterClass<AppearanceComponent>();
|
||||
RegisterClass<SnapGridComponent>();
|
||||
|
||||
@@ -224,20 +224,32 @@ namespace Robust.Server.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
switch (message.Type)
|
||||
#if EXCEPTION_TOLERANCE
|
||||
try
|
||||
#endif
|
||||
{
|
||||
case EntityMessageType.ComponentMessage:
|
||||
ReceivedComponentMessage?.Invoke(this, new NetworkComponentMessage(message, player));
|
||||
return;
|
||||
switch (message.Type)
|
||||
{
|
||||
case EntityMessageType.ComponentMessage:
|
||||
ReceivedComponentMessage?.Invoke(this, new NetworkComponentMessage(message, player));
|
||||
return;
|
||||
|
||||
case EntityMessageType.SystemMessage:
|
||||
var msg = message.SystemMessage;
|
||||
var sessionType = typeof(EntitySessionMessage<>).MakeGenericType(msg.GetType());
|
||||
var sessionMsg = Activator.CreateInstance(sessionType, new EntitySessionEventArgs(player), msg)!;
|
||||
ReceivedSystemMessage?.Invoke(this, msg);
|
||||
ReceivedSystemMessage?.Invoke(this, sessionMsg);
|
||||
return;
|
||||
case EntityMessageType.SystemMessage:
|
||||
var msg = message.SystemMessage;
|
||||
var sessionType = typeof(EntitySessionMessage<>).MakeGenericType(msg.GetType());
|
||||
var sessionMsg =
|
||||
Activator.CreateInstance(sessionType, new EntitySessionEventArgs(player), msg)!;
|
||||
ReceivedSystemMessage?.Invoke(this, msg);
|
||||
ReceivedSystemMessage?.Invoke(this, sessionMsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#if EXCEPTION_TOLERANCE
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorS("net.ent", $"Caught exception while dispatching {message.Type}: {e}");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs args)
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -139,12 +140,15 @@ namespace Robust.Server.GameStates
|
||||
if (session.Status != SessionStatus.InGame || session.AttachedEntityUid is null)
|
||||
return viewers;
|
||||
|
||||
var query = _compMan.EntityQuery<ActorComponent>();
|
||||
viewers.Add(session.AttachedEntityUid.Value);
|
||||
|
||||
foreach (var actorComp in query)
|
||||
// This is awful, but we're not gonna add the list of view subscriptions to common session.
|
||||
if (session is not IPlayerSession playerSession)
|
||||
return viewers;
|
||||
|
||||
foreach (var uid in playerSession.ViewSubscriptions)
|
||||
{
|
||||
if (actorComp.PlayerSession == session)
|
||||
viewers.Add(actorComp.Owner.Uid);
|
||||
viewers.Add(uid);
|
||||
}
|
||||
|
||||
return viewers;
|
||||
@@ -276,8 +280,9 @@ namespace Robust.Server.GameStates
|
||||
if (_compMan.TryGetComponent<EyeComponent>(eyeEuid, out var eyeComp))
|
||||
visMask = eyeComp.VisibilityMask;
|
||||
|
||||
//Always include the map entity of the eye
|
||||
//TODO: Add Map entity here
|
||||
//Always include the map entity of the eye, if it exists.
|
||||
if(_mapManager.MapExists(mapId))
|
||||
visibleEnts.Add(_mapManager.GetMapEntityId(mapId));
|
||||
|
||||
//Always include viewable ent itself
|
||||
visibleEnts.Add(eyeEuid);
|
||||
|
||||
@@ -216,7 +216,7 @@ namespace Robust.Server.GameStates
|
||||
}
|
||||
catch (Exception e) // Catch EVERY exception
|
||||
{
|
||||
_logger.Log(LogLevel.Error, e, string.Empty);
|
||||
_logger.Log(LogLevel.Error, e, "Caught exception while generating mail.");
|
||||
}
|
||||
|
||||
var msg = _networkManager.CreateNetMessage<MsgState>();
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Physics;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.Core;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Broadphase;
|
||||
|
||||
namespace Robust.Server.Physics
|
||||
{
|
||||
internal sealed class BroadPhaseSystem : SharedBroadPhaseSystem
|
||||
internal sealed class BroadPhaseSystem : SharedBroadphaseSystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Broadphase;
|
||||
using Robust.Shared.Physics.Collision.Shapes;
|
||||
using Robust.Shared.Physics.Dynamics;
|
||||
|
||||
@@ -19,51 +15,18 @@ namespace Robust.Server.Physics
|
||||
internal sealed class GridFixtureSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly SharedBroadphaseSystem _broadphase = default!;
|
||||
|
||||
private SharedBroadPhaseSystem _broadphase = default!;
|
||||
|
||||
// Is delaying fixture updates a good idea? IDEK. We definitely can't do them on every tile changed
|
||||
// because if someone changes 50 tiles that will kill perf. We could probably just run it every Update
|
||||
// (and at specific times due to race condition stuff).
|
||||
// At any rate, cooldown given here if someone wants it. CD of 0 just runs it every tick.
|
||||
private float _cooldown;
|
||||
private float _accumulator;
|
||||
|
||||
private HashSet<MapChunk> _queuedChunks = new();
|
||||
/*
|
||||
* Currently we won't defer grid updates because content may alter a bunch of tiles then decide
|
||||
* to start anchroing entities for example.
|
||||
*/
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
UpdatesBefore.Add(typeof(PhysicsSystem));
|
||||
UpdatesBefore.Add(typeof(SharedBroadphaseSystem));
|
||||
SubscribeLocalEvent<RegenerateChunkCollisionEvent>(HandleCollisionRegenerate);
|
||||
_broadphase = Get<SharedBroadPhaseSystem>();
|
||||
|
||||
var configManager = IoCManager.Resolve<IConfigurationManager>();
|
||||
configManager.OnValueChanged(CVars.GridFixtureUpdateRate, value => _cooldown = value, true);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
_accumulator += frameTime;
|
||||
if (_accumulator < _cooldown) return;
|
||||
|
||||
_accumulator -= _cooldown;
|
||||
Process();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Go through every dirty chunk and re-generate their fixtures.
|
||||
/// </summary>
|
||||
public void Process()
|
||||
{
|
||||
foreach (var chunk in _queuedChunks)
|
||||
{
|
||||
RegenerateCollision(chunk);
|
||||
}
|
||||
|
||||
_queuedChunks.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -72,13 +35,7 @@ namespace Robust.Server.Physics
|
||||
/// <param name="ev"></param>
|
||||
private void HandleCollisionRegenerate(RegenerateChunkCollisionEvent ev)
|
||||
{
|
||||
if (_cooldown <= 0f)
|
||||
{
|
||||
RegenerateCollision(ev.Chunk);
|
||||
return;
|
||||
}
|
||||
|
||||
_queuedChunks.Add(ev.Chunk);
|
||||
RegenerateCollision(ev.Chunk);
|
||||
}
|
||||
|
||||
private void RegenerateCollision(MapChunk chunk)
|
||||
@@ -97,6 +54,14 @@ namespace Robust.Server.Physics
|
||||
var origin = chunk.Indices * chunk.ChunkSize;
|
||||
bounds = bounds.Translated(origin);
|
||||
|
||||
// So we store a reference to the fixture on the chunk because it's easier to cross-reference it.
|
||||
// This is because when we get multiple fixtures per chunk there's no easy way to tell which the old one
|
||||
// corresponds with.
|
||||
// We also ideally want to avoid re-creating the fixture every time a tile changes and pushing that data
|
||||
// to the client hence we diff it.
|
||||
|
||||
// Additionally, we need to handle map deserialization where content may have stored its own data
|
||||
// on the grid (e.g. mass) which we want to preserve.
|
||||
var oldFixture = chunk.Fixture;
|
||||
|
||||
var newFixture = new Fixture(
|
||||
@@ -112,16 +77,57 @@ namespace Robust.Server.Physics
|
||||
},
|
||||
MapGridHelpers.CollisionGroup,
|
||||
MapGridHelpers.CollisionGroup,
|
||||
true) {ID = $"grid-{grid.Index}_chunk-{chunk.Indices.X}-{chunk.Indices.Y}",
|
||||
true) {ID = $"grid_chunk-{chunk.Indices.X}-{chunk.Indices.Y}",
|
||||
Body = physicsComponent};
|
||||
|
||||
// TODO: Chunk will likely need multiple fixtures but future sloth problem lmao fucking dickhead
|
||||
if (oldFixture?.Equals(newFixture) == true) return;
|
||||
// Check if we have an existing fixture on MapGrid
|
||||
var existingFixture = physicsComponent.GetFixture(newFixture.ID);
|
||||
var same = true;
|
||||
|
||||
// Some fucky shit but we gotta handle map deserialization.
|
||||
if (existingFixture is {Shape: PolygonShape poly})
|
||||
{
|
||||
var newPoly = (PolygonShape) newFixture.Shape;
|
||||
|
||||
if (newPoly.Vertices.Count == poly.Vertices.Count)
|
||||
{
|
||||
for (var i = 0; i < poly.Vertices.Count; i++)
|
||||
{
|
||||
if (!poly.Vertices[i].EqualsApprox(newPoly.Vertices[i]))
|
||||
{
|
||||
same = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
same = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
same = false;
|
||||
}
|
||||
|
||||
// TODO: Chunk will likely need multiple fixtures but future sloth problem lmao idiot
|
||||
if (same)
|
||||
{
|
||||
// If we're deserializing map this can occur so just update it.
|
||||
if (oldFixture == null && existingFixture != null)
|
||||
{
|
||||
chunk.Fixture = existingFixture;
|
||||
existingFixture.CollisionMask = MapGridHelpers.CollisionGroup;
|
||||
existingFixture.CollisionLayer = MapGridHelpers.CollisionGroup;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldFixture != null)
|
||||
physicsComponent.RemoveFixture(oldFixture);
|
||||
_broadphase.DestroyFixture(physicsComponent, oldFixture);
|
||||
|
||||
physicsComponent.AddFixture(newFixture);
|
||||
_broadphase.CreateFixture(physicsComponent, newFixture);
|
||||
chunk.Fixture = newFixture;
|
||||
|
||||
EntityManager.EventBus.RaiseLocalEvent(gridEnt.Uid,new GridFixtureChangeEvent {OldFixture = oldFixture, NewFixture = newFixture});
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Players;
|
||||
@@ -32,6 +34,8 @@ namespace Robust.Server.Player
|
||||
void OnConnect();
|
||||
void OnDisconnect();
|
||||
|
||||
IReadOnlySet<EntityUid> ViewSubscriptions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Persistent data for this player.
|
||||
/// </summary>
|
||||
@@ -43,5 +47,17 @@ namespace Robust.Server.Player
|
||||
/// and <see cref="DetachFromEntity"/> instead.
|
||||
/// </summary>
|
||||
internal void SetAttachedEntity(IEntity? entity);
|
||||
|
||||
/// <summary>
|
||||
/// Internal method to add an entity Uid to <see cref="ViewSubscriptions"/>.
|
||||
/// Do NOT use this outside of <see cref="ViewSubscriberSystem"/>.
|
||||
/// </summary>
|
||||
internal void AddViewSubscription(EntityUid eye);
|
||||
|
||||
/// <summary>
|
||||
/// Internal method to remove an entity Uid from <see cref="ViewSubscriptions"/>.
|
||||
/// Do NOT use this outside of <see cref="ViewSubscriberSystem"/>.
|
||||
/// </summary>
|
||||
internal void RemoveViewSubscription(EntityUid eye);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -35,6 +36,8 @@ namespace Robust.Server.Player
|
||||
UpdatePlayerState();
|
||||
}
|
||||
|
||||
private readonly HashSet<EntityUid> _viewSubscriptions = new();
|
||||
|
||||
[ViewVariables] public INetChannel ConnectedClient { get; }
|
||||
|
||||
[ViewVariables] public IEntity? AttachedEntity { get; set; }
|
||||
@@ -104,6 +107,7 @@ namespace Robust.Server.Player
|
||||
public NetUserId UserId { get; }
|
||||
|
||||
private readonly PlayerData _data;
|
||||
|
||||
[ViewVariables] public IPlayerData Data => _data;
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -160,10 +164,13 @@ namespace Robust.Server.Player
|
||||
{
|
||||
Status = SessionStatus.Disconnected;
|
||||
|
||||
UnsubscribeAllViews();
|
||||
DetachFromEntity();
|
||||
UpdatePlayerState();
|
||||
}
|
||||
|
||||
public IReadOnlySet<EntityUid> ViewSubscriptions => _viewSubscriptions;
|
||||
|
||||
private void SetAttachedEntityName()
|
||||
{
|
||||
if (Name != null && AttachedEntity != null)
|
||||
@@ -193,6 +200,26 @@ namespace Robust.Server.Player
|
||||
UpdatePlayerState();
|
||||
}
|
||||
|
||||
void IPlayerSession.AddViewSubscription(EntityUid eye)
|
||||
{
|
||||
_viewSubscriptions.Add(eye);
|
||||
}
|
||||
|
||||
void IPlayerSession.RemoveViewSubscription(EntityUid eye)
|
||||
{
|
||||
_viewSubscriptions.Remove(eye);
|
||||
}
|
||||
|
||||
private void UnsubscribeAllViews()
|
||||
{
|
||||
var viewSubscriberSystem = EntitySystem.Get<ViewSubscriberSystem>();
|
||||
|
||||
foreach (var eye in _viewSubscriptions)
|
||||
{
|
||||
viewSubscriberSystem.RemoveViewSubscriber(eye, this);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePlayerState()
|
||||
{
|
||||
PlayerState.Status = Status;
|
||||
|
||||
@@ -19,6 +19,7 @@ using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Reflection;
|
||||
@@ -71,6 +72,7 @@ namespace Robust.Server
|
||||
IoCManager.Register<IScriptHost, ScriptHost>();
|
||||
IoCManager.Register<IMetricsManager, MetricsManager>();
|
||||
IoCManager.Register<IAuthManager, AuthManager>();
|
||||
IoCManager.Register<IPhysicsManager, PhysicsManager>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,9 @@ namespace Robust.Shared.Maths
|
||||
[Pure]
|
||||
public Vector2 RotateVec(in Vector2 vec)
|
||||
{
|
||||
// No calculation necessery when theta is zero
|
||||
if (Theta == 0) return vec;
|
||||
|
||||
var (x, y) = vec;
|
||||
var cos = Math.Cos(Theta);
|
||||
var sin = Math.Sin(Theta);
|
||||
|
||||
15
Robust.Shared/Analyzers/FriendAttribute.cs
Normal file
15
Robust.Shared/Analyzers/FriendAttribute.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace Robust.Shared.Analyzers
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct)]
|
||||
public class FriendAttribute : Attribute
|
||||
{
|
||||
public readonly Type[] Friends;
|
||||
|
||||
public FriendAttribute(params Type[] friends)
|
||||
{
|
||||
Friends = friends;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,7 +224,7 @@ namespace Robust.Shared
|
||||
/// outside of our viewport.
|
||||
/// </remarks>
|
||||
public static readonly CVarDef<float> MaxLightRadius =
|
||||
CVarDef.Create("light.max_radius", 20.0f, CVar.CLIENTONLY);
|
||||
CVarDef.Create("light.max_radius", 32.1f, CVar.CLIENTONLY);
|
||||
|
||||
/*
|
||||
* Lookup
|
||||
@@ -351,6 +351,13 @@ namespace Robust.Shared
|
||||
* PHYSICS
|
||||
*/
|
||||
|
||||
// - Contacts
|
||||
public static readonly CVarDef<int> ContactMultithreadThreshold =
|
||||
CVarDef.Create("physics.contact_multithread_threshold", 32);
|
||||
|
||||
public static readonly CVarDef<int> ContactMinimumThreads =
|
||||
CVarDef.Create("physics.contact_minimum_threads", 2);
|
||||
|
||||
// - Sleep
|
||||
public static readonly CVarDef<float> AngularSleepTolerance =
|
||||
CVarDef.Create("physics.angsleeptol", 2.0f / 180.0f * MathF.PI);
|
||||
@@ -366,8 +373,21 @@ namespace Robust.Shared
|
||||
CVarDef.Create("physics.timetosleep", 0.2f);
|
||||
|
||||
// - Solver
|
||||
public static readonly CVarDef<int> PositionConstraintsPerThread =
|
||||
CVarDef.Create("physics.position_constraints_per_thread", 32);
|
||||
|
||||
public static readonly CVarDef<int> PositionConstraintsMinimumThread =
|
||||
CVarDef.Create("physics.position_constraints_minimum_threads", 2);
|
||||
|
||||
public static readonly CVarDef<int> VelocityConstraintsPerThread =
|
||||
CVarDef.Create("physics.velocity_constraints_per_thread", 32);
|
||||
|
||||
public static readonly CVarDef<int> VelocityConstraintMinimumThreads =
|
||||
CVarDef.Create("physics.velocity_constraints_minimum_threads", 2);
|
||||
|
||||
// These are the minimum recommended by Box2D with the standard being 8 velocity 3 position iterations.
|
||||
// Trade-off is obviously performance vs how long it takes to stabilise.
|
||||
// PhysX opts for fewer velocity iterations and more position but they also have a different solver.
|
||||
public static readonly CVarDef<int> PositionIterations =
|
||||
CVarDef.Create("physics.positer", 3);
|
||||
|
||||
@@ -462,13 +482,6 @@ namespace Robust.Shared
|
||||
public static readonly CVarDef<float> MaxAngVelocity =
|
||||
CVarDef.Create("physics.maxangvelocity", 15f);
|
||||
|
||||
/// <summary>
|
||||
/// How frequently grid fixtures are updated. Given grid updates can be expensive they aren't run immediately.
|
||||
/// Set to 0 to run them immediately.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float> GridFixtureUpdateRate =
|
||||
CVarDef.Create("physics.grid_fixture_update_rate", 0.2f);
|
||||
|
||||
/*
|
||||
* DISCORD
|
||||
*/
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Robust.Shared.Configuration
|
||||
{
|
||||
// overwrite the value with the saved one
|
||||
cfgVar.Value = tomlValue;
|
||||
cfgVar.ValueChanged?.Invoke(cfgVar.Value);
|
||||
InvokeValueChanged(cfgVar, cfgVar.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -189,16 +189,13 @@ namespace Robust.Shared.Configuration
|
||||
public void RegisterCVar<T>(string name, T defaultValue, CVar flags = CVar.NONE, Action<T>? onValueChanged = null)
|
||||
where T : notnull
|
||||
{
|
||||
Action<object>? valueChangedDelegate = null;
|
||||
if (onValueChanged != null)
|
||||
{
|
||||
valueChangedDelegate = v => onValueChanged((T) v);
|
||||
}
|
||||
RegisterCVar(name, typeof(T), defaultValue, flags);
|
||||
|
||||
RegisterCVar(name, typeof(T), defaultValue, flags, valueChangedDelegate);
|
||||
if (onValueChanged != null)
|
||||
OnValueChanged(name, onValueChanged);
|
||||
}
|
||||
|
||||
private void RegisterCVar(string name, Type type, object defaultValue, CVar flags, Action<object>? onValueChanged)
|
||||
private void RegisterCVar(string name, Type type, object defaultValue, CVar flags)
|
||||
{
|
||||
DebugTools.Assert(!type.IsEnum || type.GetEnumUnderlyingType() == typeof(int),
|
||||
$"{name}: Enum cvars must have int as underlying type.");
|
||||
@@ -219,7 +216,6 @@ namespace Robust.Shared.Configuration
|
||||
cVar.DefaultValue = defaultValue;
|
||||
cVar.Flags = flags;
|
||||
cVar.Registered = true;
|
||||
cVar.ValueChanged = onValueChanged;
|
||||
|
||||
if (cVar.OverrideValue != null)
|
||||
{
|
||||
@@ -233,7 +229,6 @@ namespace Robust.Shared.Configuration
|
||||
{
|
||||
Registered = true,
|
||||
Value = defaultValue,
|
||||
ValueChanged = onValueChanged
|
||||
});
|
||||
}
|
||||
|
||||
@@ -247,7 +242,11 @@ namespace Robust.Shared.Configuration
|
||||
where T : notnull
|
||||
{
|
||||
var reg = _configVars[name];
|
||||
reg.ValueChanged += o => onValueChanged((T) o);
|
||||
var exDel = (Action<T>?) reg.ValueChanged;
|
||||
exDel += onValueChanged;
|
||||
reg.ValueChanged = exDel;
|
||||
|
||||
reg.ValueChangedInvoker ??= (del, v) => ((Action<T>) del)((T) v);
|
||||
|
||||
if (invokeImmediately)
|
||||
{
|
||||
@@ -255,6 +254,19 @@ namespace Robust.Shared.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
public void UnsubValueChanged<T>(CVarDef<T> cVar, Action<T> onValueChanged) where T : notnull
|
||||
{
|
||||
UnsubValueChanged(cVar.Name, onValueChanged);
|
||||
}
|
||||
|
||||
public void UnsubValueChanged<T>(string name, Action<T> onValueChanged) where T : notnull
|
||||
{
|
||||
var reg = _configVars[name];
|
||||
var exDel = (Action<T>?) reg.ValueChanged;
|
||||
exDel -= onValueChanged;
|
||||
reg.ValueChanged = exDel;
|
||||
}
|
||||
|
||||
public void LoadCVarsFromAssembly(Assembly assembly)
|
||||
{
|
||||
foreach (var defField in assembly
|
||||
@@ -282,7 +294,7 @@ namespace Robust.Shared.Configuration
|
||||
throw new InvalidOperationException($"CVarDef '{defField.Name}' on '{defField.DeclaringType?.FullName}' is null.");
|
||||
}
|
||||
|
||||
RegisterCVar(def.Name, type, def.DefaultValue, def.Flags, null);
|
||||
RegisterCVar(def.Name, type, def.DefaultValue, def.Flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +328,7 @@ namespace Robust.Shared.Configuration
|
||||
cVar.OverrideValueParsed = null;
|
||||
|
||||
cVar.Value = value;
|
||||
cVar.ValueChanged?.Invoke(value);
|
||||
InvokeValueChanged(cVar, value);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -362,7 +374,7 @@ namespace Robust.Shared.Configuration
|
||||
{
|
||||
cfgVar.OverrideValue = value;
|
||||
cfgVar.OverrideValueParsed = ParseOverrideValue(value, cfgVar.DefaultValue?.GetType());
|
||||
cfgVar.ValueChanged?.Invoke(cfgVar.OverrideValueParsed);
|
||||
InvokeValueChanged(cfgVar, cfgVar.OverrideValueParsed);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -422,6 +434,11 @@ namespace Robust.Shared.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
private static void InvokeValueChanged(ConfigVar var, object value)
|
||||
{
|
||||
var.ValueChangedInvoker?.Invoke(var.ValueChanged!, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the data for a single configuration variable.
|
||||
/// </summary>
|
||||
@@ -476,7 +493,9 @@ namespace Robust.Shared.Configuration
|
||||
/// <summary>
|
||||
/// Invoked when the value of this CVar is changed.
|
||||
/// </summary>
|
||||
public Action<object>? ValueChanged { get; set; }
|
||||
public Delegate? ValueChanged { get; set; }
|
||||
|
||||
public Action<Delegate, object>? ValueChangedInvoker { get; set; }
|
||||
|
||||
// We don't know what the type of the var is until it's registered.
|
||||
// So we can't actually parse them until then.
|
||||
|
||||
@@ -63,10 +63,48 @@ namespace Robust.Shared.Configuration
|
||||
/// <param name="name">The name of the CVar</param>
|
||||
Type GetCVarType(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Listen for an event for if the config value changes.
|
||||
/// </summary>
|
||||
/// <param name="cVar">The CVar to listen for.</param>
|
||||
/// <param name="onValueChanged">The delegate to run when the value was changed.</param>
|
||||
/// <param name="invokeImmediately">
|
||||
/// Whether to run the callback immediately in this method. Can help reduce boilerplate
|
||||
/// </param>
|
||||
/// <typeparam name="T">The type of value contained in this CVar.</typeparam>
|
||||
/// <seealso cref="UnsubValueChanged{T}(Robust.Shared.Configuration.CVarDef{T},System.Action{T})"/>
|
||||
void OnValueChanged<T>(CVarDef<T> cVar, Action<T> onValueChanged, bool invokeImmediately = false)
|
||||
where T : notnull;
|
||||
|
||||
/// <summary>
|
||||
/// Listen for an event for if the config value changes.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the CVar to listen for.</param>
|
||||
/// <param name="onValueChanged">The delegate to run when the value was changed.</param>
|
||||
/// <param name="invokeImmediately">
|
||||
/// Whether to run the callback immediately in this method. Can help reduce boilerplate
|
||||
/// </param>
|
||||
/// <typeparam name="T">The type of value contained in this CVar.</typeparam>
|
||||
/// <seealso cref="UnsubValueChanged{T}(string,System.Action{T})"/>
|
||||
void OnValueChanged<T>(string name, Action<T> onValueChanged, bool invokeImmediately = false)
|
||||
where T : notnull;
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribe an event previously registered with <see cref="OnValueChanged{T}(Robust.Shared.Configuration.CVarDef{T},System.Action{T},bool)"/>.
|
||||
/// </summary>
|
||||
/// <param name="cVar">The CVar to unsubscribe from.</param>
|
||||
/// <param name="onValueChanged">The delegate to unsubscribe.</param>
|
||||
/// <typeparam name="T">The type of value contained in this CVar.</typeparam>
|
||||
void UnsubValueChanged<T>(CVarDef<T> cVar, Action<T> onValueChanged)
|
||||
where T : notnull;
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribe an event previously registered with <see cref="OnValueChanged{T}(string,System.Action{T},bool)"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the CVar to unsubscribe from.</param>
|
||||
/// <param name="onValueChanged">The delegate to unsubscribe.</param>
|
||||
/// <typeparam name="T">The type of value contained in this CVar.</typeparam>
|
||||
void UnsubValueChanged<T>(string name, Action<T> onValueChanged)
|
||||
where T : notnull;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace Robust.Shared.Configuration
|
||||
|
||||
private void HandleNetVarMessage(MsgConVars message)
|
||||
{
|
||||
if(!_receivedInitialNwVars)
|
||||
if (_netManager.IsClient && !_receivedInitialNwVars)
|
||||
{
|
||||
_receivedInitialNwVars = true;
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace Robust.Shared.Configuration
|
||||
|
||||
ApplyNetVarChange(msg.MsgChannel, msg.NetworkedVars);
|
||||
|
||||
if(msg.Tick < _timing.LastRealTick)
|
||||
if(msg.Tick != default && msg.Tick < _timing.LastRealTick)
|
||||
Logger.WarningS("cfg", $"{msg.MsgChannel}: Received late nwVar message ({msg.Tick} < {_timing.LastRealTick} ).");
|
||||
|
||||
_netVarsMessages.RemoveSwap(i);
|
||||
@@ -148,45 +148,50 @@ namespace Robust.Shared.Configuration
|
||||
|
||||
private void ApplyNetVarChange(INetChannel msgChannel, List<(string name, object value)> networkedVars)
|
||||
{
|
||||
Logger.DebugS("cfg", "Handling replicated cvars...");
|
||||
Logger.DebugS("cfg", $"{msgChannel} Handling replicated cvars...");
|
||||
|
||||
foreach (var (name, value) in networkedVars)
|
||||
if (_netManager.IsClient)
|
||||
{
|
||||
if (_netManager.IsClient) // Server sent us a CVar update.
|
||||
// Server sent us a CVar update.
|
||||
foreach (var (name, value) in networkedVars)
|
||||
{
|
||||
// Actually set the CVar
|
||||
base.SetCVar(name, value);
|
||||
Logger.DebugS("cfg", $"name={name}, val={value}");
|
||||
}
|
||||
else // Client sent us a CVar update
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Client sent us a CVar update
|
||||
if (!_replicatedCVars.TryGetValue(msgChannel, out var clientCVars))
|
||||
{
|
||||
Logger.WarningS("cfg", $"{msgChannel} tried to replicate CVars but is not in _replicatedCVars.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var (name, value) in networkedVars)
|
||||
{
|
||||
if (!_configVars.TryGetValue(name, out var cVar))
|
||||
{
|
||||
if (!_configVars.TryGetValue(name, out var cVar))
|
||||
{
|
||||
Logger.WarningS("cfg", $"{msgChannel} tried to replicate an unknown CVar '{name}.'");
|
||||
continue;
|
||||
}
|
||||
Logger.WarningS("cfg", $"{msgChannel} tried to replicate an unknown CVar '{name}.'");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!cVar.Registered)
|
||||
{
|
||||
Logger.WarningS("cfg", $"{msgChannel} tried to replicate an unregistered CVar '{name}.'");
|
||||
continue;
|
||||
}
|
||||
if (!cVar.Registered)
|
||||
{
|
||||
Logger.WarningS("cfg", $"{msgChannel} tried to replicate an unregistered CVar '{name}.'");
|
||||
continue;
|
||||
}
|
||||
|
||||
if((cVar.Flags & CVar.REPLICATED) != 0)
|
||||
{
|
||||
var clientCVars = _replicatedCVars[msgChannel];
|
||||
|
||||
if (clientCVars.ContainsKey(name))
|
||||
clientCVars[name] = value;
|
||||
else
|
||||
clientCVars.Add(name, value);
|
||||
|
||||
Logger.DebugS("cfg", $"name={name}, val={value}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.WarningS("cfg", $"{msgChannel} tried to replicate an un-replicated CVar '{name}.'");
|
||||
}
|
||||
if((cVar.Flags & CVar.REPLICATED) != 0)
|
||||
{
|
||||
clientCVars[name] = value;
|
||||
Logger.DebugS("cfg", $"name={name}, val={value}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.WarningS("cfg", $"{msgChannel} tried to replicate an un-replicated CVar '{name}.'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,7 +295,7 @@ namespace Robust.Shared.Configuration
|
||||
Logger.InfoS("cfg", "Sending client info...");
|
||||
|
||||
var msg = _netManager.CreateNetMessage<MsgConVars>();
|
||||
msg.Tick = _timing.CurTick;
|
||||
msg.Tick = default;
|
||||
msg.NetworkedVars = GetReplicatedVars();
|
||||
_netManager.ClientSendMessage(msg);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ namespace Robust.Shared.Console
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyDictionary<string, IConsoleCommand> RegisteredCommands => AvailableCommands;
|
||||
|
||||
public abstract event ConAnyCommandCallback? AnyCommandExecuted;
|
||||
|
||||
protected ConsoleHost()
|
||||
{
|
||||
LocalShell = new ConsoleShell(this, null);
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace Robust.Shared.Console
|
||||
/// <param name="args">An array of all the parsed arguments.</param>
|
||||
public delegate void ConCommandCallback(IConsoleShell shell, string argStr, string[] args);
|
||||
|
||||
public delegate void ConAnyCommandCallback(IConsoleShell shell, string commandName, string argStr, string[] args);
|
||||
|
||||
/// <summary>
|
||||
/// The console host exists as a singleton subsystem that provides all of the features of the console API.
|
||||
/// It will register console commands, spawn console shells and execute command strings.
|
||||
@@ -38,7 +40,10 @@ namespace Robust.Shared.Console
|
||||
/// </summary>
|
||||
IReadOnlyDictionary<string, IConsoleCommand> RegisteredCommands { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Invoked before any console command is executed.
|
||||
/// </summary>
|
||||
event ConAnyCommandCallback AnyCommandExecuted;
|
||||
event EventHandler ClearText;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -16,6 +16,9 @@ namespace Robust.Shared.Containers
|
||||
[ViewVariables]
|
||||
public abstract IReadOnlyList<IEntity> ContainedEntities { get; }
|
||||
|
||||
[ViewVariables]
|
||||
public abstract List<EntityUid> ExpectedEntities { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract string ContainerType { get; }
|
||||
|
||||
|
||||
@@ -24,9 +24,13 @@ namespace Robust.Shared.Containers
|
||||
[DataField("ents")]
|
||||
private readonly List<IEntity> _containerList = new();
|
||||
|
||||
private readonly List<EntityUid> _expectedEntities = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IReadOnlyList<IEntity> ContainedEntities => _containerList;
|
||||
|
||||
public override List<EntityUid> ExpectedEntities => _expectedEntities;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ContainerType => ClassName;
|
||||
|
||||
|
||||
@@ -21,12 +21,11 @@ namespace Robust.Shared.Containers
|
||||
[NetworkedComponent()]
|
||||
public class ContainerManagerComponent : Component, IContainerManager
|
||||
{
|
||||
[Dependency] private readonly IRobustSerializer _serializer = default!;
|
||||
[Dependency] private readonly IDynamicTypeFactoryInternal _dynFactory = default!;
|
||||
|
||||
[ViewVariables]
|
||||
[DataField("containers")]
|
||||
private Dictionary<string, IContainer> _containers = new();
|
||||
public Dictionary<string, IContainer> Containers = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public sealed override string Name => "ContainerContainer";
|
||||
@@ -37,12 +36,12 @@ namespace Robust.Shared.Containers
|
||||
base.OnRemove();
|
||||
|
||||
// IContianer.Shutdown modifies the _containers collection
|
||||
foreach (var container in _containers.Values.ToArray())
|
||||
foreach (var container in Containers.Values.ToArray())
|
||||
{
|
||||
container.Shutdown();
|
||||
}
|
||||
|
||||
_containers.Clear();
|
||||
Containers.Clear();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -50,7 +49,7 @@ namespace Robust.Shared.Containers
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
foreach (var container in _containers)
|
||||
foreach (var container in Containers)
|
||||
{
|
||||
var baseContainer = (BaseContainer)container.Value;
|
||||
baseContainer.Manager = this;
|
||||
@@ -58,93 +57,13 @@ namespace Robust.Shared.Containers
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
|
||||
{
|
||||
if (!(curState is ContainerManagerComponentState cast))
|
||||
return;
|
||||
|
||||
// Delete now-gone containers.
|
||||
List<string>? toDelete = null;
|
||||
foreach (var (id, container) in _containers)
|
||||
{
|
||||
if (!cast.ContainerSet.Any(data => data.Id == id))
|
||||
{
|
||||
container.Shutdown();
|
||||
toDelete ??= new List<string>();
|
||||
toDelete.Add(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (toDelete != null)
|
||||
{
|
||||
foreach (var dead in toDelete)
|
||||
{
|
||||
_containers.Remove(dead);
|
||||
}
|
||||
}
|
||||
|
||||
// Add new containers and update existing contents.
|
||||
|
||||
foreach (var (containerType, id, showEnts, occludesLight, entityUids) in cast.ContainerSet)
|
||||
{
|
||||
if (!_containers.TryGetValue(id, out var container))
|
||||
{
|
||||
container = ContainerFactory(containerType, id);
|
||||
_containers.Add(id, container);
|
||||
}
|
||||
|
||||
// sync show flag
|
||||
container.ShowContents = showEnts;
|
||||
container.OccludesLight = occludesLight;
|
||||
|
||||
// Remove gone entities.
|
||||
List<IEntity>? toRemove = null;
|
||||
foreach (var entity in container.ContainedEntities)
|
||||
{
|
||||
if (!entityUids.Contains(entity.Uid))
|
||||
{
|
||||
toRemove ??= new List<IEntity>();
|
||||
toRemove.Add(entity);
|
||||
}
|
||||
}
|
||||
|
||||
if (toRemove != null)
|
||||
{
|
||||
foreach (var goner in toRemove)
|
||||
{
|
||||
container.Remove(goner);
|
||||
}
|
||||
}
|
||||
|
||||
// Add new entities.
|
||||
foreach (var uid in entityUids)
|
||||
{
|
||||
var entity = Owner.EntityManager.GetEntity(uid);
|
||||
|
||||
if (!container.ContainedEntities.Contains(entity)) container.Insert(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IContainer ContainerFactory(string containerType, string id)
|
||||
{
|
||||
var type = _serializer.FindSerializedType(typeof(IContainer), containerType);
|
||||
if (type is null) throw new ArgumentException($"Container of type {containerType} for id {id} cannot be found.");
|
||||
|
||||
var newContainer = _dynFactory.CreateInstanceUnchecked<BaseContainer>(type);
|
||||
newContainer.ID = id;
|
||||
newContainer.Manager = this;
|
||||
return newContainer;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ComponentState GetComponentState(ICommonSession player)
|
||||
{
|
||||
// naive implementation that just sends the full state of the component
|
||||
List<ContainerManagerComponentState.ContainerData> containerSet = new();
|
||||
|
||||
foreach (var container in _containers.Values)
|
||||
foreach (var container in Containers.Values)
|
||||
{
|
||||
var uidArr = new EntityUid[container.ContainedEntities.Count];
|
||||
|
||||
@@ -171,19 +90,19 @@ namespace Robust.Shared.Containers
|
||||
/// <inheritdoc />
|
||||
public IContainer GetContainer(string id)
|
||||
{
|
||||
return _containers[id];
|
||||
return Containers[id];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasContainer(string id)
|
||||
{
|
||||
return _containers.ContainsKey(id);
|
||||
return Containers.ContainsKey(id);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryGetContainer(string id, [NotNullWhen(true)] out IContainer? container)
|
||||
{
|
||||
var ret = _containers.TryGetValue(id, out var cont);
|
||||
var ret = Containers.TryGetValue(id, out var cont);
|
||||
container = cont!;
|
||||
return ret;
|
||||
}
|
||||
@@ -191,7 +110,7 @@ namespace Robust.Shared.Containers
|
||||
/// <inheritdoc />
|
||||
public bool TryGetContainer(IEntity entity, [NotNullWhen(true)] out IContainer? container)
|
||||
{
|
||||
foreach (var contain in _containers.Values)
|
||||
foreach (var contain in Containers.Values)
|
||||
{
|
||||
if (!contain.Deleted && contain.Contains(entity))
|
||||
{
|
||||
@@ -207,7 +126,7 @@ namespace Robust.Shared.Containers
|
||||
/// <inheritdoc />
|
||||
public bool ContainsEntity(IEntity entity)
|
||||
{
|
||||
foreach (var container in _containers.Values)
|
||||
foreach (var container in Containers.Values)
|
||||
{
|
||||
if (!container.Deleted && container.Contains(entity)) return true;
|
||||
}
|
||||
@@ -218,7 +137,7 @@ namespace Robust.Shared.Containers
|
||||
/// <inheritdoc />
|
||||
public void ForceRemove(IEntity entity)
|
||||
{
|
||||
foreach (var container in _containers.Values)
|
||||
foreach (var container in Containers.Values)
|
||||
{
|
||||
if (container.Contains(entity)) container.ForceRemove(entity);
|
||||
}
|
||||
@@ -227,13 +146,13 @@ namespace Robust.Shared.Containers
|
||||
/// <inheritdoc />
|
||||
public void InternalContainerShutdown(IContainer container)
|
||||
{
|
||||
_containers.Remove(container.ID);
|
||||
Containers.Remove(container.ID);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove(IEntity entity)
|
||||
{
|
||||
foreach (var containers in _containers.Values)
|
||||
foreach (var containers in Containers.Values)
|
||||
{
|
||||
if (containers.Contains(entity)) return containers.Remove(entity);
|
||||
}
|
||||
@@ -247,7 +166,7 @@ namespace Robust.Shared.Containers
|
||||
base.Shutdown();
|
||||
|
||||
// On shutdown we won't get to process remove events in the containers so this has to be manually done.
|
||||
foreach (var container in _containers.Values)
|
||||
foreach (var container in Containers.Values)
|
||||
{
|
||||
foreach (var containerEntity in container.ContainedEntities)
|
||||
{
|
||||
@@ -265,7 +184,7 @@ namespace Robust.Shared.Containers
|
||||
container.ID = id;
|
||||
container.Manager = this;
|
||||
|
||||
_containers[id] = container;
|
||||
Containers[id] = container;
|
||||
Dirty();
|
||||
return container;
|
||||
}
|
||||
@@ -366,7 +285,7 @@ namespace Robust.Shared.Containers
|
||||
|
||||
public AllContainersEnumerator(ContainerManagerComponent manager)
|
||||
{
|
||||
_enumerator = manager._containers.Values.GetEnumerator();
|
||||
_enumerator = manager.Containers.Values.GetEnumerator();
|
||||
Current = default;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,10 @@ namespace Robust.Shared.Containers
|
||||
}
|
||||
}
|
||||
|
||||
public override List<EntityUid> ExpectedEntities => _expectedEntities;
|
||||
|
||||
private IEntity? _containedEntity;
|
||||
private readonly List<EntityUid> _expectedEntities = new();
|
||||
// Used by ContainedEntities to avoid allocating.
|
||||
private readonly IEntity?[] _containedEntityArray = new IEntity[1];
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ namespace Robust.Shared.Containers
|
||||
/// </summary>
|
||||
IReadOnlyList<IEntity> ContainedEntities { get; }
|
||||
|
||||
List<EntityUid> ExpectedEntities { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of this container.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Shared.Containers
|
||||
{
|
||||
public class ContainerSystem : EntitySystem
|
||||
public abstract class SharedContainerSystem : EntitySystem
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<EntParentChangedMessage>(HandleParentChanged);
|
||||
}
|
||||
|
||||
@@ -871,6 +871,7 @@ Types:
|
||||
IEquatable`1: { }
|
||||
IFormatProvider: { All: True }
|
||||
IFormattable: { All: True }
|
||||
Index: { All: True }
|
||||
IndexOutOfRangeException: { All: True }
|
||||
Int16: { All: True }
|
||||
Int32: { All: True }
|
||||
@@ -912,6 +913,7 @@ Types:
|
||||
ParamArrayAttribute: { All: True }
|
||||
Predicate`1: { All: True } # Delegate
|
||||
Random: { All: True }
|
||||
Range: { All: True }
|
||||
ReadOnlyMemory`1:
|
||||
Methods:
|
||||
- "!0[] ToArray()"
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Shared.GameObjects
|
||||
{
|
||||
public interface ILookupWorldBox2Component
|
||||
{
|
||||
Box2 GetWorldAABB(Vector2? worldPos = null, Angle? worldRot = null);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,10 @@
|
||||
using System;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Collision;
|
||||
using Robust.Shared.Physics.Dynamics;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Robust.Shared.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Called once when a collision starts
|
||||
/// </summary>
|
||||
public interface IStartCollide
|
||||
{
|
||||
/// <summary>
|
||||
/// We'll pass in both our body and the other body to save the behaviors having to get these components themselves.
|
||||
/// </summary>
|
||||
[Obsolete("Use StartCollideEvent instead")]
|
||||
void CollideWith(Fixture ourFixture, Fixture otherFixture, in Manifold manifold);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called once when a collision ends.
|
||||
/// </summary>
|
||||
public interface IEndCollide
|
||||
{
|
||||
/// <summary>
|
||||
/// Run behaviour after all other collision behaviors have run.
|
||||
/// </summary>
|
||||
[Obsolete("Use EndCollideEvent instead")]
|
||||
void CollideWith(Fixture ourFixture, Fixture otherFixture, in Manifold manifold);
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum BodyStatus: byte
|
||||
{
|
||||
|
||||
@@ -33,6 +33,7 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Broadphase;
|
||||
using Robust.Shared.Physics.Collision.Shapes;
|
||||
using Robust.Shared.Physics.Dynamics;
|
||||
using Robust.Shared.Physics.Dynamics.Contacts;
|
||||
using Robust.Shared.Physics.Dynamics.Joints;
|
||||
@@ -44,9 +45,10 @@ using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Shared.GameObjects
|
||||
{
|
||||
[ComponentReference(typeof(ILookupWorldBox2Component))]
|
||||
[ComponentReference(typeof(IPhysBody))]
|
||||
[NetworkedComponent()]
|
||||
public sealed class PhysicsComponent : Component, IPhysBody, ISerializationHooks
|
||||
public sealed class PhysicsComponent : Component, IPhysBody, ISerializationHooks, ILookupWorldBox2Component
|
||||
{
|
||||
[DataField("status", readOnly: true)]
|
||||
private BodyStatus _bodyStatus = BodyStatus.OnGround;
|
||||
@@ -59,6 +61,8 @@ namespace Robust.Shared.GameObjects
|
||||
/// </summary>
|
||||
public bool Island { get; set; }
|
||||
|
||||
internal BroadphaseComponent? Broadphase { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Store the body's index within the island so we can lookup its data.
|
||||
/// Key is Island's ID and value is our index.
|
||||
@@ -90,6 +94,47 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
public Box2 LocalAABB
|
||||
{
|
||||
get
|
||||
{
|
||||
var broadphaseSystem = EntitySystem.Get<SharedBroadphaseSystem>();
|
||||
var broadphase = broadphaseSystem.GetBroadphase(this);
|
||||
|
||||
if (broadphase == null) return new Box2();
|
||||
|
||||
var worldPos = Owner.Transform.WorldPosition;
|
||||
var aabb = new Box2(worldPos, worldPos);
|
||||
|
||||
foreach (var fixture in Fixtures)
|
||||
{
|
||||
foreach (var proxy in fixture.Proxies)
|
||||
{
|
||||
aabb = aabb.Union(proxy.AABB);
|
||||
}
|
||||
}
|
||||
|
||||
return aabb;
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
public Box2 WorldAABB
|
||||
{
|
||||
get
|
||||
{
|
||||
var broadphaseSystem = EntitySystem.Get<SharedBroadphaseSystem>();
|
||||
var broadphase = broadphaseSystem.GetBroadphase(this);
|
||||
|
||||
if (broadphase == null) return new Box2();
|
||||
var localAABB = LocalAABB;
|
||||
var center = broadphase.Owner.Transform.WorldMatrix.Transform(localAABB.Center);
|
||||
|
||||
return new Box2Rotated(localAABB.Translated(center), broadphase.Owner.Transform.WorldRotation, center).CalcBoundingBox();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linked-list of all of our contacts.
|
||||
/// </summary>
|
||||
@@ -136,7 +181,7 @@ namespace Robust.Shared.GameObjects
|
||||
Force = Vector2.Zero;
|
||||
Torque = 0.0f;
|
||||
|
||||
RegenerateContacts();
|
||||
EntitySystem.Get<SharedBroadphaseSystem>().RegenerateContacts(this);
|
||||
|
||||
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new PhysicsBodyTypeChangedEvent(_bodyType, oldType), false);
|
||||
}
|
||||
@@ -242,39 +287,10 @@ namespace Robust.Shared.GameObjects
|
||||
Awake = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all of our contacts and flags them as requiring regeneration next physics tick.
|
||||
/// </summary>
|
||||
public void RegenerateContacts()
|
||||
{
|
||||
var contactEdge = ContactEdges;
|
||||
while (contactEdge != null)
|
||||
{
|
||||
var contactEdge0 = contactEdge;
|
||||
contactEdge = contactEdge.Next;
|
||||
PhysicsMap.ContactManager.Destroy(contactEdge0.Contact!);
|
||||
}
|
||||
|
||||
ContactEdges = null;
|
||||
var broadphaseSystem = EntitySystem.Get<SharedBroadPhaseSystem>();
|
||||
|
||||
foreach (var fixture in Fixtures)
|
||||
{
|
||||
var proxyCount = fixture.ProxyCount;
|
||||
foreach (var (gridId, proxies) in fixture.Proxies)
|
||||
{
|
||||
var broadPhase = broadphaseSystem.GetBroadPhase(Owner.Transform.MapID, gridId);
|
||||
if (broadPhase == null) continue;
|
||||
for (var i = 0; i < proxyCount; i++)
|
||||
{
|
||||
broadPhase.TouchProxy(proxies[i].ProxyId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ISerializationHooks.AfterDeserialization()
|
||||
{
|
||||
FixtureCount = _fixtures.Count;
|
||||
|
||||
foreach (var fixture in _fixtures)
|
||||
{
|
||||
fixture.Body = this;
|
||||
@@ -446,17 +462,19 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
var broadphaseSystem = EntitySystem.Get<SharedBroadphaseSystem>();
|
||||
|
||||
foreach (var fixture in toRemoveFixtures)
|
||||
{
|
||||
computeProperties = true;
|
||||
RemoveFixture(fixture);
|
||||
broadphaseSystem.DestroyFixture(this, fixture);
|
||||
}
|
||||
|
||||
// TODO: We also still need event listeners for shapes (Probably need C# events)
|
||||
foreach (var fixture in toAddFixtures)
|
||||
{
|
||||
computeProperties = true;
|
||||
AddFixture(fixture);
|
||||
broadphaseSystem.CreateFixture(this, fixture);
|
||||
fixture.Shape.ApplyState();
|
||||
}
|
||||
|
||||
@@ -535,16 +553,17 @@ namespace Robust.Shared.GameObjects
|
||||
{
|
||||
worldPos ??= Owner.Transform.WorldPosition;
|
||||
worldRot ??= Owner.Transform.WorldRotation;
|
||||
var transform = new Transform(worldPos.Value, (float) worldRot.Value.Theta);
|
||||
|
||||
var worldPosValue = worldPos.Value;
|
||||
var worldRotValue = worldRot.Value;
|
||||
|
||||
var bounds = new Box2(worldPosValue, worldPosValue);
|
||||
var bounds = new Box2(transform.Position, transform.Position);
|
||||
|
||||
foreach (var fixture in _fixtures)
|
||||
{
|
||||
var boundy = fixture.Shape.CalculateLocalBounds(worldRotValue);
|
||||
bounds = bounds.Union(boundy.Translated(worldPosValue));
|
||||
for (var i = 0; i < fixture.Shape.ChildCount; i++)
|
||||
{
|
||||
var boundy = fixture.Shape.ComputeAABB(transform, i);
|
||||
bounds = bounds.Union(boundy);
|
||||
}
|
||||
}
|
||||
|
||||
return bounds;
|
||||
@@ -568,9 +587,12 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
public int FixtureCount { get; internal set; }
|
||||
|
||||
[DataField("fixtures")]
|
||||
[NeverPushInheritance]
|
||||
private List<Fixture> _fixtures = new();
|
||||
internal List<Fixture> _fixtures = new();
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disabled collision processing of this component.
|
||||
@@ -657,9 +679,6 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
public bool HasProxies { get; set; }
|
||||
|
||||
// I made Mass read-only just because overwriting it doesn't touch inertia.
|
||||
/// <summary>
|
||||
/// Current mass of the entity in kilograms.
|
||||
@@ -1022,22 +1041,9 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
private bool _predict;
|
||||
|
||||
/// <summary>
|
||||
/// As we defer updates need to store the MapId we used for broadphase.
|
||||
/// </summary>
|
||||
public MapId BroadphaseMapId { get; set; }
|
||||
|
||||
public IEnumerable<PhysicsComponent> GetCollidingBodies()
|
||||
{
|
||||
foreach (var entity in EntitySystem.Get<SharedBroadPhaseSystem>().GetCollidingEntities(this, Vector2.Zero))
|
||||
{
|
||||
yield return entity;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<PhysicsComponent> GetBodiesIntersecting()
|
||||
{
|
||||
foreach (var entity in EntitySystem.Get<SharedBroadPhaseSystem>().GetCollidingEntities(Owner.Transform.MapID, GetWorldAABB()))
|
||||
foreach (var entity in EntitySystem.Get<SharedBroadphaseSystem>().GetCollidingEntities(Owner.Transform.MapID, GetWorldAABB()))
|
||||
{
|
||||
yield return entity;
|
||||
}
|
||||
@@ -1051,7 +1057,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <returns>The corresponding local point relative to the body's origin.</returns>
|
||||
public Vector2 GetLocalPoint(in Vector2 worldPoint)
|
||||
{
|
||||
return Physics.Transform.MulT(GetTransform(), worldPoint);
|
||||
return Transform.MulT(GetTransform(), worldPoint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1064,24 +1070,6 @@ namespace Robust.Shared.GameObjects
|
||||
return Transform.Mul(GetTransform(), localPoint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove the proxies from all the broadphases.
|
||||
/// </summary>
|
||||
public void ClearProxies()
|
||||
{
|
||||
if (!HasProxies) return;
|
||||
|
||||
var broadPhaseSystem = EntitySystem.Get<SharedBroadPhaseSystem>();
|
||||
var mapId = BroadphaseMapId;
|
||||
|
||||
foreach (var fixture in Fixtures)
|
||||
{
|
||||
fixture.ClearProxies(mapId, broadPhaseSystem);
|
||||
}
|
||||
|
||||
HasProxies = false;
|
||||
}
|
||||
|
||||
public void FixtureChanged(Fixture fixture)
|
||||
{
|
||||
// TODO: Optimise this a LOT
|
||||
@@ -1089,12 +1077,32 @@ namespace Robust.Shared.GameObjects
|
||||
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new FixtureUpdateMessage(this, fixture));
|
||||
}
|
||||
|
||||
private string GetFixtureName(Fixture fixture)
|
||||
public string GetFixtureName(Fixture fixture)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(fixture.ID)) return fixture.ID;
|
||||
|
||||
// For any fixtures that aren't named in the code we will assign one.
|
||||
return $"fixture-{_fixtures.IndexOf(fixture)}";
|
||||
var i = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
var found = false;
|
||||
++i;
|
||||
var name = $"fixture_{i}";
|
||||
|
||||
foreach (var existing in _fixtures)
|
||||
{
|
||||
if (existing.ID.Equals(name))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetJointName(Joint joint)
|
||||
@@ -1158,73 +1166,6 @@ namespace Robust.Shared.GameObjects
|
||||
Force += force;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the proxies for each of our fixtures and add them to the broadphases.
|
||||
/// </summary>
|
||||
/// <param name="mapManager"></param>
|
||||
/// <param name="broadPhaseSystem"></param>
|
||||
public void CreateProxies(IMapManager? mapManager = null, SharedBroadPhaseSystem? broadPhaseSystem = null)
|
||||
{
|
||||
if (HasProxies) return;
|
||||
|
||||
BroadphaseMapId = Owner.Transform.MapID;
|
||||
|
||||
if (BroadphaseMapId == MapId.Nullspace)
|
||||
{
|
||||
HasProxies = true;
|
||||
return;
|
||||
}
|
||||
|
||||
broadPhaseSystem ??= EntitySystem.Get<SharedBroadPhaseSystem>();
|
||||
mapManager ??= IoCManager.Resolve<IMapManager>();
|
||||
var worldPosition = Owner.Transform.WorldPosition;
|
||||
var mapId = Owner.Transform.MapID;
|
||||
var worldAABB = GetWorldAABB();
|
||||
var worldRotation = Owner.Transform.WorldRotation.Theta;
|
||||
|
||||
// TODO: For singularity and shuttles: Any fixtures that have a MapGrid layer / mask needs to be added to the default broadphase (so it can collide with grids).
|
||||
|
||||
foreach (var gridId in mapManager.FindGridIdsIntersecting(mapId, worldAABB, true))
|
||||
{
|
||||
var broadPhase = broadPhaseSystem.GetBroadPhase(mapId, gridId);
|
||||
DebugTools.AssertNotNull(broadPhase);
|
||||
if (broadPhase == null) continue; // TODO
|
||||
|
||||
Vector2 offset = worldPosition;
|
||||
double gridRotation = worldRotation;
|
||||
|
||||
if (gridId != GridId.Invalid)
|
||||
{
|
||||
var grid = mapManager.GetGrid(gridId);
|
||||
offset -= grid.WorldPosition;
|
||||
// TODO: Should probably have a helper for this
|
||||
gridRotation = worldRotation - Owner.EntityManager.GetEntity(grid.GridEntityId).Transform.WorldRotation;
|
||||
}
|
||||
|
||||
foreach (var fixture in Fixtures)
|
||||
{
|
||||
fixture.ProxyCount = fixture.Shape.ChildCount;
|
||||
var proxies = new FixtureProxy[fixture.ProxyCount];
|
||||
|
||||
// TODO: Will need to pass in childIndex to this as well
|
||||
for (var i = 0; i < fixture.ProxyCount; i++)
|
||||
{
|
||||
var aabb = fixture.Shape.CalculateLocalBounds(gridRotation).Translated(offset);
|
||||
|
||||
var proxy = new FixtureProxy(aabb, fixture, i);
|
||||
|
||||
proxy.ProxyId = broadPhase.AddProxy(ref proxy);
|
||||
proxies[i] = proxy;
|
||||
DebugTools.Assert(proxies[i].ProxyId != DynamicTree.Proxy.Free);
|
||||
}
|
||||
|
||||
fixture.SetProxies(gridId, proxies);
|
||||
}
|
||||
}
|
||||
|
||||
HasProxies = true;
|
||||
}
|
||||
|
||||
// TOOD: Need SetTransformIgnoreContacts so we can teleport body and /ignore contacts/
|
||||
public void DestroyContacts()
|
||||
{
|
||||
@@ -1241,7 +1182,7 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
IEnumerable<IPhysBody> IPhysBody.GetCollidingEntities(Vector2 offset, bool approx)
|
||||
{
|
||||
return EntitySystem.Get<SharedBroadPhaseSystem>().GetCollidingEntities(this, offset, approx);
|
||||
return EntitySystem.Get<SharedBroadphaseSystem>().GetCollidingEntities(this, offset, approx);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -1254,6 +1195,9 @@ namespace Robust.Shared.GameObjects
|
||||
_awake = false;
|
||||
}
|
||||
|
||||
// TODO: Ordering fuckery need a new PR to fix some of this stuff
|
||||
PhysicsMap = EntitySystem.Get<SharedPhysicsSystem>().Maps[Owner.Transform.MapID];
|
||||
|
||||
Dirty();
|
||||
// Yeah yeah TODO Combine these
|
||||
// Implicitly assume that stuff doesn't cover if a non-collidable is initialized.
|
||||
@@ -1290,45 +1234,6 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
public void AddFixture(Fixture fixture)
|
||||
{
|
||||
// TODO: SynchronizeFixtures could be more optimally done. Maybe just eventbus it
|
||||
// Also we need to queue updates and also not teardown completely every time.
|
||||
_fixtures.Add(fixture);
|
||||
Dirty();
|
||||
EntitySystem.Get<SharedBroadPhaseSystem>().AddFixture(this, fixture);
|
||||
}
|
||||
|
||||
public void RemoveFixture(Fixture fixture)
|
||||
{
|
||||
if (!_fixtures.Contains(fixture))
|
||||
{
|
||||
Logger.ErrorS("physics", $"Tried to remove fixture that isn't attached to the body {Owner.Uid}");
|
||||
return;
|
||||
}
|
||||
|
||||
ContactEdge? edge = ContactEdges;
|
||||
while (edge != null)
|
||||
{
|
||||
var contact = edge.Contact!;
|
||||
edge = edge.Next;
|
||||
|
||||
var fixtureA = contact.FixtureA;
|
||||
var fixtureB = contact.FixtureB;
|
||||
|
||||
if (fixture == fixtureA || fixture == fixtureB)
|
||||
{
|
||||
PhysicsMap.ContactManager.Destroy(contact);
|
||||
}
|
||||
}
|
||||
|
||||
_fixtures.Remove(fixture);
|
||||
EntitySystem.Get<SharedBroadPhaseSystem>().RemoveFixture(this, fixture);
|
||||
ResetMassData();
|
||||
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void AddJoint(Joint joint)
|
||||
{
|
||||
var id = GetJointName(joint);
|
||||
@@ -1356,7 +1261,7 @@ namespace Robust.Shared.GameObjects
|
||||
// Need to do these immediately in case collision behaviors deleted the body
|
||||
// TODO: Could be more optimal as currently broadphase will call this ANYWAY
|
||||
DestroyContacts();
|
||||
ClearProxies();
|
||||
EntitySystem.Get<SharedBroadphaseSystem>().RemoveBody(this);
|
||||
CanCollide = false;
|
||||
}
|
||||
|
||||
@@ -1382,7 +1287,27 @@ namespace Robust.Shared.GameObjects
|
||||
var fixMass = fixture.Mass;
|
||||
|
||||
_mass += fixMass;
|
||||
localCenter += fixture.Centroid * fixMass;
|
||||
|
||||
var center = Vector2.Zero;
|
||||
|
||||
// TODO: God this is garbage
|
||||
switch (fixture.Shape)
|
||||
{
|
||||
case PhysShapeAabb aabb:
|
||||
center = aabb.Centroid;
|
||||
break;
|
||||
case PhysShapeRect rect:
|
||||
center = rect.Centroid;
|
||||
break;
|
||||
case PolygonShape poly:
|
||||
center = poly.Centroid;
|
||||
break;
|
||||
case PhysShapeCircle circle:
|
||||
center = circle.Position;
|
||||
break;
|
||||
}
|
||||
|
||||
localCenter += center * fixMass;
|
||||
_inertia += fixture.Inertia;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user