Compare commits

...

150 Commits

Author SHA1 Message Date
Pieter-Jan Briers
583b7ebf38 WPF layout (#1581) 2021-02-21 12:28:13 +01:00
Acruid
771a256925 Fixes bug with an exception being throw when trying to overwrite a deleted Component. (#1587)
Entity now uses constructor injection instead of property injection.
2021-02-20 23:30:09 -08:00
Acruid
ae79e89347 Added a shared PointLightComponent interface. (#1585)
* Added a shared PointLightComponent interface.

* Fix unit tests.
2021-02-20 16:06:34 -08:00
Acruid
6c7eeb95eb Marks Register and RegisterReference obsolete in IComponentFactory. (#1582) 2021-02-20 12:18:37 -08:00
Acruid
de0bd1887f Sprite Rendering Bugfixes (#1551)
* Added documentation to Clyde on the sprite rendering calls.

* Added a rotation debug entity.

* Non-directional RSIs and raw textures are now rotated properly.

* Directional RSIs and Sprite Smoothing work.

* Remove the Directional flag usages.

* Supports layers with different numbers of directions.

* Fixes window rendering.
2021-02-20 11:06:08 -08:00
metalgearsloth
eb3a815d48 Remove AiLogicProcessor (#1568)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-02-19 21:52:32 -08:00
DrSmugleaf
e2a4dcdff1 Fix comparing by name and not ID for entity prototype updates (#1578) 2021-02-20 02:41:51 +01:00
DrSmugleaf
68b0d7bf2e Fix not clearing the queue after hot reload (#1576) 2021-02-20 01:43:56 +01:00
DrSmugleaf
a9b163992b Fix and add test for PrototypeManager LoadString (#1574) 2021-02-20 01:43:43 +01:00
DrSmugleaf
2409965cf8 Fix build (#1575) 2021-02-20 00:15:43 +01:00
DrSmugleaf
eada37378a Add YAML hot reloading (#1571)
* Implement hot reloading for entity prototypes

* Implement automatic prototype hot-reloading

* Merge fixes

* Add yaml hot reloading and a message to notify the client

* Add reloading only changed files, remove cooldown, add retries and remove IPrototype

* Remove reload command

* Make the client listen for reloads instead and only when focused

* Fix errors

* Only queue a reload when the queue has items in it

* Make fails after 10 retries log instead of throw if reloading

Co-authored-by: Jackson Lewis <inquisitivepenguin@protonmail.com>
2021-02-20 00:02:04 +01:00
DrSmugleaf
0f1da1ba2a Add window focused callback to Clyde (#1573) 2021-02-19 22:10:03 +01:00
Acruid
e0cdcd228e Fixed Timer Namespace in unit tests. 2021-02-18 20:35:34 -08:00
Acruid
fdb5e014b5 PauseManager moved to Shared (#1553)
* Moved IPauseManager from server to shared.

* Moved ITimerManager from Timers to Timing.

* Added missing IConsoleHost to server/client RegisterIoC. Tests work again.
2021-02-18 20:12:26 -08:00
DrSmugleaf
cefcad775b Make addcomp and rmcomp give better feedback and case insensitive (#1570)
* Make addcomp and rmcomp case insensitive

* Fix up names

* Make addcomp and rmcomp give better feedback

* Make addcomp and rmcomp less fail happy
2021-02-18 20:01:14 -08:00
Vera Aguilera Puerto
e40feac1f1 Adds VV autorefresh when right-clicking the refresh button. (#1558)
* Adds VV autorefresh when right-clicking the refresh button.

* cancel token on close

* button tooltip
2021-02-18 00:14:11 -08:00
DrSmugleaf
3ef4ac7452 Make component states dependant on the player getting them (#1569) 2021-02-17 23:48:17 -08:00
Pieter-Jan Briers
93bf1b09e7 Fix disconnecting while connecting causes you to be locked out of the server. 2021-02-17 23:22:11 +01:00
DrSmugleaf
a1e557e870 Add IPrototypeManager method to load a string (#1567) 2021-02-17 13:20:39 -08:00
Pieter-Jan Briers
864adb7445 Add DateTimeStyles to sandbox. 2021-02-17 11:52:36 +01:00
mirrorcult
9e3f3f0c1c vec2i serializer (#1563)
Co-authored-by: cyclowns <cyclowns@protonmail.ch>
2021-02-16 12:19:45 -08:00
DrSmugleaf
a40c4a435c Fix file not found exceptions when starting up the game with a debugger (#1562)
* Fix exceptions when starting up the game

* Remove try catches
2021-02-16 20:05:22 +01:00
DrSmugleaf
17182dd0e8 Engine PR for enabling nullability in Content.Client (#1565) 2021-02-16 20:05:06 +01:00
DrSmugleaf
d8b50044a2 Add (de)serialization for immutable lists (#1549) 2021-02-16 20:04:28 +01:00
Pieter-Jan Briers
4dc396e73d Fixes warning in TypePropertySerialization_Test.cs 2021-02-16 09:20:06 +01:00
Pieter-Jan Briers
6ae0b0e892 Fix [GenerateTypedNameReferences] with sealed types.
Fixes #1546
2021-02-16 09:19:57 +01:00
Pieter-Jan Briers
7162ca3456 Probably fix the bug where people get locked out of the server due to duplicate connction attempts. 2021-02-16 09:02:14 +01:00
Pieter-Jan Briers
1b44c1a1b8 Allow NotImplementedException in sandbox. 2021-02-15 17:57:38 +01:00
Clyybber
5b80b33e00 Change GetFileSystemInfos to EnumerateFileSystemInfos for iteration (#1561) 2021-02-15 16:26:16 +01:00
DrSmugleaf
f05c1b2395 Add Attribute generic constraint to IReflectionManager.FindTypesWithAttribute (#1548) 2021-02-14 02:14:00 +01:00
Pieter-Jan Briers
d9b2c73440 XamlUI improvements.
1. Add XAML namespaces https://spacestation14.io with Avalonia hacks.
2. Make markup extensions work with Avalonia hacks.
3. Add LocExtension for localized strings.
4. Add Vector2 parsing type converter to XAML compilation.
5. Make SS14Window better thanks to these improvements.
2021-02-14 02:09:37 +01:00
Pieter-Jan Briers
29a39f8e0a Adds LocExtension markup extension for XAML.
Does Loc.GetString().
2021-02-13 15:13:05 +01:00
Pieter-Jan Briers
2d72a2bdb5 Server timing improvements.
Add helpers.
Fix desynchronized NetTime.
2021-02-13 11:42:12 +01:00
Pieter-Jan Briers
91da635631 Fix Robust.Shared.Interfaces namespace in ScriptInstanceShared 2021-02-13 11:42:12 +01:00
chairbender
68ab3d504a Various fixes to support new chatbox (#1547)
* #272 no arrow, actually change id on channel changer

* #272 ability to apply style class to child

* #272 try methods for selecting items in OptionButton.cs

* #272 allow escaping right angle bracket in formatted message

* #272 ability to detect when local player is set / unset

* #272 make RemoveModal public since PushModal is as well, so modals can be removed on-demand if needed rather than relying on a click elsewhere

* #272 revert
2021-02-12 18:20:29 -08:00
Pieter-Jan Briers
5187040a64 Remove unsafe code from GrowableStack 2021-02-13 00:47:05 +01:00
DrSmugleaf
e0c63e7ce6 Add SerializedType attribute to specify the id used in !type tags (#1545)
* Add SerializedType attribute to serialize types without the !type tag

* Fix nulls in tests

* Fix null in tests maybe

* Return to type tags

* Fix imports
2021-02-11 13:50:55 -08:00
Acruid
0ba2272cab Remove all dependencies from LocalizationManager.
Remove IoCManager calls from EntityPrototype.
Add missing using statements preventing EXCEPTION_TOLERANCE from building.
2021-02-11 00:39:12 -08:00
Acruid
2183cd7ca1 Massive Namespace Cleanup (#1544)
* Removed the Interfaces folder.
* All objects inside the GameObjects subfolders are now in the GameObjects namespace.
* Added a Resharper DotSettings file to mark the GameObjects subfolders as not providing namespaces.
* Simplified Robust.client.Graphics namespace.
* Automated remove redundant using statements.
2021-02-10 23:27:19 -08:00
DrSmugleaf
cbf01f0aa5 Fix ComponentChangedSerialized test (#1543) 2021-02-09 21:24:28 +01:00
Pieter-Jan Briers
6973d43006 Network timing synchronization.
Lidgren NetTime.Now is now synchronized to IGameTiming.RealTime.

NetChannel is now a nested class of NetManager.

Add IGameTiming.ServerTime, INetChannel.RemoteTimeOffset, INetChannel.RemoteTime
2021-02-09 14:28:20 +01:00
Pieter-Jan Briers
c5a961d9a0 Even better: use argStr. 2021-02-09 14:28:20 +01:00
Acruid
b4f7d71ee7 Server console can forward commands to a client. 2021-02-09 04:16:15 -08:00
metalgearsloth
cd3684e575 Guard against client appearancecomp changes (#1540)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-02-09 13:13:05 +01:00
Pieter-Jan Briers
317b8ce965 Fix sudo command mangling quotes. 2021-02-09 12:29:23 +01:00
Pieter-Jan Briers
ff96140afa Fix messed up \n. 2021-02-09 03:17:27 +01:00
Pieter-Jan Briers
bade95f6b7 Fix unit tests 2021-02-09 02:37:27 +01:00
Pieter-Jan Briers
69daaca399 Remove CVar.SECURE and replace auth CVars with env variables. 2021-02-09 01:50:42 +01:00
DrSmugleaf
5af7e60043 Add KeyValuePair YAML serialization (#1538) 2021-02-08 21:49:08 +01:00
DrSmugleaf
ab823dcd12 Add component registration lookup with case insensitive names (#1535) 2021-02-08 18:07:23 +01:00
Paul Ritter
b3976eb8d7 Analyzer Bongaloo 2: The Return (#1512)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
2021-02-08 18:05:27 +01:00
Pieter-Jan Briers
91759cdd3c Harder DynamicTree against NaN.
B2DynamicTree<T> has asserts, DynamicTree<T> handles them gracefully.

NaNs in DynamicTree were causing the internal state to corrupt resulting in the sprite flickering issues.

Fixes https://github.com/space-wizards/space-station-14/issues/2896
2021-02-08 05:03:56 +01:00
Pieter-Jan Briers
b000c3178b FileLogHandler is now internal.
Sandboxing thing.
2021-02-07 23:07:57 +01:00
Vera Aguilera Puerto
63b3ecdd13 Fix SpawnRepeating timer extensions 2021-02-07 17:04:43 +01:00
DrSmugleaf
a183a98f75 Add support for deserializing nullable enum types (#1537) 2021-02-07 14:31:38 +01:00
Acruid
bded7ad228 You can now provide a factory delegate to IoC register calls. 2021-02-06 23:00:08 -08:00
metalgearsloth
75c4f48496 Fix NPCs getting stuck (#1533)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-02-05 20:38:01 +01:00
Acruid
49fe2d59cf Removes hard-coded color support for writing console shells. Strings with formatting codes can replace this feature.
Added a separate WriteError function to console shell, to mimic writing to stderr.
2021-02-05 01:35:06 -08:00
DrSmugleaf
8a5b7f5146 Add AudioSystem extension methods for the client and server (#1532) 2021-02-05 17:23:36 +11:00
Pieter-Jan Briers
ae4f470e1f Fix duplicate .xaml files. 2021-02-04 15:22:18 +01:00
metalgearsloth
18fcab6f71 Fix loadbp on paused maps (#1531)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-02-04 23:29:37 +11:00
Acruid
1ae6c32c62 Adds the net_entityreport console command, that displays a network history of entity updates. 2021-02-03 23:19:47 -08:00
Pieter-Jan Briers
cf6925f19b Makes sudo command show output to user. (#1530) 2021-02-03 19:31:32 -08:00
Pieter-Jan Briers
b4c7ffe38a Adds an exec command.
Just like Quake. Man that Carmack guy was onto something.
2021-02-04 03:40:03 +01:00
Pieter-Jan Briers
d5c2f45f14 Fix accidental usage of OpenGL DSA in screenshot code. 2021-02-03 21:10:48 +01:00
Pieter-Jan Briers
dcc88d2d36 Fix KHR_debug detection on OpenGL ES. 2021-02-03 21:10:48 +01:00
metalgearsloth
a274b8dfc2 EntityQuery no longer yields paused by default (#1521)
* Change EntityQuery to not get paused by default

* GetAllComponents

* Fix shell commands

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-02-04 00:20:31 +11:00
Paul Ritter
f42c1379e0 Revert "Viewport improvements. (#1510)" (#1527)
This reverts commit fc5e3ab69d.
2021-02-03 12:25:12 +01:00
Pieter-Jan Briers
c4fa7e98d4 Fix clients not disconnecting correctly when client is closed. 2021-02-03 00:04:41 +01:00
Vera Aguilera Puerto
8b9dadffb1 MIDI improvements (#1526) 2021-02-02 18:46:24 +01:00
Vera Aguilera Puerto
5e99c6d04d ViewVariables server-side "Add Component" button isn't hidden anymore when searching for components. 2021-02-02 13:28:56 +01:00
Vera Aguilera Puerto
606d232dbb Update ViewVariables to use the new commands API 2021-02-02 13:26:41 +01:00
Vera Aguilera Puerto
df877582a6 You can now add or remove components from the comfort of ViewVariables (#1524) 2021-02-02 12:01:54 +01:00
Acruid
8ffdb090e6 Adds a property on ITransformComponent that prevents the entity from being rotated. Resolves #1479. 2021-02-01 20:27:17 -08:00
Acruid
033d6ffb22 Fixes bug where effects were dying in transit from lag. Resolves #1256. 2021-02-01 19:17:34 -08:00
Acruid
3eb6e067f9 Console Unify (#1513)
* Renamed shared ICommand to IConsoleCommand.

* Lots of refactoring into a shared context.

* Removed ICommonSession from server concmd Execute.

* Added argStr parameter to concmd execute.

* The execute function of client concmds now returns void, use the new shell.RemoteExecuteCommand function to forward commands.

# Conflicts:
#	Robust.Client/Console/Commands/Debug.cs

* Finally move shells and commands into shared.

* Console commands can now be registered directly without a class in a shared context.

* Pulled up ConsoleHost and Console shell into a shared context.

* Pulled up half the functions of ConsoleHost into a shared context.

* Repair rebase damage.

* Make LoadConsoleCommands function not remove any previously registered commands.
2021-02-01 16:40:26 -08:00
Vera Aguilera Puerto
1f64f93ef4 Update nfluidsynth to latest version, 0.3.1 2021-02-01 21:33:22 +01:00
Pieter-Jan Briers
7dd617b0d6 Adds reflection helper methods to script globals. 2021-02-01 19:41:02 +01:00
metalgearsloth
0567b70704 Optimise showbb (#1519)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-02-01 20:15:50 +11:00
Pieter-Jan Briers
9963e89c14 Sanitize ResourcePath to disallow .. shenigans. 2021-01-31 22:38:40 +01:00
Remie Richards
29e0faed88 Can now animate ITransformComponent.WorldPosition (#1518) 2021-01-30 23:26:01 +01:00
Pieter-Jan Briers
0ce6ff9870 Fix tickrate sync if non-default tickrate saved to client config.
Fixes #1516

Thanks to blue on Discord for helping me diagnose this.
2021-01-30 01:27:42 +01:00
Vera Aguilera Puerto
dbe9a96dfa Reorganizes NumericsHelpers into different files using partial classes. (#1514) 2021-01-29 12:46:27 +01:00
Vera Aguilera Puerto
fc5e3ab69d Viewport improvements. (#1510)
* Remove the main viewport.

* Re-add main viewport in a different place

* Move screen/map translation into ViewportContainer

* Support for viewport resolution

* Fix postfx, add WorldToScreen to Viewport

* Remove useless cast

* Some cleanup.

* Fix incorrect worldBounds when rendering viewports

* nullability

Co-authored-by: 20kdc <asdd2808@gmail.com>
2021-01-29 12:45:04 +01:00
Julian Giebel
ed4974141c Add TryCastValue to CollectionExtensions.cs (#1515)
* Add TryCastValue to CollectionExtensions.cs

* Change TryCastValue to be more generic

* Add notnull constraing for TKey to TryCastValue

Co-authored-by: Julian Giebel <j.giebel@netrocks.info>
2021-01-28 20:45:11 +01:00
Pieter-Jan Briers
3e5efd5ed0 Add AnimatedTextureRect 2021-01-24 23:00:02 +01:00
Pieter-Jan Briers
e1110eadb4 Better unified handling of SpriteSpecifiers
Add more utilities, most notably IRsiStateLike, to make working with SpriteSpecifiers easier. Especially when animated.
2021-01-24 22:59:47 +01:00
Pieter-Jan Briers
06ace83a73 Allow audio playback without grids. 2021-01-24 16:04:23 +01:00
Pieter-Jan Briers
cd01ca924b Fix broken PanelContainer due to previous commit.
God I am tired.
2021-01-24 04:20:51 +01:00
Pieter-Jan Briers
38ad8ce132 Fix UI scaling weirdness with PanelContainer. 2021-01-23 21:51:35 +01:00
20kdc
ee440c2df9 Make the lighting manager much more configurable, including a console lock (#1506) 2021-01-23 21:17:49 +01:00
Pieter-Jan Briers
32f3c863fb Fix UI scaling bugs with ProgressBar 2021-01-23 20:15:45 +01:00
Pieter-Jan Briers
b00e0bef5a Fix UI scaling bug with RichTextLabel 2021-01-23 16:02:31 +01:00
Pieter-Jan Briers
0a09b27918 Fix UI scaling bug with GridContainer 2021-01-23 16:02:23 +01:00
Paul
c9f6a4e32a fixes enum VV 2021-01-21 15:33:42 +01:00
Pieter-Jan Briers
b205a14f69 Exception tolerance for NetManager.OnDisconnect 2021-01-20 21:07:02 +01:00
Pieter-Jan Briers
d5f3292e0a Unregister OnSessionOnPlayerStatusChanged on bound user interfaces.
I am frankly flabbergasted this is only a problem now.
2021-01-20 21:00:24 +01:00
Pieter-Jan Briers
561e4b330e Fix ALL components memory leaking.
:irrational:
2021-01-20 20:45:02 +01:00
Paul
36a5d102ff prevent one error from killing the entire namegenerator from running 2021-01-17 17:17:02 +01:00
Pieter-Jan Briers
b9c39e0953 Fix reconnecting. 2021-01-17 16:08:48 +01:00
Pieter-Jan Briers
ad4c8be132 Add system for preserving Map UIDs across edits. 2021-01-17 15:51:32 +01:00
kira-er
988cbf9a87 VV Enum (#1503) 2021-01-17 01:50:26 +01:00
Acruid
e26512001a Completely removed MsgSetTickRate, the NetConfigurationManager replaces the functionality. This builds on top of the previous commit.
Fixes bug where server was not sending the entire set of replicated cvars.
2021-01-16 15:33:44 -08:00
Pieter-Jan Briers
8e97982f1e Fix net.tickrate not being replicated correctly to clients. 2021-01-16 21:46:10 +01:00
Paul
3ca686298e Fixes ViewVariablesManager using the wrong VVPropEditor for Type in shared not annotated with [NetSerializable] 2021-01-16 20:05:15 +01:00
20kdc
5e914cb13a PointLightComponent: Don't dirty if enabled is being set to what it's already set to. (#1507) 2021-01-16 00:13:55 +11:00
Pieter-Jan Briers
a1bdfca8ba Fix SimplePredictReconcileTest. 2021-01-15 11:03:52 +01:00
20kdc
79deaca409 Polar Coordinates: simplify maths, any-angle occluders are no longer evil (#1504)
Someone please performance-test this, but I think the fragment shader code simplifications speak for themselves.

Radrark found the "line in polar coordinates" equation I needed and a diagram that explained the variables.

That equation was essentially the missing piece to the whole thing.
2021-01-14 13:44:25 +01:00
20kdc
2eeb21431b Fix FileDialogManager not doing DLL mapping properly in sandbox, and FileDialogManager hard crash on multiple dialogs (#1505) 2021-01-14 13:43:39 +01:00
chairbender
c4062bcae9 #1449 new ControlFocusExited override for allowing controls to know (#1467)
when they lost control focus, separate from keyboard focus
2021-01-13 23:18:45 +01:00
Acruid
cd3a85ea04 Replicated CVars (#1489) 2021-01-13 10:02:08 +01:00
Pieter-Jan Briers
d15b5c7f22 Fix compiler warnings. 2021-01-13 03:10:51 +01:00
Leo
18bbe2271d Adds extension method to read and write colors on NetMessages (#1500) 2021-01-13 01:12:55 +01:00
Pieter-Jan Briers
ee2b7a3a66 Adds gcm function to ScriptGlobalsShared 2021-01-12 21:17:35 +01:00
Pieter-Jan Briers
ca36671131 Fix nullable error in RadioOptions 2021-01-12 21:17:26 +01:00
Pieter-Jan Briers
604a1a6960 Disable CodeQL crap since it STILL doesn't do .NET 5 and I'm sick of the errors. 2021-01-12 17:20:11 +01:00
Pieter-Jan Briers
2898f5396f Account for windows time period latency in Lidgren.
1. Set timeBeginPeriod(3) on the server to reduce scheduler latency in the lidgren thread.
2. Add 16ms of guaranteed lag bias to client prediction calculations to account for scheduler latency.

Both of these changes are to account for how the windows scheduler seems to handle time periods in related to socket polls. See this Discord conversation for why, details down below as well: https://discord.com/channels/310555209753690112/770682801607278632/798309250291204107

Basically Windows has this thing called time periods which determines the precision of sleep operations and such. By default it's like 16ms so a sleep will only be accurate to within 16ms.

Problem: Lidgren polls the socket with a timeout of 1ms.

The way Windows seems to handle this is that:
1. if a message comes into the socket, the poll immediately ends and Lidgren can handle it.
2. If nothing comes in, it takes the whole 16ms time period to actually process stuff.

Oh yeah, and Lidgren's thread needs to keep pumping at a steady rate or else it *won't flush its send queue*. On Windows it seems to normally pump at 65/125 Hz. On Linux it goes like 950 Hz as intended.

Now, the worst part is that (1) causes Lidgren's latency calculation to always read 0 (over localhost) instead of the 30~ms it SHOULD BE (assuming client and server localhost).

That 30ms of unaccounted delay worst caseis enough to cause prediction undershoot and have messages arrive too late. Yikes.

So, to fix this...

On the server we just decrease the tick period and call it a day. Screw your battery life players don't have local servers running anyways.

On the client we bias the prediction calculations to account for this "unmeasurable" lag.

Of course, all this can be configured via CVars.
2021-01-12 02:43:15 +01:00
bgare89
39541639c5 Add RadioOptions.cs (#1484)
Co-authored-by: Vera Aguilera Puerto <6766154+Zumorica@users.noreply.github.com>
2021-01-12 01:45:15 +01:00
metalgearsloth
50981ad1a1 Layered PlacementManager (#1403)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-01-11 22:42:54 +11:00
Pieter-Jan Briers
0cbfbeffae Revert "Analyzer to check if interfacemethods are explicitly marked as such" (#1499)
This reverts commit e603153016.
2021-01-11 12:26:23 +01:00
Paul Ritter
e603153016 Analyzer to check if interfacemethods are explicitly marked as such (#1477)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
2021-01-11 12:14:26 +01:00
Pieter-Jan Briers
e7c417ca0c Remove a couple MiB of memory usage. 2021-01-11 10:58:42 +01:00
Pieter-Jan Briers
a3989f28eb Re-order exception handler in StatusHost to avoid blowing up in some cases ??? 2021-01-11 10:24:29 +01:00
Pieter-Jan Briers
38ace3c348 Fix exception with trying to place entities at... NaN?
This is still a bug but it should not cause an exception on the server
2021-01-11 10:24:29 +01:00
Ygg01
0e00170f45 Make RSI directions default to 1. (#1495)
Add some helper methods, made an `example.rsi` for testing.

Closes #1463
2021-01-11 18:12:34 +11:00
Pieter-Jan Briers
261ee96cad Make client connect 1 second faster.
Whoops.
2021-01-11 02:39:35 +01:00
Pieter-Jan Briers
2c851885db Fix ItemList not working correctly with scaling. 2021-01-11 02:06:25 +01:00
Pieter-Jan Briers
849be86455 Add launchauth command to bootstrap login tokens for connecting to live servers. 2021-01-10 23:55:01 +01:00
Pieter-Jan Briers
ffd5c120be Add PreserveBaseOverridesAttribute to sandbox whitelist.
Used by covariant returns.
2021-01-10 22:03:18 +01:00
Vera Aguilera Puerto
76b15dda70 Client-side addcompc/rmcompc (#1497) 2021-01-10 20:09:14 +01:00
Vera Aguilera Puerto
0bf7f519ad Adds client-side setinputcontext command (#1498) 2021-01-10 20:08:44 +01:00
Vera Aguilera Puerto
f97f325a36 Fixes sprite scale not being taken into account. (#1496)
* Fixes sprite scale not being taken into account.
- Only apply scale if length of scale vector not close or equal to 1.

* I blame Remie

* Fix vector maths
I should spend more time studying maths instead of contributing, to be fair.

* Remie no please nO
2021-01-10 19:53:04 +01:00
metalgearsloth
24315fa787 Avoid unnecessary EntMapIdChangedMessages (#1493)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-01-10 12:46:59 +11:00
Ygg01
792179657b Fix space in dotnet breaking windows builds (#1490)
Who would win?
Thirty developers
-OR-
One sneaky ` ` boi?

On windows default path to dotnet are `C:\Program Files`. Without quoting the
the command if it contains a space, it's going to break Windows builds that
install in `C:\Program Files`.
2021-01-08 13:53:42 +01:00
Paul
9b92bcf911 intermediate fix to garantuee people with dotnet in path to launch commpilerobustxaml 2021-01-05 12:15:03 +01:00
metalgearsloth
86e34ea27b Fix enum caching (#1485)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-01-05 16:17:20 +11:00
Clyybber
62cf778958 Fix build when dotnet is not in the PATH (#1483) 2021-01-04 20:25:43 +01:00
py01
5d667e44c3 Replaces AnchoredChanged C# event with a ComponentMessage (#1482)
Co-authored-by: py01 <pyronetics01@gmail.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-01-04 10:16:05 +01:00
metalgearsloth
6d84b8741c Cache enum references (#1480)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-01-03 03:45:02 +01:00
DrSmugleaf
d08ca59b75 Make RobustUnitTest register content cvars and set _isServer (#1481) 2021-01-03 03:44:12 +01:00
Pieter-Jan Briers
f06b046c1c Fix Content-Type not being set for status API. 2021-01-03 03:42:21 +01:00
Vera Aguilera Puerto
bb412a6906 Entity Timer SpawnTimer throws if entity is deleted. 2021-01-01 15:45:13 +01:00
Radrark
1baee3004c Adds new keybind property: AllowSubCombs (#1473)
Co-authored-by: Radrark <null>
2020-12-29 15:59:34 +01:00
Pieter-Jan Briers
f18068c13a Update NetSerializer submodule to improve build times 2020-12-29 15:59:13 +01:00
Pieter-Jan Briers
0ba00a1845 Gcf command to mess with LOH compaction. 2020-12-29 14:10:15 +01:00
Pieter-Jan Briers
28caf0d74c Reduce allocations 2020-12-29 03:58:16 +01:00
Pieter-Jan Briers
ecbb32b70b Clean up various cases of failing to dispose file streams. 2020-12-29 03:58:16 +01:00
Pieter-Jan Briers
8e2a9cc597 Font atlasses are now dynamic and can render all glyphs in the font file. 2020-12-29 03:58:16 +01:00
Vera Aguilera Puerto
a7eb8201c9 Fix MIDI soundfont load error on non-rooted paths. 2020-12-26 22:05:17 +01:00
Pieter-Jan Briers
1f95fe6782 Fix XamlIL problems when publishing 2020-12-25 18:34:19 +01:00
793 changed files with 13641 additions and 8315 deletions

View File

@@ -11,14 +11,14 @@
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '30 18 * * 6'
#on:
# push:
# branches: [ master ]
# pull_request:
# # The branches below must be a subset of the branches above
# branches: [ master ]
# schedule:
# - cron: '30 18 * * 6'
jobs:
analyze:
@@ -38,12 +38,12 @@ jobs:
uses: actions/checkout@v2
with:
submodules: true
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.100
- name: Build
run: dotnet build

View File

@@ -0,0 +1,5 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
<ItemGroup>
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\Robust.Analyzers\Robust.Analyzers.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
</ItemGroup>
</Project>

View File

@@ -1,2 +1,3 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
<Import Project="Robust.Analyzers.targets" />
</Project>

View File

@@ -1,5 +1,7 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
<PropertyGroup>
<!-- Avoid MSBuild adding a None entry for XAML files because they'd show up TWICE in the project view. -->
<DefaultItemExcludes>**/*.xaml</DefaultItemExcludes>
<RobustUseExternalMSBuild>true</RobustUseExternalMSBuild>
<_RobustUseExternalMSBuild>$(RobustUseExternalMSBuild)</_RobustUseExternalMSBuild>
<_RobustUseExternalMSBuild Condition="'$(_RobustForceInternalMSBuild)' == 'true'">false</_RobustUseExternalMSBuild>
@@ -53,8 +55,11 @@
DelaySign="$(DelaySign)"
UpdateBuildIndicator="$(IntermediateOutputPath)XAML/doot"/>
<PropertyGroup>
<DOTNET_HOST_PATH Condition="'$(DOTNET_HOST_PATH)' == ''">dotnet</DOTNET_HOST_PATH>
</PropertyGroup>
<Exec
Condition="'$(_RobustUseExternalMSBuild)' == 'true'"
Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:CompileRobustXaml /p:_RobustForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:BuildProjectReferences=false"/>
Command="&quot;$(DOTNET_HOST_PATH)&quot; msbuild /nodereuse:false $(MSBuildProjectFile) /t:CompileRobustXaml /p:_RobustForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:RuntimeIdentifier=$(RuntimeIdentifier) /p:TargetFramework=$(TargetFramework) /p:BuildProjectReferences=false"/>
</Target>
</Project>

View File

@@ -17,6 +17,7 @@ namespace OpenToolkit.GraphicsLibraryFramework
// On net472, we rely on Mono's DllMap for this. See the .dll.config file.
NativeLibrary.SetDllImportResolver(typeof(GLFWNative).Assembly, (name, assembly, path) =>
{
// Please keep in sync with what Robust.Shared/DllMapHelper.cs does.
if (name != "glfw3.dll")
{
return IntPtr.Zero;

View File

@@ -0,0 +1,40 @@
- type: entity
id: debugRotation1
name: dbg_rotation1
components:
- type: Clickable
- type: InteractionOutline
- type: Sprite
netsync: false
visible: true
sprite: debugRotation.rsi
state: direction1
placement:
mode: AlignTileAny
- type: entity
id: debugRotation4
name: dbg_rotation4
components:
- type: Clickable
- type: InteractionOutline
- type: Sprite
netsync: false
visible: true
sprite: debugRotation.rsi
state: direction4
placement:
mode: AlignTileAny
- type: entity
id: debugRotationTex
name: dbg_rotationTex
components:
- type: Clickable
- type: InteractionOutline
- type: Sprite
netsync: false
visible: true
texture: debugRotation.rsi/direction1.png
placement:
mode: AlignTileAny

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

View File

@@ -0,0 +1,17 @@
{
"version": 1,
"size": {
"x": 32,
"y": 32
},
"states": [{
"name": "direction1",
"directions": 1,
"delays": [[1.0]]
}, {
"name": "direction4",
"directions": 4,
"delays": [[1.0], [1.0], [1.0], [1.0]]
}
]
}

Binary file not shown.

View File

@@ -0,0 +1,92 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Document = Microsoft.CodeAnalysis.Document;
namespace Robust.Analyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class ExplicitInterfaceAnalyzer : DiagnosticAnalyzer
{
public readonly SyntaxKind[] ExcludedModifiers =
{
SyntaxKind.VirtualKeyword,
SyntaxKind.AbstractKeyword,
SyntaxKind.OverrideKeyword
};
public const string DiagnosticId = "RA0000";
private const string Title = "No explicit interface specified";
private const string MessageFormat = "No explicit interface specified";
private const string Description = "Make sure to specify the interface in your method-declaration.";
private const string Category = "Usage";
[SuppressMessage("ReSharper", "RS2008")] private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);
private const string RequiresExplicitImplementationAttributeMetadataName =
"Robust.Shared.Analyzers.RequiresExplicitImplementationAttribute";
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.MethodDeclaration);
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.PropertyDeclaration);
}
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
ISymbol symbol;
Location location;
switch (context.Node)
{
//we already have a explicit interface specified, no need to check further
case MethodDeclarationSyntax methodDecl when methodDecl.ExplicitInterfaceSpecifier != null || methodDecl.Modifiers.Any(m => ExcludedModifiers.Contains(m.Kind())):
return;
case PropertyDeclarationSyntax propertyDecl when propertyDecl.ExplicitInterfaceSpecifier != null || propertyDecl.Modifiers.Any(m => ExcludedModifiers.Contains(m.Kind())):
return;
case MethodDeclarationSyntax methodDecl:
symbol = context.SemanticModel.GetDeclaredSymbol(methodDecl);
location = methodDecl.Identifier.GetLocation();
break;
case PropertyDeclarationSyntax propertyDecl:
symbol = context.SemanticModel.GetDeclaredSymbol(propertyDecl);
location = propertyDecl.Identifier.GetLocation();
break;
default:
return;
}
var attrSymbol = context.Compilation.GetTypeByMetadataName(RequiresExplicitImplementationAttributeMetadataName);
var isInterfaceMember = symbol?.ContainingType.AllInterfaces.Any(
i =>
i.GetMembers().Any(m => SymbolEqualityComparer.Default.Equals(symbol, symbol.ContainingType.FindImplementationForInterfaceMember(m)))
&& i.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attrSymbol))
) ?? false;
if (isInterfaceMember)
{
//we do not have an explicit interface specified. bad!
var diagnostic = Diagnostic.Create(
Rule,
location);
context.ReportDiagnostic(diagnostic);
}
}
}
}

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="3.8.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,150 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Robust.Analyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class SerializableAnalyzer : DiagnosticAnalyzer
{
// Metadata of the analyzer
public const string DiagnosticId = "RA0001";
// You could use LocalizedString but it's a little more complicated for this sample
private const string Title = "Class not marked as (Net)Serializable";
private const string MessageFormat = "Class not marked as (Net)Serializable";
private const string Description = "The class should be marked as (Net)Serializable.";
private const string Category = "Usage";
private const string RequiresSerializableAttributeMetadataName = "Robust.Shared.Analyzers.RequiresSerializableAttribute";
private const string SerializableAttributeMetadataName = "System.SerializableAttribute";
private const string NetSerializableAttributeMetadataName = "Robust.Shared.Serialization.NetSerializableAttribute";
[SuppressMessage("ReSharper", "RS2008")] private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration);
}
private bool Marked(INamedTypeSymbol namedTypeSymbol, INamedTypeSymbol attrSymbol)
{
if (namedTypeSymbol == null) return false;
if (namedTypeSymbol.GetAttributes()
.Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attrSymbol))) return true;
return Marked(namedTypeSymbol.BaseType, attrSymbol);
}
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
var attrSymbol = context.Compilation.GetTypeByMetadataName(RequiresSerializableAttributeMetadataName);
var classDecl = (ClassDeclarationSyntax) context.Node;
var classSymbol = context.SemanticModel.GetDeclaredSymbol(classDecl);
if (classSymbol == null) return;
if (Marked(classSymbol, attrSymbol))
{
var attributes = classSymbol.GetAttributes();
var serAttr = context.Compilation.GetTypeByMetadataName(SerializableAttributeMetadataName);
var netSerAttr = context.Compilation.GetTypeByMetadataName(NetSerializableAttributeMetadataName);
var hasSerAttr = attributes.Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, serAttr));
var hasNetSerAttr =
attributes.Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, netSerAttr));
if (!hasSerAttr || !hasNetSerAttr)
{
var requiredAttributes = new List<string>();
if(!hasSerAttr) requiredAttributes.Add(SerializableAttributeMetadataName);
if(!hasNetSerAttr) requiredAttributes.Add(NetSerializableAttributeMetadataName);
context.ReportDiagnostic(
Diagnostic.Create(
Rule,
classDecl.Identifier.GetLocation(),
ImmutableDictionary.CreateRange(new Dictionary<string, string>()
{
{
"requiredAttributes", string.Join(",", requiredAttributes)
}
})));
}
}
}
}
[ExportCodeFixProvider(LanguageNames.CSharp)]
public class SerializableCodeFixProvider : CodeFixProvider
{
private const string Title = "Annotate class as (Net)Serializable.";
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
foreach (var diagnostic in context.Diagnostics)
{
var span = diagnostic.Location.SourceSpan;
var classDecl = root.FindToken(span.Start).Parent.AncestorsAndSelf().OfType<ClassDeclarationSyntax>().First();
if(!diagnostic.Properties.TryGetValue("requiredAttributes", out var requiredAttributes)) return;
context.RegisterCodeFix(
CodeAction.Create(
Title,
c => FixAsync(context.Document, classDecl, requiredAttributes, c),
Title),
diagnostic);
}
}
private async Task<Document> FixAsync(Document document, ClassDeclarationSyntax classDecl,
string requiredAttributes, CancellationToken cancellationToken)
{
var attributes = new List<AttributeSyntax>();
var namespaces = new List<string>();
foreach (var attribute in requiredAttributes.Split(','))
{
var tempSplit = attribute.Split('.');
namespaces.Add(string.Join(".",tempSplit.Take(tempSplit.Length-1)));
var @class = tempSplit.Last();
@class = @class.Substring(0, @class.Length - 9); //cut out "Attribute" at the end
attributes.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName(@class)));
}
var newClassDecl =
classDecl.AddAttributeLists(SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList(attributes)));
var root = (CompilationUnitSyntax) await document.GetSyntaxRootAsync(cancellationToken);
root = root.ReplaceNode(classDecl, newClassDecl);
foreach (var ns in namespaces)
{
if(root.Usings.Any(u => u.Name.ToString() == ns)) continue;
root = root.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(ns)));
}
return document.WithSyntaxRoot(root);
}
public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(SerializableAnalyzer.DiagnosticId);
public override FixAllProvider GetFixAllProvider()
{
return WellKnownFixAllProviders.BatchFixer;
}
}
}

View File

@@ -0,0 +1,37 @@
using System.Linq;
using Pidgin;
using static Pidgin.Parser;
namespace Robust.Build.Tasks
{
public static class MathParsing
{
public static Parser<char, float> Single { get; } = Real.Select(c => (float) c);
public static Parser<char, float> Single1 { get; }
= Single.Between(SkipWhitespaces);
public static Parser<char, (float, float)> Single2 { get; }
= Single.Before(SkipWhitespaces).Repeat(2).Select(e =>
{
var arr = e.ToArray();
return (arr[0], arr[1]);
});
public static Parser<char, (float, float, float, float)> Single4 { get; }
= Single.Before(SkipWhitespaces).Repeat(4).Select(e =>
{
var arr = e.ToArray();
return (arr[0], arr[1], arr[2], arr[3]);
});
public static Parser<char, float[]> Thickness { get; }
= SkipWhitespaces.Then(
OneOf(
Try(Single4.Select(c => new[] {c.Item1, c.Item2, c.Item3, c.Item4})),
Try(Single2.Select(c => new[] {c.Item1, c.Item2})),
Try(Single1.Select(c => new[] {c}))
));
}
}

View File

@@ -0,0 +1,32 @@
using System.Reflection.Emit;
using XamlX.Ast;
using XamlX.Emit;
using XamlX.IL;
using XamlX.TypeSystem;
namespace Robust.Build.Tasks
{
internal class RXamlColorAstNode
: XamlAstNode, IXamlAstValueNode, IXamlAstILEmitableNode
{
private readonly IXamlMethod _method;
private readonly string _color;
public RXamlColorAstNode(IXamlLineInfo lineInfo, RXamlWellKnownTypes types, string color) : base(lineInfo)
{
_color = color;
Type = new XamlAstClrTypeReference(lineInfo, types.Color, false);
_method = types.ColorFromXaml;
}
public IXamlAstTypeReference Type { get; }
public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{
codeGen.Ldstr(_color);
codeGen.EmitCall(_method);
return XamlILNodeEmitResult.Type(0, Type.GetClrType());
}
}
}

View File

@@ -0,0 +1,93 @@
using System;
using System.Linq;
using System.Reflection.Emit;
using XamlX.Ast;
using XamlX.Emit;
using XamlX.IL;
using XamlX.TypeSystem;
namespace Robust.Build.Tasks
{
public abstract class RXamlVecLikeConstAstNode<T>
: XamlAstNode, IXamlAstValueNode, IXamlAstILEmitableNode
where T : unmanaged
{
private readonly IXamlConstructor _constructor;
protected readonly T[] Values;
public RXamlVecLikeConstAstNode(
IXamlLineInfo lineInfo,
IXamlType type, IXamlConstructor constructor,
IXamlType componentType, T[] values)
: base(lineInfo)
{
_constructor = constructor;
Values = values;
var @params = constructor.Parameters;
if (@params.Count != values.Length)
throw new ArgumentException("Invalid amount of parameters");
if (@params.Any(c => c != componentType))
throw new ArgumentException("Invalid constructor: not all parameters match component type");
Type = new XamlAstClrTypeReference(lineInfo, type, false);
}
public IXamlAstTypeReference Type { get; }
public virtual XamlILNodeEmitResult Emit(
XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context,
IXamlILEmitter codeGen)
{
codeGen.Newobj(_constructor);
return XamlILNodeEmitResult.Type(0, Type.GetClrType());
}
}
public sealed class RXamlSingleVecLikeConstAstNode : RXamlVecLikeConstAstNode<float>
{
public RXamlSingleVecLikeConstAstNode(
IXamlLineInfo lineInfo,
IXamlType type, IXamlConstructor constructor,
IXamlType componentType, float[] values)
: base(lineInfo, type, constructor, componentType, values)
{
}
public override XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context,
IXamlILEmitter codeGen)
{
foreach (var value in Values)
{
codeGen.Emit(OpCodes.Ldc_R4, value);
}
return base.Emit(context, codeGen);
}
}
public sealed class RXamlInt32VecLikeConstAstNode : RXamlVecLikeConstAstNode<int>
{
public RXamlInt32VecLikeConstAstNode(
IXamlLineInfo lineInfo,
IXamlType type, IXamlConstructor constructor,
IXamlType componentType, int[] values)
: base(lineInfo, type, constructor, componentType, values)
{
}
public override XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context,
IXamlILEmitter codeGen)
{
foreach (var value in Values)
{
codeGen.Emit(OpCodes.Ldc_I4, value);
}
return base.Emit(context, codeGen);
}
}
}

View File

@@ -0,0 +1,58 @@
using System.Linq;
using XamlX.Transform;
using XamlX.TypeSystem;
namespace Robust.Build.Tasks
{
class RXamlWellKnownTypes
{
public XamlTypeWellKnownTypes XamlIlTypes { get; }
public IXamlType Single { get; }
public IXamlType Int32 { get; }
public IXamlType Vector2 { get; }
public IXamlConstructor Vector2ConstructorFull { get; }
public IXamlType Vector2i { get; }
public IXamlConstructor Vector2iConstructorFull { get; }
public IXamlType Thickness { get; }
public IXamlConstructor ThicknessConstructorFull { get; }
public IXamlType Color { get; }
public IXamlMethod ColorFromXaml { get; }
public RXamlWellKnownTypes(TransformerConfiguration cfg)
{
var ts = cfg.TypeSystem;
XamlIlTypes = cfg.WellKnownTypes;
Single = ts.GetType("System.Single");
Int32 = ts.GetType("System.Int32");
(Vector2, Vector2ConstructorFull) = GetNumericTypeInfo("Robust.Shared.Maths.Vector2", Single, 2);
(Vector2i, Vector2iConstructorFull) = GetNumericTypeInfo("Robust.Shared.Maths.Vector2i", Int32, 2);
(Thickness, ThicknessConstructorFull) = GetNumericTypeInfo("Robust.Shared.Maths.Thickness", Single, 4);
(IXamlType, IXamlConstructor) GetNumericTypeInfo(string name, IXamlType componentType, int componentCount)
{
var type = cfg.TypeSystem.GetType(name);
var ctor = type.GetConstructor(Enumerable.Repeat(componentType, componentCount).ToList());
return (type, ctor);
}
Color = cfg.TypeSystem.GetType("Robust.Shared.Maths.Color");
ColorFromXaml = Color.GetMethod(new FindMethodMethodSignature("FromXaml", Color, XamlIlTypes.String)
{
IsStatic = true
});
}
}
static class RXamlWellKnownTypesExtensions
{
public static RXamlWellKnownTypes GetRobustTypes(this AstTransformationContext ctx)
{
if (ctx.TryGetItem<RXamlWellKnownTypes>(out var rv))
return rv;
ctx.SetItem(rv = new RXamlWellKnownTypes(ctx.Configuration));
return rv;
}
}
}

View File

@@ -8,6 +8,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Build.Framework" Version="16.8.0" />
<PackageReference Include="Mono.Cecil" Version="0.11.3" />
<PackageReference Include="Pidgin" Version="2.5.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -6,6 +6,7 @@ using Microsoft.Build.Framework;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using Pidgin;
using XamlX;
using XamlX.Ast;
using XamlX.Emit;
@@ -70,7 +71,7 @@ namespace Robust.Build.Tasks
{
XmlnsAttributes =
{
typeSystem.GetType("Robust.Client.UserInterface.XAML.XmlnsDefinitionAttribute"),
typeSystem.GetType("Avalonia.Metadata.XmlnsDefinitionAttribute"),
},
ContentAttributes =
@@ -98,7 +99,7 @@ namespace Robust.Build.Tasks
typeSystem,
typeSystem.TargetAssembly,
xamlLanguage,
XamlXmlnsMappings.Resolve(typeSystem, xamlLanguage));
XamlXmlnsMappings.Resolve(typeSystem, xamlLanguage), CustomValueConverter);
var contextDef = new TypeDefinition("CompiledRobustXaml", "XamlIlContext",
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
@@ -297,6 +298,112 @@ namespace Robust.Build.Tasks
return true;
}
private static bool CustomValueConverter(
AstTransformationContext context,
IXamlAstValueNode node,
IXamlType type,
out IXamlAstValueNode result)
{
if (!(node is XamlAstTextNode textNode))
{
result = null;
return false;
}
var text = textNode.Text;
var types = context.GetRobustTypes();
if (type.Equals(types.Vector2))
{
var foo = MathParsing.Single2.Parse(text);
if (!foo.Success)
throw new XamlLoadException($"Unable to parse \"{text}\" as a Vector2", node);
var (x, y) = foo.Value;
result = new RXamlSingleVecLikeConstAstNode(
node,
types.Vector2, types.Vector2ConstructorFull,
types.Single, new[] {x, y});
return true;
}
if (type.Equals(types.Thickness))
{
var foo = MathParsing.Thickness.Parse(text);
if (!foo.Success)
throw new XamlLoadException($"Unable to parse \"{text}\" as a Thickness", node);
var val = foo.Value;
float[] full;
if (val.Length == 1)
{
var u = val[0];
full = new[] {u, u, u, u};
}
else if (val.Length == 2)
{
var h = val[0];
var v = val[1];
full = new[] {h, v, h, v};
}
else // 4
{
full = val;
}
result = new RXamlSingleVecLikeConstAstNode(
node,
types.Thickness, types.ThicknessConstructorFull,
types.Single, full);
return true;
}
if (type.Equals(types.Thickness))
{
var foo = MathParsing.Thickness.Parse(text);
if (!foo.Success)
throw new XamlLoadException($"Unable to parse \"{text}\" as a Thickness", node);
var val = foo.Value;
float[] full;
if (val.Length == 1)
{
var u = val[0];
full = new[] {u, u, u, u};
}
else if (val.Length == 2)
{
var h = val[0];
var v = val[1];
full = new[] {h, v, h, v};
}
else // 4
{
full = val;
}
result = new RXamlSingleVecLikeConstAstNode(
node,
types.Thickness, types.ThicknessConstructorFull,
types.Single, full);
return true;
}
if (type.Equals(types.Color))
{
// TODO: Interpret these colors at XAML compile time instead of at runtime.
result = new RXamlColorAstNode(node, types, text);
return true;
}
result = null;
return false;
}
public const string ContextNameScopeFieldName = "RobustNameScope";
private static void EmitNameScopeField(XamlLanguageTypeMappings xamlLanguage, CecilTypeSystem typeSystem, IXamlTypeBuilder<IXamlILEmitter> typeBuilder, IXamlILEmitter constructor)

View File

@@ -24,6 +24,7 @@ namespace Robust.Client.NameGenerator
{
private const string AttributeName = "Robust.Client.AutoGenerated.GenerateTypedNameReferencesAttribute";
private const string AttributeFile = "GenerateTypedNameReferencesAttribute";
private const string AttributeCode = @"// <auto-generated />
using System;
namespace Robust.Client.AutoGenerated
@@ -54,8 +55,8 @@ namespace Robust.Client.AutoGenerated
{
var clrtype = objectNode.Type.GetClrType();
var isControl = IsControl(clrtype);
//clrtype.Interfaces.Any(i =>
//i.IsInterface && i.FullName == "Robust.Client.UserInterface.IControl");
//clrtype.Interfaces.Any(i =>
//i.IsInterface && i.FullName == "Robust.Client.UserInterface.IControl");
if (!isControl)
return node;
@@ -80,9 +81,13 @@ namespace Robust.Client.AutoGenerated
return node;
}
public void Push(IXamlAstNode node) { }
public void Push(IXamlAstNode node)
{
}
public void Pop() { }
public void Pop()
{
}
}
private static string GenerateSourceCode(
@@ -97,16 +102,20 @@ namespace Robust.Client.AutoGenerated
var compiler =
new XamlILCompiler(
new TransformerConfiguration(typeSystem, typeSystem.Assemblies[0],
new XamlLanguageTypeMappings(typeSystem)),
new XamlLanguageTypeMappings(typeSystem)
{
XmlnsAttributes = {typeSystem.GetType("Avalonia.Metadata.XmlnsDefinitionAttribute")}
}),
new XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult>(), false);
compiler.Transformers.Add(new TypeReferenceResolver());
compiler.Transform(parsed);
var initialRoot = (XamlAstObjectNode) parsed.Root;
var names = NameVisitor.GetNames(initialRoot);
var fieldAccess = classSymbol.IsSealed ? "private" : "protected";
//var names = NameVisitor.GetNames((XamlAstObjectNode)XDocumentXamlParser.Parse(xamlFile).Root);
var namedControls = names.Select(info => " " +
$"protected global::{info.type} {info.name} => " +
$"this.FindControl<global::{info.type}>(\"{info.name}\");");
$"{fieldAccess} global::{info.type} {info.name} => " +
$"this.FindControl<global::{info.type}>(\"{info.name}\");");
return $@"// <auto-generated />
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
@@ -124,7 +133,7 @@ namespace {nameSpace}
public void Execute(GeneratorExecutionContext context)
{
var comp = (CSharpCompilation) context.Compilation;
if(comp.GetTypeByMetadataName(AttributeName) == null)
if (comp.GetTypeByMetadataName(AttributeName) == null)
context.AddSource(AttributeFile, SourceText.From(AttributeCode, Encoding.UTF8));
if (!(context.SyntaxReceiver is NameReferenceSyntaxReceiver receiver))
{
@@ -132,7 +141,7 @@ namespace {nameSpace}
}
var symbols = UnpackAnnotatedTypes(context, comp, receiver);
if(symbols == null)
if (symbols == null)
return;
foreach (var typeSymbol in symbols)
@@ -153,7 +162,7 @@ namespace {nameSpace}
DiagnosticSeverity.Error,
true),
typeSymbol.Locations[0]));
return;
continue;
}
var txt = relevantXamlFile.GetText()?.ToString();
@@ -168,8 +177,9 @@ namespace {nameSpace}
"Usage",
DiagnosticSeverity.Error,
true),
Location.Create(xamlFileName, new TextSpan(0,0), new LinePositionSpan(new LinePosition(0,0),new LinePosition(0,0)))));
return;
Location.Create(xamlFileName, new TextSpan(0, 0),
new LinePositionSpan(new LinePosition(0, 0), new LinePosition(0, 0)))));
continue;
}
try
@@ -189,12 +199,13 @@ namespace {nameSpace}
DiagnosticSeverity.Error,
true),
typeSymbol.Locations[0]));
return;
continue;
}
}
}
private IReadOnlyList<INamedTypeSymbol> UnpackAnnotatedTypes(in GeneratorExecutionContext context, CSharpCompilation comp, NameReferenceSyntaxReceiver receiver)
private IReadOnlyList<INamedTypeSymbol> UnpackAnnotatedTypes(in GeneratorExecutionContext context,
CSharpCompilation comp, NameReferenceSyntaxReceiver receiver)
{
var options = (CSharpParseOptions) comp.SyntaxTrees[0].Options;
var compilation =

View File

@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using Robust.Client.GameObjects.Components.Animations;
using Robust.Client.GameObjects;
namespace Robust.Client.Animations
{

View File

@@ -1,7 +1,7 @@
using System;
using JetBrains.Annotations;
using Robust.Shared.Animations;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
namespace Robust.Client.Animations
{

View File

@@ -1,8 +1,7 @@
using System;
using Robust.Client.Animations;
using Robust.Shared.Animations;
namespace Content.Client.Animations
namespace Robust.Client.Animations
{
public class AnimationTrackControlProperty : AnimationTrackProperty
{

View File

@@ -1,11 +1,8 @@
using System;
using System.Collections.Generic;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Client.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Utility;
using Robust.Shared.GameObjects;
namespace Robust.Client.Animations
{

View File

@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Utility;
namespace Robust.Client.Animations

View File

@@ -1,6 +1,5 @@
using System;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Clyde;
namespace Robust.Client.Audio
{

View File

@@ -4,16 +4,15 @@ using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using NFluidsynth;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Log;
using Robust.Shared.Interfaces.Physics;
using Robust.Shared.Interfaces.Resources;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.ContentPack;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Utility;
using Logger = Robust.Shared.Log.Logger;
@@ -379,9 +378,16 @@ namespace Robust.Client.Audio.Midi
public override IntPtr Open(string filename)
{
if (string.IsNullOrEmpty(filename))
{
return IntPtr.Zero;
}
Stream? stream;
var resourceCache = IoCManager.Resolve<IResourceCache>();
if (resourceCache.ContentFileExists(filename))
var resourcePath = new ResourcePath(filename);
if (resourcePath.IsRooted && resourceCache.ContentFileExists(filename))
{
if (!resourceCache.TryContentFileRead(filename, out stream))
return IntPtr.Zero;

View File

@@ -1,11 +1,9 @@
using System;
using System.IO;
using System.Runtime.Intrinsics.X86;
using NFluidsynth;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Graphics;
using Robust.Shared.Asynchronous;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Log;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
@@ -72,9 +70,9 @@ namespace Robust.Client.Audio.Midi
int PlayerTotalTick { get; }
/// <summary>
/// Gets the current tick of the MIDI player.
/// Gets or sets (seeks) the current tick of the MIDI player.
/// </summary>
int PlayerTick { get; }
int PlayerTick { get; set; }
/// <summary>
/// Gets the current tick of the sequencer.
@@ -235,7 +233,16 @@ namespace Robust.Client.Audio.Midi
public bool DisableProgramChangeEvent { get; set; } = true;
public int PlayerTotalTick => _player?.GetTotalTicks ?? 0;
public int PlayerTick => _player?.CurrentTick ?? 0;
public int PlayerTick
{
get => _player?.CurrentTick ?? 0;
set
{
lock (_playerStateLock)
_player?.Seek(Math.Max(Math.Min(value, PlayerTotalTick), 0));
}
}
public uint SequencerTick => _sequencer?.Tick ?? 0;
public double SequencerTimeScale => _sequencer?.TimeScale ?? 0;
@@ -310,9 +317,8 @@ namespace Robust.Client.Audio.Midi
lock (_playerStateLock)
{
if (_player == null)
_player = new NFluidsynth.Player(_synth);
_player.Stop();
_player?.Dispose();
_player = new NFluidsynth.Player(_synth);
_player.AddMem(buffer);
_player.SetPlaybackCallback(MidiPlayerEventHandler);
_player.Play();
@@ -351,10 +357,7 @@ namespace Robust.Client.Audio.Midi
public void StopAllNotes()
{
for (var i = 0; i < 16; i++)
{
_synth.AllNotesOff(i);
}
_synth.AllNotesOff(-1);
}
public void LoadSoundfont(string filename, bool resetPresets = false)
@@ -475,12 +478,6 @@ namespace Robust.Client.Audio.Midi
lock(_playerStateLock)
switch (midiEvent.Type)
{
// Sometimes MIDI files spam these for no good reason and I can't find any info on what they are.
case 1:
case 5:
case 81:
break;
// Note On 0x80
case 144:
_synth.NoteOn(midiEvent.Channel, midiEvent.Key, midiEvent.Velocity);
@@ -503,8 +500,10 @@ namespace Robust.Client.Audio.Midi
// Program Change - 0xC0
case 192:
if(!DisableProgramChangeEvent)
if (!DisableProgramChangeEvent)
_synth.ProgramChange(midiEvent.Channel, midiEvent.Program);
else
return;
break;
// Channel Pressure - 0xD0
@@ -517,13 +516,17 @@ namespace Robust.Client.Audio.Midi
_synth.PitchBend(midiEvent.Channel, midiEvent.Pitch);
break;
// Sometimes MIDI files spam these for no good reason and I can't find any info on what they are.
case 1:
case 5:
case 81:
// System Messages - 0xF0
case 240:
break;
return;
default:
_midiSawmill.Warning("Unhandled midi event of type {0}", midiEvent.Type, midiEvent);
break;
return;
}
}
catch (FluidSynthInteropException)

View File

@@ -1,21 +1,18 @@
using System;
using System;
using System.Net;
using Robust.Client.Interfaces;
using Robust.Client.Interfaces.Debugging;
using Robust.Client.Interfaces.GameObjects;
using Robust.Client.Interfaces.GameStates;
using Robust.Client.Interfaces.Utility;
using Robust.Client.Debugging;
using Robust.Client.GameObjects;
using Robust.Client.GameStates;
using Robust.Client.Player;
using Robust.Client.Utility;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Network.Messages;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Robust.Client
@@ -25,7 +22,7 @@ namespace Robust.Client
{
[Dependency] private readonly IClientNetManager _net = default!;
[Dependency] private readonly IPlayerManager _playMan = default!;
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly INetConfigurationManager _configManager = default!;
[Dependency] private readonly IClientEntityManager _entityManager = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IDiscordRichPresence _discord = default!;
@@ -50,18 +47,28 @@ namespace Robust.Client
/// <inheritdoc />
public void Initialize()
{
_net.RegisterNetMessage<MsgServerInfo>(MsgServerInfo.NAME, HandleServerInfo);
_net.RegisterNetMessage<MsgSetTickRate>(MsgSetTickRate.NAME, HandleSetTickRate);
_net.RegisterNetMessage<MsgServerInfoReq>(MsgServerInfoReq.NAME);
_net.Connected += OnConnected;
_net.ConnectFailed += OnConnectFailed;
_net.Disconnect += OnNetDisconnect;
_configManager.OnValueChanged(CVars.NetTickrate, TickRateChanged, invokeImmediately: true);
_playMan.Initialize();
_debugDrawMan.Initialize();
Reset();
}
private void TickRateChanged(int tickrate)
{
if (GameInfo != null)
{
GameInfo.TickRate = (byte) tickrate;
}
_timing.TickRate = (byte) tickrate;
Logger.InfoS("client", $"Tickrate changed to: {tickrate} on tick {_timing.CurTick}");
}
/// <inheritdoc />
public void ConnectToServer(DnsEndPoint endPoint)
{
@@ -98,9 +105,39 @@ namespace Robust.Client
private void OnConnected(object? sender, NetChannelArgs args)
{
// request base info about the server
var msgInfo = _net.CreateNetMessage<MsgServerInfoReq>();
_net.ClientSendMessage(msgInfo);
_configManager.SyncWithServer();
_configManager.ReceivedInitialNwVars += OnReceivedClientData;
}
private void OnReceivedClientData(object? sender, EventArgs e)
{
_configManager.ReceivedInitialNwVars -= OnReceivedClientData;
var info = GameInfo;
var serverName = _configManager.GetCVar<string>("game.hostname");
if (info == null)
{
GameInfo = info = new ServerInfo(serverName);
}
else
{
info.ServerName = serverName;
}
var maxPlayers = _configManager.GetCVar<int>("game.maxplayers");
info.ServerMaxPlayers = maxPlayers;
var userName = _net.ServerChannel!.UserName;
var userId = _net.ServerChannel.UserId;
_discord.Update(info.ServerName, userName, info.ServerMaxPlayers.ToString());
// start up player management
_playMan.Startup(_net.ServerChannel!);
_playMan.LocalPlayer!.UserId = userId;
_playMan.LocalPlayer.Name = userName;
_playMan.LocalPlayer.StatusChanged += OnLocalStatusChanged;
}
/// <summary>
@@ -135,6 +172,7 @@ namespace Robust.Client
private void Reset()
{
_configManager.ClearReceivedInitialNwVars();
OnRunLevelChanged(ClientRunLevel.Initialize);
}
@@ -152,6 +190,7 @@ namespace Robust.Client
LastDisconnectReason = args.Reason;
IoCManager.Resolve<INetConfigurationManager>().FlushMessages();
_gameStates.Reset();
_playMan.Shutdown();
_entityManager.Shutdown();
@@ -160,42 +199,6 @@ namespace Robust.Client
Reset();
}
private void HandleServerInfo(MsgServerInfo msg)
{
var info = GameInfo;
if (info == null)
{
GameInfo = info = new ServerInfo(msg.ServerName);
}
else
{
info.ServerName = msg.ServerName;
}
info.ServerMaxPlayers = msg.ServerMaxPlayers;
info.TickRate = msg.TickRate;
_timing.TickRate = msg.TickRate;
Logger.InfoS("client", $"Tickrate changed to: {msg.TickRate}");
var userName = msg.MsgChannel.UserName;
var userId = msg.MsgChannel.UserId;
_discord.Update(info.ServerName, userName, info.ServerMaxPlayers.ToString());
// start up player management
_playMan.Startup(_net.ServerChannel!);
_playMan.LocalPlayer!.UserId = userId;
_playMan.LocalPlayer.Name = userName;
_playMan.LocalPlayer.StatusChanged += OnLocalStatusChanged;
}
private void HandleSetTickRate(MsgSetTickRate message)
{
_timing.TickRate = message.NewTickRate;
Logger.InfoS("client", $"Tickrate changed to: {message.NewTickRate} on tick {_timing.CurTick}");
}
private void OnLocalStatusChanged(object? obj, StatusEventArgs eventArgs)
{
// player finished fully connecting to the server.

View File

@@ -1,33 +1,16 @@
using System;
using System;
using Robust.Client.Audio.Midi;
using Robust.Client.Console;
using Robust.Client.Debugging;
using Robust.Client.GameObjects;
using Robust.Client.GameStates;
using Robust.Client.Graphics;
using Robust.Client.Graphics.ClientEye;
using Robust.Client.Graphics.Clyde;
using Robust.Client.Graphics.Lighting;
using Robust.Client.Graphics.Overlays;
using Robust.Client.Input;
using Robust.Client.Interfaces;
using Robust.Client.Interfaces.Debugging;
using Robust.Client.Interfaces.GameObjects;
using Robust.Client.Interfaces.GameStates;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.Graphics.Lighting;
using Robust.Client.Interfaces.Graphics.Overlays;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.Map;
using Robust.Client.Interfaces.Placement;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Interfaces.State;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Interfaces.Utility;
using Robust.Client.Map;
using Robust.Client.Placement;
using Robust.Client.Player;
using Robust.Client.Prototypes;
using Robust.Client.Reflection;
using Robust.Client.ResourceManagement;
using Robust.Client.State;
@@ -35,15 +18,14 @@ using Robust.Client.UserInterface;
using Robust.Client.Utility;
using Robust.Client.ViewVariables;
using Robust.Shared;
using Robust.Shared.Console;
using Robust.Shared.ContentPack;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.Interfaces.Resources;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Reflection;
namespace Robust.Client
{
@@ -53,7 +35,7 @@ namespace Robust.Client
{
SharedIoC.RegisterIoC();
IoCManager.Register<IPrototypeManager, PrototypeManager>();
IoCManager.Register<IPrototypeManager, ClientPrototypeManager>();
IoCManager.Register<IEntityManager, ClientEntityManager>();
IoCManager.Register<IComponentFactory, ClientComponentFactory>();
IoCManager.Register<ITileDefinitionManager, ClydeTileDefinitionManager>();
@@ -78,10 +60,12 @@ namespace Robust.Client
IoCManager.Register<IDebugDrawingManager, DebugDrawingManager>();
IoCManager.Register<ILightManager, LightManager>();
IoCManager.Register<IDiscordRichPresence, DiscordRichPresence>();
IoCManager.Register<IClientConsole, ClientConsole>();
IoCManager.Register<IClientConsoleHost, ClientConsoleHost>();
IoCManager.Register<IConsoleHost, ClientConsoleHost>();
IoCManager.Register<IFontManager, FontManager>();
IoCManager.Register<IFontManagerInternal, FontManager>();
IoCManager.Register<IMidiManager, MidiManager>();
IoCManager.Register<IAuthManager, AuthManager>();
switch (mode)
{
case GameController.DisplayMode.Headless:

View File

@@ -1,243 +0,0 @@
using System;
using System.Collections.Generic;
using Robust.Client.Interfaces.Console;
using Robust.Client.Log;
using Robust.Client.Utility;
using Robust.Shared.Console;
using Robust.Shared.Interfaces.Log;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.Network.Messages;
using Robust.Shared.Reflection;
using Robust.Shared.Utility;
namespace Robust.Client.Console
{
public class AddStringArgs : EventArgs
{
public string Text { get; }
public Color Color { get; }
public AddStringArgs(string text, Color color)
{
Text = text;
Color = color;
}
}
public class AddFormattedMessageArgs : EventArgs
{
public readonly FormattedMessage Message;
public AddFormattedMessageArgs(FormattedMessage message)
{
Message = message;
}
}
internal sealed class ClientConsole : IClientConsole, IDebugConsole
{
private static readonly Color MsgColor = new Color(65, 105, 225);
[Dependency] private readonly IClientNetManager _network = default!;
[Dependency] private readonly IReflectionManager _reflectionManager = default!;
[Dependency] private readonly ILogManager logManager = default!;
private readonly Dictionary<string, IConsoleCommand> _commands = new Dictionary<string, IConsoleCommand>();
private bool _requestedCommands;
/// <inheritdoc />
public void Initialize()
{
_network.RegisterNetMessage<MsgConCmdReg>(MsgConCmdReg.NAME, HandleConCmdReg);
_network.RegisterNetMessage<MsgConCmdAck>(MsgConCmdAck.NAME, HandleConCmdAck);
_network.RegisterNetMessage<MsgConCmd>(MsgConCmd.NAME);
Reset();
logManager.RootSawmill.AddHandler(new DebugConsoleLogHandler(this));
}
/// <inheritdoc />
public void Reset()
{
_commands.Clear();
_requestedCommands = false;
_network.Connected += OnNetworkConnected;
InitializeCommands();
SendServerCommandRequest();
}
private void OnNetworkConnected(object? sender, NetChannelArgs netChannelArgs)
{
SendServerCommandRequest();
}
/// <inheritdoc />
public void Dispose()
{
// We don't have anything to dispose.
}
public IReadOnlyDictionary<string, IConsoleCommand> Commands => _commands;
public void AddLine(string text, Color color)
{
AddString?.Invoke(this, new AddStringArgs(text, color));
}
public void AddLine(string text)
{
AddLine(text, Color.White);
}
public void Clear()
{
ClearText?.Invoke(this, EventArgs.Empty);
}
public event EventHandler<AddStringArgs>? AddString;
public event EventHandler? ClearText;
public event EventHandler<AddFormattedMessageArgs>? AddFormatted;
private void HandleConCmdAck(MsgConCmdAck msg)
{
AddLine("< " + msg.Text, MsgColor);
}
private void HandleConCmdReg(MsgConCmdReg msg)
{
foreach (var cmd in msg.Commands)
{
var commandName = cmd.Name;
// Do not do duplicate commands.
if (_commands.ContainsKey(commandName))
{
Logger.DebugS("console", $"Server sent console command {commandName}, but we already have one with the same name. Ignoring.");
continue;
}
var command = new ServerDummyCommand(commandName, cmd.Help, cmd.Description);
_commands[commandName] = command;
}
}
/// <summary>
/// Processes commands (chat messages starting with /)
/// </summary>
/// <param name="text">input text</param>
public void ProcessCommand(string text)
{
if (string.IsNullOrWhiteSpace(text))
return;
// echo the command locally
AddLine("> " + text, Color.Lime);
//Commands are processed locally and then sent to the server to be processed there again.
var args = new List<string>();
CommandParsing.ParseArguments(text, args);
var commandname = args[0];
var forward = true;
if (_commands.ContainsKey(commandname))
{
var command = _commands[commandname];
args.RemoveAt(0);
forward = command.Execute(this, args.ToArray());
}
else if (!_network.IsConnected)
{
AddLine("Unknown command: " + commandname, Color.Red);
return;
}
if (forward)
SendServerConsoleCommand(text);
}
/// <summary>
/// Locates and registeres all local commands.
/// </summary>
private void InitializeCommands()
{
foreach (var t in _reflectionManager.GetAllChildren<IConsoleCommand>())
{
var instance = (IConsoleCommand)Activator.CreateInstance(t)!;
if (_commands.ContainsKey(instance.Command))
throw new InvalidOperationException($"Command already registered: {instance.Command}");
_commands[instance.Command] = instance;
}
}
/// <summary>
/// Requests remote commands from server.
/// </summary>
public void SendServerCommandRequest()
{
if (_requestedCommands)
return;
if (!_network.IsConnected)
return;
var msg = _network.CreateNetMessage<MsgConCmdReg>();
_network.ClientSendMessage(msg);
_requestedCommands = true;
}
/// <summary>
/// Sends a command directly to the server.
/// </summary>
private void SendServerConsoleCommand(string text)
{
if (_network == null || !_network.IsConnected)
return;
var msg = _network.CreateNetMessage<MsgConCmd>();
msg.Text = text;
_network.ClientSendMessage(msg);
}
public void AddFormattedLine(FormattedMessage message)
{
// Why the hell does this class implement IDebugConsole.
AddFormatted?.Invoke(this, new AddFormattedMessageArgs(message));
}
}
/// <summary>
/// These dummies are made purely so list and help can list server-side commands.
/// </summary>
[Reflect(false)]
internal class ServerDummyCommand : IConsoleCommand
{
internal ServerDummyCommand(string command, string help, string description)
{
Command = command;
Help = help;
Description = description;
}
public string Command { get; }
public string Help { get; }
public string Description { get; }
// Always forward to server.
public bool Execute(IDebugConsole console, params string[] args)
{
return true;
}
}
}

View File

@@ -0,0 +1,218 @@
using System;
using System.Collections.Generic;
using Robust.Client.Log;
using Robust.Shared.Console;
using Robust.Shared.Log;
using Robust.Shared.Network;
using Robust.Shared.Network.Messages;
using Robust.Shared.Players;
using Robust.Shared.Reflection;
using Robust.Shared.Utility;
namespace Robust.Client.Console
{
public class AddStringArgs : EventArgs
{
public string Text { get; }
public bool Local { get; }
public bool Error { get; }
public AddStringArgs(string text, bool local, bool error)
{
Text = text;
Local = local;
Error = error;
}
}
public class AddFormattedMessageArgs : EventArgs
{
public readonly FormattedMessage Message;
public AddFormattedMessageArgs(FormattedMessage message)
{
Message = message;
}
}
/// <inheritdoc cref="IClientConsoleHost" />
internal class ClientConsoleHost : ConsoleHost, IClientConsoleHost
{
private bool _requestedCommands;
/// <inheritdoc />
public void Initialize()
{
NetManager.RegisterNetMessage<MsgConCmdReg>(MsgConCmdReg.NAME, HandleConCmdReg);
NetManager.RegisterNetMessage<MsgConCmdAck>(MsgConCmdAck.NAME, HandleConCmdAck);
NetManager.RegisterNetMessage<MsgConCmd>(MsgConCmd.NAME, ProcessCommand);
Reset();
LogManager.RootSawmill.AddHandler(new DebugConsoleLogHandler(this));
}
private void ProcessCommand(MsgConCmd message)
{
string? text = message.Text;
LogManager.GetSawmill(SawmillName).Info($"SERVER:{text}");
ExecuteCommand(null, text);
}
/// <inheritdoc />
public void Reset()
{
AvailableCommands.Clear();
_requestedCommands = false;
NetManager.Connected += OnNetworkConnected;
LoadConsoleCommands();
SendServerCommandRequest();
}
/// <inheritdoc />
public event EventHandler<AddStringArgs>? AddString;
/// <inheritdoc />
public event EventHandler<AddFormattedMessageArgs>? AddFormatted;
/// <inheritdoc />
public void AddFormattedLine(FormattedMessage message)
{
AddFormatted?.Invoke(this, new AddFormattedMessageArgs(message));
}
/// <inheritdoc />
public override void WriteError(ICommonSession? session, string text)
{
OutputText(text, true, true);
}
/// <inheritdoc />
public override void ExecuteCommand(ICommonSession? session, string command)
{
if (string.IsNullOrWhiteSpace(command))
return;
// echo the command locally
WriteError(null, "> " + command);
//Commands are processed locally and then sent to the server to be processed there again.
var args = new List<string>();
CommandParsing.ParseArguments(command, args);
var commandName = args[0];
if (AvailableCommands.ContainsKey(commandName))
{
var command1 = AvailableCommands[commandName];
args.RemoveAt(0);
command1.Execute(new ConsoleShell(this, null), command, args.ToArray());
}
else
WriteError(null, "Unknown command: " + commandName);
}
/// <inheritdoc />
public override void RemoteExecuteCommand(ICommonSession? session, string command)
{
if (!NetManager.IsConnected) // we don't care about session on client
return;
var msg = NetManager.CreateNetMessage<MsgConCmd>();
msg.Text = command;
NetManager.ClientSendMessage(msg);
}
/// <inheritdoc />
public override void WriteLine(ICommonSession? session, string text)
{
OutputText(text, true, false);
}
/// <inheritdoc />
public void Dispose()
{
// We don't have anything to dispose.
}
private void OutputText(string text, bool local, bool error)
{
AddString?.Invoke(this, new AddStringArgs(text, local, error));
}
private void OnNetworkConnected(object? sender, NetChannelArgs netChannelArgs)
{
SendServerCommandRequest();
}
private void HandleConCmdAck(MsgConCmdAck msg)
{
OutputText("< " + msg.Text, false, msg.Error);
}
private void HandleConCmdReg(MsgConCmdReg msg)
{
foreach (var cmd in msg.Commands)
{
string? commandName = cmd.Name;
// Do not do duplicate commands.
if (AvailableCommands.ContainsKey(commandName))
{
Logger.DebugS("console", $"Server sent console command {commandName}, but we already have one with the same name. Ignoring.");
continue;
}
var command = new ServerDummyCommand(commandName, cmd.Help, cmd.Description);
AvailableCommands[commandName] = command;
}
}
/// <summary>
/// Requests remote commands from server.
/// </summary>
private void SendServerCommandRequest()
{
if (_requestedCommands)
return;
if (!NetManager.IsConnected)
return;
var msg = NetManager.CreateNetMessage<MsgConCmdReg>();
NetManager.ClientSendMessage(msg);
_requestedCommands = true;
}
}
/// <summary>
/// These dummies are made purely so list and help can list server-side commands.
/// </summary>
[Reflect(false)]
internal class ServerDummyCommand : IConsoleCommand
{
internal ServerDummyCommand(string command, string help, string description)
{
Command = command;
Help = help;
Description = description;
}
public string Command { get; }
public string Description { get; }
public string Help { get; }
// Always forward to server.
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
shell.RemoteExecuteCommand(argStr);
}
}
}

View File

@@ -1,24 +1,23 @@
using JetBrains.Annotations;
using Robust.Server.Interfaces.Console;
using Robust.Server.Interfaces.Player;
using JetBrains.Annotations;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Robust.Server.Console.Commands
namespace Robust.Client.Console.Commands
{
[UsedImplicitly]
internal sealed class AddCompCommand : IClientCommand
internal sealed class AddCompCommand : IConsoleCommand
{
public string Command => "addcomp";
public string Description => "Adds a component to an entity";
public string Help => "addcomp <uid> <componentName>";
public string Command => "addcompc";
public string Description => "Adds a component to an entity on the client";
public string Help => "addcompc <uid> <componentName>";
public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != 2)
{
shell.SendText(player, "Wrong number of arguments");
shell.WriteLine("Wrong number of arguments");
return;
}
@@ -38,16 +37,18 @@ namespace Robust.Server.Console.Commands
}
}
internal sealed class RemoveCompCommand : IClientCommand
[UsedImplicitly]
internal sealed class RemoveCompCommand : IConsoleCommand
{
public string Command => "rmcomp";
public string Command => "rmcompc";
public string Description => "Removes a component from an entity.";
public string Help => "rmcomp <uid> <componentName>";
public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args)
public string Help => "rmcompc <uid> <componentName>";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != 2)
{
shell.SendText(player, "Wrong number of arguments");
shell.WriteLine("Wrong number of arguments");
return;
}

View File

@@ -1,7 +1,7 @@
using JetBrains.Annotations;
using Robust.Client.Interfaces.Console;
using Robust.Client.Player;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
namespace Robust.Client.Console.Commands
@@ -13,18 +13,17 @@ namespace Robust.Client.Console.Commands
public string Description => "Spawns a client-side entity with specific type at your feet.";
public string Help => "cspawn <entity type>";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var player = IoCManager.Resolve<IPlayerManager>().LocalPlayer;
if (player?.ControlledEntity == null)
{
console.AddLine("You don't have an attached entity.");
return false;
shell.WriteLine("You don't have an attached entity.");
return;
}
var entityManager = IoCManager.Resolve<IEntityManager>();
entityManager.SpawnEntity(args[0], player.ControlledEntity.Transform.Coordinates);
return false;
}
}
}

View File

@@ -1,23 +1,21 @@
using System;
using System.Linq;
using JetBrains.Annotations;
using Robust.Client.Interfaces.Console;
using Robust.Shared.Configuration;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Console;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
namespace Robust.Client.Console.Commands
{
[UsedImplicitly]
internal sealed class CVarCommand : SharedCVarCommand, IConsoleCommand
{
public bool Execute(IDebugConsole console, params string[] args)
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length < 1 || args.Length > 2)
{
console.AddLine("Must provide exactly one or two arguments.", Color.Red);
return false;
shell.WriteError("Must provide exactly one or two arguments.");
return;
}
var configManager = IoCManager.Resolve<IConfigurationManager>();
@@ -26,21 +24,21 @@ namespace Robust.Client.Console.Commands
if (name == "?")
{
var cvars = configManager.GetRegisteredCVars().OrderBy(c => c);
console.AddLine(string.Join("\n", cvars));
return false;
shell.WriteLine(string.Join("\n", cvars));
return;
}
if (!configManager.IsCVarRegistered(name))
{
console.AddLine($"CVar '{name}' is not registered. Use 'cvar ?' to get a list of all registered CVars.", Color.Red);
return false;
shell.WriteError($"CVar '{name}' is not registered. Use 'cvar ?' to get a list of all registered CVars.");
return;
}
if (args.Length == 1)
{
// Read CVar
var value = configManager.GetCVar<object>(name);
console.AddLine(value.ToString() ?? "");
shell.WriteLine(value.ToString() ?? "");
}
else
{
@@ -54,11 +52,9 @@ namespace Robust.Client.Console.Commands
}
catch (FormatException)
{
console.AddLine($"Input value is in incorrect format for type {type}");
shell.WriteLine($"Input value is in incorrect format for type {type}");
}
}
return false;
}
}
@@ -69,10 +65,9 @@ namespace Robust.Client.Console.Commands
public string Description => "Saves the client configuration to the config file";
public string Help => "saveconfig";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
IoCManager.Resolve<IConfigurationManager>().SaveToFile();
return false;
}
}

View File

@@ -1,13 +1,8 @@
// This file is for commands that do something to the console itself.
// This file is for commands that do something to the console itself.
// Not some generic console command type.
// Couldn't think of a better name sorry.
using System;
using Robust.Client.Interfaces.Console;
using Robust.Shared.Console;
using Robust.Shared.Interfaces.Random;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
namespace Robust.Client.Console.Commands
{
@@ -17,10 +12,9 @@ namespace Robust.Client.Console.Commands
public string Help => "Clears the debug console of all messages.";
public string Description => "Clears the console.";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
console.Clear();
return false;
shell.Clear();
}
}
@@ -30,15 +24,12 @@ namespace Robust.Client.Console.Commands
public string Help => "Fills the console with some nonsense for debugging.";
public string Description => "Fill up the console for debugging.";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
Color[] colors = { Color.Green, Color.Blue, Color.Red };
var random = IoCManager.Resolve<IRobustRandom>();
for (int x = 0; x < 50; x++)
{
console.AddLine("filling...", colors[random.Next(0, colors.Length)]);
shell.WriteLine("filling...");
}
return false;
}
}
}

View File

@@ -6,37 +6,25 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using Robust.Client.Input;
using System.Threading;
using Robust.Client.Interfaces;
using Robust.Client.Interfaces.Console;
using Robust.Client.Interfaces.Debugging;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.Graphics.Lighting;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Interfaces.State;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Debugging;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.ResourceManagement.ResourceTypes;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Asynchronous;
using Robust.Shared.Console;
using Robust.Shared.ContentPack;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.Interfaces.Resources;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.Reflection;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
@@ -49,16 +37,14 @@ namespace Robust.Client.Console.Commands
public string Help => "Dump entity list";
public string Description => "Dumps entity list of UIDs and prototype.";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var entityManager = IoCManager.Resolve<IEntityManager>();
foreach (var e in entityManager.GetEntities().OrderBy(e => e.Uid))
{
console.AddLine($"entity {e.Uid}, {e.Prototype?.ID}, {e.Transform.Coordinates}.", Color.White);
shell.WriteLine($"entity {e.Uid}, {e.Prototype?.ID}, {e.Transform.Coordinates}.");
}
return false;
}
}
@@ -68,12 +54,12 @@ namespace Robust.Client.Console.Commands
public string Help => "Usage: getcomponentregistration <componentName>";
public string Description => "Gets component registration information";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length < 1)
{
console.AddLine(Help);
return false;
shell.WriteLine(Help);
return;
}
var componentFactory = IoCManager.Resolve<IComponentFactory>();
@@ -94,19 +80,17 @@ namespace Robust.Client.Console.Commands
message.Append($", NSE: {registration.NetworkSynchronizeExistence}, references:");
console.AddLine(message.ToString(), Color.White);
shell.WriteLine(message.ToString());
foreach (var type in registration.References)
{
console.AddLine($" {type}", Color.White);
shell.WriteLine($" {type}");
}
}
catch (UnknownComponentException)
{
console.AddLine($"No registration found for '{args[0]}'", Color.Red);
shell.WriteError($"No registration found for '{args[0]}'");
}
return false;
}
}
@@ -119,14 +103,14 @@ namespace Robust.Client.Console.Commands
public string Description => "Toggles a debug monitor in the F3 menu.";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var monitor = IoCManager.Resolve<IUserInterfaceManager>().DebugMonitors;
if (args.Length != 1)
{
console.AddLine(Help);
return false;
shell.WriteLine(Help);
return;
}
switch (args[0])
@@ -159,11 +143,9 @@ namespace Robust.Client.Console.Commands
monitor.ShowInput ^= true;
break;
default:
console.AddLine($"Invalid key: {args[0]}");
shell.WriteLine($"Invalid key: {args[0]}");
break;
}
return false;
}
}
@@ -173,7 +155,7 @@ namespace Robust.Client.Console.Commands
public string Help => "Throws an exception";
public string Description => "Throws an exception";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
throw new InvalidOperationException("Fuck");
}
@@ -185,11 +167,10 @@ namespace Robust.Client.Console.Commands
public string Help => "";
public string Description => "Enables debug drawing over all bounding boxes in the game, showing their size.";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var mgr = IoCManager.Resolve<IDebugDrawing>();
mgr.DebugColliders = !mgr.DebugColliders;
return false;
}
}
@@ -199,11 +180,10 @@ namespace Robust.Client.Console.Commands
public string Help => "";
public string Description => "Enables debug drawing over all entity positions in the game.";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var mgr = IoCManager.Resolve<IDebugDrawing>();
mgr.DebugPositions = !mgr.DebugPositions;
return false;
}
}
@@ -213,25 +193,24 @@ namespace Robust.Client.Console.Commands
public string Help => "Usage: showrays <raylifetime>";
public string Description => "Toggles debug drawing of physics rays. An integer for <raylifetime> must be provided";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != 1)
{
console.AddLine(Help);
return false;
shell.WriteLine(Help);
return;
}
if (!int.TryParse(args[0], out var id))
{
console.AddLine($"{args[0]} is not a valid integer.",Color.Red);
return false;
shell.WriteError($"{args[0]} is not a valid integer.");
return;
}
var mgr = IoCManager.Resolve<IDebugDrawingManager>();
mgr.DebugDrawRays = !mgr.DebugDrawRays;
console.AddLine("Toggled showing rays to:" + mgr.DebugDrawRays.ToString(), Color.Green);
shell.WriteError("Toggled showing rays to:" + mgr.DebugDrawRays.ToString());
mgr.DebugRayLifetime = TimeSpan.FromSeconds((double)int.Parse(args[0], CultureInfo.InvariantCulture));
return false;
}
}
@@ -241,10 +220,9 @@ namespace Robust.Client.Console.Commands
public string Help => "";
public string Description => "Immediately disconnect from the server and go back to the main menu.";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
IoCManager.Resolve<IClientNetManager>().ClientDisconnect("Disconnect command used.");
return false;
}
}
@@ -257,33 +235,33 @@ namespace Robust.Client.Console.Commands
public string Description => "Displays verbose diagnostics for an entity.";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != 1)
{
console.AddLine(Help);
return false;
shell.WriteLine(Help);
return;
}
if ((!new Regex(@"^c?[0-9]+$").IsMatch(args[0])))
{
console.AddLine("Malformed UID", Color.Red);
return false;
shell.WriteError("Malformed UID");
return;
}
var uid = EntityUid.Parse(args[0]);
var entmgr = IoCManager.Resolve<IEntityManager>();
if (!entmgr.TryGetEntity(uid, out var entity))
{
console.AddLine("That entity does not exist. Sorry lad.", Color.Red);
return false;
shell.WriteError("That entity does not exist. Sorry lad.");
return;
}
console.AddLine($"{entity.Uid}: {entity.Prototype?.ID}/{entity.Name}");
console.AddLine($"init/del/lmt: {entity.Initialized}/{entity.Deleted}/{entity.LastModifiedTick}");
shell.WriteLine($"{entity.Uid}: {entity.Prototype?.ID}/{entity.Name}");
shell.WriteLine($"init/del/lmt: {entity.Initialized}/{entity.Deleted}/{entity.LastModifiedTick}");
foreach (var component in entity.GetAllComponents())
{
console.AddLine(component.ToString() ?? "");
shell.WriteLine(component.ToString() ?? "");
if (component is IComponentDebug debug)
{
foreach (var line in debug.GetDebugString().Split('\n'))
@@ -293,12 +271,10 @@ namespace Robust.Client.Console.Commands
continue;
}
console.AddLine("\t" + line);
shell.WriteLine("\t" + line);
}
}
}
return false;
}
}
@@ -308,12 +284,12 @@ namespace Robust.Client.Console.Commands
public string Help => "sggcell <gridID> <vector2i> [offset]\nThat vector2i param is in the form x<int>,y<int>.";
public string Description => "Lists entities on a snap grid cell.";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != 2 && args.Length != 3)
{
console.AddLine(Help);
return false;
shell.WriteLine(Help);
return;
}
string gridId = args[0];
@@ -322,14 +298,14 @@ namespace Robust.Client.Console.Commands
if (!int.TryParse(args[0], out var id))
{
console.AddLine($"{args[0]} is not a valid integer.",Color.Red);
return false;
shell.WriteError($"{args[0]} is not a valid integer.");
return;
}
if (!new Regex(@"^-?[0-9]+,-?[0-9]+$").IsMatch(indices))
{
console.AddLine("mapIndicies must be of form x<int>,y<int>", Color.Red);
return false;
shell.WriteError("mapIndicies must be of form x<int>,y<int>");
return;
}
SnapGridOffset selectedOffset;
@@ -339,8 +315,8 @@ namespace Robust.Client.Console.Commands
}
else
{
console.AddLine("given offset type is not defined", Color.Red);
return false;
shell.WriteError("given offset type is not defined");
return;
}
var mapMan = IoCManager.Resolve<IMapManager>();
@@ -354,16 +330,13 @@ namespace Robust.Client.Console.Commands
int.Parse(indices.Split(',')[1], CultureInfo.InvariantCulture)),
selectedOffset))
{
console.AddLine(entity.Owner.Uid.ToString());
shell.WriteLine(entity.Owner.Uid.ToString());
}
}
else
{
console.AddLine("grid does not exist", Color.Red);
return false;
shell.WriteError("grid does not exist");
}
return false;
}
}
@@ -373,19 +346,17 @@ namespace Robust.Client.Console.Commands
public string Description => "Changes the name used when attempting to connect to the server.";
public string Help => Command + " <name>";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length < 1)
{
console.AddLine(Help);
return false;
shell.WriteLine(Help);
return;
}
var client = IoCManager.Resolve<IBaseClient>();
client.PlayerNameOverride = args[0];
console.AddLine($"Overriding player name to \"{args[0]}\".", Color.White);
return false;
shell.WriteLine($"Overriding player name to \"{args[0]}\".");
}
}
@@ -395,12 +366,12 @@ namespace Robust.Client.Console.Commands
public string Description => "Pre-caches a resource.";
public string Help => "ldrsc <path> <type>";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length < 2)
{
console.AddLine(Help);
return false;
shell.WriteLine(Help);
return;
}
var resourceCache = IoCManager.Resolve<IResourceCache>();
var reflection = IoCManager.Resolve<IReflectionManager>();
@@ -412,8 +383,8 @@ namespace Robust.Client.Console.Commands
}
catch(ArgumentException)
{
console.AddLine("Unable to find type", Color.Red);
return false;
shell.WriteError("Unable to find type");
return;
}
var getResourceMethod =
@@ -423,7 +394,6 @@ namespace Robust.Client.Console.Commands
DebugTools.Assert(getResourceMethod != null);
var generic = getResourceMethod!.MakeGenericMethod(type);
generic.Invoke(resourceCache, new object[] { args[0], true });
return false;
}
}
@@ -433,12 +403,12 @@ namespace Robust.Client.Console.Commands
public string Description => "Reloads a resource.";
public string Help => "rldrsc <path> <type>";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length < 2)
{
console.AddLine(Help);
return false;
shell.WriteLine(Help);
return;
}
var resourceCache = IoCManager.Resolve<IResourceCache>();
var reflection = IoCManager.Resolve<IReflectionManager>();
@@ -450,15 +420,14 @@ namespace Robust.Client.Console.Commands
}
catch(ArgumentException)
{
console.AddLine("Unable to find type", Color.Red);
return false;
shell.WriteError("Unable to find type");
return;
}
var getResourceMethod = resourceCache.GetType().GetMethod("ReloadResource", new[] { typeof(string) });
DebugTools.Assert(getResourceMethod != null);
var generic = getResourceMethod!.MakeGenericMethod(type);
generic.Invoke(resourceCache, new object[] { args[0] });
return false;
}
}
@@ -468,18 +437,18 @@ namespace Robust.Client.Console.Commands
public string Description => "Gets the tile count of a grid";
public string Help => "Usage: gridtc <gridId>";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != 1)
{
console.AddLine(Help);
return false;
shell.WriteLine(Help);
return;
}
if (!int.TryParse(args[0], out var id))
{
console.AddLine($"{args[0]} is not a valid integer.");
return false;
shell.WriteLine($"{args[0]} is not a valid integer.");
return;
}
var gridId = new GridId(int.Parse(args[0]));
@@ -487,13 +456,11 @@ namespace Robust.Client.Console.Commands
if (mapManager.TryGetGrid(gridId, out var grid))
{
console.AddLine(mapManager.GetGrid(gridId).GetAllTiles().Count().ToString());
return false;
shell.WriteLine(mapManager.GetGrid(gridId).GetAllTiles().Count().ToString());
}
else
{
console.AddLine($"No grid exists with id {id}",Color.Red);
return false;
shell.WriteError($"No grid exists with id {id}");
}
}
}
@@ -504,7 +471,7 @@ namespace Robust.Client.Console.Commands
public string Description => "Dump GUI tree to /guidump.txt in user data.";
public string Help => "guidump";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var root = IoCManager.Resolve<IUserInterfaceManager>().RootControl;
var res = IoCManager.Resolve<IResourceManager>();
@@ -515,7 +482,7 @@ namespace Robust.Client.Console.Commands
_writeNode(root, 0, writer);
}
return false;
shell.WriteLine("Saved guidump");
}
private static void _writeNode(Control control, int indents, TextWriter writer)
@@ -575,9 +542,9 @@ namespace Robust.Client.Console.Commands
public string Description => "Open a dummy UI testing window";
public string Help => "uitest";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var window = new SS14Window { CustomMinimumSize = (500, 400)};
var window = new SS14Window { MinSize = (500, 400)};
var tabContainer = new TabContainer();
window.Contents.AddChild(tabContainer);
var scroll = new ScrollContainer();
@@ -597,7 +564,7 @@ namespace Robust.Client.Console.Commands
optionButton.OnItemSelected += eventArgs => optionButton.SelectId(eventArgs.Id);
vBox.AddChild(optionButton);
var tree = new Tree { SizeFlagsVertical = Control.SizeFlags.FillExpand };
var tree = new Tree { VerticalExpand = true };
var root = tree.CreateItem();
root.Text = "Honk!";
var child = tree.CreateItem();
@@ -634,7 +601,7 @@ namespace Robust.Client.Console.Commands
{
grid.AddChild(new Button
{
CustomMinimumSize = (50, 50),
MinSize = (50, 50),
Text = $"{x}, {y}"
});
}
@@ -666,9 +633,30 @@ namespace Robust.Client.Console.Commands
}
});
window.OpenCentered();
tabContainer.AddChild(new HSplitContainer
{
Children =
{
new PanelContainer
{
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.Red},
Children =
{
new Label{ Text = "FOOBARBAZ"},
}
},
new PanelContainer
{
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.Blue},
Children =
{
new Label{ Text = "FOOBARBAZ"},
}
},
}
});
return false;
window.OpenCentered();
}
}
@@ -678,11 +666,10 @@ namespace Robust.Client.Console.Commands
public string Description => "Sets the system clipboard";
public string Help => "setclipboard <text>";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var mgr = IoCManager.Resolve<IClipboardManager>();
mgr.SetText(args[0]);
return false;
}
}
@@ -692,11 +679,10 @@ namespace Robust.Client.Console.Commands
public string Description => "Gets the system clipboard";
public string Help => "getclipboard";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var mgr = IoCManager.Resolve<IClipboardManager>();
console.AddLine(mgr.GetText());
return false;
shell.WriteLine(mgr.GetText());
}
}
@@ -706,11 +692,11 @@ namespace Robust.Client.Console.Commands
public string Description => "Toggles light rendering.";
public string Help => "togglelight";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var mgr = IoCManager.Resolve<ILightManager>();
mgr.Enabled = !mgr.Enabled;
return false;
if (!mgr.LockConsoleAccess)
mgr.Enabled = !mgr.Enabled;
}
}
@@ -720,12 +706,11 @@ namespace Robust.Client.Console.Commands
public string Description => "Toggles fov for client.";
public string Help => "togglefov";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var mgr = IoCManager.Resolve<IEyeManager>();
if (mgr.CurrentEye != null)
mgr.CurrentEye.DrawFov = !mgr.CurrentEye.DrawFov;
return false;
}
}
@@ -735,11 +720,11 @@ namespace Robust.Client.Console.Commands
public string Description => "Toggles hard fov for client (for debugging space-station-14#2353).";
public string Help => "togglehardfov";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var mgr = IoCManager.Resolve<ILightManager>();
mgr.DrawHardFov = !mgr.DrawHardFov;
return false;
if (!mgr.LockConsoleAccess)
mgr.DrawHardFov = !mgr.DrawHardFov;
}
}
@@ -749,11 +734,24 @@ namespace Robust.Client.Console.Commands
public string Description => "Toggles shadow rendering.";
public string Help => "toggleshadows";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var mgr = IoCManager.Resolve<ILightManager>();
mgr.DrawShadows = !mgr.DrawShadows;
return false;
if (!mgr.LockConsoleAccess)
mgr.DrawShadows = !mgr.DrawShadows;
}
}
internal class ToggleLightBuf : IConsoleCommand
{
public string Command => "togglelightbuf";
public string Description => "Toggles lighting rendering. This includes shadows but not FOV.";
public string Help => "togglelightbuf";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var mgr = IoCManager.Resolve<ILightManager>();
if (!mgr.LockConsoleAccess)
mgr.DrawLighting = !mgr.DrawLighting;
}
}
@@ -763,7 +761,7 @@ namespace Robust.Client.Console.Commands
public string Description => "Run the GC.";
public string Help => "gc [generation]";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length == 0)
{
@@ -774,10 +772,21 @@ namespace Robust.Client.Console.Commands
if (int.TryParse(args[0], out int result))
GC.Collect(result);
else
console.AddLine("Failed to parse argument.",Color.Red);
shell.WriteError("Failed to parse argument.");
}
}
}
return false;
internal class GcFullCommand : IConsoleCommand
{
public string Command => "gcf";
public string Description => "Run the GC, fully, compacting LOH and everything.";
public string Help => "gcf";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect(2, GCCollectionMode.Forced, true, true);
}
}
@@ -790,16 +799,16 @@ namespace Robust.Client.Console.Commands
public string Help => "gc_mode\nSee current GC Latencymode\ngc_mode [type]\n Change GC Latency mode to [type]";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var prevMode = GCSettings.LatencyMode;
if (args.Length == 0)
{
console.AddLine($"current gc latency mode: {(int) prevMode} ({prevMode})");
console.AddLine("possible modes:");
shell.WriteLine($"current gc latency mode: {(int) prevMode} ({prevMode})");
shell.WriteLine("possible modes:");
foreach (int mode in (int[]) Enum.GetValues(typeof(GCLatencyMode)))
{
console.AddLine($" {mode}: {Enum.GetName(typeof(GCLatencyMode), mode)}");
shell.WriteLine($" {mode}: {Enum.GetName(typeof(GCLatencyMode), mode)}");
}
}
else
@@ -811,16 +820,14 @@ namespace Robust.Client.Console.Commands
}
else if (!Enum.TryParse(args[0], true, out mode))
{
console.AddLine($"unknown gc latency mode: {args[0]}");
return false;
shell.WriteLine($"unknown gc latency mode: {args[0]}");
return;
}
console.AddLine($"attempting gc latency mode change: {(int) prevMode} ({prevMode}) -> {(int) mode} ({mode})");
shell.WriteLine($"attempting gc latency mode change: {(int) prevMode} ({prevMode}) -> {(int) mode} ({mode})");
GCSettings.LatencyMode = mode;
console.AddLine($"resulting gc latency mode: {(int) GCSettings.LatencyMode} ({GCSettings.LatencyMode})");
shell.WriteLine($"resulting gc latency mode: {(int) GCSettings.LatencyMode} ({GCSettings.LatencyMode})");
}
return false;
}
}
@@ -834,15 +841,13 @@ namespace Robust.Client.Console.Commands
public string Help => "szr_stats";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
console.AddLine($"serialized: {RobustSerializer.BytesSerialized} bytes, {RobustSerializer.ObjectsSerialized} objects");
console.AddLine($"largest serialized: {RobustSerializer.LargestObjectSerializedBytes} bytes, {RobustSerializer.LargestObjectSerializedType} objects");
console.AddLine($"deserialized: {RobustSerializer.BytesDeserialized} bytes, {RobustSerializer.ObjectsDeserialized} objects");
console.AddLine($"largest serialized: {RobustSerializer.LargestObjectDeserializedBytes} bytes, {RobustSerializer.LargestObjectDeserializedType} objects");
return false;
shell.WriteLine($"serialized: {RobustSerializer.BytesSerialized} bytes, {RobustSerializer.ObjectsSerialized} objects");
shell.WriteLine($"largest serialized: {RobustSerializer.LargestObjectSerializedBytes} bytes, {RobustSerializer.LargestObjectSerializedType} objects");
shell.WriteLine($"deserialized: {RobustSerializer.BytesDeserialized} bytes, {RobustSerializer.ObjectsDeserialized} objects");
shell.WriteLine($"largest serialized: {RobustSerializer.LargestObjectDeserializedBytes} bytes, {RobustSerializer.LargestObjectDeserializedType} objects");
}
}
@@ -853,7 +858,7 @@ namespace Robust.Client.Console.Commands
public string Description => "Gets info about a chunk under your mouse cursor.";
public string Help => Command;
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var mapMan = IoCManager.Resolve<IMapManager>();
var inputMan = IoCManager.Resolve<IInputManager>();
@@ -863,8 +868,8 @@ namespace Robust.Client.Console.Commands
if (!mapMan.TryFindGridAt(mousePos, out var grid))
{
console.AddLine("No grid under your mouse cursor.");
return false;
shell.WriteLine("No grid under your mouse cursor.");
return;
}
var internalGrid = (IMapGridInternal)grid;
@@ -872,8 +877,7 @@ namespace Robust.Client.Console.Commands
var chunkIndex = grid.LocalToChunkIndices(grid.MapToGrid(mousePos));
var chunk = internalGrid.GetChunk(chunkIndex);
console.AddLine($"worldBounds: {chunk.CalcWorldBounds()} localBounds: {chunk.CalcLocalBounds()}");
return false;
shell.WriteLine($"worldBounds: {chunk.CalcWorldBounds()} localBounds: {chunk.CalcLocalBounds()}");
}
}
@@ -890,7 +894,7 @@ namespace Robust.Client.Console.Commands
public static ConcurrentDictionary<string, bool>? _reloadShadersQueued = new();
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
IResourceCacheInternal resC;
if (args.Length == 1)
@@ -899,8 +903,8 @@ namespace Robust.Client.Console.Commands
{
if (_watchers != null)
{
console.AddLine("Already watching.");
return false;
shell.WriteLine("Already watching.");
return;
}
resC = IoCManager.Resolve<IResourceCacheInternal>();
@@ -969,11 +973,11 @@ namespace Robust.Client.Console.Commands
{
IoCManager.Resolve<IResourceCache>()
.ReloadResource<ShaderSourceResource>(resPath);
console.AddLine($"Reloaded shader: {resPath}");
shell.WriteLine($"Reloaded shader: {resPath}");
}
catch (Exception)
{
console.AddLine($"Failed to reload shader: {resPath}");
shell.WriteLine($"Failed to reload shader: {resPath}");
}
_reloadShadersQueued.TryRemove(ev.FullPath, out var _);
@@ -993,17 +997,17 @@ namespace Robust.Client.Console.Commands
++created;
}
console.AddLine($"Created {created} shader directory watchers for {shaderCount} shaders.");
shell.WriteLine($"Created {created} shader directory watchers for {shaderCount} shaders.");
return false;
return;
}
if (args[0] == "-watch")
{
if (_watchers == null)
{
console.AddLine("No shader directory watchers active.");
return false;
shell.WriteLine("No shader directory watchers active.");
return;
}
var disposed = 0;
@@ -1015,19 +1019,19 @@ namespace Robust.Client.Console.Commands
_watchers = null;
console.AddLine($"Disposed of {disposed} shader directory watchers.");
shell.WriteLine($"Disposed of {disposed} shader directory watchers.");
return false;
return;
}
}
if (args.Length > 1)
{
console.AddLine("Not implemented.");
return false;
shell.WriteLine("Not implemented.");
return;
}
console.AddLine("Reloading content shader resources...");
shell.WriteLine("Reloading content shader resources...");
resC = IoCManager.Resolve<IResourceCacheInternal>();
@@ -1039,13 +1043,11 @@ namespace Robust.Client.Console.Commands
}
catch (Exception)
{
console.AddLine($"Failed to reload shader: {path}");
shell.WriteLine($"Failed to reload shader: {path}");
}
}
console.AddLine("Done.");
return false;
shell.WriteLine("Done.");
}
}
@@ -1056,14 +1058,14 @@ namespace Robust.Client.Console.Commands
public string Description => "Toggle fov and light debug layers";
public string Help => "cldbglyr <layer>: Toggle <layer>\ncldbglyr: Turn all Layers off";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var clyde = IoCManager.Resolve<IClydeInternal>();
if (args.Length < 1)
{
clyde.DebugLayers = ClydeDebugLayers.None;
return false;
return;
}
clyde.DebugLayers = args[0] switch
@@ -1072,8 +1074,6 @@ namespace Robust.Client.Console.Commands
"light" => ClydeDebugLayers.Light,
_ => ClydeDebugLayers.None
};
return false;
}
}
@@ -1083,12 +1083,12 @@ namespace Robust.Client.Console.Commands
public string Description => "Keys key info for a key";
public string Help => "keyinfo <Key>";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != 1)
{
console.AddLine(Help);
return false;
shell.WriteLine(Help);
return;
}
var clyde = IoCManager.Resolve<IClydeInternal>();
@@ -1101,15 +1101,13 @@ namespace Robust.Client.Console.Commands
var scanCode = clyde.GetKeyScanCode(key);
var nameScanCode = clyde.GetKeyNameScanCode(scanCode);
console.AddLine($"name: '{name}' scan code: '{scanCode}' name via scan code: '{nameScanCode}'");
shell.WriteLine($"name: '{name}' scan code: '{scanCode}' name via scan code: '{nameScanCode}'");
}
else if (int.TryParse(args[0], out var scanCode))
{
var nameScanCode = clyde.GetKeyNameScanCode(scanCode);
console.AddLine($"name via scan code: '{nameScanCode}'");
shell.WriteLine($"name via scan code: '{nameScanCode}'");
}
return false;
}
}
}

View File

@@ -1,7 +1,6 @@
using System;
using Robust.Client.Interfaces.Console;
using Robust.Shared.Console;
using Robust.Shared.ContentPack;
using Robust.Shared.Maths;
namespace Robust.Client.Console.Commands
{
@@ -12,23 +11,21 @@ namespace Robust.Client.Console.Commands
public string Description => "Dumps a type's members in a format suitable for the sandbox configuration file.";
public string Help => "Usage: dmetamem <type>";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var type = Type.GetType(args[0]);
if (type == null)
{
console.AddLine("That type does not exist", Color.Red);
return false;
shell.WriteError("That type does not exist");
return;
}
foreach (var sig in AssemblyTypeChecker.DumpMetaMembers(type))
{
System.Console.WriteLine(@$"- ""{sig}""");
console.AddLine(sig);
shell.WriteLine(sig);
}
return false;
}
}
#endif

View File

@@ -1,8 +1,7 @@
using System.Linq;
using Robust.Client.Interfaces.Console;
using Robust.Shared.Interfaces.Network;
using System.Linq;
using Robust.Shared.Console;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Network;
namespace Robust.Client.Console.Commands
{
@@ -12,37 +11,36 @@ namespace Robust.Client.Console.Commands
public string Help => "When no arguments are provided, displays a generic help text. When an argument is passed, display the help text for the command with that name.";
public string Description => "Display help text.";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
switch (args.Length)
{
case 0:
console.AddLine("To display help for a specific command, write 'help <command>'. To list all available commands, write 'list'.");
shell.WriteLine("To display help for a specific command, write 'help <command>'. To list all available commands, write 'list'.");
break;
case 1:
string commandname = args[0];
if (!console.Commands.ContainsKey(commandname))
if (!shell.ConsoleHost.RegisteredCommands.ContainsKey(commandname))
{
if (!IoCManager.Resolve<IClientNetManager>().IsConnected)
{
// No server so nothing to respond with unknown command.
console.AddLine("Unknown command: " + commandname, Color.Red);
return false;
shell.WriteError("Unknown command: " + commandname);
return;
}
// TODO: Maybe have a server side help?
return false;
return;
}
IConsoleCommand command = console.Commands[commandname];
console.AddLine(string.Format("{0} - {1}", command.Command, command.Description));
console.AddLine(command.Help);
IConsoleCommand command = shell.ConsoleHost.RegisteredCommands[commandname];
shell.WriteLine(string.Format("{0} - {1}", command.Command, command.Description));
shell.WriteLine(command.Help);
break;
default:
console.AddLine("Invalid amount of arguments.", Color.Red);
shell.WriteError("Invalid amount of arguments.");
break;
}
return false;
}
}
@@ -55,7 +53,7 @@ namespace Robust.Client.Console.Commands
"only commands that contain the given string in their name will be listed.";
public string Description => "List all commands, optionally with a filter.";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var filter = "";
if (args.Length == 1)
@@ -64,14 +62,12 @@ namespace Robust.Client.Console.Commands
}
var conGroup = IoCManager.Resolve<IClientConGroupController>();
foreach (var command in console.Commands.Values
foreach (var command in shell.ConsoleHost.RegisteredCommands.Values
.Where(p => p.Command.Contains(filter) && conGroup.CanCommand(p.Command))
.OrderBy(c => c.Command))
{
console.AddLine(command.Command + ": " + command.Description);
shell.WriteLine(command.Command + ": " + command.Description);
}
return false;
}
}
}

View File

@@ -0,0 +1,67 @@
#if !FULL_RELEASE
using System;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using Robust.Client.Utility;
using Robust.Shared.Console;
using Robust.Shared.IoC;
using Robust.Shared.Network;
namespace Robust.Client.Console.Commands
{
internal sealed class LauncherAuthCommand : IConsoleCommand
{
public string Command => "launchauth";
public string Description => "Load authentication tokens from launcher data to aid in testing of live servers";
public string Help => "launchauth [account name]";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var wantName = args.Length > 0 ? args[0] : null;
var basePath = Path.GetDirectoryName(UserDataDir.GetUserDataDir())!;
var cfgPath = Path.Combine(basePath, "launcher", "launcher_config.json");
var data = JsonSerializer.Deserialize<LauncherConfig>(File.ReadAllText(cfgPath))!;
var login = wantName != null
? data.Logins.FirstOrDefault(p => p.Username == wantName)
: data.Logins.FirstOrDefault();
if (login == null)
{
shell.WriteLine("Unable to find a matching login");
return;
}
var token = login.Token.Token;
var userId = login.UserId;
var cfg = IoCManager.Resolve<IAuthManager>();
cfg.Token = token;
cfg.UserId = new NetUserId(Guid.Parse(userId));
}
private sealed class LauncherConfig
{
[JsonInclude] [JsonPropertyName("logins")]
public LauncherLogin[] Logins = default!;
}
private sealed class LauncherLogin
{
[JsonInclude] public string Username = default!;
[JsonInclude] public string UserId = default!;
[JsonInclude] public LauncherToken Token = default!;
}
private sealed class LauncherToken
{
[JsonInclude] public string Token = default!;
}
}
}
#endif

View File

@@ -1,8 +1,7 @@
using System.Linq;
using System.Runtime.Loader;
using System.Text;
using JetBrains.Annotations;
using Robust.Client.Interfaces.Console;
using Robust.Shared.Console;
namespace Robust.Client.Console.Commands
{
@@ -13,18 +12,16 @@ namespace Robust.Client.Console.Commands
public string Description => "Lists loaded assemblies by load context.";
public string Help => Command;
public bool Execute(IDebugConsole console, string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
foreach (var context in AssemblyLoadContext.All)
{
console.AddLine($"{context.Name}:");
shell.WriteLine($"{context.Name}:");
foreach (var assembly in context.Assemblies.OrderBy(a => a.FullName))
{
console.AddLine($" {assembly.FullName}");
shell.WriteLine($" {assembly.FullName}");
}
}
return false;
}
}
}

View File

@@ -1,7 +1,6 @@
using Robust.Client.Interfaces.Console;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Log;
using System;
using Robust.Shared.Console;
namespace Robust.Client.Console.Commands
{
@@ -13,12 +12,12 @@ namespace Robust.Client.Console.Commands
+ "\n sawmill: A label prefixing log messages. This is the one you're setting the level for."
+ "\n level: The log level. Must match one of the values of the LogLevel enum.";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != 2)
{
console.AddLine("Invalid argument amount. Expected 2 arguments.", Color.Red);
return false;
shell.WriteError("Invalid argument amount. Expected 2 arguments.");
return;
}
var name = args[0];
@@ -32,13 +31,12 @@ namespace Robust.Client.Console.Commands
{
if (!Enum.TryParse<LogLevel>(levelname, out var result))
{
console.AddLine("Failed to parse 2nd argument. Must be one of the values of the LogLevel enum.");
return false;
shell.WriteLine("Failed to parse 2nd argument. Must be one of the values of the LogLevel enum.");
return;
}
level = result;
}
Logger.GetSawmill(name).Level = level;
return false;
}
}
@@ -51,12 +49,12 @@ namespace Robust.Client.Console.Commands
+ "\n level: The log level. Must match one of the values of the LogLevel enum."
+ "\n message: The message to be logged. Wrap this in double quotes if you want to use spaces.";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != 3)
{
console.AddLine("Invalid argument amount. Expected 3 arguments.", Color.Red);
return false;
shell.WriteError("Invalid argument amount. Expected 3 arguments.");
return;
}
var name = args[0];
@@ -64,13 +62,12 @@ namespace Robust.Client.Console.Commands
var message = args[2]; // yes this doesn't support spaces idgaf.
if (!Enum.TryParse<LogLevel>(levelname, out var result))
{
console.AddLine("Failed to parse 2nd argument. Must be one of the values of the LogLevel enum.");
return false;
shell.WriteLine("Failed to parse 2nd argument. Must be one of the values of the LogLevel enum.");
return;
}
var level = result;
Logger.LogS(level, name, message);
return false;
}
}
}

View File

@@ -1,5 +1,5 @@
using Robust.Client.Interfaces.Console;
using System;
using Robust.Shared.Console;
namespace Robust.Client.Console.Commands
{
@@ -9,10 +9,9 @@ namespace Robust.Client.Console.Commands
public string Description => "Kills the game client instantly.";
public string Help => "Kills the game client instantly, leaving no traces. No telling the server goodbye";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
Environment.Exit(0);
return false;
}
}
}

View File

@@ -1,22 +1,19 @@
using Robust.Client.Interfaces.Console;
using Robust.Shared.Console;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
namespace Robust.Client.Console.Commands
{
#if CLIENT_SCRIPTING
internal sealed class ScriptConsoleCommand : IConsoleCommand
internal sealed class ScriptCommand : IConsoleCommand
{
public string Command => "csi";
public string Description => "Opens a C# interactive console.";
public string Help => "csi";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
new ScriptConsoleClient().OpenCentered();
return false;
}
}
@@ -26,33 +23,29 @@ namespace Robust.Client.Console.Commands
public string Description => "Opens a variable watch window.";
public string Help => "watch";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
new WatchWindow().OpenCentered();
return false;
}
}
#endif
internal sealed class ServerScriptConsoleCommand : IConsoleCommand
internal sealed class ServerScriptCommand : IConsoleCommand
{
public string Command => "scsi";
public string Description => "Opens a C# interactive console on the server.";
public string Help => "scsi";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var mgr = IoCManager.Resolve<IScriptClient>();
if (!mgr.CanScript)
{
console.AddLine(Loc.GetString("You do not have server side scripting permission."), Color.Red);
return false;
shell.WriteError(Loc.GetString("You do not have server side scripting permission."));
return;
}
mgr.StartSession();
return false;
}
}
}

View File

@@ -1,5 +1,4 @@
using Robust.Client.Interfaces.Console;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Console;
using Robust.Shared.IoC;
using Robust.Shared.Network;
@@ -11,7 +10,7 @@ namespace Robust.Client.Console.Commands
public string Description => "Sends garbage to the server.";
public string Help => "The server will reply with 'no u'";
public bool Execute(IDebugConsole console, params string[] args)
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
// MsgStringTableEntries is registered as NetMessageAccept.Client so the server will immediately deny it.
// And kick us.
@@ -19,8 +18,6 @@ namespace Robust.Client.Console.Commands
var msg = net.CreateNetMessage<MsgStringTableEntries>();
msg.Entries = new MsgStringTableEntries.Entry[0];
net.ClientSendMessage(msg);
return false;
}
}
}

View File

@@ -0,0 +1,34 @@
using JetBrains.Annotations;
using Robust.Client.Input;
using Robust.Shared.Console;
using Robust.Shared.IoC;
namespace Robust.Client.Console.Commands
{
[UsedImplicitly]
public class SetInputContextCommand : IConsoleCommand
{
public string Command => "setinputcontext";
public string Description => "Sets the active input context.";
public string Help => "setinputcontext <context>";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != 1)
{
shell.WriteLine("Invalid number of arguments!");
return;
}
var inputMan = IoCManager.Resolve<IInputManager>();
if (!inputMan.Contexts.Exists(args[0]))
{
shell.WriteLine("Context not found!");
return;
}
inputMan.Contexts.SetActiveContext(args[0]);
}
}
}

View File

@@ -1,6 +1,4 @@
using System;
namespace Robust.Client.Console
namespace Robust.Client.Console
{
public interface IClientConGroupController : IClientConGroupImplementation
{

View File

@@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using Robust.Client.Interfaces.Console;
namespace Robust.Client.Console
{
public interface IClientConsole : IDisposable
{
/// <summary>
/// Initializes the console into a useable state.
/// </summary>
void Initialize();
/// <summary>
/// Resets the console to a post-initialized state.
/// </summary>
void Reset();
event EventHandler<AddStringArgs> AddString;
event EventHandler<AddFormattedMessageArgs> AddFormatted;
event EventHandler ClearText;
IReadOnlyDictionary<string, IConsoleCommand> Commands { get; }
/// <summary>
/// Parses console commands (verbs).
/// </summary>
/// <param name="text"></param>
void ProcessCommand(string text);
void SendServerCommandRequest();
}
}

View File

@@ -0,0 +1,24 @@
using System;
using Robust.Shared.Console;
using Robust.Shared.Utility;
namespace Robust.Client.Console
{
public interface IClientConsoleHost : IConsoleHost, IDisposable
{
/// <summary>
/// Initializes the console into a useable state.
/// </summary>
void Initialize();
/// <summary>
/// Resets the console to a post-initialized state.
/// </summary>
void Reset();
event EventHandler<AddStringArgs> AddString;
event EventHandler<AddFormattedMessageArgs> AddFormatted;
void AddFormattedLine(FormattedMessage message);
}
}

View File

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Network.Messages;
namespace Robust.Client.Console

View File

@@ -10,10 +10,10 @@ using Microsoft.CodeAnalysis.Scripting;
using Microsoft.CodeAnalysis.Text;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.ViewVariables;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Reflection;
using Robust.Shared.Scripting;
using Robust.Shared.Utility;

View File

@@ -7,10 +7,10 @@ using Microsoft.CodeAnalysis.Scripting;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Reflection;
using Robust.Shared.Scripting;
using Robust.Shared.Timing;
@@ -20,8 +20,6 @@ namespace Robust.Client.Console
{
private readonly IReflectionManager _reflectionManager;
protected override Vector2? CustomSize => (300, 300);
private readonly VBoxContainer _watchesVBox;
private readonly LineEdit _addWatchEdit;
private readonly Button _addWatchButton;
@@ -37,12 +35,12 @@ namespace Robust.Client.Console
var mainVBox = new VBoxContainer
{
CustomMinimumSize = (500, 300),
MinSize = (500, 300),
Children =
{
(_watchesVBox = new VBoxContainer
{
SizeFlagsVertical = SizeFlags.FillExpand
VerticalExpand = true
}),
new HBoxContainer
{
@@ -50,7 +48,7 @@ namespace Robust.Client.Console
{
(_addWatchEdit = new HistoryLineEdit
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
HorizontalExpand = true,
PlaceHolder = Loc.GetString("Add watch (C# interactive)")
}),
(_addWatchButton = new Button
@@ -66,6 +64,8 @@ namespace Robust.Client.Console
_addWatchEdit.OnTextEntered += _ => AddWatch();
Contents.AddChild(mainVBox);
SetSize = (300, 300);
}
private void AddWatch()
@@ -113,7 +113,7 @@ namespace Robust.Client.Console
{
(_outputLabel = new Label
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
HorizontalExpand = true,
ClipText = true
}),
(delButton = new Button
@@ -176,7 +176,7 @@ namespace Robust.Client.Console
{
Text = message,
ClipText = true,
SizeFlagsHorizontal = SizeFlags.FillExpand
HorizontalExpand = true
},
(delButton = new Button {Text = Loc.GetString("Remove")})
}

View File

@@ -1,6 +1,6 @@
using System.Collections.Generic;
using System.IO;
using Robust.Shared.Interfaces.Resources;
using Robust.Shared.ContentPack;
using Robust.Shared.IoC;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;

View File

@@ -1,17 +1,9 @@
using System;
using System.Collections.Generic;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Graphics.Overlays;
using Robust.Client.Graphics.Shaders;
using Robust.Client.Interfaces.Debugging;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.Graphics.Overlays;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Input;
using Robust.Client.ResourceManagement;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
@@ -26,6 +18,7 @@ namespace Robust.Client.Debugging
[Dependency] private readonly IComponentManager _componentManager = default!;
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IPhysicsManager _physicsManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
@@ -48,7 +41,7 @@ namespace Robust.Client.Debugging
if (value)
{
_overlayManager.AddOverlay(new PhysicsOverlay(_componentManager, _eyeManager,
_prototypeManager, _inputManager));
_prototypeManager, _inputManager, _physicsManager));
}
else
{
@@ -86,6 +79,7 @@ namespace Robust.Client.Debugging
private readonly IComponentManager _componentManager;
private readonly IEyeManager _eyeManager;
private readonly IInputManager _inputManager;
private readonly IPhysicsManager _physicsManager;
public override OverlaySpace Space => OverlaySpace.WorldSpace | OverlaySpace.ScreenSpace;
private readonly ShaderInstance _shader;
@@ -94,12 +88,13 @@ namespace Robust.Client.Debugging
private Vector2 _hoverStartScreen = Vector2.Zero;
private List<IPhysBody> _hoverBodies = new();
public PhysicsOverlay(IComponentManager compMan, IEyeManager eyeMan, IPrototypeManager protoMan, IInputManager inputManager)
public PhysicsOverlay(IComponentManager compMan, IEyeManager eyeMan, IPrototypeManager protoMan, IInputManager inputManager, IPhysicsManager physicsManager)
: base(nameof(PhysicsOverlay))
{
_componentManager = compMan;
_eyeManager = eyeMan;
_inputManager = inputManager;
_physicsManager = physicsManager;
_shader = protoMan.Index<ShaderPrototype>("unshaded").Instance();
var cache = IoCManager.Resolve<IResourceCache>();
@@ -158,23 +153,20 @@ namespace Robust.Client.Debugging
_hoverStartScreen = mouseScreenPos;
var viewport = _eyeManager.GetWorldViewport();
foreach (var boundingBox in _componentManager.EntityQuery<IPhysicsComponent>())
{
var physBody = (IPhysBody) boundingBox;
if (viewport.IsEmpty()) return;
var mapId = _eyeManager.CurrentMap;
foreach (var physBody in _physicsManager.GetCollidingEntities(mapId, viewport))
{
// all entities have a TransformComponent
var transform = physBody.Entity.Transform;
// if not on the same map, continue
if (transform.MapID != _eyeManager.CurrentMap || !transform.IsMapTransform)
continue;
var worldBox = physBody.WorldAABB;
var colorEdge = Color.Red.WithAlpha(0.33f);
if (worldBox.IsEmpty()) continue;
// if not on screen, or too small, continue
if (!worldBox.Intersects(in viewport) || worldBox.IsEmpty())
continue;
var colorEdge = Color.Red.WithAlpha(0.33f);
foreach (var shape in physBody.PhysicsShapes)
{

View File

@@ -1,15 +1,11 @@
using Robust.Client.Interfaces.Debugging;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.IoC;
using Robust.Shared.Network.Messages;
using System;
using System.Collections.Generic;
using Robust.Client.Graphics.Overlays;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Graphics;
using Robust.Shared.Maths;
using Robust.Client.Interfaces.Graphics.Overlays;
using Robust.Shared.Timing;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.Network;
namespace Robust.Client.Debugging
{

View File

@@ -1,4 +1,4 @@
namespace Robust.Client.Interfaces.Debugging
namespace Robust.Client.Debugging
{
/// <summary>
/// A collection of visual debug overlays for the client game.

View File

@@ -1,11 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Robust.Shared.Timing;
namespace Robust.Client.Interfaces.Debugging
namespace Robust.Client.Debugging
{
public interface IDebugDrawingManager
{

View File

@@ -1,20 +1,17 @@
using System;
using System;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using Robust.Client.Console;
using Robust.Client.Interfaces;
using Robust.Client.Interfaces.GameObjects;
using Robust.Client.Interfaces.GameStates;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Interfaces.Graphics.Overlays;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.Placement;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Interfaces.State;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Interfaces.Utility;
using Robust.Client.GameObjects;
using Robust.Client.GameStates;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.Placement;
using Robust.Client.Player;
using Robust.Client.ResourceManagement;
using Robust.Client.State;
using Robust.Client.UserInterface;
using Robust.Client.Utility;
using Robust.Client.ViewVariables;
using Robust.LoaderApi;
@@ -22,15 +19,11 @@ using Robust.Shared;
using Robust.Shared.Asynchronous;
using Robust.Shared.Configuration;
using Robust.Shared.ContentPack;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Log;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.Interfaces.Timers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Timing;
@@ -50,7 +43,7 @@ namespace Robust.Client
[Dependency] private readonly IUserInterfaceManagerInternal _userInterfaceManager = default!;
[Dependency] private readonly IBaseClient _client = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IClientConsole _console = default!;
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
[Dependency] private readonly ITimerManager _timerManager = default!;
[Dependency] private readonly IClientEntityManager _entityManager = default!;
[Dependency] private readonly IPlacementManager _placementManager = default!;
@@ -67,6 +60,7 @@ namespace Robust.Client
[Dependency] private readonly IComponentManager _componentManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IRobustMappedStringSerializer _stringSerializer = default!;
[Dependency] private readonly IAuthManager _authManager = default!;
private CommandLineArgs? _commandLineArgs;
private bool _disableAssemblyLoadContext;
@@ -164,9 +158,11 @@ namespace Robust.Client
_userInterfaceManager.Initialize();
_networkManager.Initialize(false);
IoCManager.Resolve<INetConfigurationManager>().SetupNetworking();
_serializer.Initialize();
_inputManager.Initialize();
_console.Initialize();
_consoleHost.Initialize();
_prototypeManager.Initialize();
_prototypeManager.LoadDirectory(new ResourcePath(@"/Prototypes/"));
_prototypeManager.Resync();
_mapManager.Initialize();
@@ -185,6 +181,8 @@ namespace Robust.Client
_client.PlayerNameOverride = _commandLineArgs.Username;
}
_authManager.LoadFromEnv();
_clyde.Ready();
if ((_commandLineArgs?.Connect == true || _commandLineArgs?.Launcher == true)

View File

@@ -1,4 +1,4 @@
using Robust.Client.Input;
using Robust.Client.Input;
namespace Robust.Client
{

View File

@@ -1,67 +1,9 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Robust.Client.Graphics.Clyde;
using Robust.Client.Console;
using Robust.Client.Debugging;
using Robust.Client.GameObjects;
using Robust.Client.GameStates;
using Robust.Client.Graphics;
using Robust.Client.Graphics.ClientEye;
using Robust.Client.Graphics.Lighting;
using Robust.Client.Graphics.Overlays;
using Robust.Client.Input;
using Robust.Client.Interfaces;
using Robust.Client.Interfaces.Debugging;
using Robust.Client.Interfaces.GameObjects;
using Robust.Client.Interfaces.GameStates;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.Graphics.Lighting;
using Robust.Client.Interfaces.Graphics.Overlays;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.Map;
using Robust.Client.Interfaces.Placement;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Interfaces.State;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Interfaces.Utility;
using Robust.Client.Map;
using Robust.Client.Placement;
using Robust.Client.Player;
using Robust.Client.Reflection;
using Robust.Client.ResourceManagement;
using Robust.Client.State;
using Robust.Client.UserInterface;
using Robust.Client.Utility;
using Robust.Client.ViewVariables;
using Robust.Shared;
using Robust.Shared.Asynchronous;
using Robust.Shared.Configuration;
using Robust.Shared.ContentPack;
using Robust.Shared.Exceptions;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Log;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Physics;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.Interfaces.Resources;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.Interfaces.Timers;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Physics;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Timers;
using Robust.Shared.Timing;
using Robust.Shared.Reflection;
namespace Robust.Client
{

View File

@@ -1,4 +1,4 @@
using Robust.Client;
using Robust.Client;
using Robust.LoaderApi;
[assembly: LoaderEntryPoint(typeof(GameController.LoaderEntryPoint))]
@@ -11,7 +11,7 @@ namespace Robust.Client
{
public void Main(IMainArgs args)
{
GameController.Start(args.Args, contentStart: false, args);
Start(args.Args, contentStart: false, args);
}
}
}

View File

@@ -1,7 +1,5 @@
using System;
using Robust.Client.Interfaces;
using System;
using Robust.LoaderApi;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Timing;

View File

@@ -0,0 +1,3 @@
Everything in this folder and subfolders needs to be in:
Robust.Client.GameObjects

View File

@@ -1,18 +1,4 @@
using Robust.Client.GameObjects.Components;
using Robust.Client.GameObjects.Components.Animations;
using Robust.Client.GameObjects.Components.Containers;
using Robust.Client.GameObjects.Components.UserInterface;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.GameObjects.Components.Appearance;
using Robust.Shared.GameObjects.Components.Eye;
using Robust.Shared.GameObjects.Components.Map;
using Robust.Shared.GameObjects.Components.Renderable;
using Robust.Shared.GameObjects.Components.Timers;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.GameObjects.Components.UserInterface;
using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.Physics;
namespace Robust.Client.GameObjects
@@ -39,7 +25,6 @@ namespace Robust.Client.GameObjects
RegisterReference<PhysicsComponent, IPhysBody>();
RegisterReference<PhysicsComponent, IPhysicsComponent>();
RegisterIgnore("KeyBindingInput");
Register<PointLightComponent>();
Register<InputComponent>();
@@ -55,15 +40,13 @@ namespace Robust.Client.GameObjects
Register<AppearanceComponent>();
RegisterReference<AppearanceComponent, SharedAppearanceComponent>();
Register<AppearanceTestComponent>();
Register<SnapGridComponent>();
Register<ClientUserInterfaceComponent>();
RegisterReference<ClientUserInterfaceComponent, SharedUserInterfaceComponent>();
RegisterIgnore("IgnorePause");
Register<AnimationPlayerComponent>();
Register<ContainerManagerComponent>();

View File

@@ -1,11 +1,8 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Client.Interfaces.GameObjects;
using Robust.Shared.Exceptions;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;

View File

@@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
using Robust.Client.Interfaces.GameStates;
using Robust.Client.GameStates;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Network;
using Robust.Shared.Network.Messages;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Robust.Client.GameObjects

View File

@@ -5,7 +5,7 @@ using Robust.Client.Animations;
using Robust.Shared.GameObjects;
using static Robust.Client.Animations.AnimationPlaybackShared;
namespace Robust.Client.GameObjects.Components.Animations
namespace Robust.Client.GameObjects
{
/// <summary>
/// Plays back <see cref="Animation"/>s on entities.
@@ -48,11 +48,21 @@ namespace Robust.Client.GameObjects.Components.Animations
return;
}
List<string>? toRemove = null;
// TODO: Get rid of this ToArray() allocation.
foreach (var (key, playback) in _playingAnimations.ToArray())
{
var keep = UpdatePlayback(Owner, playback, frameTime);
if (!keep)
{
toRemove ??= new List<string>();
toRemove.Add(key);
}
}
if (toRemove != null)
{
foreach (var key in toRemove)
{
_playingAnimations.Remove(key);
AnimationCompleted?.Invoke(key);

View File

@@ -1,13 +1,9 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Appearance;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.IoC;
using Robust.Shared.Reflection;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
@@ -78,6 +74,8 @@ namespace Robust.Client.GameObjects
private void SetData(object key, object value)
{
if (data.TryGetValue(key, out var existing) && existing.Equals(value)) return;
data[key] = value;
MarkDirty();
@@ -85,10 +83,9 @@ namespace Robust.Client.GameObjects
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{
if (curState == null)
if (curState is not AppearanceComponentState actualState)
return;
var actualState = (AppearanceComponentState) curState;
data = actualState.Data;
MarkDirty();
}

View File

@@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.ViewVariables;
namespace Robust.Client.GameObjects.Components.Containers
namespace Robust.Client.GameObjects
{
public sealed partial class ContainerManagerComponent
{

View File

@@ -2,14 +2,10 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Containers;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.ViewVariables;
namespace Robust.Client.GameObjects.Components.Containers
namespace Robust.Client.GameObjects
{
public sealed partial class ContainerManagerComponent : SharedContainerManagerComponent
{

View File

@@ -1,8 +1,5 @@
using Robust.Client.Graphics.ClientEye;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Graphics;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Eye;
using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;

View File

@@ -1,9 +1,9 @@
using Robust.Client.Graphics;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.ResourceManagement;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
@@ -31,11 +31,11 @@ namespace Robust.Client.GameObjects
}
}
private static IDirectionalTextureProvider TextureForConfig(ObjectSerializer serializer, IResourceCache resourceCache)
private static IRsiStateLike TextureForConfig(ObjectSerializer serializer, IResourceCache resourceCache)
{
DebugTools.Assert(serializer.Reading);
if (serializer.TryGetCacheData<IDirectionalTextureProvider>(SerializationCache, out var dirTex))
if (serializer.TryGetCacheData<IRsiStateLike>(SerializationCache, out var dirTex))
{
return dirTex;
}
@@ -93,7 +93,7 @@ namespace Robust.Client.GameObjects
}
}
public static IDirectionalTextureProvider? GetPrototypeIcon(EntityPrototype prototype, IResourceCache resourceCache)
public static IRsiStateLike? GetPrototypeIcon(EntityPrototype prototype, IResourceCache resourceCache)
{
if (!prototype.Components.TryGetValue("Icon", out var mapping))
{

View File

@@ -1,10 +1,9 @@
using Robust.Client.GameObjects.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Input;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
namespace Robust.Client.GameObjects.Components
namespace Robust.Client.GameObjects
{
/// <summary>
/// Defines data fields used in the <see cref="InputSystem"/>.

View File

@@ -1,7 +1,5 @@
using System;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.ViewVariables;

View File

@@ -1,21 +1,22 @@
using Robust.Client.GameObjects.EntitySystems;
using System;
using Robust.Client.Graphics;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.ResourceManagement;
using Robust.Shared.Animations;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using System;
namespace Robust.Client.GameObjects
{
public class PointLightComponent : Component
[RegisterComponent]
[ComponentReference(typeof(IPointLightComponent))]
public class PointLightComponent : Component, IPointLightComponent
{
[Dependency] private readonly IResourceCache _resourceCache = default!;
public override string Name => "PointLight";
public override uint? NetID => NetIDs.POINT_LIGHT;
@@ -68,6 +69,21 @@ namespace Robust.Client.GameObjects
set => _rotation = value;
}
/// <inheritdoc />
/// <summary>
/// The resource path to the mask texture the light will use.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public string? MaskPath
{
get => _maskPath;
set
{
_maskPath = value;
UpdateMask();
}
}
/// <summary>
/// Set a mask texture that will be applied to the light while rendering.
/// The mask's red channel will be linearly multiplied.p
@@ -120,7 +136,7 @@ namespace Robust.Client.GameObjects
private float _radius = 5;
private bool _visibleNested = true;
private bool _lightOnParent = false;
private bool _lightOnParent;
private Color _color = Color.White;
private Vector2 _offset;
private bool _enabled = true;
@@ -128,6 +144,7 @@ namespace Robust.Client.GameObjects
private Angle _rotation;
private float _energy;
private float _softness;
private string? _maskPath;
/// <summary>
/// Radius, in meters.
@@ -144,6 +161,20 @@ namespace Robust.Client.GameObjects
}
}
private void UpdateMask()
{
if (_maskPath is not null)
Mask = _resourceCache.GetResource<TextureResource>(_maskPath);
else
Mask = null;
}
public override void Initialize()
{
base.Initialize();
UpdateMask();
}
/// <inheritdoc />
public override void HandleMessage(ComponentMessage message, IComponent? component)
{
@@ -183,11 +214,7 @@ namespace Robust.Client.GameObjects
serializer.DataFieldCached(ref _softness, "softness", 1f);
serializer.DataFieldCached(ref _maskAutoRotate, "autoRot", false);
serializer.DataFieldCached(ref _visibleNested, "nestedvisible", true);
if (serializer.Reading && serializer.TryReadDataField<string>("mask", out var value))
{
Mask = IoCManager.Resolve<IResourceCache>().GetResource<TextureResource>(value);
}
serializer.DataFieldCached(ref _maskPath, "mask", null);
}
public override void OnRemove()

View File

@@ -1,9 +1,8 @@
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths;
namespace Robust.Client.Interfaces.GameObjects
namespace Robust.Client.GameObjects
{
public interface IRenderableComponent : IComponent
{

View File

@@ -1,14 +1,12 @@
using System;
using System;
using System.Collections.Generic;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Shaders;
using Robust.Shared.Animations;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
namespace Robust.Client.Interfaces.GameObjects.Components
namespace Robust.Client.GameObjects
{
public interface ISpriteComponent : IComponent, IAnimationProperties
{
@@ -51,8 +49,26 @@ namespace Robust.Client.Interfaces.GameObjects.Components
/// Rotation transformations on individual layers still apply.
/// If false, all layers get locked to south and rotation is a transformation.
/// </summary>
[Obsolete("Use NoRotation and/or DirectionOverride")]
bool Directional { get; set; }
/// <summary>
/// All sprite rotation is locked, and will always be drawn upright on
/// the screen, regardless of world or view orientation.
/// </summary>
bool NoRotation {get; set; }
/// <summary>
/// Enables overriding the calculated directional RSI state for this sprite.
/// The state to use is defined in <see cref="DirectionOverride"/>.
/// </summary>
bool EnableDirectionOverride { get; set; }
/// <summary>
/// The directional RSI state that will always be displayed, regardless of orientation.
/// </summary>
Direction DirectionOverride { get; set; }
// NOTE: The below are ALL designed to NOT throw exceptions ever,
// instead making a bunch of noisy error logs.
@@ -205,29 +221,4 @@ namespace Robust.Client.Interfaces.GameObjects.Components
IEnumerable<ISpriteLayer> AllLayers { get; }
}
public interface ISpriteLayer
{
SpriteComponent.DirectionOffset DirOffset { get; set; }
RSI? Rsi { get; set; }
RSI.StateId RsiState { get; set; }
RSI? ActualRsi { get; }
Texture? Texture { get; set; }
Angle Rotation { get; set; }
Vector2 Scale { get; set; }
bool Visible { get; set; }
Color Color { get; set; }
float AnimationTime { get; set; }
int AnimationFrame { get; }
bool AutoAnimated { get; set; }
RSI.State.Direction EffectiveDirection(Angle worldRotation);
Vector2 LocalToLayer(Vector2 localPos);
}
}

View File

@@ -0,0 +1,30 @@
using Robust.Client.Graphics;
using Robust.Shared.Maths;
namespace Robust.Client.GameObjects
{
public interface ISpriteLayer
{
SpriteComponent.DirectionOffset DirOffset { get; set; }
RSI? Rsi { get; set; }
RSI.StateId RsiState { get; set; }
RSI? ActualRsi { get; }
Texture? Texture { get; set; }
Angle Rotation { get; set; }
Vector2 Scale { get; set; }
bool Visible { get; set; }
Color Color { get; set; }
float AnimationTime { get; set; }
int AnimationFrame { get; }
bool AutoAnimated { get; set; }
RSI.State.Direction EffectiveDirection(Angle worldRotation);
Vector2 LocalToLayer(Vector2 localPos);
}
}

View File

@@ -1,33 +1,24 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Text;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Client.Graphics;
using Robust.Client.Graphics.ClientEye;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Graphics.Shaders;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.ResourceManagement;
using Robust.Client.Utility;
using Robust.Shared.Animations;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Renderable;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Reflection;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using System.Linq;
using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using DrawDepthTag = Robust.Shared.GameObjects.DrawDepth;
@@ -110,6 +101,7 @@ namespace Robust.Client.GameObjects
/// If false, all layers get locked to south and rotation is a transformation.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[Obsolete("Use NoRotation and/or DirectionOverride")]
public bool Directional
{
get => _directional;
@@ -197,34 +189,34 @@ namespace Robust.Client.GameObjects
public void CopyFrom(SpriteComponent other)
{
//deep copying things to avoid entanglement
this._baseRsi = other._baseRsi;
this._directional = other._directional;
this._visible = other._visible;
this._layerMapShared = other._layerMapShared;
this.color = other.color;
this.offset = other.offset;
this.rotation = other.rotation;
this.scale = other.scale;
this.drawDepth = other.drawDepth;
this.Layers = new List<Layer>(other.Layers.Count);
_baseRsi = other._baseRsi;
_directional = other._directional;
_visible = other._visible;
_layerMapShared = other._layerMapShared;
color = other.color;
offset = other.offset;
rotation = other.rotation;
scale = other.scale;
drawDepth = other.drawDepth;
Layers = new List<Layer>(other.Layers.Count);
foreach (var otherLayer in other.Layers)
{
this.Layers.Add(new Layer(otherLayer, this));
Layers.Add(new Layer(otherLayer, this));
}
this.IsInert = other.IsInert;
this.LayerMap = other.LayerMap.ToDictionary(entry => entry.Key,
IsInert = other.IsInert;
LayerMap = other.LayerMap.ToDictionary(entry => entry.Key,
entry => entry.Value);
if (other.PostShader != null)
{
// only need to copy the shader if it's mutable
this.PostShader = other.PostShader.Mutable ? other.PostShader.Duplicate() : other.PostShader;
PostShader = other.PostShader.Mutable ? other.PostShader.Duplicate() : other.PostShader;
}
else
{
this.PostShader = null;
PostShader = null;
}
this.RenderOrder = other.RenderOrder;
RenderOrder = other.RenderOrder;
}
/// <inheritdoc />
@@ -974,38 +966,61 @@ namespace Robust.Client.GameObjects
public ISpriteLayer this[object layerKey] => this[LayerMap[layerKey]];
public IEnumerable<ISpriteLayer> AllLayers => Layers;
internal void Render(DrawingHandleWorld drawingHandle, in Matrix3 worldTransform, Angle worldRotation,
Direction? overrideDirection = null)
// Lobby SpriteView rendering path
internal void Render(DrawingHandleWorld drawingHandle, Angle worldRotation, Direction? overrideDirection = null)
{
var angle = Rotation;
if (Directional)
RenderInternal(drawingHandle, worldRotation, Vector2.Zero, overrideDirection);
}
private bool _screenLock = false;
private Direction _overrideDirection = Direction.South;
private bool _enableOverrideDirection = false;
/// <inheritdoc />
[ViewVariables(VVAccess.ReadWrite)]
public bool NoRotation { get => _screenLock; set => _screenLock = value; }
/// <inheritdoc />
[ViewVariables(VVAccess.ReadWrite)]
public Direction DirectionOverride { get => _overrideDirection; set => _overrideDirection = value; }
/// <inheritdoc />
[ViewVariables(VVAccess.ReadWrite)]
public bool EnableDirectionOverride { get => _enableOverrideDirection; set => _enableOverrideDirection = value; }
// Sprite rendering path
internal void Render(DrawingHandleWorld drawingHandle, in Angle worldRotation, in Vector2 worldPosition)
{
Direction? overrideDir = null;
if (_enableOverrideDirection)
{
angle -= worldRotation;
overrideDir = _overrideDirection;
}
RenderInternal(drawingHandle, worldRotation, worldPosition, overrideDir);
}
private void CalcModelMatrix(int numDirs, Angle worldRotation, Vector2 worldPosition, out Matrix3 modelMatrix)
{
Angle angle;
if (_screenLock)
{
angle = Angle.Zero;
}
else
{
angle -= new Angle(MathHelper.PiOver2);
angle = CalcRectWorldAngle(worldRotation, numDirs);
}
var mOffset = Matrix3.CreateTranslation(Offset);
var mRotation = Matrix3.CreateRotation(angle);
Matrix3.Multiply(ref mRotation, ref mOffset, out var transform);
transform.Multiply(worldTransform);
RenderInternal(drawingHandle, worldRotation, overrideDirection, transform);
var sWorldRotation = angle;
modelMatrix = Matrix3.CreateTransform(in worldPosition, in sWorldRotation);
}
internal void Render(DrawingHandleWorld drawingHandle, Angle worldRotation, Direction? overrideDirection = null)
private void RenderInternal(DrawingHandleWorld drawingHandle, Angle worldRotation, Vector2 worldPosition, Direction? overrideDirection)
{
RenderInternal(drawingHandle, worldRotation, overrideDirection, Matrix3.Identity);
}
private void RenderInternal(DrawingHandleWorld drawingHandle, Angle worldRotation, Direction? overrideDirection,
in Matrix3 transform)
{
drawingHandle.SetTransform(transform);
var localMatrix = Matrix3.CreateTransform(in offset, in rotation, in scale);
foreach (var layer in Layers)
{
if (!layer.Visible)
@@ -1013,26 +1028,87 @@ namespace Robust.Client.GameObjects
continue;
}
// TODO: Implement layer-specific rotation and scale.
// Oh and when you do update Layer.LocalToLayer so content doesn't break.
var dirType = GetLayerDirectionType(layer);
var texture = GetRenderTexture(layer, worldRotation, overrideDirection);
if (layer.Shader != null)
int numDirs;
switch (dirType)
{
drawingHandle.UseShader(layer.Shader);
case RSI.State.DirectionType.Dir1:
numDirs = 1;
break;
case RSI.State.DirectionType.Dir4:
numDirs = 4;
break;
case RSI.State.DirectionType.Dir8:
numDirs = 8;
break;
default:
throw new ArgumentOutOfRangeException();
}
drawingHandle.DrawTexture(texture, -(Vector2) texture.Size / (2f * EyeManager.PixelsPerMeter),
color * layer.Color);
CalcModelMatrix(numDirs, worldRotation, worldPosition, out var modelMatrix);
Matrix3.Multiply(ref localMatrix, ref modelMatrix, out var transformMatrix);
drawingHandle.SetTransform(in transformMatrix);
if (layer.Shader != null)
{
drawingHandle.UseShader(null);
}
RenderLayer(drawingHandle, layer, worldRotation, overrideDirection);
}
}
private void RenderLayer(DrawingHandleWorld drawingHandle, Layer layer, Angle worldRotation, Direction? overrideDirection)
{
var texture = GetRenderTexture(layer, worldRotation, overrideDirection);
if (layer.Shader != null)
{
drawingHandle.UseShader(layer.Shader);
}
var layerColor = color * layer.Color;
var position = -(Vector2) texture.Size / (2f * EyeManager.PixelsPerMeter);
var textureSize = texture.Size / (float) EyeManager.PixelsPerMeter;
var quad = Box2.FromDimensions(position, textureSize);
// TODO: Implement layer-specific rotation and scale.
// Apply these directly to the box.
// Oh and when you do update Layer.LocalToLayer so content doesn't break.
// handle.Modulate changes the color
// drawingHandle.SetTransform() is set above, turning the quad into local space vertices
drawingHandle.DrawTextureRectRegion(texture, quad, layerColor);
if (layer.Shader != null)
{
drawingHandle.UseShader(null);
}
}
private static Angle CalcRectWorldAngle(Angle worldAngle, int numDirections)
{
var theta = worldAngle.Theta;
var segSize = (MathF.PI*2) / (numDirections * 2);
var segments = (int)(theta / segSize);
var odd = segments % 2;
var result = theta - (segments * segSize) - (odd * segSize);
return result;
}
private RSI.State.DirectionType GetLayerDirectionType(Layer layer)
{
if (!layer.State.IsValid)
return RSI.State.DirectionType.Dir1;
// Pull texture from RSI state instead.
var rsi = layer.RSI ?? BaseRSI;
if (rsi == null || !rsi.TryGetState(layer.State, out var state))
{
state = GetFallbackState(resourceCache);
}
return state.Directions;
}
private Texture GetRenderTexture(Layer layer, Angle worldRotation, Direction? overrideDirection)
{
var texture = layer.Texture;
@@ -1043,9 +1119,9 @@ namespace Robust.Client.GameObjects
var rsi = layer.RSI ?? BaseRSI;
if (rsi == null || !rsi.TryGetState(layer.State, out var state))
{
state = GetFallbackState();
state = GetFallbackState(resourceCache);
}
var layerSpecificDir = layer.EffectiveDirection(state, worldRotation, overrideDirection);
texture = state.GetFrame(layerSpecificDir, layer.AnimationFrame);
}
@@ -1064,8 +1140,11 @@ namespace Robust.Client.GameObjects
serializer.DataFieldCached(ref drawDepth, "drawdepth", DrawDepthTag.Default,
WithFormat.Constants<DrawDepthTag>());
serializer.DataFieldCached(ref color, "color", Color.White);
serializer.DataFieldCached(ref _directional, "directional", true);
serializer.DataFieldCached(ref _visible, "visible", true);
serializer.DataFieldCached(ref _directional, "directional", true); //TODO: Kill ME
serializer.DataFieldCached(ref _screenLock, "noRot", false);
serializer.DataFieldCached(ref _enableOverrideDirection, "enableOverrideDir", false);
serializer.DataFieldCached(ref _overrideDirection, "overrideDir", Direction.East);
// TODO: Writing?
if (!serializer.Reading)
@@ -1276,7 +1355,7 @@ namespace Robust.Client.GameObjects
var rsi = layer.RSI ?? BaseRSI;
if (rsi == null || !rsi.TryGetState(layer.State, out var state))
{
state = GetFallbackState();
state = GetFallbackState(resourceCache);
}
if (!state.IsAnimated)
@@ -1320,7 +1399,6 @@ namespace Robust.Client.GameObjects
Rotation = thestate.Rotation;
Offset = thestate.Offset;
Color = thestate.Color;
Directional = thestate.Directional;
RenderOrder = thestate.RenderOrder;
if (thestate.BaseRsiPath != null && BaseRSI != null)
@@ -1377,16 +1455,28 @@ namespace Robust.Client.GameObjects
}
}
private RSI.State.Direction GetDir(RSI.State.DirectionType type, Angle worldRotation)
private RSI.State.Direction GetDir(RSI.State.DirectionType rsiDirectionType, Angle worldRotation)
{
if (!Directional)
var dir = rsiDirectionType switch
{
return RSI.State.Direction.South;
}
RSI.State.DirectionType.Dir1 => Direction.South,
RSI.State.DirectionType.Dir4 => worldRotation.GetCardinalDir(),
RSI.State.DirectionType.Dir8 => worldRotation.GetDir(),
_ => throw new ArgumentException($"Unknown RSI DirectionType: {rsiDirectionType}.", nameof(rsiDirectionType))
};
var angle = new Angle(worldRotation);
return angle.GetDir().Convert(type);
return dir switch
{
Direction.North => RSI.State.Direction.North,
Direction.South => RSI.State.Direction.South,
Direction.East => RSI.State.Direction.East,
Direction.West => RSI.State.Direction.West,
Direction.SouthEast => RSI.State.Direction.SouthEast,
Direction.SouthWest => RSI.State.Direction.SouthWest,
Direction.NorthEast => RSI.State.Direction.NorthEast,
Direction.NorthWest => RSI.State.Direction.NorthWest,
_ => throw new ArgumentOutOfRangeException(nameof(dir), dir, null)
};
}
private void UpdateIsInert()
@@ -1404,7 +1494,7 @@ namespace Robust.Client.GameObjects
var rsi = layer.RSI ?? BaseRSI;
if (rsi == null || !rsi.TryGetState(layer.State, out var state))
{
state = GetFallbackState();
state = GetFallbackState(resourceCache);
}
if (state.IsAnimated)
@@ -1415,9 +1505,9 @@ namespace Robust.Client.GameObjects
}
}
private RSI.State GetFallbackState()
internal static RSI.State GetFallbackState(IResourceCache cache)
{
var rsi = resourceCache.GetResource<RSIResource>("/Textures/error.rsi").RSI;
var rsi = cache.GetResource<RSIResource>("/Textures/error.rsi").RSI;
return rsi["error"];
}
@@ -1735,14 +1825,14 @@ namespace Robust.Client.GameObjects
var rsi = ActualRsi;
if (rsi == null)
{
state = _parent.GetFallbackState();
state = GetFallbackState(_parent.resourceCache);
Logger.ErrorS(LogCategory, "No RSI to pull new state from! Trace:\n{0}", Environment.StackTrace);
}
else
{
if (!rsi.TryGetState(stateId, out state))
{
state = _parent.GetFallbackState();
state = GetFallbackState(_parent.resourceCache);
Logger.ErrorS(LogCategory, "State '{0}' does not exist in RSI. Trace:\n{1}", stateId,
Environment.StackTrace);
}
@@ -1793,7 +1883,7 @@ namespace Robust.Client.GameObjects
}
}
public IDirectionalTextureProvider? Icon
public IRsiStateLike? Icon
{
get
{
@@ -1803,13 +1893,13 @@ namespace Robust.Client.GameObjects
var texture = layer.Texture;
if (!layer.State.IsValid) return null;
if (!layer.State.IsValid) return texture;
// Pull texture from RSI state instead.
var rsi = layer.RSI ?? BaseRSI;
if (rsi == null || !rsi.TryGetState(layer.State, out var state))
{
state = GetFallbackState();
state = GetFallbackState(resourceCache);
}
return state;
@@ -1867,21 +1957,21 @@ namespace Robust.Client.GameObjects
}
public static IDirectionalTextureProvider? GetPrototypeIcon(EntityPrototype prototype, IResourceCache resourceCache)
public static IRsiStateLike GetPrototypeIcon(EntityPrototype prototype, IResourceCache resourceCache)
{
var icon = IconComponent.GetPrototypeIcon(prototype, resourceCache);
if (icon != null) return icon;
if (!prototype.Components.TryGetValue("Sprite", out var spriteNode))
if (!prototype.Components.ContainsKey("Sprite"))
{
return resourceCache.GetFallback<TextureResource>().Texture;
return GetFallbackState(resourceCache);
}
var dummy = new DummyIconEntity() {Prototype = prototype};
var dummy = new DummyIconEntity {Prototype = prototype};
var spriteComponent = dummy.AddComponent<SpriteComponent>();
dummy.Delete();
return spriteComponent?.Icon ?? resourceCache.GetFallback<TextureResource>().Texture;
return spriteComponent.Icon ?? GetFallbackState(resourceCache);
}
#region DummyIconEntity

View File

@@ -1,15 +1,13 @@
using System;
using System.Collections.Generic;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.UserInterface;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Players;
using Robust.Shared.Reflection;
using Robust.Shared.Serialization;
using IComponent = Robust.Shared.Interfaces.GameObjects.IComponent;
namespace Robust.Client.GameObjects.Components.UserInterface
namespace Robust.Client.GameObjects
{
public class ClientUserInterfaceComponent : SharedUserInterfaceComponent
{

View File

@@ -1,7 +1,6 @@
using Robust.Client.Interfaces.GameStates;
using Robust.Client.GameStates;
using Robust.Client.Player;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Utility;

View File

@@ -1,13 +1,12 @@
using Robust.Client.GameObjects.Components.Animations;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.GameObjects;
namespace Robust.Client.GameObjects.EntitySystems
namespace Robust.Client.GameObjects
{
internal sealed class AnimationPlayerSystem : EntitySystem
{
public override void FrameUpdate(float frameTime)
{
foreach (var animationPlayerComponent in EntityManager.ComponentManager.EntityQuery<AnimationPlayerComponent>())
foreach (var animationPlayerComponent in EntityManager.ComponentManager.EntityQuery<AnimationPlayerComponent>(true))
{
animationPlayerComponent.Update(frameTime);
}

View File

@@ -1,7 +1,7 @@
using System.Collections.Generic;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.GameObjects;
namespace Robust.Client.GameObjects.EntitySystems
namespace Robust.Client.GameObjects
{
internal sealed class AppearanceSystem : EntitySystem
{

View File

@@ -1,12 +1,12 @@
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.GameObjects;
namespace Robust.Client.GameObjects.EntitySystems
namespace Robust.Client.GameObjects
{
class AppearanceTestSystem : EntitySystem
{
public override void Update(float frameTime)
{
foreach (var appearanceTestComponent in EntityManager.ComponentManager.EntityQuery<AppearanceTestComponent>())
foreach (var appearanceTestComponent in EntityManager.ComponentManager.EntityQuery<AppearanceTestComponent>(true))
{
appearanceTestComponent.OnUpdate(frameTime);
}

View File

@@ -2,23 +2,18 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using Robust.Client.Audio;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Physics;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Utility;
namespace Robust.Client.GameObjects.EntitySystems
namespace Robust.Client.GameObjects
{
[UsedImplicitly]
public class AudioSystem : EntitySystem
@@ -56,12 +51,12 @@ namespace Robust.Client.GameObjects.EntitySystems
private void PlayAudioPositionalHandler(PlayAudioPositionalMessage ev)
{
var gridId = ev.Coordinates.GetGridId(_entityManager);
if (!_mapManager.GridExists(gridId))
var mapId = ev.Coordinates.GetMapId(_entityManager);
if (!_mapManager.MapExists(mapId))
{
Logger.Error(
$"Server tried to play sound on grid {gridId}, which does not exist. Ignoring.");
$"Server tried to play sound on map {mapId}, which does not exist. Ignoring.");
return;
}
@@ -111,13 +106,13 @@ namespace Robust.Client.GameObjects.EntitySystems
if (stream.TrackingCoordinates != null)
{
var coords = stream.TrackingCoordinates.Value;
if (_mapManager.GridExists(coords.GetGridId(_entityManager)))
if (_mapManager.MapExists(coords.GetMapId(_entityManager)))
{
mapPos = stream.TrackingCoordinates.Value.ToMap(_entityManager);
}
else
{
// Grid no longer exists, delete stream.
// Map no longer exists, delete stream.
StreamDone(stream);
continue;
}
@@ -356,4 +351,76 @@ namespace Robust.Client.GameObjects.EntitySystems
event Action PlaybackDone;
}
public static class AudioSystemExtensions
{
/// <summary>
/// Play an audio file following an entity.
/// </summary>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="entity">The entity "emitting" the audio.</param>
/// <param name="audioParams"></param>
/// <param name="audioSystem">A pre-fetched instance of <see cref="AudioSystem"/> to use, can be null.</param>
public static IPlayingAudioStream? Play(
this IEntity entity,
string filename,
AudioParams? audioParams,
AudioSystem? audioSystem = null)
{
audioSystem ??= EntitySystem.Get<AudioSystem>();
return audioSystem.Play(filename, entity, audioParams);
}
/// <summary>
/// Play an audio stream following an entity.
/// </summary>
/// <param name="stream">The audio stream to play.</param>
/// <param name="entity">The entity "emitting" the audio.</param>
/// <param name="audioParams"></param>
/// <param name="audioSystem">A pre-fetched instance of <see cref="AudioSystem"/> to use, can be null.</param>
public static IPlayingAudioStream? Play(
this IEntity entity,
AudioStream stream,
AudioParams? audioParams = null,
AudioSystem? audioSystem = null)
{
audioSystem ??= EntitySystem.Get<AudioSystem>();
return audioSystem.Play(stream, entity, audioParams);
}
/// <summary>
/// Play an audio file at a static position.
/// </summary>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="coordinates">The coordinates at which to play the audio.</param>
/// <param name="audioParams"></param>
/// <param name="audioSystem">A pre-fetched instance of <see cref="AudioSystem"/> to use, can be null.</param>
public static IPlayingAudioStream? Play(
this EntityCoordinates coordinates,
string filename,
AudioParams? audioParams = null,
AudioSystem? audioSystem = null)
{
audioSystem ??= EntitySystem.Get<AudioSystem>();
return audioSystem.Play(filename, coordinates, audioParams);
}
/// <summary>
/// Play an audio stream at a static position.
/// </summary>
/// <param name="stream">The audio stream to play.</param>
/// <param name="coordinates">The coordinates at which to play the audio.</param>
/// <param name="audioParams"></param>
/// <param name="audioSystem">A pre-fetched instance of <see cref="AudioSystem"/> to use, can be null.</param>
public static IPlayingAudioStream? Play(
this EntityCoordinates coordinates,
AudioStream stream,
AudioParams? audioParams = null,
AudioSystem? audioSystem = null)
{
audioSystem ??= EntitySystem.Get<AudioSystem>();
return audioSystem.Play(stream, coordinates, audioParams);
}
}
}

View File

@@ -3,15 +3,11 @@ using System.Linq;
using JetBrains.Annotations;
using Robust.Client.Physics;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
namespace Robust.Client.GameObjects.EntitySystems
namespace Robust.Client.GameObjects
{
// NOTE: this class handles both snap grid updates of occluders, as well as occluder tree updates (via its parent).
// This seems like it's doing somewhat double work because it already has an update queue for occluders but...

View File

@@ -1,9 +1,8 @@
using System.Collections.Generic;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
namespace Robust.Client.GameObjects.EntitySystems
namespace Robust.Client.GameObjects
{
public class ContainerSystem : EntitySystem
{

View File

@@ -1,25 +1,15 @@
using Robust.Client.Graphics;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.GameObjects.EntitySystemMessages;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using System;
using System.Collections.Generic;
using Robust.Client.Graphics.Overlays;
using Robust.Client.Graphics.Shaders;
using Robust.Client.Interfaces.Graphics.Overlays;
using Robust.Client.Player;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Log;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Robust.Client.GameObjects
@@ -57,47 +47,54 @@ namespace Robust.Client.GameObjects
public void CreateEffect(EffectSystemMessage message)
{
// The source of effects is either local actions during FirstTimePredicted, or the network at LastServerTick
// When replaying predicted input, don't spam effects.
if(gameTiming.InPrediction && !gameTiming.IsFirstTimePredicted)
return;
if (message.AttachedEntityUid != null && message.Coordinates != default)
{
Logger.Warning("Set both an AttachedEntityUid and EntityCoordinates on an EffectSystemMessage for sprite {0} which is not supported!", message.EffectSprite);
}
var gameTime = gameTiming.CurTime;
if (gameTime > message.DeathTime) //Did we already die in transit? That's pretty troubling isn't it
if (message.LifeTime <= TimeSpan.Zero)
{
Logger.Warning("Effect using sprite {0} died in transit to the client", message.EffectSprite);
Logger.Warning("Effect using sprite {0} had zero lifetime.", message.EffectSprite);
return;
}
//Create effect from creation message
var effect = new Effect(message, resourceCache, _mapManager, _entityManager);
effect.Deathtime = gameTiming.CurTime + message.LifeTime;
if (effect.AttachedEntityUid != null)
{
effect.AttachedEntity = _entityManager.GetEntity(effect.AttachedEntityUid.Value);
}
//Age the effect through a single update to the previous update tick of the effect system
//effect.Update((float)((lasttimeprocessed - effect.Age).TotalSeconds));
_Effects.Add(effect);
}
public override void FrameUpdate(float frameTime)
{
var curTime = gameTiming.CurTime;
for (int i = 0; i < _Effects.Count; i++)
{
var effect = _Effects[i];
//Update variables of the effect via its deltas
effect.Update(frameTime);
//These effects have died
if (effect.Age > effect.Deathtime)
// Effects are purely visual, so they don't need to be ran through prediction.
// once CurTime ever passes DeathTime (clients render the top at IsFirstTimePredicted, where this happens) just remove them.
if (curTime > effect.Deathtime)
{
//Remove from the effects list and decrement the iterator
_Effects.Remove(effect);
i--;
}
else
{
//Update variables of the effect via its deltas
effect.Update(frameTime);
}
}
}
@@ -205,14 +202,9 @@ namespace Robust.Client.GameObjects
public bool Shaded = true;
/// <summary>
/// Effect's age -- from 0f
/// CurTime after which the effect will "die"
/// </summary>
public TimeSpan Age = TimeSpan.Zero;
/// <summary>
/// Time after which the effect will "die"
/// </summary>
public TimeSpan Deathtime = TimeSpan.FromSeconds(1);
public TimeSpan Deathtime;
private readonly IMapManager _mapManager;
private readonly IEntityManager _entityManager;
@@ -245,8 +237,6 @@ namespace Robust.Client.GameObjects
RadialAcceleration = effectcreation.RadialAcceleration;
TangentialVelocity = effectcreation.TangentialVelocity;
TangentialAcceleration = effectcreation.TangentialAcceleration;
Age = effectcreation.Born;
Deathtime = effectcreation.DeathTime;
Rotation = effectcreation.Rotation;
RotationRate = effectcreation.RotationRate;
Size = effectcreation.Size;
@@ -260,10 +250,6 @@ namespace Robust.Client.GameObjects
public void Update(float frameTime)
{
Age += TimeSpan.FromSeconds(frameTime);
if (Age >= Deathtime)
return;
Velocity += Acceleration * frameTime;
RadialVelocity += RadialAcceleration * frameTime;
TangentialVelocity += TangentialAcceleration * frameTime;

View File

@@ -1,8 +1,8 @@
using System;
using JetBrains.Annotations;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Graphics;
using Robust.Client.Physics;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.GameObjects;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.IoC;
@@ -10,7 +10,7 @@ using Robust.Shared.Maths;
#nullable enable
namespace Robust.Client.GameObjects.EntitySystems
namespace Robust.Client.GameObjects
{
/// <summary>
/// Updates the position of every Eye every frame, so that the camera follows the player around.
@@ -87,7 +87,7 @@ namespace Robust.Client.GameObjects.EntitySystems
}
}
foreach (var eyeComponent in EntityManager.ComponentManager.EntityQuery<EyeComponent>())
foreach (var eyeComponent in EntityManager.ComponentManager.EntityQuery<EyeComponent>(true))
{
eyeComponent.UpdateEyePosition();
}

View File

@@ -1,19 +1,15 @@
using System;
using Robust.Client.GameObjects.Components;
using Robust.Client.Interfaces.GameStates;
using Robust.Client.Interfaces.Input;
using Robust.Client.GameStates;
using Robust.Client.Input;
using Robust.Client.Player;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Players;
using Robust.Shared.Utility;
namespace Robust.Client.GameObjects.EntitySystems
namespace Robust.Client.GameObjects
{
/// <summary>
/// Client-side processing of all input commands through the simulation.
@@ -44,7 +40,7 @@ namespace Robust.Client.GameObjects.EntitySystems
/// <param name="message">Arguments for this event.</param>
/// <param name="replay">if true, current cmd state will not be checked or updated - use this for "replaying" an
/// old input that was saved or buffered until further processing could be done</param>
public bool HandleInputCommand(ICommonSession session, BoundKeyFunction function, FullInputCmdMessage message, bool replay = false)
public bool HandleInputCommand(ICommonSession? session, BoundKeyFunction function, FullInputCmdMessage message, bool replay = false)
{
#if DEBUG
@@ -128,7 +124,8 @@ namespace Robust.Client.GameObjects.EntitySystems
if (!entity.TryGetComponent(out InputComponent? inputComp))
{
Logger.DebugS("input.context", $"AttachedEnt has no InputComponent: entId={entity.Uid}, entProto={entity.Prototype}");
Logger.DebugS("input.context", $"AttachedEnt has no InputComponent: entId={entity.Uid}, entProto={entity.Prototype}. Setting default \"{InputContextContainer.DefaultContextName}\" context...");
inputMan.Contexts.SetActiveContext(InputContextContainer.DefaultContextName);
return;
}
@@ -138,7 +135,8 @@ namespace Robust.Client.GameObjects.EntitySystems
}
else
{
Logger.ErrorS("input.context", $"Unknown context: entId={entity.Uid}, entProto={entity.Prototype}, context={inputComp.ContextName}");
Logger.ErrorS("input.context", $"Unknown context: entId={entity.Uid}, entProto={entity.Prototype}, context={inputComp.ContextName}. . Setting default \"{InputContextContainer.DefaultContextName}\" context...");
inputMan.Contexts.SetActiveContext(InputContextContainer.DefaultContextName);
}
}

View File

@@ -1,8 +1,8 @@
using Robust.Client.Audio.Midi;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
namespace Robust.Client.GameObjects.EntitySystems
namespace Robust.Client.GameObjects
{
public class MidiSystem : EntitySystem
{

View File

@@ -1,16 +1,13 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using Robust.Client.Physics;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.GameObjects.EntitySystemMessages;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
namespace Robust.Client.GameObjects.EntitySystems
namespace Robust.Client.GameObjects
{
/// <summary>
/// Keeps track of <see cref="DynamicTree{T}"/>s for various rendering-related components.

View File

@@ -1,10 +1,10 @@
using JetBrains.Annotations;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Shared.GameObjects.Systems;
using Robust.Client.Graphics;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
namespace Robust.Client.GameObjects.EntitySystems
namespace Robust.Client.GameObjects
{
/// <summary>
/// Updates the layer animation for every visible sprite.

View File

@@ -1,16 +1,14 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.GameObjects.EntitySystemMessages;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
namespace Robust.Client.GameObjects.EntitySystems
namespace Robust.Client.GameObjects
{
/// <summary>
/// Handles interpolation of transform positions.

View File

@@ -1,8 +1,7 @@
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using System.Collections.Generic;
using System.Collections.Generic;
using Robust.Shared.GameObjects;
namespace Robust.Client.Interfaces.GameObjects
namespace Robust.Client.GameObjects
{
public interface IClientEntityManager : IEntityManager
{

View File

@@ -1,23 +1,19 @@
using System;
using System;
using System.Collections.Generic;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Client.Interfaces;
using Robust.Client.Interfaces.GameObjects;
using Robust.Client.Interfaces.GameStates;
using Robust.Client.Interfaces.Input;
using System.Diagnostics;
using Robust.Client.GameObjects;
using Robust.Client.Input;
using Robust.Shared.GameStates;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Network.Messages;
using Robust.Client.Player;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.Input;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -41,7 +37,7 @@ namespace Robust.Client.GameStates
[Dependency] private readonly IBaseClient _client = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IConfigurationManager _config = default!;
[Dependency] private readonly INetConfigurationManager _config = default!;
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
[Dependency] private readonly IComponentManager _componentManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
@@ -57,7 +53,8 @@ namespace Robust.Client.GameStates
public bool Predicting { get; private set; }
public int PredictSize { get; private set; }
public int PredictTickBias { get; private set; }
public float PredictLagBias { get; private set; }
public int StateBufferMergeThreshold { get; private set; }
@@ -82,14 +79,16 @@ namespace Robust.Client.GameStates
_config.OnValueChanged(CVars.NetInterpRatio, i => _processor.InterpRatio = i, true);
_config.OnValueChanged(CVars.NetLogging, b => _processor.Logging = b, true);
_config.OnValueChanged(CVars.NetPredict, b => Predicting = b, true);
_config.OnValueChanged(CVars.NetPredictSize, i => PredictSize = i, true);
_config.OnValueChanged(CVars.NetPredictTickBias, i => PredictTickBias = i, true);
_config.OnValueChanged(CVars.NetPredictLagBias, i => PredictLagBias = i, true);
_config.OnValueChanged(CVars.NetStateBufMergeThreshold, i => StateBufferMergeThreshold = i, true);
_processor.Interpolation = _config.GetCVar(CVars.NetInterp);
_processor.InterpRatio = _config.GetCVar(CVars.NetInterpRatio);
_processor.Logging = _config.GetCVar(CVars.NetLogging);
Predicting = _config.GetCVar(CVars.NetPredict);
PredictSize = _config.GetCVar(CVars.NetPredictSize);
PredictTickBias = _config.GetCVar(CVars.NetPredictTickBias);
PredictLagBias = _config.GetCVar(CVars.NetPredictLagBias);
}
/// <inheritdoc />
@@ -174,7 +173,7 @@ namespace Robust.Client.GameStates
var i = 0;
for (; i < applyCount; i++)
{
_timing.CurTick = _lastProcessedTick + 1;
_timing.LastRealTick = _timing.CurTick = _lastProcessedTick + 1;
// TODO: We could theoretically communicate with the GameStateProcessor better here.
// Since game states are sliding windows, it is possible that we need less than applyCount applies here.
@@ -256,9 +255,9 @@ namespace Robust.Client.GameStates
var hasPendingInput = pendingInputEnumerator.MoveNext();
var hasPendingMessage = pendingMessagesEnumerator.MoveNext();
var ping = _network.ServerChannel!.Ping / 1000f; // seconds.
var ping = _network.ServerChannel!.Ping / 1000f + PredictLagBias; // seconds.
var targetTick = _timing.CurTick.Value + _processor.TargetBufferSize +
(int) Math.Ceiling(_timing.TickRate * ping) + PredictSize;
(int) Math.Ceiling(_timing.TickRate * ping) + PredictTickBias;
// Logger.DebugS("net.predict", $"Predicting from {_lastProcessedTick} to {targetTick}");
@@ -354,7 +353,10 @@ namespace Robust.Client.GameStates
foreach (var component in _componentManager.GetNetComponents(createdEntity))
{
var state = component.GetComponentState();
Debug.Assert(_players.LocalPlayer != null, "_players.LocalPlayer != null");
var player = _players.LocalPlayer.Session;
var state = component.GetComponentState(player);
if (state.GetType() == typeof(ComponentState))
{
@@ -377,6 +379,7 @@ namespace Robust.Client.GameStates
private List<EntityUid> ApplyGameState(GameState curState, GameState? nextState)
{
_config.TickProcessMessages();
_mapManager.ApplyGameStatePre(curState.MapData);
var createdEntities = _entities.ApplyEntityStates(curState.EntityStates, curState.EntityDeletions,
nextState?.EntityStates);

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