Compare commits

...

107 Commits

Author SHA1 Message Date
metalgearsloth
04d94f87fc Fix movement lerping (#1924) 2021-08-04 00:11:04 +10:00
metalgearsloth
f809375389 Cache broadphase on PhysicsMap (#1923) 2021-08-03 22:24:01 +10:00
metalgearsloth
530ea5f4e6 Remove BroadphaseMapid from physicscomp
Was made redundant in the broadphase refactor
2021-08-03 19:08:45 +10:00
Visne
590a23d540 Make it possible to set lighting per map (#1921) 2021-08-03 09:55:54 +02:00
Vera Aguilera Puerto
52351e8b11 Clyde can now render multiple viewports with different maps. (#1917)
* Clyde can now render multiple viewports with different maps.

* remove todo comment
https://tenor.com/view/emoji-disintergrating-meme-emoji-disintegrating-meme-gif-21239978

* Fix tests
2021-08-03 13:24:11 +10:00
metalgearsloth
f75a764ff3 Multi-thread physics solver (#1905) 2021-08-02 13:50:26 +02:00
metalgearsloth
d14f4f0ce3 Use structs for position constraints (#1919)
Co-authored-by: metalgearsloth <metalgearsloth@gmail.com>
2021-08-02 21:47:57 +10:00
Vera Aguilera Puerto
5367570c7f Log simple human-readable error message when PVS mail generation throws an exception. 2021-08-02 12:29:37 +02:00
Vera Aguilera Puerto
e523a733c8 TestLogHandler logs exception, too. 2021-08-02 12:29:37 +02:00
metalgearsloth
06af61106c Fix grid rendering for rotation (#1881)
* Fix grid rendering

* Actually feex

* spellcheck

* Add a test for chunk bounds

* Revert that
2021-08-02 16:41:24 +10:00
metalgearsloth
2239c30924 Fix potential contact crash 2021-08-02 16:19:40 +10:00
Vera Aguilera Puerto
f9f55b6862 Transform sets GridId before raising EntParentChangedMessage event. 2021-08-01 13:35:58 +02:00
Vera Aguilera Puerto
83a5560850 Transform EntMapIdChangedMessage is raised directed. 2021-08-01 12:20:45 +02:00
Visne
9a8f139fb9 Make ScreenToMap not default to main viewport (#1916) 2021-07-31 23:45:08 +02:00
Pieter-Jan Briers
20dae60fd4 Add NumericsHelpers add method. 2021-07-31 16:52:24 +02:00
Pieter-Jan Briers
b4098668bb Use ring buffer for IGameTiming._realFrameTimes.
List.RemoveAt(0) is inefficient.
2021-07-31 16:06:08 +02:00
mirrorcult
9397cc4a6b Fix serv warnings (#1915) 2021-07-31 15:01:18 +10:00
Pieter-Jan Briers
1601e75879 Forgot the debug code oops. 2021-07-31 04:21:37 +02:00
Pieter-Jan Briers
a7b9c87926 Save 0.4% Windows server CPU. 2021-07-31 04:20:50 +02:00
metalgearsloth
8fea42ff9a Fix GetTilesIntersecting for circles (#1912) 2021-07-30 10:01:14 +02:00
metalgearsloth
86d20a0ef1 Bump up light radius
The ones around the singularity are 32 radius for whatever reason
2021-07-30 17:22:23 +10:00
metalgearsloth
09012ea4ff Change velocity constraints to structs (#1906) 2021-07-29 22:14:01 +02:00
metalgearsloth
e68297eb93 Multi-thread physics contacts (#1897) 2021-07-29 22:13:42 +02:00
metalgearsloth
c1a2e23ce2 Fix mission-critical typo 2021-07-30 00:08:17 +10:00
metalgearsloth
f208f6bfa9 Use ref var for manifold points (#1911) 2021-07-29 15:38:12 +02:00
Pieter-Jan Briers
ae526e2e10 FixedArray helpers.
May your stack allocations be fast and your GCs infrequent.
2021-07-29 15:37:43 +02:00
metalgearsloth
25549869b1 Use more values by reference in Collision (#1910)
Also a sneaky Span<ClipVertex> I forgot
2021-07-29 14:49:50 +02:00
metalgearsloth
f71e81d204 Use circle.Position for collisions. (#1909) 2021-07-29 14:49:18 +02:00
metalgearsloth
e67812fdb4 Add shutdowns to VirtualControllers (#1887) 2021-07-29 13:31:34 +02:00
Vera Aguilera Puerto
aa44b1cb8a RaiseLocalEvent non-generic overload that checks for GetType() (#1907)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2021-07-29 13:30:29 +02:00
Vera Aguilera Puerto
8ec75be244 Minor ViewSubscriber cleanup, remove all mentions of PVS eye 2021-07-29 13:29:54 +02:00
Vera Aguilera Puerto
48746b7bd3 Adds ViewSubscriberComponent and ViewSubscriberSystem (#1900) 2021-07-29 13:16:25 +02:00
metalgearsloth
a9791d2033 Fix potential SetTile crash when it unanchors entities (#1903) 2021-07-29 13:15:50 +02:00
Vera Aguilera Puerto
709f1f4284 EntityLookup now uses ILookupWorldBox2Component for getting entities' world AABB. 2021-07-29 13:01:24 +02:00
metalgearsloth
907094a5c8 Minor solver optimisation for invmass 2021-07-29 18:57:35 +10:00
Pieter-Jan Briers
a35a5e1645 Add EntitySystem.Subs property to aid helper methods. 2021-07-29 01:51:51 +02:00
Pieter-Jan Briers
ad8a59a72f Revert "Adds SetButtonDisabledRecursive() method to Control" (#1902)
This reverts commit e93c0f76a9.
2021-07-27 21:44:31 +02:00
Visne
e93c0f76a9 Adds SetButtonDisabledRecursive() method to Control (#1901) 2021-07-27 20:08:24 +02:00
metalgearsloth
7bac32d18e Don't use DeferMoveEvent if the position is NaN (#1896)
The issue is that currently moving around means any non-anchored entities have their positions updated to / from NaN. As you can imagine this is a performance nightmare for anything subscribing to it, especially considering it leads to the broadphase getting desynced for physics.

Realistically we need one of the alternatives Acruid has laid out because flooding the eventbus with NaNs will kill performance.
2021-07-28 00:28:07 +10:00
Pieter-Jan Briers
b6b1d46892 Ignore "CON" in DebugConsoleLogHandler. 2021-07-27 09:38:08 +02:00
Vera Aguilera Puerto
6f0bc3822e InputComponent is now public. 2021-07-27 08:51:02 +02:00
Vera Aguilera Puerto
b7c8452285 Use EntitySystem dependencies in a few places that cached systems before. 2021-07-26 12:57:39 +02:00
Paul Ritter
8c1e075c91 EntitySystem DependencyCollection & EntitySystem dependencies (#1890)
* started work

* tests

* namespace

* working

* thonk

Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
Co-authored-by: Vera Aguilera Puerto <gradientvera@outlook.com>
2021-07-26 12:10:03 +02:00
metalgearsloth
b340e40c99 Cache physics transforms internally (#1873)
* Cache physics transforms internally

3 main points to cache them for:
1. Contact updates
2. Physics Islands solving
3. GetWorldManifold (though this is primarily for ss14).

Whenever multi-threading is done it will need adjustments to make sure no race conditions on accessing the transforms dictionary

* Also cache position and angle for GetWorldAABB

* Fix boogs

* woops
2021-07-26 18:23:10 +10:00
metalgearsloth
c4b124f48d Cleanup physics contacts a bit (#1895)
Removed a lot of the listener comments as we use the eventbus instead in this house.
2021-07-25 23:40:45 +10:00
metalgearsloth
7efae8fbc1 Remove IStartCollide (#1875)
* Remove IStartCollide

Needs several content PRs to be merged as well.

* Feex
2021-07-25 23:06:34 +10:00
Pieter-Jan Briers
7feeeb2f6f OOps 2021-07-25 14:50:14 +02:00
mirrorcult
f90462cf82 Improve RSI error messages (#1894) 2021-07-25 12:06:36 +02:00
metalgearsloth
b19ae9e69e Add AABB VVs for debugging 2021-07-25 19:04:25 +10:00
metalgearsloth
2132d6cbae Comment out the contactmanager crash safeguard for now 2021-07-24 13:50:27 +10:00
Ygg01
d2d6f9d08e Update Linguini to latest to fix escaping text literals (#1880) 2021-07-23 17:43:14 +02:00
metalgearsloth
4b58fcbff2 Fix anchoring on moved grid (#1885) 2021-07-23 10:16:19 +02:00
metalgearsloth
f83f6a8cd6 Remove manifolds from collision events
Nothing uses em anymore.
2021-07-23 13:06:24 +10:00
metalgearsloth
dfd7711506 Stop EndCollision from throwing exceptions
Won't fix the underlying problem but will log it and handle it more gracefully at least until I can reproduce it.
2021-07-23 13:03:54 +10:00
Pieter-Jan Briers
78f9d92c07 Add exception tolerance to DispatchEntityNetworkMessage. 2021-07-22 23:27:39 +02:00
Paul
3a86c827ea made xamlil errors show up in msbuild 2021-07-22 20:01:15 +02:00
metalgearsloth
325f25c547 Fix occluders for moved grid (#1878)
* Refactor occluders

* Copy pasting

* Reduce bounds

* Clear system updates on shutdown
2021-07-22 13:07:45 +10:00
Pieter-Jan Briers
be57b5d20b Add AnyCommandExecuted callback to IConsoleHost.
Intended use case here is for content to listen to ConCmds for AFK detection.
2021-07-21 21:32:32 +02:00
Pieter-Jan Briers
7124d86f94 Allow localization to pass through TimeSpan values. 2021-07-21 18:58:43 +02:00
Pieter-Jan Briers
229380a71d Add TimeSpan read/write helpers to NetMessageExt 2021-07-21 16:25:15 +02:00
metalgearsloth
e9eb536df5 Don't get fixture pairs if they're deleted 2021-07-21 23:08:10 +10:00
metalgearsloth
22297ef6d8 Out of the way System.Numerics 2021-07-21 21:14:41 +10:00
metalgearsloth
7f2e433087 Broadphase refactor (#1848)
* Broadphase refactor

* Stuff

* Working

* TODO

* Changes

* Which fucking madman came up with this shit

* Known gud state

* Kinda shitcodey but it works so fuck it doin it live

* Shuttle jankiness

* Refactor entitylookups to be 30% more based

* Refactor gucci

* Done?

* Fix most tests

* nothing suss

* Vera single-handedly saving shuttles

* fex

* Fix renderingtreecomp for relativity

* Fix IEntityLookup

* Fixes

* Testing jank please revert some of it before merging

* Fix the remaining bugs

* Fix crash

* Fix grid physics initialization

* Shuttle collisions working

* Fixes

* Fixes

* Velocity on transfers

* Velocity on parent change

* Fixes

* world angular velocity too

* Slightly faster map velocities

* showbb revert

* Sketch grids kinda workin

* Fix PVS contact crash

* Cleanup gridfixture updates 0.1%

* Grid fixtures

* AAAAAAAAAAAAAAA

* a

* termp

* Fixes

* Test reversion reversion?

* Tests

* Fix Equals

* Slight box2i cleanup

* Better initializer

* Fix merge issues

* Shuttles go BRRT

* Remove MoveProxy from DynamicTreeBroadphase

* Optimise a shit tonne

* Approx

* fix showbb

* clean

* Slightly more optimised

* My almonds are activating

* Contact transform caching

* Avoid duplicates

* Typo

* Logger

* Jitter 1% better

* Okay shit maybe that's not it.

* Contact fixes

* Move check thingy up front

* Revert some jank caching

* Contact filtering

* Fix master merge

* Test fixes

* Re-fix MapLoaderTest

* Use proxies instead

* uhh wtf?

* Woops

* Fix collisions

* Fix grid fixture generation

* Fix deserializing

* Tile window fix

* Cleanup broadphase

* Bit more cleanup

Co-authored-by: metalgearsloth <metalgearsloth@gmail.com>
2021-07-21 21:12:58 +10:00
Pieter-Jan Briers
18c32a0258 Don't ServerSendToAll to channels without completed handshake. 2021-07-21 03:06:32 +02:00
Pieter-Jan Briers
72314a102d EventBus improvements
Can do ordered session event subscription.

Can subscribe to "All" in one call, to reduce shared boilerplate.
2021-07-21 00:56:42 +02:00
Pieter-Jan Briers
719ea26a31 IConfigurationManager.UnsubValueChanged. 2021-07-20 17:26:52 +02:00
metalgearsloth
5cb8fe1897 End IEndCollide (#1874) 2021-07-20 17:01:30 +02:00
metalgearsloth
f35a52fc24 Change KinematicControllerCollision to use WorldNormal instead (#1872)
Content cares about the WorldNormal and not the LocalNormal so this fixes pushing bugs.
2021-07-19 10:17:39 +02:00
metalgearsloth
6bdb0cef47 Fix IMapGrid WorldToLocal + LocalToWorld (#1871) 2021-07-19 10:17:15 +02:00
Pieter-Jan Briers
fe3c9fe28f Fix late nwVar warning on connect. 2021-07-19 10:16:24 +02:00
Pieter-Jan Briers
6085671f22 Fix memory leak with physics islands and contact solvers.
They were doing config OnValueChanged for every instance and, as such, never getting released.
2021-07-19 10:06:20 +02:00
Visne
a2398da324 Replace most VBox/HBoxContainers with BoxContainers (#1867) 2021-07-18 18:42:08 +02:00
Pieter-Jan Briers
b27304cc58 Add System.Index and System.Range to sandbox whitelist. 2021-07-17 23:51:57 +02:00
Swept
3bf851a6cf FPS Counter no longer shows a decimal 2021-07-17 16:46:09 +00:00
Pieter-Jan Briers
cef92efd0f NetManager now enforces that only specific messages can be sent before serializer handshake completes. 2021-07-17 14:37:40 +02:00
Pieter-Jan Briers
c5961a5ab1 Fix possible race condition in net var handling and improve logging. 2021-07-17 14:37:35 +02:00
Pieter-Jan Briers
8ddd92993d Don't do initial net var stuff on server. 2021-07-17 02:03:37 +02:00
Pieter-Jan Briers
da253a5f34 Log user ID correctly on connection approval 2021-07-17 02:02:59 +02:00
Pieter-Jan Briers
ca9400a1ff Don't log encryption secrets on auth handshake. 2021-07-17 01:24:39 +02:00
Pieter-Jan Briers
f232195ceb Fix audio log warning not using interpolated string correctly. 2021-07-17 01:17:23 +02:00
Pieter-Jan Briers
b54a803519 Add ToString to NetChannel.
Some things already try to log like this so let's just go with it.
2021-07-17 01:16:47 +02:00
Vera Aguilera Puerto
a0d3d2108f Use ResourcePath instead of Path.Join 2021-07-16 21:48:19 +02:00
Vera Aguilera Puerto
977e4a017b Fixes tile window hardcoding tile sprites. 2021-07-16 08:21:58 +02:00
Swept
2d8b159016 Updates the dumb shit stupid path for tile window 2021-07-16 05:38:19 +00:00
Visne
9caa0dde4b Remove unused IEntityManager parameter from EntityCoordinates.FromMap() (#1866) 2021-07-15 18:51:11 +02:00
Pieter-Jan Briers
7a5a8c5eb1 Remove unused Process.WaitForExitAsync helper.
.NET 5 has its own implementation so we use that now.
2021-07-15 10:07:52 +02:00
Swept
95ba58f0a4 Fixes SpriteComponent error reporting 2021-07-14 22:41:51 +00:00
metalgearsloth
f780f04784 Deprecate PhysShapeGrid (#1862)
* Grid fixtures

* termp

* Fixes

* Test reversion reversion?

* Tests

* Fix Equals

* Slight box2i cleanup

* Better initializer

* Also add static grid assert
2021-07-14 18:47:17 +10:00
Pieter-Jan Briers
85782bda92 Make Split- and BoxContainer orientation adjustable, obsolete subtypes. 2021-07-13 17:21:21 +02:00
metalgearsloth
14a01df5b1 Add physics stacking tests (#1865)
Ported from content; only reason for PR is to make sure remote tests are also gucci.
2021-07-13 18:43:09 +10:00
metalgearsloth
644da60bfc ContactCount VV (#1864) 2021-07-13 14:11:27 +10:00
Pieter-Jan Briers
8c83999ad2 Make window creation synchronous.
The async code path isn't really async and if we ever make it so (by using a non shit rendering API) I'll just make it implicitly asynchronous.
2021-07-13 03:39:38 +02:00
Pieter-Jan Briers
24b9fc9eec Add ImageSharp to script console assemblies. 2021-07-12 17:26:54 +02:00
metalgearsloth
ba40185179 Make entitylookup grid-relative (#1849)
* Refactor entitylookups to be 30% more based

* Refactor gucci

* Done?

* Fix most tests

* nothing suss

* Vera single-handedly saving shuttles

* fex

* Copy lookup from shuttles

* sys

* comp recursion
2021-07-12 13:39:02 +02:00
Vera Aguilera Puerto
8b013cb424 Fix engine integration tests not generating Net IDs. 2021-07-12 10:42:38 +02:00
Vera Aguilera Puerto
b67d24efee ITileDefinition now has a Path string that ClydeTileDefinitionManager uses (#1860) 2021-07-12 10:29:13 +02:00
mirrorcult
d992e47f30 Remove NetMessage deprecated boilerplate entirely (#1830)
* Remove NetMessage boilerplate in favor of virtual properties

* forgot some stuff
2021-07-12 10:28:46 +02:00
Acruid
dadd7b4cc3 Remove Static Component NetIds (#1842)
* ComponentNames are not sent over the network when components are created.

* Removed ComponentStates array from EntityState, now the state is stored directly inside the CompChange struct.

* Remove the unnecessary NetID property from ComponentState.

* Remove Component.NetworkSynchronizeExistence.

* Change GetNetComponents to return both the component and the component NetId.

* Remove public usages of the Component.NetID property.

* Adds the NetIDAttribute that can be applied to components.

* Removed Component.NetID.

* Revert changes to GetComponentState and how prediction works.

* Adds component netID automatic generation.

* Modifies ClientConsoleHost so that commands can be called before Initialize().

* Completely remove static NetIds.

* Renamed NetIDAttribute to NetworkedComponentAttribute.

* Fixing unit tests.
2021-07-12 10:23:13 +02:00
Paul Ritter
baef2bc7f8 some misc serv3 fixes (#1861)
adds a typeserializer
adds null parser to read
adds another overload for deserializationresult.value

Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
2021-07-11 15:44:12 +02:00
metalgearsloth
e0b1a7d64a Add Contains Vector2 method to Box2Rotated (#1851) 2021-07-11 22:49:59 +10:00
metalgearsloth
aea5f83002 Preserve world velocities on parent change (#1859)
* Preserve world velocities on parent change

* Faster func

* Test

* lag

* uhh LAAAGGG
2021-07-11 12:25:02 +10:00
Swept
7df2d1f430 Fixes console loc string (#1858) 2021-07-09 15:13:30 +02:00
Vera Aguilera Puerto
d216c3a1f6 VV command can now get IoC services that don't have an interface. 2021-07-07 18:03:20 +02:00
metalgearsloth
986ec3ef06 Do showbb transforms in the iterator (#1847) 2021-07-04 19:52:21 +02:00
metalgearsloth
60cec9cb84 Make showbb awakeness binary (#1846)
Makes it easier to spot mapping issues because otherwise it might have a massive sleep timer and not be easily visible.
2021-07-04 22:31:34 +10:00
Vera Aguilera Puerto
c06707d519 Adds ServerOptions, improve GameControllerOptions, fix engine integration tests (#1844)
* Adds ServerOptions, improve GameControllerOptions, fix engine integration tests

* Do component auto-registration in engine integration tests by default

* Fix integration tests on content, register components ONLY if not contentstarted or options are null

* Add integration test for engine integration tests working correctly

* Move cvar overrides out of content and into engine.
2021-07-03 15:19:46 +02:00
Pieter-Jan Briers
63128324ab Stop RunTicks overriding tick deltas in integration tests.
Now listens to game timing tick rate.
2021-07-03 13:06:19 +02:00
272 changed files with 6373 additions and 3539 deletions

View File

@@ -4,4 +4,8 @@ entity-spawn-window-title = Entity Spawn Panel
entity-spawn-window-search-bar-placeholder = search
entity-spawn-window-clear-button = Clear
entity-spawn-window-erase-button-text = Erase Mode
entity-spawn-window-override-menu-tooltip = Override placement
entity-spawn-window-override-menu-tooltip = Override placement
## Console
console-line-edit-placeholder = Command Here

View 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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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,

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Net;
using Robust.Client.Debugging;
using Robust.Client.GameObjects;

View File

@@ -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;
@@ -46,13 +47,15 @@ namespace Robust.Client
IoCManager.Register<IClientMapManager, ClientMapManager>();
IoCManager.Register<IEntityManager, ClientEntityManager>();
IoCManager.Register<IEntityLookup, EntityLookup>();
IoCManager.Register<IReflectionManager, ClientReflectionManager>();
IoCManager.Register<IConsoleHost, ClientConsoleHost>();
IoCManager.Register<IClientConsoleHost, ClientConsoleHost>();
IoCManager.Register<IComponentFactory, ClientComponentFactory>();
IoCManager.Register<ITileDefinitionManager, ClydeTileDefinitionManager>();
IoCManager.Register<IClydeTileDefinitionManager, ClydeTileDefinitionManager>();
IoCManager.Register<GameController, GameController>();
IoCManager.Register<IGameController, GameController>();
IoCManager.Register<IGameControllerInternal, GameController>();
IoCManager.Register<IReflectionManager, ClientReflectionManager>();
IoCManager.Register<IResourceManager, ResourceCache>();
IoCManager.Register<IResourceManagerInternal, ResourceCache>();
IoCManager.Register<IResourceCache, ResourceCache>();
@@ -72,10 +75,9 @@ namespace Robust.Client
IoCManager.Register<IDebugDrawingManager, DebugDrawingManager>();
IoCManager.Register<ILightManager, LightManager>();
IoCManager.Register<IDiscordRichPresence, DiscordRichPresence>();
IoCManager.Register<IClientConsoleHost, ClientConsoleHost>();
IoCManager.Register<IConsoleHost, ClientConsoleHost>();
IoCManager.Register<IMidiManager, MidiManager>();
IoCManager.Register<IAuthManager, AuthManager>();
IoCManager.Register<IPhysicsManager, PhysicsManager>();
switch (mode)
{
case GameController.DisplayMode.Headless:

View File

@@ -49,7 +49,11 @@ namespace Robust.Client.Console
NetManager.RegisterNetMessage<MsgConCmdAck>(HandleConCmdAck);
NetManager.RegisterNetMessage<MsgConCmd>(ProcessCommand);
Reset();
_requestedCommands = false;
NetManager.Connected += OnNetworkConnected;
LoadConsoleCommands();
SendServerCommandRequest();
LogManager.RootSawmill.AddHandler(new DebugConsoleLogHandler(this));
}
@@ -61,17 +65,6 @@ namespace Robust.Client.Console
ExecuteCommand(null, text);
}
/// <inheritdoc />
public void Reset()
{
AvailableCommands.Clear();
_requestedCommands = false;
NetManager.Connected += OnNetworkConnected;
LoadConsoleCommands();
SendServerCommandRequest();
}
/// <inheritdoc />
public event EventHandler<AddStringArgs>? AddString;
@@ -90,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)
{
@@ -97,7 +92,7 @@ namespace Robust.Client.Console
return;
// echo the command locally
WriteError(null, "> " + command);
WriteLine(null, "> " + command);
//Commands are processed locally and then sent to the server to be processed there again.
var args = new List<string>();
@@ -110,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);
@@ -142,6 +141,9 @@ namespace Robust.Client.Console
private void OutputText(string text, bool local, bool error)
{
AddString?.Invoke(this, new AddStringArgs(text, local, error));
var level = error ? LogLevel.Warning : LogLevel.Info;
Logger.LogS(level, "CON", text);
}
private void OnNetworkConnected(object? sender, NetChannelArgs netChannelArgs)

View File

@@ -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
{
@@ -77,7 +78,7 @@ namespace Robust.Client.Console.Commands
message.Append($"net ID: {registration.NetID}");
}
message.Append($", NSE: {registration.NetworkSynchronizeExistence}, references:");
message.Append($", References:");
shell.WriteLine(message.ToString());
@@ -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()}");
}
}

View 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;
}
}
}

View File

@@ -11,11 +11,6 @@ namespace Robust.Client.Console
/// </summary>
void Initialize();
/// <summary>
/// Resets the console to a post-initialized state.
/// </summary>
void Reset();
event EventHandler<AddStringArgs> AddString;
event EventHandler<AddFormattedMessageArgs> AddFormatted;

View File

@@ -13,10 +13,11 @@ using Microsoft.CodeAnalysis.Text;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.ViewVariables;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Reflection;
using Robust.Shared.Scripting;
using Robust.Shared.Utility;
using SixLabors.ImageSharp;
using Color = Robust.Shared.Maths.Color;
#nullable enable
@@ -116,7 +117,7 @@ namespace Robust.Client.Console
}
else
{
var options = ScriptInstanceShared.GetScriptOptions(_reflectionManager);
var options = ScriptInstanceShared.GetScriptOptions(_reflectionManager).AddReferences(typeof(Image).Assembly);
newScript = CSharpScript.Create(code, options, typeof(ScriptGlobals));
}

View File

@@ -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

View File

@@ -7,13 +7,13 @@ namespace Robust.Client
#if FULL_RELEASE
throw new System.InvalidOperationException("ContentStart.Start is not available on a full release.");
#else
GameController.Start(args, true);
GameController.Start(args, new GameControllerOptions(), true);
#endif
}
public static void StartLibrary(string[] args, GameControllerOptions options)
{
GameController.Start(args, true, null, options);
GameController.Start(args, options, true, null);
}
}
}

View File

@@ -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;
@@ -177,8 +178,9 @@ namespace Robust.Client.Debugging
foreach (var fixture in physBody.Fixtures)
{
var shape = fixture.Shape;
var sleepPercent = physBody.Awake ? physBody.SleepTime / sleepThreshold : 1.0f;
var sleepPercent = physBody.Awake ? 0.0f : 1.0f;
shape.DebugDraw(drawing, transform.WorldMatrix, in viewport, sleepPercent);
drawing.SetTransform(in Matrix3.Identity);
}
foreach (var joint in physBody.Joints)
@@ -187,6 +189,7 @@ namespace Robust.Client.Debugging
drawnJoints.Add(joint);
joint.DebugDraw(drawing, in viewport);
drawing.SetTransform(in Matrix3.Identity);
}
if (worldBox.Contains(mouseWorldPos))

View File

@@ -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)
{

View File

@@ -11,7 +11,7 @@ namespace Robust.Client
{
public void Main(IMainArgs args)
{
Start(args.Args, contentStart: false, args);
Start(args.Args, new GameControllerOptions(), contentStart: false, args);
}
}
}

View File

@@ -22,10 +22,10 @@ namespace Robust.Client
public static void Main(string[] args)
{
Start(args);
Start(args, new GameControllerOptions());
}
public static void Start(string[] args, bool contentStart = false, IMainArgs? loaderArgs=null, GameControllerOptions? options = null)
public static void Start(string[] args, GameControllerOptions options, bool contentStart = false, IMainArgs? loaderArgs=null)
{
if (_hasStarted)
{
@@ -40,7 +40,7 @@ namespace Robust.Client
}
}
private static void ParsedMain(CommandLineArgs args, bool contentStart, IMainArgs? loaderArgs, GameControllerOptions? options)
private static void ParsedMain(CommandLineArgs args, bool contentStart, IMainArgs? loaderArgs, GameControllerOptions options)
{
IoCManager.InitThread();
@@ -51,15 +51,13 @@ namespace Robust.Client
var gc = IoCManager.Resolve<GameController>();
gc.SetCommandLineArgs(args);
gc._loaderArgs = loaderArgs;
if(options != null)
gc.Options = options;
// When the game is ran with the startup executable being content,
// we have to disable the separate load context.
// Otherwise the content assemblies will be loaded twice which causes *many* fun bugs.
gc.ContentStart = contentStart;
gc.Run(mode);
gc.Run(mode, options);
}
public void OverrideMainLoop(IGameLoop gameLoop)
@@ -67,9 +65,9 @@ namespace Robust.Client
_mainLoop = gameLoop;
}
public void Run(DisplayMode mode, Func<ILogHandler>? logHandlerFactory = null)
public void Run(DisplayMode mode, GameControllerOptions options, Func<ILogHandler>? logHandlerFactory = null)
{
if (!StartupSystemSplash(logHandlerFactory))
if (!StartupSystemSplash(options, logHandlerFactory))
{
Logger.Fatal("Failed to start game controller!");
return;

View File

@@ -75,8 +75,6 @@ namespace Robust.Client
public GameControllerOptions Options { get; private set; } = new();
public InitialLaunchState LaunchState { get; private set; } = default!;
public bool LoadConfigAndUserData { get; set; } = true;
public void SetCommandLineArgs(CommandLineArgs args)
{
_commandLineArgs = args;
@@ -95,7 +93,7 @@ namespace Robust.Client
_modLoader.SetUseLoadContext(!ContentStart);
_modLoader.SetEnableSandboxing(Options.Sandboxing);
if (!_modLoader.TryLoadModulesFrom(new ResourcePath("/Assemblies/"), Options.ContentModulePrefix))
if (!_modLoader.TryLoadModulesFrom(Options.AssemblyDirectory, Options.ContentModulePrefix))
{
Logger.Fatal("Errors while loading content assemblies.");
return false;
@@ -196,8 +194,9 @@ namespace Robust.Client
return true;
}
internal bool StartupSystemSplash(Func<ILogHandler>? logHandlerFactory)
internal bool StartupSystemSplash(GameControllerOptions options, Func<ILogHandler>? logHandlerFactory)
{
Options = options;
ReadInitialLaunchState();
SetupLogging(_logManager, logHandlerFactory ?? (() => new ConsoleLogHandler()));
@@ -234,7 +233,7 @@ namespace Robust.Client
_configurationManager.LoadCVarsFromAssembly(typeof(GameController).Assembly); // Client
_configurationManager.LoadCVarsFromAssembly(typeof(IConfigurationManager).Assembly); // Shared
if (LoadConfigAndUserData)
if (Options.LoadConfigAndUserData)
{
var configFile = Path.Combine(userDataDir, Options.ConfigFileName);
if (File.Exists(configFile))
@@ -258,13 +257,13 @@ namespace Robust.Client
ProfileOptSetup.Setup(_configurationManager);
_resourceCache.Initialize(LoadConfigAndUserData ? userDataDir : null);
_resourceCache.Initialize(Options.LoadConfigAndUserData ? userDataDir : null);
var mountOptions = _commandLineArgs != null
? MountOptions.Merge(_commandLineArgs.MountOptions, Options.MountOptions) : Options.MountOptions;
ProgramShared.DoMounts(_resourceCache, mountOptions, Options.ContentBuildDirectory,
_loaderArgs != null && !Options.ResourceMountDisabled, ContentStart);
ProgramShared.DoMounts(_resourceCache, mountOptions, Options.ContentBuildDirectory, Options.AssemblyDirectory,
Options.LoadContentResources, _loaderArgs != null && !Options.ResourceMountDisabled, ContentStart);
if (_loaderArgs != null)
{

View File

@@ -42,6 +42,11 @@ namespace Robust.Client
/// </summary>
public string ContentBuildDirectory { get; init; } = "Content.Client";
/// <summary>
/// Directory to load all assemblies from.
/// </summary>
public ResourcePath AssemblyDirectory { get; init; } = new(@"/Assemblies/");
/// <summary>
/// Directory to load all prototypes from.
/// </summary>
@@ -52,6 +57,16 @@ namespace Robust.Client
/// </summary>
public bool ResourceMountDisabled { get; init; } = false;
/// <summary>
/// Whether to mount content resources when not on FULL_RELEASE.
/// </summary>
public bool LoadContentResources { get; init; } = true;
/// <summary>
/// Whether to load config and user data.
/// </summary>
public bool LoadConfigAndUserData { get; init; } = true;
/// <summary>
/// Whether to disable command line args server auto-connecting.
/// </summary>

View File

@@ -1,12 +1,15 @@
using Robust.Shared.Console;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.Physics;
using Robust.Shared.IoC;
using Robust.Shared.Reflection;
namespace Robust.Client.GameObjects
{
public class ClientComponentFactory : ComponentFactory
internal class ClientComponentFactory : ComponentFactory
{
public ClientComponentFactory()
public ClientComponentFactory(IDynamicTypeFactoryInternal typeFactory, IReflectionManager reflectionManager, IConsoleHost conHost)
: base(typeFactory, reflectionManager, conHost)
{
// Required for the engine to work
RegisterIgnore("KeyBindingInput");
@@ -22,6 +25,7 @@ namespace Robust.Client.GameObjects
RegisterClass<InputComponent>();
RegisterClass<SpriteComponent>();
RegisterClass<ClientOccluderComponent>();
RegisterClass<OccluderTreeComponent>();
RegisterClass<EyeComponent>();
RegisterClass<AppearanceComponent>();
RegisterClass<AppearanceTestComponent>();

View File

@@ -109,13 +109,15 @@ namespace Robust.Client.GameObjects
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
public void SendComponentNetworkMessage(INetChannel? channel, IEntity entity, IComponent component, ComponentMessage message)
{
if (!component.NetID.HasValue)
var netId = ComponentFactory.GetRegistration(component.GetType()).NetID;
if (!netId.HasValue)
throw new ArgumentException($"Component {component.Name} does not have a NetID.", nameof(component));
var msg = _networkManager.CreateNetMessage<MsgEntity>();
msg.Type = EntityMessageType.ComponentMessage;
msg.EntityUid = entity.Uid;
msg.NetId = component.NetID.Value;
msg.NetId = netId.Value;
msg.ComponentMessage = message;
msg.SourceTick = _gameTiming.CurTick;

View File

@@ -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";

View File

@@ -5,6 +5,7 @@ using Robust.Client.ResourceManagement;
using Robust.Shared.Animations;
using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
@@ -17,12 +18,12 @@ namespace Robust.Client.GameObjects
{
[RegisterComponent]
[ComponentReference(typeof(IPointLightComponent))]
[NetworkedComponent()]
public class PointLightComponent : Component, IPointLightComponent, ISerializationHooks
{
[Dependency] private readonly IResourceCache _resourceCache = default!;
public override string Name => "PointLight";
public override uint? NetID => NetIDs.POINT_LIGHT;
internal bool TreeUpdateQueued { get; set; }

View File

@@ -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);
}
}
}

View File

@@ -15,29 +15,43 @@ namespace Robust.Client.GameObjects
private static Box2 SpriteAabbFunc(in SpriteComponent value)
{
var worldPos = value.Owner.Transform.WorldPosition;
return new Box2(worldPos, worldPos);
var tree = RenderingTreeSystem.GetRenderTree(value.Owner);
var pos = worldPos - tree?.Owner.Transform.WorldPosition ?? Vector2.Zero;
return new Box2(pos, pos);
}
private static Box2 LightAabbFunc(in PointLightComponent value)
{
var worldPos = value.Owner.Transform.WorldPosition;
var tree = RenderingTreeSystem.GetRenderTree(value.Owner);
var boxSize = value.Radius * 2;
return Box2.CenteredAround(worldPos, (boxSize, boxSize));
var pos = worldPos - tree?.Owner.Transform.WorldPosition ?? Vector2.Zero;
return Box2.CenteredAround(pos, (boxSize, boxSize));
}
internal static Box2 SpriteAabbFunc(SpriteComponent value, Vector2? worldPos = null)
{
worldPos ??= value.Owner.Transform.WorldPosition;
var tree = RenderingTreeSystem.GetRenderTree(value.Owner);
return new Box2(worldPos.Value, worldPos.Value);
var pos = worldPos - tree?.Owner.Transform.WorldPosition ?? Vector2.Zero;
return new Box2(pos, pos);
}
internal static Box2 LightAabbFunc(PointLightComponent value, Vector2? worldPos = null)
{
worldPos ??= value.Owner.Transform.WorldPosition;
var tree = RenderingTreeSystem.GetRenderTree(value.Owner);
var boxSize = value.Radius * 2;
return Box2.CenteredAround(worldPos.Value, (boxSize, boxSize));
var pos = worldPos - tree?.Owner.Transform.WorldPosition ?? Vector2.Zero;
return Box2.CenteredAround(pos, (boxSize, boxSize));
}
}
}

View File

@@ -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;
}

View File

@@ -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);
}
}
}
}
}

View File

@@ -41,22 +41,12 @@ namespace Robust.Client.GameObjects
{
if (mapId == MapId.Nullspace) yield break;
var enclosed = false;
foreach (var grid in _mapManager.FindGridsIntersecting(mapId, worldAABB))
{
yield return EntityManager.GetEntity(grid.GridEntityId).GetComponent<RenderingTreeComponent>();
// if we're enclosed then we know no other grids relevant + don't need the map's rendertree
if (grid.WorldBounds.Encloses(in worldAABB))
{
enclosed = true;
break;
}
}
if (!enclosed)
yield return _mapManager.GetMapEntity(mapId).GetComponent<RenderingTreeComponent>();
yield return _mapManager.GetMapEntity(mapId).GetComponent<RenderingTreeComponent>();
}
internal IEnumerable<DynamicTree<SpriteComponent>> GetSpriteTrees(MapId mapId, Box2 worldAABB)
@@ -259,9 +249,8 @@ namespace Robust.Client.GameObjects
EntityManager.GetEntity(_mapManager.GetGrid(gridId).GridEntityId).EnsureComponent<RenderingTreeComponent>();
}
private RenderingTreeComponent? GetRenderTree(IEntity entity)
internal static RenderingTreeComponent? GetRenderTree(IEntity entity)
{
if (entity.Transform.MapID == MapId.Nullspace ||
entity.HasComponent<RenderingTreeComponent>()) return null;
@@ -302,8 +291,7 @@ namespace Robust.Client.GameObjects
continue;
}
var treePos = newMapTree?.Owner.Transform.WorldPosition ?? Vector2.Zero;
var aabb = RenderingTreeComponent.SpriteAabbFunc(sprite, worldPos).Translated(-treePos);
var aabb = RenderingTreeComponent.SpriteAabbFunc(sprite, worldPos);
// If we're on a new map then clear the old one.
if (oldMapTree != newMapTree)
@@ -348,7 +336,7 @@ namespace Robust.Client.GameObjects
}
var treePos = newMapTree?.Owner.Transform.WorldPosition ?? Vector2.Zero;
var aabb = RenderingTreeComponent.LightAabbFunc(light, worldPos).Translated(-treePos);
var aabb = RenderingTreeComponent.LightAabbFunc(light, worldPos);
// If we're on a new map then clear the old one.
if (oldMapTree != newMapTree)

View File

@@ -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);
}

View File

@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Input;
using Robust.Client.Map;
@@ -25,6 +26,7 @@ using Robust.Shared.Utility;
namespace Robust.Client.GameStates
{
/// <inheritdoc />
[UsedImplicitly]
public class ClientGameStateManager : IClientGameStateManager
{
private GameStateProcessor _processor = default!;
@@ -36,6 +38,8 @@ namespace Robust.Client.GameStates
_pendingSystemMessages
= new();
private uint _metaCompNetId;
[Dependency] private readonly IComponentFactory _compFactory = default!;
[Dependency] private readonly IClientEntityManagerInternal _entities = default!;
[Dependency] private readonly IEntityLookup _lookup = default!;
@@ -99,6 +103,12 @@ namespace Robust.Client.GameStates
Predicting = _config.GetCVar(CVars.NetPredict);
PredictTickBias = _config.GetCVar(CVars.NetPredictTickBias);
PredictLagBias = _config.GetCVar(CVars.NetPredictLagBias);
var metaId = _compFactory.GetRegistration(typeof(MetaDataComponent)).NetID;
if (!metaId.HasValue)
throw new InvalidOperationException("MetaDataComponent does not have a NetId.");
_metaCompNetId = metaId.Value;
}
/// <inheritdoc />
@@ -343,11 +353,11 @@ namespace Robust.Client.GameStates
}
// TODO: handle component deletions/creations.
foreach (var comp in _componentManager.GetNetComponents(entity.Uid))
foreach (var (netId, comp) in _componentManager.GetNetComponents(entity.Uid))
{
DebugTools.AssertNotNull(comp.NetID);
DebugTools.AssertNotNull(netId);
if (comp.LastModifiedTick < curTick || !last.TryGetValue(comp.NetID!.Value, out var compState))
if (comp.LastModifiedTick < curTick || !last.TryGetValue(netId, out var compState))
{
continue;
}
@@ -368,24 +378,22 @@ namespace Robust.Client.GameStates
// so that we can later roll back to it (if necessary).
var outputData = new Dictionary<EntityUid, Dictionary<uint, ComponentState>>();
Debug.Assert(_players.LocalPlayer != null, "_players.LocalPlayer != null");
var player = _players.LocalPlayer.Session;
foreach (var createdEntity in createdEntities)
{
var compData = new Dictionary<uint, ComponentState>();
outputData.Add(createdEntity, compData);
foreach (var component in _componentManager.GetNetComponents(createdEntity))
foreach (var (netId, component) in _componentManager.GetNetComponents(createdEntity))
{
Debug.Assert(_players.LocalPlayer != null, "_players.LocalPlayer != null");
var player = _players.LocalPlayer.Session;
var state = component.GetComponentState(player);
if (state.GetType() == typeof(ComponentState))
{
if(state.GetType() == typeof(ComponentState))
continue;
}
compData.Add(state.NetID, state);
compData.Add(netId, state);
}
}
@@ -432,8 +440,7 @@ namespace Robust.Client.GameStates
}
else //Unknown entities
{
var metaState = (MetaDataComponentState?) es.ComponentStates
?.FirstOrDefault(c => c.NetID == NetIDs.META_DATA);
var metaState = (MetaDataComponentState?) es.ComponentChanges?.FirstOrDefault(c => c.NetID == _metaCompNetId).State;
if (metaState == null)
{
throw new InvalidOperationException($"Server sent new entity state for {es.Uid} without metadata component!");
@@ -543,7 +550,7 @@ namespace Robust.Client.GameStates
private void HandleEntityState(IComponentManager compMan, IEntity entity, EntityEventBus bus, EntityState? curState,
EntityState? nextState)
{
var compStateWork = new Dictionary<uint, (ComponentState? curState, ComponentState? nextState)>();
var compStateWork = new Dictionary<ushort, (ComponentState? curState, ComponentState? nextState)>();
var entityUid = entity.Uid;
if (curState?.ComponentChanges != null)
@@ -559,42 +566,46 @@ namespace Robust.Client.GameStates
}
else
{
//Right now we just assume every state from an unseen entity is added
if (compMan.HasComponent(entityUid, compChange.NetID))
continue;
var newComp = (Component) _compFactory.GetComponent(compChange.ComponentName!);
var newComp = (Component) _compFactory.GetComponent(compChange.NetID);
newComp.Owner = entity;
compMan.AddComponent(entity, newComp, true);
compStateWork[compChange.NetID] = (compChange.State, null);
}
}
}
if (curState?.ComponentStates != null)
if (curState?.ComponentChanges != null)
{
foreach (var compState in curState.ComponentStates)
foreach (var compChange in curState.ComponentChanges)
{
compStateWork[compState.NetID] = (compState, null);
compStateWork[compChange.NetID] = (compChange.State, null);
}
}
if (nextState?.ComponentStates != null)
if (nextState?.ComponentChanges != null)
{
foreach (var compState in nextState.ComponentStates)
foreach (var compState in nextState.ComponentChanges)
{
if (compStateWork.TryGetValue(compState.NetID, out var state))
{
compStateWork[compState.NetID] = (state.curState, compState);
compStateWork[compState.NetID] = (state.curState, compState.State);
}
else
{
compStateWork[compState.NetID] = (null, compState);
compStateWork[compState.NetID] = (null, compState.State);
}
}
}
foreach (var (netId, (cur, next)) in compStateWork)
{
if (compMan.TryGetComponent(entityUid, netId, out var component))
if (compMan.TryGetComponent(entityUid, (ushort) netId, out var component))
{
try
{

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Robust.Shared.GameObjects;
@@ -195,14 +195,10 @@ namespace Robust.Client.GameStates
{
compData.Remove(change.NetID);
}
}
}
if (entityState.ComponentStates != null)
{
foreach (var compState in entityState.ComponentStates)
{
compData[compState.NetID] = compState;
else if (change.State is not null)
{
compData[change.NetID] = change.State;
}
}
}
}

View File

@@ -21,6 +21,7 @@ namespace Robust.Client.GameStates
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IClientNetManager _netManager = default!;
[Dependency] private readonly IClientGameStateManager _gameStateManager = default!;
[Dependency] private readonly IComponentFactory _componentFactory = default!;
private const int HistorySize = 60 * 3; // number of ticks to keep in history.
private const int TargetPayloadBps = 56000 / 8; // Target Payload size in Bytes per second. A mind-numbing fifty-six thousand bits per second, who would ever need more?
@@ -90,17 +91,14 @@ namespace Robust.Client.GameStates
sb.Append($"\n Changes:");
foreach (var compChange in entState.ComponentChanges)
{
var del = compChange.Deleted ? 'D' : 'C';
sb.Append($"\n [{del}]{compChange.NetID}:{compChange.ComponentName}");
}
}
var registration = _componentFactory.GetRegistration(compChange.NetID);
var create = compChange.Created ? 'C' : '\0';
var mod = !(compChange.Created || compChange.Created) ? 'M' : '\0';
var del = compChange.Deleted ? 'D' : '\0';
sb.Append($"\n [{create}{mod}{del}]{compChange.NetID}:{registration.Name}");
if (entState.ComponentStates is not null)
{
sb.Append($"\n States:");
foreach (var compState in entState.ComponentStates)
{
sb.Append($"\n {compState.NetID}:{compState.GetType().Name}");
if(compChange.State is not null)
sb.Append($"\n STATE:{compChange.State.GetType().Name}");
}
}
}

View File

@@ -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 />

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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>();
@@ -467,13 +468,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);

View File

@@ -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;

View File

@@ -210,11 +210,11 @@ namespace Robust.Client.Graphics.Clyde
_windowing!.WindowRequestAttention(_windowing.MainWindow!);
}
public async Task<IClydeWindow> CreateWindow(WindowCreateParameters parameters)
public IClydeWindow CreateWindow(WindowCreateParameters parameters)
{
DebugTools.AssertNotNull(_windowing);
return await _windowing!.WindowCreate(parameters);
return _windowing!.WindowCreate(parameters);
}
private void DoDestroyWindow(WindowReg reg)

View File

@@ -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!;

View File

@@ -210,7 +210,7 @@ namespace Robust.Client.Graphics.Clyde
yield break;
}
public Task<IClydeWindow> CreateWindow(WindowCreateParameters parameters)
public IClydeWindow CreateWindow(WindowCreateParameters parameters)
{
var window = new DummyWindow(CreateRenderTarget((123, 123), default))
{
@@ -218,7 +218,7 @@ namespace Robust.Client.Graphics.Clyde
};
_windows.Add(window);
return Task.FromResult<IClydeWindow>(window);
return window;
}
public ClydeHandle LoadShader(ParsedShader shader, string? name = null)

View File

@@ -22,8 +22,7 @@ namespace Robust.Client.Graphics.Clyde
{
internal partial class Clyde
{
// Wait for it.
private sealed partial class GlfwWindowingImpl
private unsafe sealed partial class GlfwWindowingImpl
{
private readonly List<GlfwWindowReg> _windows = new();
@@ -36,45 +35,23 @@ namespace Robust.Client.Graphics.Clyde
private int _nextWindowId = 1;
private static bool _eglLoaded;
public async Task<WindowHandle> WindowCreate(WindowCreateParameters parameters)
public WindowHandle WindowCreate(WindowCreateParameters parameters)
{
// tfw await not allowed in unsafe contexts
// GL APIs don't take kindly to making a new window without unbinding the main context. Great.
// Leaving code for async path in, in case it works on like GLX.
var unbindContextAndBlock = true;
DebugTools.AssertNotNull(_mainWindow);
Task<GlfwWindowCreateResult> task;
unsafe
{
if (unbindContextAndBlock)
GLFW.MakeContextCurrent(null);
GLFW.MakeContextCurrent(null);
task = SharedWindowCreate(
_clyde._chosenRenderer,
parameters,
_mainWindow!.GlfwWindow);
}
var task = SharedWindowCreate(
_clyde._chosenRenderer,
parameters,
_mainWindow!.GlfwWindow);
if (unbindContextAndBlock)
{
unsafe
{
// Block the main thread (to avoid stuff like texture uploads being problematic).
WaitWindowCreate(task);
// Block the main thread (to avoid stuff like texture uploads being problematic).
WaitWindowCreate(task);
if (unbindContextAndBlock)
GLFW.MakeContextCurrent(_mainWindow.GlfwWindow);
}
}
else
{
await task;
}
GLFW.MakeContextCurrent(_mainWindow.GlfwWindow);
var (reg, error) = await task;
var (reg, error) = task.Result;
if (reg == null)
{
@@ -85,18 +62,11 @@ namespace Robust.Client.Graphics.Clyde
_clyde.CreateWindowRenderTexture(reg);
_clyde.InitWindowBlitThread(reg);
unsafe
{
GLFW.MakeContextCurrent(_mainWindow.GlfwWindow);
}
GLFW.MakeContextCurrent(_mainWindow.GlfwWindow);
return reg.Handle;
}
}
// Yes, you read that right.
private sealed unsafe partial class GlfwWindowingImpl
{
public bool TryInitMainWindow(Renderer renderer, [NotNullWhen(false)] out string? error)
{
var width = _cfg.GetCVar(CVars.DisplayWidth);
@@ -167,6 +137,21 @@ namespace Robust.Client.Graphics.Clyde
WindowCreateParameters parameters,
Window* share)
{
//
// IF YOU'RE WONDERING WHY THIS IS TASK-BASED:
// I originally wanted this to be async so we could avoid blocking the main thread
// while the OS takes its stupid 100~ms just to initialize a fucking GL context.
// This doesn't *work* because
// we have to release the GL context while the shared context is being created.
// (at least on WGL, I didn't test other platforms and I don't care to.)
// Not worth it to avoid a main thread blockage by allowing Clyde to temporarily release the GL context,
// because rendering would be locked up *anyways*.
//
// Basically what I'm saying is that everything about OpenGL is a fucking mistake
// and I should get on either Veldrid or Vulkan some time.
// Probably Veldrid tbh.
//
// Yes we ping-pong this TCS through the window thread and back, deal with it.
var tcs = new TaskCompletionSource<GlfwWindowCreateResult>();
SendCmd(new CmdWinCreate(
@@ -525,7 +510,6 @@ namespace Robust.Client.Graphics.Clyde
}
return window;
}

View File

@@ -38,7 +38,7 @@ namespace Robust.Client.Graphics.Clyde
void WindowRequestAttention(WindowReg window);
void WindowSwapBuffers(WindowReg window);
uint? WindowGetX11Id(WindowReg window);
Task<WindowHandle> WindowCreate(WindowCreateParameters parameters);
WindowHandle WindowCreate(WindowCreateParameters parameters);
void WindowDestroy(WindowReg reg);
string KeyGetName(Keyboard.Key key);

View File

@@ -130,6 +130,6 @@ namespace Robust.Client.Graphics
IEnumerable<IClydeMonitor> EnumerateMonitors();
Task<IClydeWindow> CreateWindow(WindowCreateParameters parameters);
IClydeWindow CreateWindow(WindowCreateParameters parameters);
}
}

View File

@@ -10,8 +10,7 @@ namespace Robust.Client
GameControllerOptions Options { get; }
bool ContentStart { get; set; }
void SetCommandLineArgs(CommandLineArgs args);
bool LoadConfigAndUserData { get; set; }
void Run(GameController.DisplayMode mode, Func<ILogHandler>? logHandlerFactory = null);
void Run(GameController.DisplayMode mode, GameControllerOptions options, Func<ILogHandler>? logHandlerFactory = null);
void KeyDown(KeyEventArgs keyEvent);
void KeyUp(KeyEventArgs keyEvent);
void TextEntered(TextEventArgs textEvent);

View File

@@ -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);

View File

@@ -32,12 +32,12 @@ namespace Robust.Client.Map
//get shared euid of map comp entity
foreach (var entityState in entityStates!)
{
if(entityState.ComponentStates is null)
if(entityState.ComponentChanges is null)
continue;
foreach (var compState in entityState.ComponentStates)
foreach (var compChange in entityState.ComponentChanges)
{
if (compState is not MapComponentState mapCompState || mapCompState.MapId != mapId)
if (compChange.State is not MapComponentState mapCompState || mapCompState.MapId != mapId)
continue;
mapEuid = entityState.Uid;
@@ -67,12 +67,12 @@ namespace Robust.Client.Map
//get shared euid of map comp entity
foreach (var entityState in entityStates!)
{
if(entityState.ComponentStates is null)
if (entityState.ComponentChanges is null)
continue;
foreach (var compState in entityState.ComponentStates)
foreach (var compState in entityState.ComponentChanges)
{
if (compState is not MapGridComponentState gridCompState || gridCompState.GridIndex != gridId)
if (compState.State is not MapGridComponentState gridCompState || gridCompState.GridIndex != gridId)
continue;
gridEuid = entityState.Uid;

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
@@ -7,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;
@@ -17,7 +19,7 @@ namespace Robust.Client.Map
[Dependency] private readonly IResourceCache _resourceCache = default!;
private Texture? _tileTextureAtlas;
public Texture TileTextureAtlas => _tileTextureAtlas ?? Texture.Transparent;
private readonly Dictionary<ushort, Box2> _tileRegions = new();
@@ -61,7 +63,7 @@ namespace Robust.Client.Map
var row = i / dimensionX;
Image<Rgba32> image;
using (var stream = _resourceCache.ContentFileRead($"/Textures/Constructible/Tiles/{def.SpriteName}.png"))
using (var stream = _resourceCache.ContentFileRead(new ResourcePath(def.Path) / $"{def.SpriteName}.png"))
{
image = Image.Load<Rgba32>(stream);
}

View File

@@ -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()
{

View File

@@ -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)

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -1,5 +1,5 @@
using Robust.Shared.Enums;
using Robust.Client.Graphics;
using Robust.Client.Graphics;
namespace Robust.Client.Placement

View File

@@ -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++)

View File

@@ -6,20 +6,31 @@ namespace Robust.Client.UserInterface.Controls
{
/// <summary>
/// A container that lays out its children sequentially.
/// Use <see cref="VBoxContainer"/> or <see cref="HBoxContainer"/> for an implementation.
/// </summary>
public abstract class BoxContainer : Container
public class BoxContainer : Container
{
private LayoutOrientation _orientation;
public const string StylePropertySeparation = "separation";
private const int DefaultSeparation = 0;
private protected abstract bool Vertical { get; }
/// <summary>
/// Specifies "where" the controls should be laid out.
/// </summary>
public AlignMode Align { get; set; }
private bool Vertical => Orientation == LayoutOrientation.Vertical;
public LayoutOrientation Orientation
{
get => _orientation;
set
{
_orientation = value;
InvalidateMeasure();
}
}
private int ActualSeparation
{
get
@@ -237,5 +248,11 @@ namespace Robust.Client.UserInterface.Controls
/// </summary>
End = 2
}
public enum LayoutOrientation : byte
{
Horizontal,
Vertical
}
}
}

View File

@@ -10,7 +10,7 @@ namespace Robust.Client.UserInterface.Controls
{
public Label Label { get; }
public Button() : base()
public Button()
{
AddStyleClass(StyleClassButton);
Label = new Label

View File

@@ -14,12 +14,13 @@ namespace Robust.Client.UserInterface.Controls
public Label Label { get; }
public TextureRect TextureRect { get; }
public CheckBox() : base()
public CheckBox()
{
ToggleMode = true;
var hBox = new HBoxContainer
var hBox = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
StyleClasses = { StyleClassCheckBox },
};
AddChild(hBox);

View File

@@ -13,7 +13,7 @@ namespace Robust.Client.UserInterface.Controls
public const string StylePseudoClassHover = "hover";
public const string StylePseudoClassDisabled = "disabled";
public ContainerButton() : base()
public ContainerButton()
{
DrawModeChanged();
}

View File

@@ -1,10 +1,16 @@
namespace Robust.Client.UserInterface.Controls
using System;
namespace Robust.Client.UserInterface.Controls
{
/// <summary>
/// Container that lays its children out horizontally: from left to right.
/// </summary>
[Obsolete("Use BoxContainer and set Orientation instead")]
public class HBoxContainer : BoxContainer
{
private protected override bool Vertical => false;
public HBoxContainer()
{
Orientation = LayoutOrientation.Horizontal;
}
}
}

View File

@@ -1,7 +1,13 @@
using System;
namespace Robust.Client.UserInterface.Controls
{
[Obsolete("Use SplitContainer directly and set Orientation")]
public class HSplitContainer : SplitContainer
{
private protected sealed override bool Vertical => false;
public HSplitContainer()
{
Orientation = SplitOrientation.Horizontal;
}
}
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -52,7 +52,7 @@ namespace Robust.Client.UserInterface.Controls
public event EventHandler<ValueChangedEventArgs>? ValueChanged;
public SpinBox() : base()
public SpinBox()
{
MouseFilter = MouseFilterMode.Pass;

View File

@@ -4,7 +4,7 @@ using Robust.Shared.Maths;
namespace Robust.Client.UserInterface.Controls
{
public abstract class SplitContainer : Container
public class SplitContainer : Container
{
/// <summary>
/// Defines how user-initiated moving of the split should work. See documentation
@@ -22,11 +22,10 @@ namespace Robust.Client.UserInterface.Controls
/// </summary>
public float SplitEdgeSeparation { get; set; }
private protected abstract bool Vertical { get; }
private float _splitCenter;
private SplitState _splitState;
private bool _dragging;
private SplitOrientation _orientation;
// min / max x and y extents in relative virtual pixels of where the split can go regardless
// of anything else.
@@ -35,6 +34,18 @@ namespace Robust.Client.UserInterface.Controls
private float SplitMax =>
Vertical ? Height - (SplitWidth + SplitEdgeSeparation) : Width - (SplitWidth + SplitEdgeSeparation);
private bool Vertical => Orientation == SplitOrientation.Vertical;
public SplitOrientation Orientation
{
get => _orientation;
set
{
_orientation = value;
InvalidateMeasure();
}
}
public SplitContainer()
{
MouseFilter = MouseFilterMode.Stop;
@@ -264,5 +275,11 @@ namespace Robust.Client.UserInterface.Controls
/// </summary>
Manual = 1
}
public enum SplitOrientation : byte
{
Horizontal,
Vertical
}
}
}

View File

@@ -1,10 +1,16 @@
namespace Robust.Client.UserInterface.Controls
using System;
namespace Robust.Client.UserInterface.Controls
{
/// <summary>
/// Container that lays its children out vertically: from top to bottom.
/// </summary>
[Obsolete("Use BoxContainer and set Orientation instead")]
public class VBoxContainer : BoxContainer
{
private protected override bool Vertical => true;
public VBoxContainer()
{
Orientation = LayoutOrientation.Vertical;
}
}
}

View File

@@ -1,7 +1,13 @@
using System;
namespace Robust.Client.UserInterface.Controls
{
[Obsolete("Use SplitContainer directly and set Orientation")]
public class VSplitContainer : SplitContainer
{
private protected sealed override bool Vertical => true;
public VSplitContainer()
{
Orientation = SplitOrientation.Vertical;
}
}
}

View File

@@ -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>

View File

@@ -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

View File

@@ -25,7 +25,7 @@ namespace Robust.Client.UserInterface.CustomControls
}
var fps = _gameTiming.FramesPerSecondAvg;
Text = $"FPS: {fps:N1}";
Text = $"FPS: {fps:N0}";
}
}
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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);
}

View File

@@ -24,7 +24,7 @@ namespace Robust.Client.UserInterface
monitor = clyde.EnumerateMonitors().Single(m => m.Id == id);
}
var window = await clyde.CreateWindow(new WindowCreateParameters
var window = clyde.CreateWindow(new WindowCreateParameters
{
Maximized = true,
Title = "SS14 Debug Window",

View File

@@ -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!;

View File

@@ -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),
};

View File

@@ -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)
};

View File

@@ -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()
{

View File

@@ -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!;

View File

@@ -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),
};

View File

@@ -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),
};

View File

@@ -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"));

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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>

View File

@@ -33,6 +33,9 @@ namespace Robust.Client.ViewVariables
var valArg = args[0];
if (valArg.StartsWith("SI"))
{
if (valArg.StartsWith("SIoC"))
valArg = valArg.Substring(4);
// Server-side IoC selector.
var selector = new ViewVariablesIoCSelector(valArg.Substring(1));
vvm.OpenVV(selector);
@@ -41,6 +44,9 @@ namespace Robust.Client.ViewVariables
if (valArg.StartsWith("I"))
{
if (valArg.StartsWith("IoC"))
valArg = valArg.Substring(3);
// Client-side IoC selector.
var reflection = IoCManager.Resolve<IReflectionManager>();
if (!reflection.TryLooseGetType(valArg, out var type))

View File

@@ -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
{

View File

@@ -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);

View File

@@ -94,14 +94,12 @@ 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);
public ServerOptions Options { get; private set; } = new();
/// <inheritdoc />
public int MaxPlayers => _config.GetCVar(CVars.GameMaxPlayers);
@@ -114,7 +112,7 @@ namespace Robust.Server
Logger.InfoS("srv", "Restarting Server...");
Cleanup();
Start(_logHandlerFactory);
Start(Options, _logHandlerFactory);
}
/// <inheritdoc />
@@ -141,15 +139,16 @@ namespace Robust.Server
}
/// <inheritdoc />
public bool Start(Func<ILogHandler>? logHandlerFactory = null)
public bool Start(ServerOptions options, Func<ILogHandler>? logHandlerFactory = null)
{
Options = options;
var profilePath = Path.Join(Environment.CurrentDirectory, "AAAAAAAA");
ProfileOptimization.SetProfileRoot(profilePath);
ProfileOptimization.StartProfile("AAAAAAAAAA");
_config.Initialize(true);
if (LoadConfigAndUserData)
if (Options.LoadConfigAndUserData)
{
// Sets up the configMgr
// If a config file path was passed, use it literally.
@@ -269,22 +268,26 @@ namespace Robust.Server
return true;
}
var dataDir = LoadConfigAndUserData
var dataDir = Options.LoadConfigAndUserData
? _commandLineArgs?.DataDir ?? PathHelpers.ExecutableRelativeFile("data")
: null;
// Set up the VFS
_resources.Initialize(dataDir);
ProgramShared.DoMounts(_resources, _commandLineArgs?.MountOptions, "Content.Server", contentStart:ContentStart);
var mountOptions = _commandLineArgs != null
? MountOptions.Merge(_commandLineArgs.MountOptions, Options.MountOptions) : Options.MountOptions;
ProgramShared.DoMounts(_resources, mountOptions, Options.ContentBuildDirectory, Options.AssemblyDirectory,
Options.LoadContentResources, Options.ResourceMountDisabled, ContentStart);
// When the game is ran with the startup executable being content,
// we have to disable the separate load context.
// Otherwise the content assemblies will be loaded twice which causes *many* fun bugs.
_modLoader.SetUseLoadContext(!ContentStart);
_modLoader.SetEnableSandboxing(false);
_modLoader.SetEnableSandboxing(Options.Sandboxing);
if (!_modLoader.TryLoadModulesFrom(new ResourcePath("/Assemblies/"), "Content."))
if (!_modLoader.TryLoadModulesFrom(Options.AssemblyDirectory, Options.ContentModulePrefix))
{
Logger.Fatal("Errors while loading content assemblies.");
return true;
@@ -335,13 +338,23 @@ namespace Robust.Server
// otherwise the prototypes will be cleared
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
prototypeManager.Initialize();
prototypeManager.LoadDirectory(new ResourcePath(@"/Prototypes"));
prototypeManager.LoadDirectory(Options.PrototypeDirectory);
prototypeManager.Resync();
IoCManager.Resolve<IServerConsoleHost>().Initialize();
_entityManager.Startup();
IoCManager.Resolve<IEntityLookup>().Startup();
_stateManager.Initialize();
// sometime after content init
{
var reg = _entityManager.ComponentFactory.GetRegistration<TransformComponent>();
if (!reg.NetID.HasValue)
throw new InvalidOperationException("TransformComponent does not have a NetId.");
_stateManager.SetTransformNetId(reg.NetID.Value);
}
_scriptHost.Initialize();
_modLoader.BroadcastRunLevel(ModRunLevel.PostInit);
@@ -492,35 +505,12 @@ namespace Robust.Server
}
public bool ContentStart { get; set; }
public bool LoadConfigAndUserData { private get; set; } = true;
public void OverrideMainLoop(IGameLoop gameLoop)
{
_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.
@@ -577,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();
@@ -606,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())
{

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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.
}
}
}

View File

@@ -7,13 +7,13 @@ namespace Robust.Server
#if FULL_RELEASE
throw new System.InvalidOperationException("ContentStart.Start is not available on a full release.");
#else
Program.Start(args, true);
Program.Start(args, new ServerOptions(), true);
#endif
}
public static void StartLibrary(string[] args)
public static void StartLibrary(string[] args, ServerOptions options)
{
Program.Start(args, true);
Program.Start(args, options, true);
}
}
}

View File

@@ -1,4 +1,5 @@
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Players;

View File

@@ -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();
}
}

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