Compare commits

..

791 Commits

Author SHA1 Message Date
PJB3005
93c887eec5 Version: 261.2.3 2025-09-26 13:40:43 +02:00
PJB3005
45a2895e4b Validate that content assemblies have a limited list of names.
Also, only read assemblies once from disk

(cherry picked from commit 443a8dfca65be7d60c4bd46181b4c749b4756114)
2025-09-26 13:40:43 +02:00
PJB3005
7d6def6adf Version: 261.2.2 2025-09-19 09:17:27 +02:00
Skye
f733a9efa5 Fix resource loading on non-Windows platforms (#6201)
(cherry picked from commit 51bbc5dc45)
2025-09-19 09:17:27 +02:00
PJB3005
8a68dce987 Version: 261.2.1 2025-09-14 14:55:51 +02:00
PJB3005
b8d840437e Squashed commit of the following:
commit d4f265c314
Author: PJB3005 <pieterjan.briers+git@gmail.com>
Date:   Sun Sep 14 14:32:44 2025 +0200

    Fix incorrect path combine in DirLoader and WritableDirProvider

    This (and the other couple past commits) reported by Elelzedel.

commit 7654d38612
Author: PJB3005 <pieterjan.briers+git@gmail.com>
Date:   Sat Sep 13 22:50:51 2025 +0200

    Move CEF cache out of data directory

    Don't want content messing with this...

commit cdcc255123
Author: PJB3005 <pieterjan.briers+git@gmail.com>
Date:   Sat Sep 13 19:11:16 2025 +0200

    Make Robust.Client.WebView.Cef.Program internal.

commit 2f56a6a110
Author: PJB3005 <pieterjan.briers+git@gmail.com>
Date:   Sat Sep 13 19:10:46 2025 +0200

    Update SpaceWizards.NFluidSynth to 0.2.2

commit 16fc48cef2
Author: PJB3005 <pieterjan.briers+git@gmail.com>
Date:   Sat Sep 13 19:09:43 2025 +0200

    Hide IWritableDirProvider.RootDir on client

    This shouldn't be exposed.

(cherry picked from commit 2f07159336bc640e41fbbccfdec4133a68c13bdb)
(cherry picked from commit d6c3212c74373ed2420cc4be2cf10fcd899c2106)
(cherry picked from commit bfa70d7e2ca6758901b680547fcfa9b24e0610b7)
(cherry picked from commit 06e52f5d58efc1491915822c2650f922673c82c6)
2025-09-14 14:55:51 +02:00
metalgearsloth
2b8057acf0 Version: 261.2.0 2025-06-05 22:55:09 +10:00
Tayrtahn
bec3caa5da Fix error when using tpto on a grid (#5991)
* Fix error when using tpto on a grid

* Calculate map coords outside of loop
2025-06-05 22:45:30 +10:00
metalgearsloth
ea6126563b Add NearestChunkEnumerator (#5972)
Not super fast but want it for biome loading to prio chunks nearby first.
2025-06-05 22:36:22 +10:00
slarticodefast
00494ad9eb fix TryQueueDelete (#5996) 2025-06-05 22:34:50 +10:00
Tayrtahn
6672b7b1bd Correct misleading error message in ShareMapSystem.OnParentChange (#5992) 2025-06-05 22:29:47 +10:00
ruddygreat
8dc55e8748 fix the lifestage checks on predicted entity deletion (#5993)
Co-authored-by: Ruddygreat <ruddygreat1@gmail.com>
2025-06-05 22:29:22 +10:00
Tayrtahn
44ea2cd396 Implement IEquatable for ResolvedPathSpecifier and ResolvedCollectionSpecifier (#5980) 2025-06-01 18:10:55 +10:00
metalgearsloth
2c5604432b Update some GetComponentName usages (#5942)
Rider tells me to use generic and generic one seems better.
2025-06-01 17:54:43 +10:00
Tayrtahn
c696466522 Remove ITileDefinition.ID (#5982) 2025-06-01 17:51:59 +10:00
slarticodefast
01bb98e400 fix static grid center of mass (#5985) 2025-05-29 23:05:54 +10:00
metalgearsloth
af08e747de Defer grid state handling TileChangedEvent (#5981)
Rather than doing the old raise-event-per-tile we just raise it at the end.
2025-05-29 09:21:45 +10:00
metalgearsloth
8c35c2c380 Version: 261.1.0 2025-05-29 00:15:26 +10:00
Tayrtahn
6d46d3f4a5 Cleanup most warnings in unit tests (#5946)
* 2 warnings in JointDeletion_Test

* 1 warning in Collision_Test

* 2 warnings in Color_Test (deleted test of deprecated HCY color space)

* 1 warning in MapVelocity_Test

* 2 warnings in MapManager_Tests

* 2 warnings in MapPauseTests

* 1 warning in NetDisconnectMessageTest

* 1 warning in ContainerTests

* Suppress 1 warning in EntityEventBusTests.ComponentEvent

* 4 warnings in MapGridMap_Tests

* 1 warning in GridDeletion_Test

* Remove TryGetContainingContainer foolishness

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2025-05-29 00:12:58 +10:00
Tayrtahn
50e06e43fa Automatic Sawmill generation for UIControllers (#5967) 2025-05-29 00:06:55 +10:00
metalgearsloth
986b0f979d Fix physics forces not autoclearing (#5978)
* Fix physics forces not autoclearing

* Changes
2025-05-29 00:04:55 +10:00
metalgearsloth
a51d786dee Version: 261.0.0 2025-05-28 19:34:47 +10:00
metalgearsloth
5f5fed5d6c Update contact xform usage (#5977)
Forgot this one as well.
2025-05-28 19:30:50 +10:00
Tayrtahn
e475cc7898 Cleanup warning in SpriteBoundsOverlay (#5944)
* Cleanup warning in SpriteBoundsOverlay

* Make better use of the primary constructor
2025-05-28 19:28:53 +10:00
metalgearsloth
ee8ea4ec3b Purge PhysicsMapComponent (#5766)
* Replace PhysicsMapComponent

- Dumb idea
- Lots of book-keeping and perf overhead.
- Much saner this way.

* stuff

* More work

* Purge

* Fixes

* Eh?

* Fixes

* Also this

* weh

* Fixes

* ice-cream

* Fix

* Fix stacking / gravity

* Gravity query

* MoveBuffer optimisations

* Fixes for test

* World gravity

* Fix build

* Avoid some transform resolves for contactless ents

* Less getcomps

* Fix contact caching

* Possibly less copies

* reh

* bulldoze

* Test "fix"

* seikrets

* a

* I saw this but now I decideded against it

* true
2025-05-28 19:18:36 +10:00
slarticodefast
7482451ec4 optimize ToMapCoordinates (#5953) 2025-05-28 12:07:23 +10:00
metalgearsloth
dddf5cd2fb Add entities to SpawnEntitiesAttachedTo (#5971)
* Add entities to SpawnEntitiesAttachedTo

Need it for biome stuff.

* factorio
2025-05-27 19:45:48 +10:00
metalgearsloth
01979c451d Make RaiseMoveEvent internal (#5918)
I don't think content should really be calling this tbh.
2025-05-27 19:45:04 +10:00
slarticodefast
181a5ef0b4 fix GetMapLinearVelocity (#5950)
* fix GetMapLinearVelocity

* resolve and adjust other methods
2025-05-27 19:41:43 +10:00
Princess Cheeseballs
e7c7011cc0 Init Commit (#5909) 2025-05-27 19:34:32 +10:00
metalgearsloth
dc97615fd4 Add some Box2i methods (#5969)
Equivalent to Box2.
2025-05-27 19:26:50 +10:00
metalgearsloth
3b4944376b Fix FastNoiseLite fractal bounding (#5970)
This shouldn't be datafielded because it gets set by other datafields.
2025-05-27 19:14:49 +10:00
Tayrtahn
fa6bd8f7ba Cleanup TypeSerializer Logger warnings (#5966) 2025-05-24 20:23:28 +02:00
Whatstone
2398cbcf26 GameController: init LocMgr before init broadcast (#5965) 2025-05-24 19:02:26 +02:00
Tayrtahn
38ce48a83f Cleanup 3 warnings in SharedContainerSystem (#5949)
* Cleanup 3 warnings in SharedContainerSystem

* Don't call Transform twice
2025-05-24 19:00:57 +02:00
PJB3005
4e7de2f272 File dialog fixes and improvements
File dialog requests can now specify the share and access mode they want out of the opened file. This means read-only access is now possible.

While doing this I noticed that the SDL3 backend had a memory leak *and* didn't match the behavior of the other backends. Cleaned up the code to avoid that.

In-engine commands that *can* specify read-only access on file open now do.
2025-05-24 16:38:01 +02:00
Cami
b61075c660 Stopped recursive updates for controls that are not visible, as it vi… (#5960)
* Stopped recursive updates for controls that are not visible, as it violates framerate in large menus.

* Update Robust.Client/UserInterface/Control.cs

---------

Co-authored-by: Cam <Nop>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2025-05-23 17:42:47 +02:00
Tayrtahn
7b571dc80e Fix 2 instances of warning CS0162 (#5951) 2025-05-23 17:37:08 +02:00
TemporalOroboros
f1c76ca899 Remove unused obsolete TryGetContainingContainer override (#5660)
* Remove unused obsolete TryGetContainingContainer override

* poke tests

---------

Co-authored-by: PJB3005 <pieterjan.briers+git@gmail.com>
2025-05-23 17:36:38 +02:00
metalgearsloth
84dcd658aa Version: 260.2.0 2025-05-21 23:30:58 +10:00
metalgearsloth
a634d6bd04 Add WorldNormal to StartCollideEvent (#5954)
We already have the value just a matter of adding it to the event.
2025-05-21 20:41:57 +10:00
DrSmugleaf
36f9df3079 Add System.Text.StringBuilder Insert(int, string) to sandbox.yml (#5955) 2025-05-21 11:20:10 +02:00
keronshb
824c018a69 Version: 260.1.0 2025-05-19 13:11:32 -04:00
Tayrtahn
4b6b688c72 Cleanup warnings in PlacementManager (#5939) 2025-05-18 19:14:16 +10:00
Tayrtahn
71df25b251 Cleanup warning in Clyde.Sprite (#5940) 2025-05-18 18:51:27 +10:00
metalgearsloth
be14a3c249 Expose CompFactory to systems (#5941) 2025-05-18 00:56:09 -04:00
metalgearsloth
3c2a4d5c79 Version: 260.0.0 2025-05-18 03:07:24 +10:00
metalgearsloth
44180b3ee0 Fix / remove startcollidevent worldpoint (#5936)
Now it's worldpoints because it may not necessarily be 1 pointr and internally we fix the actual points themselves.
2025-05-18 03:03:12 +10:00
metalgearsloth
bb0e77e937 Add some EntProtoId overloads (#5938)
Need it for some content stuff didn't feel like doing the rest yet.
2025-05-17 18:28:12 +10:00
ArtisticRoomba
684b9bc852 Add new Vertical property to progress bars (#5932) 2025-05-17 18:27:44 +10:00
Tayrtahn
9f3db6693e Add SpriteSystem dependency to VisualizerSystem (#5935)
* Add protected SpriteSystem reference to VisualizerSystem

* Capital S
2025-05-17 13:26:40 +10:00
metalgearsloth
40d869948d Version: 259.0.0 2025-05-15 20:26:10 +10:00
Tayrtahn
5c97b15849 Mark Entity methods as readonly (#5919)
* Mark Entity methods as readonly

* Add to GenericEntityPrint

* No but really
2025-05-15 20:23:29 +10:00
Tayrtahn
3d8a9a41fa Combine TileChangedEvents in SetTiles (#5912)
* Combine TileChangedEvents in SetTiles

* Raise event after regenerating collision

* continue, not return

* No need for GetComponent

* Swap TileRef for Tile + Vector2i

* Estimate size of tileChanges
2025-05-15 20:22:05 +10:00
metalgearsloth
92fc8722da Version: 258.0.1 2025-05-15 19:28:25 +10:00
metalgearsloth
73f6555624 Fix static ent collision spawn (#5933)
* Fix static ent collision spawn

* Fix test

* cool
2025-05-15 19:11:20 +10:00
metalgearsloth
2ac7bc3ce4 Version: 258.0.0 2025-05-15 00:51:12 +10:00
Leon Friedrich
05cb4bb1c9 Make SpriteSystem.LayerMapReserve not throw (#5930)
* Make SpriteSystem.LayerMapReserve not throw

* fix SpriteComponent.Visible

* remove region
2025-05-14 23:23:51 +10:00
Leon Friedrich
a393efc87a Modify markup tag interfaces and fix some bugs (#5442)
* Modify markup tag interfaces

* Why are nullable structs like this.

* AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

* Avoid breaking changes

* Replace IMarkupTag with IMarkupTagHandler in engine

* Its a breaking change now I guess

* cleanup
2025-05-12 14:09:18 +10:00
Leon Friedrich
4d47cfa1a6 Minor respath improvements (#5876)
* Minor respath improvements

* Add helpers

* tweak helper

* Throw on more than 1 char

* comments

* No emoji separators
2025-05-12 13:04:40 +10:00
DrSmugleaf
2b1d755d9f Fix Container state handling not forcing inserts (#5916) 2025-05-11 22:45:31 +10:00
ElectroJr
db7de0a99f Version: 257.0.2 2025-05-11 23:47:14 +12:00
Leon Friedrich
47f18703af Fix unshaded sprite layers (#5924)
* Fix unshaded sprite layers

* update comment
2025-05-11 21:42:40 +10:00
Leon Friedrich
97c1548301 Add SpriteBoundsTest (#5922) 2025-05-11 15:30:14 +10:00
ElectroJr
cd97f1583f Version: 257.0.1 2025-05-11 13:56:27 +12:00
Leon Friedrich
5fbe25ec9d Fix sprite layer bounds (#5920) 2025-05-11 11:52:20 +10:00
metalgearsloth
516ee47b51 Version: 257.0.0 2025-05-10 22:12:35 +10:00
metalgearsloth
89be682e24 Don't raise wake events for terminating contacts (#5757) 2025-05-10 22:02:22 +10:00
metalgearsloth
6086076559 Avoid checking grid traversal for rotation events (#5778)
* Avoid checking grid traversal for rotation events

* Also this one
2025-05-10 22:01:43 +10:00
beck-thompson
5bd90c908a Optimization RSI preloading / atlas creation (#5817)
* First commit

* Fix multiatlas bug

* Use ValueList instead

* Add FFDH sorting for atlases

* Minor cleanup and value lists
2025-05-10 22:00:03 +10:00
Leon Friedrich
a3d0921cc9 Pause entities that leave PVS range (#5878)
* Pause entities that leave PVS range

* Fix merge

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2025-05-10 21:57:04 +10:00
Leon Friedrich
15d5b9aa02 Move parts of SpriteComponent to SpriteSystem (#5602)
* Partial sprite component ECS

* release notes

* tests

* Why

* SetSnapCardinals

* NoRotation

* DirectionOverride

* This is why I love distinct overrides that take in object

* LayerSetData

* ISerializationHooks continue to haunt me

* Relocate SetShader

* LayerSetSprite

* LayerSetTexture

* yipeeeee

* LayerSetRsi

* Remove GetFallbackState

* LayerSet Scale,Rotation,Color,Visible

* Fix LayerSetRsi

* LayerSetOffset

* LayerSetDirOffset

* Add overrides that take in a Layer

* LayerSetAnimationTime

* LayerSetRenderingStrategy

* Reduce Resolves, Add Layer.Index

* Access

* Try fix NREs

* Asserts

* LayerGetState

* Cleanup

* Merge helper partial classes

* partial rendering

* GetLayerDirectionCount

* Cache local bounds

* RenderLayer

* RefreshCachedState

* RoundToCardinalAngle

* Fix the pr

* Fix debug assert

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2025-05-10 21:56:53 +10:00
Leon Friedrich
d24854d94f Improve yaml validation errors for ignored prototypes (#5886)
* Improve yaml validation errors for ignored prototypes

* release notes

* Comments
2025-05-10 21:37:42 +10:00
Tayrtahn
b3cf427013 Catch NotYamlSerializable DataFields with analyzer (#5704)
* Catch NotYamlSerializable DataFields with analyzer

* Extract common defs into shared source
2025-05-10 21:36:33 +10:00
Leon Friedrich
c458abdc69 Move TestPair & PoolManager to engine (#5877)
* Engine pool manager

* Move documentation

* Move namespace

* Move TestMapData to engine

* Option to prevent loading test assembly

* release notes

* Rename to avoid conflicts
2025-05-10 21:35:28 +10:00
metalgearsloth
c76444a33f Version: 256.0.0 2025-05-10 13:40:38 +10:00
B_Kirill
4754661467 Cleanup warnings: CS0649 (#5891)
* Clean up

* Remove "struct UpdateTreesJob"

* Use #pragma

* Use #if DEBUG

* More #if DEBUG
2025-05-10 12:40:15 +10:00
B_Kirill
2a8b776ee9 Cleanup warnings: CS0414 (#5892)
* Clean up

* Use #pragma
2025-05-10 12:39:46 +10:00
SpaceManiac
7d8e5a5841 Fix linear lookup on a dictionary in PlacementManager (#5911) 2025-05-06 16:05:58 +02:00
Centronias
8e416e4519 Makes ItemList not run deselection callback on all list items (#5861)
* Makes ItemList not run deselection callback on all list items

even when they weren't selected

* I cannot be expected to do things intelligently at 2a

* Optimize local usage.

* I'm pretty sure the test failure isn't from ItemList

* switch to avoiding doing anything in the `Selected` setter if the value-to-set-to is the same as the current value.
2025-05-06 14:05:05 +02:00
SlamBamActionman
65f74943d3 Add support for rotated/mirrored tiles (#5652)
* Initial commit

* Add tile rotation/mirror perms

* Nicer UI for the rotation

* Review fixes (also seemed to have missed applying the serialization reading oops)

* One less byte, one less struct size!

* Pretty sure it goes here too

* Fix error
2025-05-05 23:13:31 +10:00
Errant
eb5ed12270 Serialize TimeSpan from text (#5865)
* timespanserializer cleanup

* string reading

* high speed, low drag

* unit tests

* Update Robust.Shared/Serialization/TypeSerializers/Implementations/TimespanSerializer.cs

---------

Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2025-05-05 00:57:01 +02:00
PJB3005
c43b7b16c0 Add CancellationTokenRegistration to sandbox 2025-05-05 00:45:05 +02:00
slarticodefast
aee03f0805 fix yaml hotreloading (#5907) 2025-05-04 04:33:37 +02:00
dffdff2423
cfd2b03248 Check audio file signatures instead of extensions (#5894)
* Check audio file signatures instead of extensions

Fixes #5789

Test audio files based on their magic bytes.

* Test for a seekable stream

* Remove Take and Skip linq
2025-05-04 04:33:01 +02:00
dffdff2423
8905a3fe14 Add documentation to the serializer interfaces and remove ITypeReaderWriter (#5897)
* Add documentation to the serializer interfaces

* Remove ITypeReaderWriter and fix the docs

* Fix spelling errors and incorrect docstrings
2025-05-04 04:03:17 +02:00
PJB3005
a878da5b80 Allow texture preload to be skipped for some textures
This is a far cry from a proper resource tracking system, but it's something to avoid a ton of otherwise-unused parallax textures being loaded at game start and consuming VRAM.
2025-05-04 02:24:57 +02:00
Leon Friedrich
806c23e034 Move EntityExt.AsNullable extension methods into the Entity struct (#5899)
* Move `EntityExt.AsNullable` extension methods into the Entity struct

* use constructor

* a
2025-05-04 01:24:23 +02:00
metalgearsloth
e80f5d13a1 Add Vector2i / bitmask conversions (#5901)
Content uses for a couple tile-based flags.
2025-05-04 01:23:04 +02:00
PJB3005
a6905151b6 Move PointLight component states to shared
Necessary so the client can calculate an initial state, which is necessary for prediction and replay seeking to work properly.

Fixes the nuke in SS14 not having its light turn off when going back in a replay.
2025-05-02 01:21:17 +02:00
PJB3005
e742f021fa Dev window tab to show all loaded textures 2025-04-30 15:50:39 +02:00
metalgearsloth
62b4714f1f Version: 255.1.0 2025-04-30 23:38:21 +10:00
Leon Friedrich
1d0404953f Add GridUidChangedEvent and MapUidChangedEvent (#5893)
* Add GridUidChangedEvent and MapUidChangedEvent

* cleanup

* Fix assert

* more fixes

* docs

* record struct

* Use implicit tuple constructor

* stinky review

---------

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2025-04-30 18:36:53 +10:00
Leon Friedrich
d0da13f895 Fix CompileRobustXamlTask for benchmarks (#5902)
* Fix benchmarks

* I love it when path separators are also escape chars
2025-04-30 13:16:28 +10:00
metalgearsloth
ff23f98b26 Document container events (#5904)
It's hard to discern what it's raised directed on and this makes it much easier.
2025-04-30 13:10:03 +10:00
Leon Friedrich
ccfef2a786 Fix PVS NRE (#5900) 2025-04-28 20:11:18 +10:00
B_Kirill
62ce9724fc Clean up (#5890) 2025-04-26 22:59:02 +10:00
Milon
3bbe0e7f44 ftl hot reloading (#5874)
* sloth is so going to kill me

* the voices in my head told me to do this

* Register ILocalizationManagerInternal on client

* Avoid breaking change

* Cleanup

* Release notes
2025-04-26 22:38:56 +10:00
chromiumboy
addd8b5bdd Initial commit (#5880) 2025-04-25 22:19:11 +10:00
ElectroJr
03f8d4d3e0 Version: 255.0.0 2025-04-25 17:32:45 +12:00
Leon Friedrich
728d541ca5 Remove assert in UserInterfaceManager.KeyBindDown (#5889) 2025-04-25 15:30:26 +10:00
Leon Friedrich
4cbce064b8 Fix grid fixtures using locale dependent ids (#5887) 2025-04-24 12:49:04 +02:00
IProduceWidgets
93bb7b1532 Sandbox whitelist for calendar stuff. (#5888) 2025-04-24 12:46:41 +02:00
Pieter-Jan Briers
3ba91d2ed0 Add cycle detection when setting MIDI renderer masters (#5879)
If these things ever get in a cycle (as they did in some SS14 replays),
it'll likely get the client stuck in an infinite loop. Avoid that.
2025-04-24 18:12:59 +10:00
Tayrtahn
8f9e0f6bab Fix warnings in PhysicsMap_Test (#5884) 2025-04-24 18:10:13 +10:00
Tayrtahn
3ed408de5d Fix warnings in Joints_Test (#5885) 2025-04-24 18:09:27 +10:00
DrSmugleaf
2f85408f8f Fix SharedPhysicsSystem.CollideContacts looping contacts that are in nullspace (#5881)
* Fix SharedJointSystem.CreateDistanceJoint taking in an int for minimumDistance instead of a float

* Fix SharedPhysicsSystem.CollideContacts looping contacts that are in nullspace
2025-04-22 22:50:56 +10:00
Leon Friedrich
f49b01b1b7 PredictedDeleteEntity fixes (#5873)
* PredictedDeleteEntity fixes

* release notes
2025-04-20 23:38:43 +10:00
Leon Friedrich
3ce764311d Make RobustIntegrationTest pool by default (#5872) 2025-04-20 17:53:55 +10:00
B_Kirill
adf0b6ae78 Fix CA2264 in Resource Manager (#5870) 2025-04-20 05:02:16 +02:00
metalgearsloth
04406311dc Use EntityQuery for map / grid calls (#5869)
Avoids the type lookup etc etc.
2025-04-20 12:59:06 +10:00
Kyle Tyo
ee45a608b9 Replace IsMap and IsGrid calls with HasComp (#5866) 2025-04-20 12:21:19 +10:00
metalgearsloth
077c91a54b Add autocomplete to scale command (#5864)
* Add autocomplete to scale command

* Also the scale

* this
2025-04-19 22:50:09 +10:00
metalgearsloth
2ac17009ee Deep-copy fixtures on client (#5863)
Fixes a LOTTA bugs
2025-04-19 19:31:36 +10:00
metalgearsloth
a73d1b6666 Update container log warning for pred spawns (#5860)
This was on the full branch I just forgot to pull it out. This is intended that they can go into containers.
2025-04-19 18:08:19 +10:00
metalgearsloth
e5d6f194be Add nullable PredictedDel overloads (#5859)
Forgor when I updated it to Entity<T>
2025-04-19 17:47:25 +10:00
Pieter-Jan Briers
72d893dec5 Add "obsolete inheritance" analyzer (#5858)
This allows us to make it obsolete to *inherit* from a class, and only that.

Intended so people stop inheriting UI controls for no good reason.

Fixes #5856
2025-04-19 17:29:17 +10:00
metalgearsloth
191d7ab81c Version: 254.1.0 2025-04-19 16:53:53 +10:00
metalgearsloth
65d2f2dd2f Entity spawn prediction v1 (#5841)
* Entity spawn prediction v1

Client can't properly interact with this but that requires additional work on top so we can cleanly split this.

* This

* delete fix

* cats
2025-04-19 16:50:41 +10:00
Dae
02b451db2a Add no derivatives licenses to rga validation (#5749) 2025-04-19 12:23:21 +10:00
Ed
d5d4584e11 Update Clyde.GridRendering.cs (#5852) 2025-04-19 00:01:16 +02:00
metalgearsloth
b146b1b82c Version: 254.0.0 2025-04-18 19:06:45 +10:00
Leon Friedrich
2f8f4f2f7a Make MappingDataNode use string keys (#5783)
* string keys

* obsoletions

* Fix ValueTupleSerializer

* Release notes

* fix release note conflict

* cleanup

* Fix yaml validator & tests

* cleanup release notes

* a

* enumerator allocations

* Also sequence enumerator alloc
2025-04-18 19:01:34 +10:00
Tayrtahn
7365a59bd9 Cleanup warnings in CollisionWake_Test (#5847) 2025-04-18 12:05:48 +10:00
Tayrtahn
37560f663b Add GetContainingContainers method to SharedContainerSystem (#5803)
* Add SharedContainerSystem.EnumerateContainingContainers

* More obvious name
2025-04-17 21:51:23 +10:00
TemporalOroboros
bd489e9218 A compilation of simple one-line fixes (#5661)
* Fix warnings in SharedJointSystem

* Fix reference to EC TransformComponent method
Replaces call to TransformComponent.GetMapUid with SharedTransformSystem.GetMap

* Fix obsolete calls in SharedPhysicsSystem.Contacts.cs
Fixes a couple calls to obsolete varients of SetAwake and an obsolete call to RegenerateContacts by converting them to their Entity<T> varients

* Fix obsolete call in SharedPhysicsSystem.Components.cs
Adds one set of parenthesis to convert a 'uid, comp, comp, comp' call to an 'Entity<T, T, T> call.

* Removes unused local var
Removes an unused list of broadphases that was being allocated in TryCollideRect

* One-line fixes in SharedPhysicsSystem.Islands.cs
Fixes all of the easy warnings regarding physics island processing, the rest require more complicated changes than a simple argument rearrangement

* Fix obsolete method call in SharedMapSystem

* Fix a few obsolete ToMap calls in EntityLookup.Queries

* Fix calls to obsolete EntityCoordinate methods in SharedMapSystem.Grids

* Fix calls to obsolete EntityCoordinate methods in SharedLookupSystem.ComponentQueries

* Fix a few obsolete method calls in entity spawning

* Fix obsolete method calls in MapLoaderSystem

* Fix obsolete method call in GridFixtureSystem

* Fix obsolete IsMapInitialized call in SaveMap command

* Fix obsolete MapPosition reference in Client.EyeSystem

* Fix obsolete EntitySystem.Get<TSystem> references in DebugLightTreeSystem

* Fix obsolete EntitySystem.Get<TSystem> reference in DebugEntityLookup command

* Fix obsolete method calls in SpriteBoundsOverlay
Slightly more complicated than the rest, but it's really just changing an unused dependency over to use SharedTransformSystem

* Remove unused IClyde references from controls
LineEdit and TextEdit never use their IClyde dependencies and it generates a warning so yeet

* Remove use of EntitySystem.Get from lightbb command

* Fix DebugDrawingSystem
Removes a bunch of unused private IEntityManager vars
Also removes an obsolete use of TransformComponent.GetWorldPositionRotation

* Removes duplicate position set when splitting grids
There's nothing saying why this is this way and the blame looks like it was an oversight when replacing a bit where they set position and then rotation
Please, oh Chesterton's Fence, spare me your wrath

* Fix obsolete method use in PlacementMode

* Fix obsolete method use in Placement Modes

* Removes unused local var in gamestate management

* Fix unreachable code warnings in gamestate management
Use #else sections to make sure they don't complain about being on the wrong side of a throw

* Fix obsolete ToMap use in EyeManager

* Make InputManager use a sawmill to log

* Fix obsolete ContainerManagerComponent method calls in ContainerSystem

* Make ClientPrototypeManager use a sawmill for logging

* poke tests

* Use LocalizedEntityCommands for SpriteBoundsOverlay toggle

* Use LocalizedEntityCommands for system toggles

---------

Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
2025-04-17 11:57:03 +10:00
metalgearsloth
33166e8866 Component lifecycle generics (#5844)
Non-breaking minor.
2025-04-16 21:46:14 +10:00
Leon Friedrich
ed16032280 Disable tile edges (#5842) 2025-04-16 21:25:31 +10:00
metalgearsloth
cf785c886b Mark GetCollidingEntities as obsolete (#5831)
Bad methods, entitylookup is better (it does everything for area queries) and anyone who wants contacts should be querying those directly.
2025-04-14 18:50:01 +10:00
metalgearsloth
6f28c396cf Version: 253.0.0 2025-04-14 14:12:32 +10:00
metalgearsloth
b631f408f2 ItemList optimisation (#5796)
- VV AddComponent window no longer takes 300ms every time you press a key.
- Significantly optimise ItemList internally.
2025-04-14 13:55:48 +10:00
Leon Friedrich
34f4cf9452 More map validator fixes (#5820) 2025-04-14 13:55:02 +10:00
B_Kirill
6a4e4cf3b4 Cleanup warnings: Commands (#5825) 2025-04-14 13:54:42 +10:00
metalgearsloth
8aefa5c53e Make TestPoint use generics (#5828) 2025-04-14 01:49:07 +10:00
DrSmugleaf
2cfc981aa3 Fix popup text overflowing the sides of the screen (#5788)
* Fix popup text overflowing the sides of the screen

* Fix not escaping text
2025-04-13 12:59:23 +02:00
Leon Friedrich
4987c324d9 Fix bad debug assert (#5826) 2025-04-13 20:50:46 +10:00
DrSmugleaf
5450ddd0ba Fix SharedJointSystem.CreateDistanceJoint taking in an int for minimumDistance instead of a float (#5824) 2025-04-13 16:22:22 +10:00
Tayrtahn
378a10678c Improve location reporting for non-writeable DataFields (#5715)
* Better location reporting for readonly DataField errors

* Better location reporting for readonly DataField property errors

* Use SyntaxKind instead of string for TryGetModifierLocation
2025-04-13 16:22:05 +10:00
Leon Friedrich
2e0735b92f Fix NRE in screen-space overlays (#5823)
* Fix pre-init screen-space overlays

* Debug asserts
2025-04-13 16:21:02 +10:00
Leon Friedrich
5756d15333 Make BoundUserInterfaceMessageAttempt broadcast again (#5821) 2025-04-12 18:22:13 +10:00
Leon Friedrich
b6f74b8dea Fix logMissing in EntitySystem.Resolve() (#5822) 2025-04-12 17:40:08 +10:00
Leon Friedrich
3800c5707e Add new SerializationManager.PushComposition overload (#5785) 2025-04-12 12:58:40 +10:00
Leon Friedrich
8f49785b4e Fix RemCompDeferred not always setting lifestage (#5786)
* Fix RemCompDeferred not setting lifestage

* spaelling
2025-04-12 12:57:11 +10:00
metalgearsloth
f274de0f10 Version: 252.0.0 2025-04-12 01:43:29 +10:00
Milon
e128338f9d hi (#5811) 2025-04-12 01:29:41 +10:00
metalgearsloth
588c46273e Version: 251.0.0 2025-04-10 20:53:09 +10:00
Whatstone
919de8ce0e SharedPhysicsSystem.Island: set position after velocity (#5801) 2025-04-09 01:10:17 +10:00
Errant
af27d2d872 equatable FormattedMessage, take 2 (#5780)
* improved Equals and getHashCode

* less jank
2025-04-08 16:50:08 +02:00
Tayrtahn
45bb8740a0 Add ForbidLiteralAttribute and analyzer (#5808)
* Add ForbidLiteral attribute, analyzer, and test

* Removed unused code

* Switch order of methods. It's better this way.
2025-04-08 16:39:38 +02:00
Tobias Berger
4a24539629 Don't implement GetMassData twice (#5816)
The removed body didn't calculate mass for circles
2025-04-09 00:14:45 +10:00
PJB3005
7536c4ec68 Log late MsgEntity again
Yay :)
2025-04-07 15:50:40 +02:00
metalgearsloth
9268c8629d Refactor TileEdgeOverlay (#5295)
* Refactor TileEdgeOverlay

* weh

* Updates

* exweh

* Stupid weh noises

* I am le stupid

* Add logging about tile atlas build time

Seems fine, but wanted to check.

* Don't over-allocate edge tile region array

* Add DirectionExtensions.AllDirections

* Clean up iteration in ClydeTileDefinitionManager

* Don't stackalloc large chunk edge buffers, other code cleanup.

* More release notes

---------

Co-authored-by: PJB3005 <pieterjan.briers+git@gmail.com>
2025-04-03 07:52:28 +02:00
PJB3005
0bc0cafe64 Show entity name in "physics shapeinfo" output 2025-04-03 02:59:09 +02:00
PJB3005
8891f3fa0a Make EntitySystem.Subscriptions.SubscribeLocalEvent not require EntityEventArgs
This means it can be used with struct events.
2025-04-03 02:58:20 +02:00
Tornado Tech
4f96c2d233 Added separate localization & clean up (#5227)
* Added separate localization & clean up

* Added new methods docs

* Added GetFoundCultures method

* Clean up code

* Removed some formating shit

* Do better CultureInfo comparison

* Oops

* Review

* Command fixes

---------

Co-authored-by: PJB3005 <pieterjan.briers+git@gmail.com>
2025-04-02 16:41:02 +02:00
PJB3005
ab55d5b2f2 Revert "Add Loc property to LocalizedCommands"
This reverts commit 806c5b694b.
2025-04-02 05:23:43 +02:00
PJB3005
806c5b694b Add Loc property to LocalizedCommands
Avoids some ~300 usages of static Loc in SS14 and RT
2025-04-02 05:21:43 +02:00
metalgearsloth
6898053dbd Add autocomplete to tp command (#5795) 2025-04-02 03:48:16 +02:00
metalgearsloth
ae625ebad8 Inline manifold points (#5794)
* Inline manifold points

Max is 2 so no reason to use an array over a fixedarray.

* this
2025-04-02 00:04:51 +11:00
metalgearsloth
3c754a4f49 Don't disable contacting collisionwake ents (#5798)
Good for some content stuff I don't think it caused issues.
2025-04-01 15:04:05 +11:00
Tayrtahn
d84cb6327c Fix SharedTransformSystem methods erroring on failed Resolves (#5787)
* Don't error when GetGrid fails

* Fix other Resolves in SharedTransformSystem
2025-04-01 04:59:47 +11:00
Ciarán Walsh
4bfd92dbc5 Add button to jump to live chat when scrolled up (#5750)
* Add button to jump to live chat when scrolled up

* Expose scroll button class name as a public constant

* Add localisation string to engine

* Make enabling the OutputPanel scroll button opt-in

* Enable scroll button for the debug console

* De-duplicate visibility logic

* Update scroll button visibility when the enabling property is changed
2025-03-30 03:07:54 +02:00
metalgearsloth
c7d228c223 savemap / savegrid autocomplete (#5784)
How mappers coping without this.
2025-03-27 18:54:13 +11:00
Tayrtahn
f244c94905 Switch from checking comp.Owner == ent to GetComp(ent) == comp (#5776) 2025-03-27 15:21:05 +11:00
Tayrtahn
01cac6465b Cleanup warnings in EntityCoordinates_Tests (#5771)
* Fix warnings

* Use transform refs to simplify WithEntityId
2025-03-27 15:20:20 +11:00
metalgearsloth
5a5f238d9a Version: 250.0.0 2025-03-27 15:12:01 +11:00
Tayrtahn
089224cd44 Cleanup warnings in EntityLookup_Test (#5775)
* Replace MapManager.DeleteMap calls with MapSystem.DeleteMap

* Remove unused resolves
2025-03-27 15:07:05 +11:00
Tayrtahn
9f807f1ad2 Cleanup warnings in ClientGameStateManager (#5774)
* Fix unreachable code

* Remove unused variable
2025-03-27 15:06:37 +11:00
metalgearsloth
4be95ea375 Add OtherBody API to contacts (#5779)
* Add OtherBody API to contacts

Thought I had a pr for this.

* Update Robust.Shared/Physics/Dynamics/Contacts/Contact.cs

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2025-03-27 15:06:04 +11:00
Jerry
03010bf4be Fix DirectoryNotFoundException when saving map or grid on Unix systems (#5773)
* fix(maploader): Fix DirectoryNotFoundException

Someone forgor to create directory before saving map or grid, this caused
an exception on trying to save smth anywhere else than /

* update release notes
2025-03-27 13:56:26 +11:00
Tayrtahn
dacaa974d4 Replace MapManager.DeleteMap with SharedMapSystem.DeleteMap in misc tests (#5777)
* Replace MapManager.DeleteMap with SharedMapSystem.DeleteMap in various tests

* Poke tests

* I guess this is was technically a breaking change?
2025-03-27 13:50:56 +11:00
DrSmugleaf
9f73e0398a Make MappingDataNode.Equals take 2952 times less time to run when loading maps (#5781) 2025-03-27 12:52:29 +11:00
Tayrtahn
ccc383b1bf Cleanup: Remove redundant Prototype names (#5721)
* Cleanup: Remove redundant Prototype names

* Actually this one probably should stay

* Suppress warning

* Remove warning suppression on AudioMetadataPrototype

* But wait, there's more!
2025-03-26 01:39:10 +01:00
PJB3005
ceb59402a1 Make status and info APIs have CORS allow-origin: *
Allows it to be queried from browser JS. No harm in not allowing this.

Added helper function StatusExt.AddAllowOriginAny to make this easy to add.
2025-03-26 01:16:23 +01:00
Errant
5a6b29fcd2 equatable FormattedMessage (#5772) 2025-03-25 15:32:47 +01:00
PJB3005
6b87cd1e1c Deprecate HCY color space functions
These functions use the wrong color primaries (Rec 601 instead of 709) to calculate the luminance, so I'm just gonna throw them out.

Also, I don't actually trust anybody to know to do sRGB conversion before using them.

Discovered this as a result of reviewing #5360
2025-03-24 04:47:34 +01:00
Leon Friedrich
cf2d6a1dbf Make unshaded sprite layers not require shader/texture changes. (#5248)
* Make unshaded sprite layers not require shader/texture changes.

* Always sample texture

* revert some variable name changes

* Use color SIMD
2025-03-24 02:37:04 +01:00
chromiumboy
f8c838f425 Pass AnimationPlayerComponent in AnimationCompletionEvent (#5755)
* Added a field for the animation player component to the animation completion event

* Addressed review comment

* Updated
2025-03-24 02:22:46 +01:00
Tayrtahn
7405904041 Add entity description as tooltip on entity spawn panel (#5761) 2025-03-23 14:07:22 +01:00
metalgearsloth
2eeebab275 Add pure to some angle methods (#5763)
Saw some of these floating around in mover code.
2025-03-22 13:43:18 +01:00
PJB3005
2856bb3626 Shut up RS1038 warnings
We aren't going to fix these until #5610 is figured out, and these aren't even an indicator of an issue itself.

They indicate that we have code fixes in the same assembly as analyzers, meaning the analyzers COULD fail if we relied on some code fix libs - something we don't do.
2025-03-22 06:20:43 +01:00
PJB3005
be0189748b Fix serialization source gen with partial types
This fixes RMC compilation
2025-03-22 06:09:48 +01:00
Tayrtahn
4529a7569a Replace uses of ProtoId<EntityPrototype> with ProtoId<EntityCategoryPrototype> (#5762) 2025-03-21 04:08:12 +01:00
metalgearsloth
2b16e4db96 Version: 249.0.0 2025-03-21 00:52:45 +11:00
metalgearsloth
64f2245194 Add UpdateVisibilityMask method (#5745)
* Add UpdateVisibilityMask method

We tipped over to the point of systems stepping on each other's toes. Now we do the normal thing and just use the eventbus and it makes content a whole lot cleaner.

* Update resolve

* Update name in line with normal.

* Unserialize this

* weh
2025-03-21 00:47:40 +11:00
Milon
1029047e2f fix (#5752) 2025-03-20 22:30:59 +11:00
metalgearsloth
45dc9ad80e Inline polygon vertices (#5758)
* FastPoly

* Inline polygon vertices

No more pooling, pooling bad. No more arrays in engine, only span.

I made a slim version that's only the 4 verts so no padding on it compared to Polygon. Slightly more clamplicated code but entitylookup + mapmanager are both hotpaths and it's easy to do. Memory usage will likely go up for now but heap allocations should drop significantly due to removing the pooling.

* Unhide these

* Fixes

* More fixes

* More fixes

* Avoid potential bomb
2025-03-20 21:26:05 +11:00
metalgearsloth
54ad808eea Add GetWorldManifold overload (#5756)
* Add GetWorldManifold overload

* revert
2025-03-20 21:10:04 +11:00
metalgearsloth
37c75df6a2 Fix showvelocities (#5759)
* Fix showvelocities

Can't use StateRoot anymore so just pretend it's a window.

* Also file-scoped
2025-03-20 21:05:58 +11:00
slarticodefast
e93c1fae61 Add velocity and angular velocity debug overlays (#5693)
* add velocity and angular velocity debug overlays

* minor improvement

* add descriptions

* fix

* review

* Update RELEASE-NOTES.md

* Update RELEASE-NOTES.md

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2025-03-20 13:10:16 +11:00
metalgearsloth
cd0a35f542 Fix light Aabb query (#5744)
Forgot when this got dropped but we need it for grid-tree query as lights spill over grids.
2025-03-13 19:18:23 +11:00
PJB3005
80f2dc6dd3 Fix BoxContainer stretching causing controls to be made too small
In which I fix a bug by just deleting a ton of code and doing nothing else.

(also I added unit tests)
2025-03-13 01:01:18 +01:00
metalgearsloth
139b6f796c Version: 248.0.2 2025-03-12 20:26:50 +11:00
metalgearsloth
2ee7c35fd3 Don't throw on invalid MapUids for overlays (#5740) 2025-03-12 20:16:13 +11:00
metalgearsloth
56eae5ad08 Reduce EntityManager.IsDefault allocations (#5741)
* Reduce EntityManager.IsDefault allocations

We don't actually need the MappingDataNode so we can avoid allocating the entire class per entity.

* Adjust this order
2025-03-12 19:42:08 +11:00
DrSmugleaf
0662cae224 Version: 248.0.1 2025-03-11 19:38:08 -07:00
metalgearsloth
0e2b00edd0 Fix NaN gain audio (#5737) 2025-03-10 20:16:05 +11:00
Richard Van Tassel
d48f7ecb5b bumps ImageSharp version (#5733) 2025-03-08 15:19:23 +01:00
metalgearsloth
e064b7a4f9 Version: 248.0.0 2025-03-08 15:34:53 +11:00
metalgearsloth
654480862e Use Prototype for ITileDef (#5731)
Forgot to push this.
2025-03-08 15:20:25 +11:00
metalgearsloth
353c044b52 Hot reload resources (#5443)
* Fix ResPath CanonPath

Apparently this is supposed to standardise to / but this isn't always the case. Alternatively we could just assert for performance reasons I'm good with either. The comment as written says this should happen.

* Fixes

* change

* assert

* Fix bad respath input

* Buffer

* Merge conflicts

* review

* Fix
2025-03-08 15:16:31 +11:00
Whatstone
3dda8d9e93 Try/catch blocks around BUI open/dispose calls (#5730) 2025-03-08 15:16:11 +11:00
metalgearsloth
41ea10083d Fix ResPath CanonPath (#5452)
* Fix ResPath CanonPath

Apparently this is supposed to standardise to / but this isn't always the case. Alternatively we could just assert for performance reasons I'm good with either. The comment as written says this should happen.

* assert

* Fix bad respath input

* review
2025-03-08 15:02:46 +11:00
eoineoineoin
6290bb7af1 Adds method to Controls.ItemList which updates the item list without erasing contents (#5425)
* Add algorithm from ss14#30292 to ItemList, for use in other UIs

* Add overload for common case of comparing items by their text label
2025-03-08 14:43:43 +11:00
metalgearsloth
348ab70a8d Update B2DynamicTree (#5332)
* Update B2DynamicTree

* API updates

* weh

* forcing it

* Fix all of the bugs

* Rebuild

* A crumb of danger

* Fix merge conflicts
2025-03-08 14:15:47 +11:00
IProduceWidgets
47e11e988c Fix map netId completions (#5495)
* make map netId completions function.

* Update Robust.Shared/Console/CompletionHelper.cs

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2025-03-08 13:57:13 +11:00
Leon Friedrich
c459b55052 Add TryLoadGrid override (#5701)
* Add TryLoadGrid override

* fix cmd-addmap-help
2025-03-08 13:50:14 +11:00
Tayrtahn
f10e96a6d1 Clean up warnings in Stack_Test (#5705) 2025-03-08 13:49:52 +11:00
metalgearsloth
e8bac558c6 Use Entity<T> for TileChangedEvent (#5698)
Content is manually resolving this in a few spots so we can avoid that overhead.
2025-03-08 13:48:32 +11:00
metalgearsloth
ffa3bb7202 Fix savedpos caching on UI shutdown (#5729)
Don't need this as it gets handled already.
2025-03-08 13:28:29 +11:00
Dylan Craine
9bcdc95651 Fix deceptive "successfully saved" messages for mappers (#5714)
* Actually check if map save succeeded before displaying success message

It would be great to offer more clarity to the mapper about *why* the
save didn't succeed, but at least they won't be deceived into thinking
their work has been saved when it hasn't.

Portuguese localization text is via DuckDuckGo Translate, so I hope it's
reasonable.

* Actually check save success for saving grids

These messages need localization, too, but that seems out of scope for
my PR.

* Improve map save error message

Now it tells the mapper to go look at the server log.
Still translated via DuckDuckGo Translate.

* Normalize indentation and style
2025-03-08 13:27:59 +11:00
TemporalOroboros
543088ea1f Remove unused private members/local vars (#5722) 2025-03-05 15:50:54 +01:00
deltanedas
56daa63783 make map loading logs better (#5723)
Co-authored-by: deltanedas <@deltanedas:kde.org>
2025-03-05 15:49:20 +01:00
metalgearsloth
9fe9730d4a Add public API for physicshull (#5719) 2025-03-03 22:07:38 +11:00
SlamBamActionman
a1a7ea92d9 Add Regex.Count and StringBuilder.set_Chars to sandbox whitelist (#5717) 2025-03-01 22:42:19 +01:00
poklj
0dec6a425f Modify TryCopyComponents metadata TryGetComponent (#5710) 2025-02-27 11:25:28 +11:00
metalgearsloth
56ced913b7 Audio fixes (#5707) 2025-02-26 22:08:17 +11:00
PJB3005
76b46479b6 Version: 247.2.0 2025-02-23 01:44:44 +01:00
PJB3005
de9a8d286a Release notes 2025-02-23 01:43:58 +01:00
Milon
a1df0fb4af fix some issues with ClientDisconnect (#5625)
* fix

* actually fix for real this time

* just use HappyEyeballsHttp :godo:

* review
2025-02-23 01:33:58 +01:00
pathetic meowmeow
e6bc5a1057 Proxy scrollbar values and value targets in ScrollContainer (#5697) 2025-02-22 22:10:32 +01:00
beck-thompson
11b24579a2 Fix MultiRootInheritanceGraph not detecting circular inheritance (#5672)
* Fix

* This is better!

* Fixes
2025-02-22 22:08:31 +01:00
metalgearsloth
685d002bb7 Move VisibilitySystem to shared (#5694)
* Move VisibilitySystem to shared

* this

* Remove redundant qualifiers.

---------

Co-authored-by: PJB3005 <pieterjan.briers+git@gmail.com>
2025-02-22 21:36:49 +01:00
Tobias Berger
2e0d18aeaf Fix wrong parameters for Regex.Escape in Sandbox whitelist (#5688) 2025-02-22 18:08:28 +01:00
Kyle Tyo
06dbff0429 believe that should be all of em. (#5691) 2025-02-22 18:01:07 +01:00
Southbridge
15958a9447 Fix issue regarding Tilemaps not saving when modified (#5696)
* One line C# fix

* fixed typo

* after spending way too long trying to figure out the problem, turns out all we needed was a simple one line change
2025-02-22 17:33:33 +01:00
pathetic meowmeow
fd5a4d9b8a Refactor audio system to send collection IDs over the network (#5540)
This is important groundwork for future features such as captioning,
as a caption and other data can be associated with the collection
prototype instead of passing extra data everywhere with the sound.
2025-02-22 17:29:47 +01:00
DrSmugleaf
6d958847cb Fix prototype hot reloading crashing when adding a component that an existing entity already has (#5695) 2025-02-22 16:30:05 +01:00
Milon
8a04a4f3a5 Add a method for copying components (#5654)
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2025-02-21 09:46:13 +11:00
ElectroJr
7104a4f459 Version: 247.1.0 2025-02-20 16:26:04 +13:00
Leon Friedrich
f29949a32c Revert "Add ICloneable support to ComponentNetworkGenerator (#5656)" (#5687)
This reverts commit e14537074e.
2025-02-20 14:22:36 +11:00
Leon Friedrich
3bbbabf238 Update map format validator (#5686)
* Update map format validator

* string -> str
2025-02-20 12:11:12 +11:00
metalgearsloth
d95aca3d9e Fix DirtyFields proxy method (#5684) 2025-02-20 00:15:05 +11:00
Tayrtahn
e14537074e Add ICloneable support to ComponentNetworkGenerator (#5656) 2025-02-18 23:21:40 +11:00
DrSmugleaf
af2d01981f Add optional minimumDistance parameter to SharedJointSystem.CreateDistanceJoint (#5682) 2025-02-18 14:18:15 +11:00
Fildrance
7df23e047c feat: shaders now can accept array of Color as parameter (#5679)
* feat: shaders now can accept array of Color as parameter

* fix: Clyde.SetUniformDirect for Color[] doesn't mutate original array, removed invalid 'in' keyword on SetUniform

---------

Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
2025-02-16 14:13:04 +01:00
ElectroJr
5c7ab43049 Fix typo in RELEASE-NOTES.md 2025-02-17 00:15:27 +13:00
ElectroJr
8f75560ec4 Version: 247.0.0 2025-02-17 00:14:18 +13:00
Leon Friedrich
b323c8bd1e Add support for optional and params T[] toolshed command arguments. (#5573)
* Include argument name in completion suggestions

* Support optional args

* It (not so shrimply) works

* Add tests

* Add TestGenericPipeInference

* Fix tests

* Release notes

* Overzealous YAMLLinter

* Improve help signatures, fix map command

* Improve NoImplementationError

* Better type argument help signatures

* better pipe syntax

* fix NRE

* Add test

* a

* Fix silent toolshed failure

* Fix GetConcreteMethodInternal

* Improve vars command

* EntProtoId IAsType

* More GetConcreteMethodInternal fixes

* I hate this so much

* update tp command description

The command arguments call the the "other" entity the "target"

* Support localized argument hints/signatures
2025-02-16 21:55:05 +11:00
Leon Friedrich
faef44daaa Make PVS overrides respect vismasks (#5598)
* Make overrides respect vismasks

* Thread safety

* Release notes

* Use ExpandPvsEvent.Mask for other overrides

* check if already queued
2025-02-16 21:32:23 +11:00
Leon Friedrich
fbc706f37b Refactor map loading & saving (#5572)
* Refactor map loading & saving

* test fixes

* ISerializationManager tweaks

* Fix component composition

* Try fix entity deserialization component composition

* comments

* CL

* error preinit

* a

* cleanup

* error if version is too new

* Add AlwaysPushSerializationTest

* Add auto-inclusion test

* Better categorization

* Combine test components

* Save -> TrySave

Also better handling for saving multiple entities individually

* Create new partial class for map loading

* Add OrphanSerializationTest

* Include MapIds in BeforeSerializationEvent

* Addd LifetimeSerializationTest

* Add TestMixedLifetimeSerialization

* Add CategorizationTest

* explicitly serialize list of nullspace entities

* Add backwards compatibility test

* Version comments

also fixes wrong v4 format

* add MapMergeTest

* Add NetEntity support

* Optimize EntityDeserializer

Avoid unnecessary component deserialization

* fix assert & other bugs

* fucking containers strike again

* Fix deletion of pre-init entities

* fix release note merge conflict

* Update Robust.Shared/Map/MapManager.GridCollection.cs

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>

* VV

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2025-02-16 21:25:07 +11:00
metalgearsloth
9d1b15ab4b Version: 246.0.0 2025-02-16 19:32:42 +11:00
metalgearsloth
ea1cc5e446 Planet lighting pre-reqs (#5490)
* Add another lookup overload

* Fix RenderInRenderTarget

See the linked issue for what happens.

* Also this one

* stuff

* Fix stencilling

* fixes

* mix blend

* fix

* blur fixes

* Tile flag

* Minor tweak

* Fixes

* Render state fixes

* Fixes

* Fix stupidity

* More state render bug fixes

* MapUid on overlay draw

* Remove blur comment

* Fixes

* Fixes

* Remove

* Engine vibe
2025-02-16 19:29:32 +11:00
metalgearsloth
bcb5c2d35d Version: 245.1.0 2025-02-16 14:56:39 +11:00
metalgearsloth
c011eff80e Increase audio despawn buffer (#5665)
Apparently it can clip and the buffer is really just there so we despawn 'at some point' and rather than hunching over my debugger for potentially an hour this is easier and almost no impact.

I've also considered flagging some audio as "play the full thing" if someone misses the start of it but need to thonk on that one a bit in future.
2025-02-16 14:30:18 +11:00
Fildrance
e163c496c3 fix: fixed EntityPrototypeView not reacting on SetPrototype when EnteredTree already was called with _currentPrototype empty (#5649)
Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
2025-02-16 14:29:59 +11:00
Tayrtahn
fec81bc2a1 Add more info to AnchorEntity debug assert (#5668) 2025-02-16 03:16:23 +01:00
Leon Friedrich
7016facb9a Tweak UserInterfaceComponent shutdown to prevent bugs (#5678) 2025-02-14 18:16:24 +11:00
Simon
0c41a041e3 Move ParseObject method into a public class for content to use (#5674) 2025-02-14 14:21:22 +11:00
ElectroJr
55571ef5b1 Version: 245.0.0 2025-02-14 16:11:50 +13:00
Leon Friedrich
afaef645b0 Fix MappingDataNode.TryAddCopy() (#5677) 2025-02-14 14:10:13 +11:00
Milon
d442d90d60 no more (#5676) 2025-02-13 01:41:42 -05:00
metalgearsloth
fea592e1d5 Version: 244.0.0 2025-02-12 13:31:03 +11:00
metalgearsloth
bb9517fd19 Check equatable on client-predicted BUI states (#5671) 2025-02-12 13:29:19 +11:00
metalgearsloth
a734bc50fa Avoid unnecessary UpdateState calls for BUIs (#5670) 2025-02-12 12:50:33 +11:00
metalgearsloth
9e9ac56c95 Bump physics speed cap (#5667) 2025-02-11 20:54:21 +11:00
metalgearsloth
6979a63b1e Add CreateWindowCenteredRight method (#5666) 2025-02-11 15:02:31 +11:00
metalgearsloth
ae7725aafe Add compreg methods to entitymanager (#5655) 2025-02-10 21:39:41 +11:00
metalgearsloth
1a7e490e4b Version: 243.0.1 2025-02-08 19:06:50 +11:00
metalgearsloth
51971d0994 Revert basewindow change (#5664) 2025-02-08 17:38:40 +11:00
Mohamed Dwidar
d2aa8ecb5a Fixing guidebook not resizable from left and right (#5618)
* Fixing guidebook not resizable from left and right

issue 34504 in space-wizards/space-station-14 needs this fix

* update fix guideBood not resizable

a safer and more error resistent solution to https://github.com/space-wizards/space-station-14/issues/34504

* Mask DragMode.Move

---------

Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
2025-02-08 17:14:08 +11:00
ScarKy0
c4a5752c2a Shared portion of PvsOverrideSystem to allow for usage in shared (#5651) 2025-02-04 12:23:42 -05:00
metalgearsloth
6a336d236b Version: 243.0.0 2025-02-04 00:25:15 +11:00
metalgearsloth
fc55c8e0d3 Add saved BUI positions (#5650) 2025-02-04 00:19:22 +11:00
metalgearsloth
2719b9f0c8 Tweak grid state slightly (#5644) 2025-02-04 00:15:36 +11:00
metalgearsloth
bd69d51d36 Version: 242.0.1 2025-02-02 12:29:24 +11:00
metalgearsloth
1bf0687671 Fix poly pooling (#5645) 2025-02-01 15:19:34 +11:00
Leon Friedrich
bdef9e3401 Fix reloading prototypes with AlwaysPushInheritance (#5612) 2025-01-31 15:38:13 +11:00
metalgearsloth
43648201ce Drop debug allocs a lot (#5638)
IDK why the lifestage one in particular ballooned my dotmemory one up in particular but it did; I would've thought if it's boxing the other ones would've shown up. Doesn't matter for release just QOL to drop allocs by more than half.
2025-01-30 05:07:57 +01:00
slarticodefast
2b2d08ba47 don't normalize direction vector when calling atan2 (#5641) 2025-01-30 12:07:34 +11:00
metalgearsloth
d7f6a9ba43 Version: 242.0.0 2025-01-29 23:45:59 +11:00
metalgearsloth
15f81751f7 Reduce lookup allocs significantly (#5639) 2025-01-29 23:43:20 +11:00
metalgearsloth
033c52751a MergeImplicitData fix (#5640) 2025-01-29 23:36:14 +11:00
Leon Friedrich
51edceae4d Ensure parents are always initialized & started before children (#5595)
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2025-01-29 23:16:14 +11:00
ShadowCommander
5d7720755a Fix keyboard not focusing on search bar of the tile spawn window on open (#5630) 2025-01-29 22:48:59 +11:00
Leon Friedrich
acc7bf7595 Add support for overlays to draw controls (#5223)
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2025-01-29 22:48:11 +11:00
Fildrance
de55d1bc52 fix: EntityPrototypeView now only creates entities when the UI is open
Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2025-01-28 00:25:52 +11:00
metalgearsloth
d5e6e91b58 Make collisionwake resolve false (#5637) 2025-01-28 00:05:29 +11:00
metalgearsloth
da2bfdaa10 Version: 241.0.0 2025-01-27 21:31:31 +11:00
Leon Friedrich
af6cac14d6 Add CollisionPredictionTest (#5493)
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2025-01-27 21:23:23 +11:00
Leon Friedrich
3f37846731 Avoid unnecessary DirtyField() calls (#5620) 2025-01-27 21:21:53 +11:00
metalgearsloth
d9bf1d1afb BUI deferral tweaks (#5503) 2025-01-27 21:04:27 +11:00
metalgearsloth
b9b80192e7 Minor contact QOL (#5560) 2025-01-27 16:20:04 +11:00
DrSmugleaf
e03aec47ef Fix component network generator not working for dicts with entityuid values but not keys 2025-01-21 19:09:22 -08:00
DrSmugleaf
ee906af16e Version: 240.1.2 2025-01-21 18:43:28 -08:00
wixoa
e205ae3627 Use the color arg when drawing a font character in world space (#5626) 2025-01-21 22:39:07 +01:00
Jerry
d818c5aa0c fix StatusHost RespondJsonAsync method (#5622) 2025-01-21 16:58:37 +01:00
ElectroJr
aa8fe8ac92 Version: 240.1.1 2025-01-20 14:16:39 +13:00
Leon Friedrich
4ba6687b9d Fix OverlayManager.RemoveOverlay (#5623) 2025-01-20 12:14:58 +11:00
ElectroJr
8f2817aa4e Version: 240.1.0 2025-01-20 13:04:19 +13:00
Leon Friedrich
89c7839fe2 Fix exception in DestroyContacts (#5619) 2025-01-19 16:25:58 +11:00
DrSmugleaf
9799132001 Make GamePrototypeLoadManager send a single message with all uploaded prototypes in a single message (#5616) 2025-01-19 11:49:27 +11:00
Milon
34ffa56c57 add AsNullable() extension method to Entity<T> (#5617)
* just works first try

* use a constructor instead
2025-01-18 20:52:18 +01:00
ElectroJr
f8410a4674 Version: 240.0.1 2025-01-18 16:54:03 +13:00
Leon Friedrich
43b991c690 Fix SharedBroadphaseSystem.GetBroadphases (#5615) 2025-01-18 14:37:54 +11:00
PJB3005
c463fc5e78 Make source generators emit EditorBrowsable(Never)
This hides the generated types from intellisense if you have the relevant option in Rider enabled.

Good because honestly these just bloat IntelliSense, and if you want to show them there's an IDE setting for it.
2025-01-18 01:23:35 +01:00
PJB3005
e21b3e069a Version: 240.0.0 2025-01-17 17:57:31 +01:00
PJB3005
c8f94ab40d Update release notes 2025-01-17 17:57:14 +01:00
Tornado Tech
2a882b5555 Moved Overlay sorting to OverlayManager (#5614)
* Moved Overlay sorting to OverlayManager

* Changed Add to AddRange
2025-01-17 17:47:13 +01:00
Leon Friedrich
32d8a1cba9 Misc grid state changes (#5597) 2025-01-17 17:07:09 +01:00
Leon Friedrich
5d84be9c78 Make ComponentRegistry not implement ISerializationContext (#5613) 2025-01-17 15:01:25 +01:00
PJB3005
eaaa70437a Reduce DynamicMethod use in Serv3
Data definitions created individual read/write methods for every single field that can be serialized. This was extremely inefficient and likely caused lots of overhead.

These methods are necessary because, in some cases, we can't directly use expression trees to write fields. But... we can still do it most of the time! So now for most data fields we can avoid a DynamicMethod entirely.
2025-01-16 15:10:35 +01:00
Leon Friedrich
448e8b0c2c Validate static EntProtoId<T> fields (#5593) 2025-01-16 10:36:47 +01:00
Leon Friedrich
42948d8f8e Fix autocompletion hint for toolshed strings (#5584)
* Fix autocompletion hint for toolshed strings

* Split functionality

* Remove combined flag
2025-01-16 10:30:42 +01:00
c4llv07e
039468f4b6 Add function to check if localization culture was already loaded. (#5603) 2025-01-16 10:28:15 +01:00
Leon Friedrich
6a3f88b1c6 Fix replay playback bugs (#5604)
* Sort replay entities

* Fix nameof(TState)

* I forgot to generate implicit states

* release notes
2025-01-16 10:26:53 +01:00
PJB3005
a314c5f797 Tickrate is now a ushort
Fixes #5592

This allows net.tickrate to be set to a max of 65535 instead of 255.

I didn't raise it fully to a uint because there are many places it's cast to an int, so uint would cause various compiler errors and compat issues I don't wanna deal with.
2025-01-16 01:13:50 +01:00
PJB3005
bcc4cd77cf Version: 239.0.1 2025-01-15 20:16:05 +01:00
PJB3005
941cb4c1d6 Release notes 2025-01-15 20:15:21 +01:00
Myra
7b58760331 Downgrade VorbisPizza back to 1.3.0 (#5607)
Somewhere between 1.3.0 and 1.4.0 (I tested all versions) exists a bug that for some reason messes with the audio on some devices.

A proper fix would require us trying to make contact with the developer of VorbisPizza, find the buggy commit and waiting them to update their repo. This repo has been inactive for 8 months. I doubt we can get support unless we fork it and find the bug ourselves.

Closes & fixes #5605
2025-01-15 17:18:23 +01:00
PJB3005
f0306b593a Optimize Robust.Serialization.Generator
Slightly less bad use of incremental generators.

Remove format of generated code, it was taking most of the CPU time.

This seems to significantly cut compile time cost of this generator. Nice. I'm seeing 20 -> 5 seconds on my system.
2025-01-15 02:41:57 +01:00
PJB3005
5e1935c310 Optimize ByRefEventAnalyzer
According to a log, like 20 seconds of the build is spent in this analyzer. It now takes ~200ms. Hooray!
2025-01-13 05:52:31 +01:00
PJB3005
67c44a5fc5 Add unit test for ByRefEventAnalyzer 2025-01-13 05:44:35 +01:00
PJB3005
3ea0a0244b Fix net.packet RECV logging 2025-01-10 18:09:27 +01:00
PJB3005
325a39ee4b Wow way to expose that my lazy ass didn't actually try running package_webview.py on this build. 2025-01-09 04:22:25 +01:00
PJB3005
e4190f4f29 Version: 239.0.0 2025-01-09 01:45:49 +01:00
PJB3005
4d163ed818 Update release notes 2025-01-09 01:44:16 +01:00
ike709
09c6a816e0 Bump cefglue (#5585)
* Bump cefglue

* another bump

* Update build-test.yml

* Update to latest CEF natives and fix code to be compatible.

* Switch CEF CreateBrowserWindow to Alloy style

you will NOT open Chrome

* Update cefglue, again

---------

Co-authored-by: ike709 <ike709@github.com>
Co-authored-by: PJB3005 <pieterjan.briers+git@gmail.com>
2025-01-08 02:32:24 +01:00
Pieter-Jan Briers
dfc4894c8b Dependencies update & cleanup (#5590)
* Dependencies update & cleanup

Fixes security vuln warnings etc

* Remove ILReader dependency

RIP in piss FastAccessors.
2025-01-08 02:19:27 +01:00
PJB3005
f2b096f145 Fix SDL3 backend
.NET 9 update changed library import generator behavior and it broke my funny shit.
2025-01-08 01:39:56 +01:00
PJB3005
1984e97d2f Show "null" in loglevel command completions
This was already supported, but the completions didn't list it.
2025-01-07 21:33:37 +01:00
PJB3005
57291b88c0 Log received/sent net messages at verbose level
This has always been in the code but commented out for debugging. Now it's actually logging to Verbose level. Also the log level is "net.packet" now instead of just "net". Also it logs received size too.

This makes use of the new IsLogLevelEnabled to avoid the perf overhead when not being used.
2025-01-07 21:11:56 +01:00
PJB3005
f40dd51648 Add ISawmill.IsLogLevelEnabled
So you can avoid logging things unless somebody's actually trying to debug something.
2025-01-07 20:54:14 +01:00
Leon Friedrich
d08fdd3a18 Fix component delta state auto-generation (#5589)
* Fix component delta state auto-generation

* re-use ApplyToFullState

* release notes
2025-01-07 16:54:59 +01:00
Leon Friedrich
80dbf02af4 Log errors when encountering entity data fields (#5578)
* Log errors when encountering entity data fields

* Cleanup & comments

* Remove unnecessary GetGenericTypeDefinition
2025-01-07 16:54:25 +01:00
IProduceWidgets
a2983a5ee0 safe dictionary assignment (#5587) 2025-01-06 21:02:02 +01:00
PJB3005
7810cd0c2e Disable CETCompat in Robust.Client.WebView
Guess what doesn't work with CEF (not that it works in the first place for us)
2025-01-06 03:15:36 +01:00
PJB3005
6c8b863731 Add string split with ROS<char> to sandbox 2025-01-06 03:08:28 +01:00
ike709
c2ca7c7811 .NET 9 (#5552)
Co-authored-by: ike709 <ike709@github.com>
2025-01-06 01:16:01 +01:00
PJB3005
347d240fae Add API for creating mock configuration managers in unit tests. 2025-01-05 23:27:59 +01:00
Pieter-Jan Briers
87a5745519 SDL3 (#5583)
* Start converting SDL2 backend to SDL3.

Game starts, but a lot of stuff is broken. Oh well.

* Fix text input

SDL3 changed the API somewhat, for the better. Changes all over UI/Clyde/SDL3 layer.

* Fix mouse buttons being broken

* Remove records from SDL3 WSI

The fact that this shaved 2-3% off Robust.Client.dll is mindboggling. Records are so bad.

* Set Windows/X11 native window properties

* Fix window resize events getting wrong size

oops

* Remove "using static" from SDL3 WSI

Seriously seems to hurt IDE performance, oh well.

* Apparently I never called CheckThreadApartment().

* Add STAThreadAttribute to sandbox

Necessary for content start

* Set window title on creation properly.

* Load window icons

* Fix GLFW NoTitleBar style handling

Yeah this PR is supposed to be about SDL3, so what?

* Implement more window creation settings in SDL3

Mostly the ones that need a lot of platform-specific stuff to work.

* Make fullscreen work properly in SDL3.

* File dialogs with SDL3

Removes need for swnfd.

* Fix some TODOs

* Fix WebView build
2025-01-03 18:42:57 +01:00
ElectroJr
e47ba0faea Version: 238.0.1 2024-12-28 18:51:38 +13:00
Southbridge
fb705702fb PlacementManager CurrentEraserMouseCoordinates fix (#5576) 2024-12-28 16:48:26 +11:00
sleepyyapril
a2aec44ebb Fix Build Error with Auto-networked EntityUid Dictionaries (#5569) 2024-12-22 21:12:44 +11:00
ElectroJr
5e97db435c Version: 238.0.0 2024-12-21 19:51:56 +13:00
Leon Friedrich
9af119f57a Toolshed Rejig (#5455)
* Toolshed Rejig

* shorten hint string

* Try fix conflicts. Ill make with work later

* bodge

* Fix ProtoIdTypeParser assert

* comment

* AllEntities

* Remove more linq from WhereCommand

* better help strings

* Add ContainsCommand

* loc strings

* Add contains command description

* Add $self variable

* Errors for writing to readonly variables

* A
2024-12-21 17:49:11 +11:00
MLGTASTICa
6247be2c84 Changes SharedGridTraversalSystem accesibility from internal to public (#5551)
* Make this public.

* Add warnings.
2024-12-21 17:11:18 +11:00
metalgearsloth
acb1d37b99 Version: 237.4.0 2024-12-21 15:53:21 +11:00
metalgearsloth
82c94fc8b0 transform traversals (#5564) 2024-12-21 15:49:43 +11:00
metalgearsloth
9837c33de7 Add sourcegenned field deltas (#5155)
* Remove full "delta" states

* Update MapGridComponentState

* abstract ComponentState

* Release notes

* Fix tests

* Fix nullable errors

* A

* Sourcegen component deltas

* Audio deltas + methids

* Also eye

* Optimise out the dictionary

* Minor fixes

* Physics deltas

* Also this

* Fix field deltas

* remove old release notes

* Make IComponentDelta implement IComponent

* add sourcegen launch settings

* make silent error loud

* Review

* UI deltas

* Slimmer

* Sourcegen bandaid

---------

Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
2024-12-21 15:48:33 +11:00
MilenVolf
ac30ad1820 Replace all usages of obsolete MapGridComponent methods (#5547)
* Replace obsolete MapGridComponent methods

Some other obsolete methods were also replaced in edited files

* Whitespace and better readability

* Value instead of cast

* Fix ISawmill not initialized and incorrect log
2024-12-18 18:46:53 +01:00
metalgearsloth
9c30fdf5fd Version: 237.3.0 2024-12-16 16:33:24 +11:00
metalgearsloth
0b7e8c2560 Add shapecasts + raycasts (#5440)
* Add shapecasts + raycasts

Actual raycasts. Need this for AI LIDAR experiment.

* cassette

* more cudin

* Mostly ported

* more work

* More ports

* the big house

* rays

* builds

* Janky not working raycasts

* Fix GJK

* Test fixes

* Shapecast + fixes

* free

* tests

* More fixes

* Minor changes

* Not these

* Release notes
2024-12-16 16:07:24 +11:00
IProduceWidgets
7982aa236c TryFindComponentOnEntityContainerOrParent no fail please (#5322)
* TryFindComponentsOnEntityContainerOrParent no fail please

* remove my comments because Im dumb

* out makes sense to me!

* Revert "out makes sense to me!" because PJB no want breaky

This reverts commit 54f4a6d50c.
2024-12-14 17:16:43 +01:00
PJB3005
0559339143 Add AssetPassFilterDrop
Planning to use this to drop .svg files from SS14's resources folder. Tiny opt.
2024-12-14 17:07:57 +01:00
Zachary Higgs
89fcd1dd2b Add InterfaceData constructor (#5559)
* Add InterfaceData constructor

Add InterfaceData constructor to allow for dynamic UI assignment via
SharedUiSystem::setUi

* empty commit because of heisentest
2024-12-14 16:19:05 +01:00
metalgearsloth
649378e59a BUI helpers (#5558)
* BUI helpers

- Some virtual methods for BUI to make it slightly easier. Haven't though of a good way to do it via sourcegen yet.
- TryGetUiState which is occasionally useful.

* Also this one
2024-12-13 01:33:17 +01:00
SpaceManiac
0c7ace16d1 Fix most non-obsolete warnings (#5555) 2024-12-13 01:25:00 +01:00
metalgearsloth
27f7f5ee36 Add Pure attribute to some entmanager methods (#5557) 2024-12-12 18:24:20 +01:00
Pieter-Jan Briers
fe0fcbd851 Add RSI key to disable meta-atlas (#5544)
This allows huge textures (e.g. Ratvar) to be removed from the meta-atlas. This saves a significant chunk of VRAM from the meta atlas in SS14 (~126 MB) which might help a bit with low-VRAM systems.
2024-12-08 23:49:12 +01:00
Pieter-Jan Briers
aca7847933 Add CVars for privacy policy information (#5545)
* Add CVars for privacy policy information

Engine side of https://github.com/space-wizards/SS14.Launcher/issues/194

* Improve/fix cvar desc
2024-12-08 23:48:50 +01:00
Leon Friedrich
1621d25a92 Fix UserInterfaceSystem debug assert (#5546) 2024-11-30 13:09:51 +01:00
Amy
b7e0a9bc03 Make font drawing more generic (#5533)
* make richtextentry more generic

* font

* oops
2024-11-29 11:28:27 +01:00
metalgearsloth
9909416006 Fix grid container layout (#5543)
This decrements index and cooks the layout if controls are invisible.
2024-11-29 10:54:34 +01:00
Leon Friedrich
c3e487b61c Fix IPrototypeManager.TryGetKindFrom() (#5542) 2024-11-29 01:48:02 +01:00
Nikolai Korolev
89ad8b6c9f Upgrade GitHub actions in workflows (#5536)
* Upgrade github workflows to node20

* Fix incorrect version for actions/checkout in test-content.yml
2024-11-28 19:52:14 +01:00
Nikolai Korolev
efbc9ef2bf Fix codeql-analysis breaking in every fork repo that enables GitHub Actions (#5537) 2024-11-28 19:50:39 +01:00
Pieter-Jan Briers
ce240773e8 ValueList<T> extensions (#5534)
Stack-like functions. Just some code I had lying around and never committed.

Add ROS overload for AddRange
2024-11-28 19:49:51 +01:00
SpaceManiac
8563466011 Fix wrong filename used when log.enabled is set (#5541) 2024-11-28 19:46:53 +01:00
Nikolai Korolev
af4d53fb54 No need for disabling RA0003 warning in FastNoise (#5535) 2024-11-25 00:37:05 +01:00
Pieter-Jan Briers
3086fc446c Sandbox error reference locator now works with generic method calls
This means resolving the MethodSpec table entry for it.
2024-11-22 18:06:33 +01:00
Nikolai Korolev
5f3a54376d Fix warnings for using async without any await (#5532)
* Fix warnings for using async without any await

* Fix async without await warning in EntityTypeParser

* Fix async without await in EnumTypeParser

* Update SessionTypeParser.cs

* Update EntityTypeParser.cs

* Update BoolTypeParser.cs

* Update EntityTypeParser.cs

* Update EnumTypeParser.cs

* Update SessionTypeParser.cs

* Fix compilation and formatting
2024-11-22 02:18:35 +01:00
Nikolai Korolev
9bb7af364e Fix warning for using non-generic variant of TryComp for MetaDataComponent and TransformComponent RA0030 (#5531)
* Fix warning for using non-generic variant of TryComp for MetaDataComponent RA0030 (Use non-generic variant)

* Use non-generic variant of TryComp for TransformComponent
2024-11-22 01:30:55 +01:00
Pieter-Jan Briers
92b0e7f1a8 Version: 237.2.0 2024-11-21 00:03:19 +01:00
Pieter-Jan Briers
47d1c372b2 Mute null error from Rider 2024-11-20 23:45:47 +01:00
SpaceManiac
453f763128 Fix minor layout bugs in SplitContainer and BoxContainer (#5529)
* Fix SplitContainer using invalidated measures when clamping SplitCenter

* Fix BoxContainer adding separation for invisible children
2024-11-20 23:41:10 +01:00
Nikolai Korolev
65a7942d63 Remove unused variable, local function and private field (#5528)
* Remove unused local function

* Remove unused variable

* Remove private field
2024-11-20 02:51:46 +01:00
Saphire Lattice
f1f3c60d1f Improve Toolshed type intersection mechanism, add WithCommand for ProtoId (#5515) 2024-11-20 01:00:13 +01:00
SpaceManiac
d4e8a27c23 Add FormattedMessage.TrimEnd (#5524)
* Add FormattedMessage.TrimTrailingNewlines

* Trim all trailing whitespace
2024-11-19 19:55:19 +01:00
Pieter-Jan Briers
18a17da8fa .NET 9 forward compatibility changes
This doesn't switch the projects over to .NET 9, but it does make them work on .NET 9 when we decide to switch in the future.
2024-11-19 19:54:01 +01:00
Nikolai Korolev
90a8c66e96 Fix System.ArgumentException: '0' cannot be greater than -0.01 for very fast audios (#5521)
* Fix `System.ArgumentException: '0' cannot be greater than -0.01`

In case of playing empty audio files

* Add semicolon
2024-11-18 18:46:01 +01:00
MilenVolf
45c14b2bc3 Replace remaining obsolete TileAccess methods (#5519)
* Replace remaining TileAccess methods

* Small fix
2024-11-18 17:19:57 +01:00
SpaceManiac
d227613997 Fix cursor getting stuck when click-dragging off of a control (#5523) 2024-11-16 23:51:32 +01:00
Partmedia
7557cc703c Add FreeBSD packaging target (#5522) 2024-11-16 02:01:17 +01:00
Leon Friedrich
7b81d0d881 Make PVS ignore duplicate view subscriber (#5502) 2024-11-13 00:07:53 +01:00
Leon Friedrich
b59f7801ac More UniqueIndex fixes (#5501) 2024-11-12 23:40:01 +01:00
FluffMe
d724c5b3eb Add conditional formatting to SpinBox buttons text (#5511) 2024-11-12 23:32:14 +01:00
Saphire Lattice
f812dc4dac Hopefully fix the dreaded VV refresh blink (#5517) 2024-11-12 23:31:39 +01:00
MilenVolf
2a1bcb6f1e Replace some obsolete TileAccess methods (#5516)
* Replace some obsolete TileAccess methods

* Guh
2024-11-12 23:17:40 +01:00
slarticodefast
fa9030e59c correct sandbox whitelist for Regex.Matches Method (#5513) 2024-11-12 21:48:39 +01:00
Pieter-Jan Briers
8dcae8631b Update NetSerializer
This enables sending of ImmutableArray<T>
2024-11-11 21:36:41 +01:00
Pieter-Jan Briers
21c3535486 Avoid unhandled exception handlers logging into disposed sawmills on shutdown
This caused a crash & exception swallow on Salamander.
2024-11-11 16:26:04 +01:00
lzk
4e100d96bc Add dative case function to loc manager (#5510)
* dative

* slipped it

* slipped it twice
2024-11-05 19:55:30 +01:00
qrtDaniil
14d3699ae2 Fix for server consoles without width and length (#5507)
* Update SystemConsoleManager.cs

* Update SystemConsoleManager.cs
2024-11-01 23:39:30 +01:00
Amy
350fa8736d add ref readonly to sandbox (#5506) 2024-10-30 02:49:25 +01:00
eoineoineoin
5a82df216d Fixes for rendering in multiple windows (#5497)
* Fix race condition when swapping buffers of secondary windows

* Avoid creating opengl 3.3 windows, to avoid Steam overlay bug

* Revert "Avoid creating opengl 3.3 windows, to avoid Steam overlay bug"

This reverts commit 97b5e7f461.

* Add CVar to perform unlocking test
2024-10-19 16:13:29 +02:00
Pieter-Jan Briers
32bca7cfd4 Version: 237.1.0 2024-10-19 12:03:52 +02:00
wixoa
008babebc6 Fix some window UIScale bugs (#5499)
* Fix some window UIScale bugs

* Use CalculateAutoScale()
2024-10-19 00:08:16 +02:00
Pieter-Jan Briers
c65c4ba57e Made csi reflection helpers get members up the inheritance chain too 2024-10-18 18:40:39 +02:00
Pieter-Jan Briers
eb5b838e61 Made csi type auto-completion aware of generic types 2024-10-18 18:40:39 +02:00
Pieter-Jan Briers
6b43036c9d Fix UniqueIndexHkm memory leaking
Yeah that's just great this goddamn data structure had no damn API to ever remove anything from it. Incredible.
2024-10-18 18:40:39 +02:00
ElectroJr
f23a55793d Version: 237.0.0 2024-10-18 16:11:33 +13:00
wixoa
46143d2589 Separate window creation in OSWindow.Show() to allow creation in the background (#5489)
* OSWindow rework
OSWindow now created ClydeWindow and WindowRoot immediately, but non-visible in the background
Also added the ability to programatically resize an open window

* Implement window resizing on SDL2

* Revert OSWindow changes

* Split `Show()` into `Create()` and `Show()`

* Formatting
2024-10-17 17:21:38 +02:00
MilenVolf
ba7d1452c1 Add Erase button for TileSpawnWindow (#5488)
* Add Erase button for TileSpawnWindow

Small QoL for mappers. Basically, it just selects space tile on "Erase" button toggled.

* Remove copy paste. Conevrt this into method
2024-10-13 15:55:57 +02:00
Pieter-Jan Briers
1c1343466e Improve docs for IConsoleShell.Player
Just realized this relation of "no player = server console" is not clearly documented.
2024-10-11 15:14:38 +02:00
Pieter-Jan Briers
0d534e8bcd Allow watchdog to specify more information about why the server should restart.
Had a plan to use this, but realized for what I'm doing immediately I don't quite need it yet.

/update server endpoint can now receive a Reason code and Message field. These are available with IWatchdogApi.RestartRequested.

Cleaned up IWatchdogApi: Added comments, moved symbols that should only be called by the engine to an internal interface. Also cleaned up some code in WatchdogApi to remove some IDE warnings.
2024-10-11 00:26:37 +02:00
Pieter-Jan Briers
c83c6f9592 Fix RobustSerializer breaking for non-seekable streams.
Shows up in replay loading from zip files, as the stream may be compressed. The statistics code in RobustSerializer assumes the stream is always seekable (by accessing .Position).

Now we don't run the statistics logic when reading/writing non-seekable-streams.
2024-10-10 04:31:37 +02:00
Pieter-Jan Briers
c794bd84bf Replay load: remove unnecessary bufferSize parameter.
This usage really doesn't make sense, and it makes the usage invalid if the size is zero. Now realistically I don't think this happens except in edge-case replay files, but it's still silly.

Removed if for no other reason than spite for making me look at this code and reason about it.
2024-10-10 04:06:39 +02:00
Pieter-Jan Briers
d1d43f834b Version: 236.1.0 2024-10-08 22:59:51 +02:00
Pieter-Jan Briers
9505cb68df Add SwitchExpressionException to sandbox
Fixes #5450
2024-10-07 19:05:17 +02:00
Ed
9763f5fdf4 filter entities (#5473) 2024-10-07 18:48:39 +02:00
Mervill
80a963ec05 Replace obsolete functions in MapSystem (#5483) 2024-10-07 18:48:09 +02:00
Mervill
3a670ec25e Replace obsolete functions in EntityLookup Test (#5482) 2024-10-07 18:34:22 +02:00
mhamster
e45950a557 Update BaseServer.cs (#5487)
+ Server now gives a proper reason of shutdown when shutting down before main loop has been started
2024-10-07 14:06:49 +02:00
eoineoineoin
6f1427ef3c Interface to remove a controls child by index (#5485)
Co-authored-by: Eoin Mcloughlin <helloworld@eoinrul.es>
2024-10-06 22:51:53 +02:00
Mervill
9a7d1a39c1 Replace obsolete functions in GridFixtureSystem (#5484) 2024-10-06 02:03:01 +02:00
Mervill
9be903ee56 Replace obsolete functions in GridRotation Tests (#5481) 2024-10-05 13:21:26 +10:00
Mervill
72f9f9c343 Trim unused method variables (#5480) 2024-10-05 13:19:21 +10:00
metalgearsloth
3ad760a99e Add another lookup overload (#5477) 2024-10-03 18:56:44 +02:00
metalgearsloth
e2f3722ce9 Set sprite flicks immediately (#5467)
So on content we have an issue where the animation is played in doorsystem but sprite visibility is controlled by airlocksystem. The issue then is that we get a single frame where the incorrect sprite is shown before it corrects itself. The easiest way to reproduce this is to walk into a door that denies you and observe it shows the incorrect sprite then flickers to the denied one.

There might be more systems with these issues which is why I did this here instead.
2024-10-03 18:56:06 +02:00
Vasilis
b4beca6562 Expose GameTitle, WindowIconSet and SplashLogo to content (#5475)
* Expose GameTitle to public

Requirement for upstream ss14 pr

* Missing method implemented

* Add windowiconset and splashlogo (I think this is what pjb meant?)

I don't think its worth it to add the other stuff (modules, assemblyprefix, autocnnect, clientassemblies)

* Docs
2024-10-01 12:05:44 +02:00
Pieter-Jan Briers
ea02260230 Add LineEdit.SelectAllOnFocus 2024-10-01 01:07:08 +02:00
Leon Friedrich
3b243e487d Add required keyword attributes to sandbox whitelist (#5474)
* Add `required` keyword attributes to sandbox

* Release notes
2024-09-30 16:00:24 +02:00
Pieter-Jan Briers
f40ccb7558 New HWID system prep (#5446)
* New HWID system prep

* Allow HWID to be disabled.

Both client and server can now request HWID to be disabled.

On the server via CVar, if disabled the client won't send it.

On the client via env var, if disabled it won't be sent to the client.

This involved moving legacy HWID to be sent in MsgEncryptionResponse instead of MsgLoginStart. This means the legacy HWID won't be available anymore if the connection isn't authenticated.

* Fix tests

* Fix another test

* Review

* Thanks Rider
2024-09-29 00:29:02 +02:00
Stalen
f467a7027b Added MuteSounds property for BaseButton control (#5465) 2024-09-29 00:25:56 +02:00
eoineoineoin
c9d7d442d9 Make IPlayerManager accessible to derived classes (#5471)
Co-authored-by: Eoin Mcloughlin <helloworld@eoinrul.es>
2024-09-28 23:48:07 +02:00
eoineoineoin
342626ad9b Account for scale when calculating sprite offset (#5470)
Co-authored-by: Eoin Mcloughlin <helloworld@eoinrul.es>
2024-09-28 17:31:24 +02:00
metalgearsloth
1c3ea968e4 Version: 236.0.0 2024-09-28 19:16:35 +10:00
Pieter-Jan Briers
f0ed3537ee Duplicate dependency field analyzer (#5463)
* Duplicate dependency field analyzer

Detects cases of duplicate [Dependency] fields in a type. We apparently have 27 of these across RT + SS14.

* Fix duplicate dependencies in Robust
2024-09-28 15:35:18 +10:00
metalgearsloth
74e7e61a98 Revert "Make resetting contacts on the client only set is touching if it is true" (#5469)
This reverts commit cdb94748c8.
2024-09-28 14:33:37 +10:00
metalgearsloth
fb9b0ae89b Remove IsTouching set on physics prediction (#5468)
Just because an entity sleeps doesn't mean it's not touching necessarily. This causes client to mispredict against server and continuously fire collision events if we try to move into an entity.

Easiest way to reproduced is to walk into a locked airlock and watch it flicker constantly.
2024-09-28 14:13:05 +10:00
Stalen
dbe297b1fc Activate XAML hot reload on file rename (for VS support) (#5429) 2024-09-24 09:43:00 +10:00
Leon Friedrich
b84917e8e4 Obsolete some static localization methods (#5460) 2024-09-24 09:40:42 +10:00
Leon Friedrich
abb3f65fe4 Make EnsureEntityDictionary use TryAdd (#5461) 2024-09-24 09:40:16 +10:00
Leon Friedrich
41ec2dc131 Try improve PVS exception tolerance a bit more (#5454) 2024-09-24 09:39:33 +10:00
eoineoineoin
e714dcc83c Fix TabContainer click detection when UIScale was not == 1.0 (#5456)
* Fix tabcontainer click detection when UIScale was not == 1.0

* Remove whitespace

---------

Co-authored-by: Eoin Mcloughlin <helloworld@eoinrul.es>
2024-09-22 14:41:27 +02:00
ShadowCommander
46291af1be Add ProtoId parser to Toolshed (#5220)
* Add ProtoId parser to Toolshed

* Change obsolete FromMarkup to FromMarkupOrThrow
2024-09-21 21:57:08 +10:00
Leon Friedrich
ad929c9955 Fix ICommonSession.Ping (#5453) 2024-09-20 16:43:12 +02:00
metalgearsloth
c86cb0b795 Version: 235.0.0 2024-09-18 12:13:35 +10:00
metalgearsloth
8d03feb84f Transform precision thing (#5451)
Just noticed it but probably doesn't affect anything really, we'll go from 64bit to 32bit after the math operations and not before.
2024-09-18 12:08:36 +10:00
Plykiya
0fa21ee2d2 Completely obsolete noSpawn (#5364) 2024-09-18 11:48:13 +10:00
eoineoineoin
9be0f032e8 Fix DistanceJoints drawn by physics debug system (#5439)
Co-authored-by: Eoin Mcloughlin <helloworld@eoinrul.es>
2024-09-18 11:45:01 +10:00
Leon Friedrich
afffb33446 Stop empty audio system filters from playing sounds for all players (#5444)
* Fix audio system empty filter bug

* The nullable attributes are lying
2024-09-18 11:44:16 +10:00
Leon Friedrich
19a87fb67a Remove incorrect NotNullIfNotNull attributes in SharedAudioSystem (#5449) 2024-09-18 11:43:49 +10:00
DrSmugleaf
2fda62a274 Fix physics.maxlinvelocity not being a replicated cvar (#5445) 2024-09-17 12:51:54 +10:00
ike709
5218bf70b0 Bump cefglue (#5441)
* Bump cefglue

* Another bump

* Third time's the charm

---------

Co-authored-by: ike709 <ike709@github.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2024-09-16 22:31:10 +02:00
Pieter-Jan Briers
4f95c07ab3 Add missing Roslyn components to solution 2024-09-16 21:34:59 +02:00
Lgibb18
786acae47a Fix tags with controls in RichText and OutputPanel (#5428)
* Controls in RichText fixes

* useless

* Get FormattedMessage from RichTextLabel

* dont go through nodes

* Comments and minor changes

---------

Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
2024-09-16 14:13:59 +10:00
Leon Friedrich
f81e30a031 Try fix invalid PVS index bug (#5422)
* Try fix invalid PVS index bug

* bounds check

* More Asserts

* fix assert?

* remove deletion

* a

* A!
2024-09-16 14:12:20 +10:00
Leon Friedrich
f5c1d870f9 Improve FlushEntities() error logs (#5427)
* Improve FlushEntities() error logs

* log count before flush
2024-09-16 14:06:04 +10:00
Leon Friedrich
4949b34c88 Fix "to" and "take" toolshed commands (#5438) 2024-09-13 22:34:30 +10:00
metalgearsloth
0f60ad9018 Version: 234.1.0 2024-09-12 17:56:50 +10:00
metalgearsloth
f7287b181d Fix audioparams for playglobal (#5437) 2024-09-12 17:48:37 +10:00
Fildrance
45b7500d93 feat: added audio system predicted method for only one receiver (#5435)
* feat: added audio system predicted method for only one receiver

* renamed to PlayLocal

* tweak

---------

Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2024-09-12 17:41:40 +10:00
metalgearsloth
dbe6f65880 Version: 234.0.0 2024-09-12 13:56:27 +10:00
metalgearsloth
4faef1bfd3 Add another lookup override (#5436) 2024-09-12 13:53:36 +10:00
Kara
48d70a09c6 Remove most fully-obsoleted code (#5433) 2024-09-11 19:38:26 +10:00
Pieter-Jan Briers
f682fb9cc7 Obsolete some useless type proxies on IResourceCache
These aren't even used, but they're pretty objectively bad ideas so let's obsolete them so we can get rid of them later.
2024-09-09 11:22:07 +02:00
Pieter-Jan Briers
814e5bcf17 Mark large replays as requiring Server GC.
This should significantly improve loading performance of large replays.

System can be controlled by replay.server_gc_size_threshold, which defaults to 50 MiB.

This is the engine-side of https://github.com/space-wizards/SS14.Launcher/issues/177
2024-09-09 08:23:20 +02:00
metalgearsloth
dbc4e80e61 Version: 233.1.0 2024-09-08 17:55:56 +10:00
metalgearsloth
5eb5ddd96e Add some entitylookup methods (#5431) 2024-09-08 17:22:48 +10:00
Leon Friedrich
405ed378c0 Re-attempt FlushEntities() on failure (#5423) 2024-09-06 20:51:34 +10:00
Leon Friedrich
be9db264dd Minor toolshed fixes / tweaks (#5315)
* Don't use markup for type names

* Cache TypeTypeParser completions

* Cache all type parsers

* Release notes

* More IConError fixes

* a
2024-09-06 10:48:50 +10:00
Pieter-Jan Briers
2f73f6190d Fix warning in ScriptGlobalsShared.cs 2024-09-04 21:31:37 +02:00
metalgearsloth
f3dfa1f666 Move testbed command to benchmarks (#5424) 2024-09-03 22:02:00 +10:00
Pieter-Jan Briers
b0d17e9527 Fix dead code equals method in Polygon
Fixes #5420

Sloth clarified it's dead code from copy pasting.
2024-09-02 13:17:02 +02:00
Pieter-Jan Briers
4c81e68bf1 Remove last FormattedMessage.FromMarkup calls 2024-09-02 07:36:34 +02:00
Pieter-Jan Briers
4490751001 Fix warnings in FormattedMessageSerializerTest.cs 2024-09-02 07:33:26 +02:00
Pieter-Jan Briers
bc8d2c154c Fix warnings in EntityManager_Components_Tests.cs 2024-09-02 07:32:47 +02:00
Pieter-Jan Briers
3c83f8e62a Make Rider not complain about Is. in Robust.UnitTesting, globally. 2024-09-02 07:27:23 +02:00
Pieter-Jan Briers
c36919d76a Fix warnings in ArithmeticTest.cs 2024-09-02 05:45:08 +02:00
Pieter-Jan Briers
70a853cdd5 Fix most warnings in AnchoredSystemTests.cs
Remaining warnings are cases where AnchorEntity, SetWorldPosition and SetLocalPosition subtly different from their component counterparts, and this triggers a test failure. Some help would be appreciated here.
2024-09-02 05:38:40 +02:00
Pieter-Jan Briers
fd3eb092cc EntityUid-only overloads for some TransformSystem methods
AnchorEntity and Unanchor
2024-09-02 05:37:49 +02:00
Pieter-Jan Briers
c740026014 Entity<T> overloads for some MapSystem methods.
GetTileRef, TileIndicesFor, and GetAnchoredEntities
2024-09-02 05:36:11 +02:00
Pieter-Jan Briers
44f9262d1a SimulationExtensions helpers for RobustServerSimulation
No more need to manually resolve IEntityManager in every test.
2024-09-02 05:30:10 +02:00
Pieter-Jan Briers
df2160b151 Fix warnings in Broadphase_Test.cs 2024-09-02 04:10:54 +02:00
Pieter-Jan Briers
5c7b1e6823 Fix warnings in ToolshedTest.cs 2024-09-02 04:01:24 +02:00
Pieter-Jan Briers
eaf7a6ba0f Fix warnings in ToolshedTypesTest.cs 2024-09-02 03:59:55 +02:00
Pieter-Jan Briers
9ab4286592 Wait why is that even returning a task in the first place 2024-09-02 03:59:25 +02:00
Pieter-Jan Briers
3f02ef3730 Fix warnings in PvsSystemTests.cs 2024-09-02 03:57:54 +02:00
Pieter-Jan Briers
2f17cbb1dc Fix warnings in ToolshedTypesTest.BugCheck.cs 2024-09-02 03:57:09 +02:00
Pieter-Jan Briers
c2657812f5 Fix warnings in GridTraversalTest.cs 2024-09-02 03:56:42 +02:00
Pieter-Jan Briers
f17f077849 Fix warnings in FormattedMessage_Test.cs 2024-09-02 03:55:14 +02:00
Pieter-Jan Briers
306deddbd2 Fix warnings in TransformComponent_Tests.cs 2024-09-02 03:54:52 +02:00
Pieter-Jan Briers
cdd8df743a Fix warnings in Transform_Test.cs 2024-09-02 03:49:06 +02:00
Pieter-Jan Briers
e7ac5ad047 Fix warnings in UserInterfaceManagerTest.cs 2024-09-02 03:45:46 +02:00
Pieter-Jan Briers
0e621a26be Fix warnings in ControlTest.cs 2024-09-02 03:45:46 +02:00
Pieter-Jan Briers
bbcc7cfe1f Fix warnings in GameLoop_Test.cs 2024-09-02 03:45:46 +02:00
Mervill
1208c25dcd resolve instances of the CS8974 warning (#5418) 2024-09-02 03:29:10 +02:00
Pieter-Jan Briers
38c227b692 Fix MarkupNode equality
Implement GetHashCode()

Fix Equals doing reference equality on the attributes.

Small code cleanup.

Actually mark it as IEquatable<MarkupNode> because we already implement Equals() so there's no reason not to.
2024-09-02 03:27:25 +02:00
Mervill
4e73d72753 Remove unused IoC dependencies (#5419) 2024-09-01 23:23:02 +02:00
Pieter-Jan Briers
b1e1a0cd88 Quick warning fixes (#5417) 2024-09-01 04:54:28 +02:00
metalgearsloth
6e25ead588 Version: 233.0.2 2024-08-31 18:39:01 +10:00
metalgearsloth
cfae6e1f95 Don't rely on client for grid fixture rebuilds (#5348)
* Don't rely on client for grid fixture rebuilds

Server is already networking fixture data and this has a chance to go bad.
Easier to just stop this entirely and remove the fixture references to just network the relevant ones for each chunk. Performance impact should pretty much be non-existent and it should be less buggy.

* a

* weh notes

* fix aabb update

* Fix AABB gen

* weh

* More networking
2024-08-31 18:37:43 +10:00
metalgearsloth
da56851846 Version: 233.0.1 2024-08-31 18:22:39 +10:00
metalgearsloth
69ed2c3c33 Fix IsHardCollidable (#5416) 2024-08-31 17:49:59 +10:00
metalgearsloth
c558a0327b Version: 233.0.0 2024-08-31 14:37:23 +10:00
metalgearsloth
3bb7df3254 Relative lookup fix (#5415)
* Relative lookup fix

Some of the transforms weren't being transformed, added another test.

* test

* better test

* Reduce any-entities-intersecting tests
2024-08-31 14:35:17 +10:00
metalgearsloth
ab6bd19817 Fix mouse hover not updating for new controls (#5313)
* Fix mouse hover not updating for new controls

It only ever updated on movement previously. The issue is for example if a new window shows up where the mouse is (or any control) it doesn't handle it. Just checking it every frame AFAIK shouldn't be that expensive. Worst case we just have some flag to check it that gets set on <mouse movement OR controls changed>.

* review
2024-08-31 11:45:59 +10:00
Leon Friedrich
73ef69aa94 Try and ensure that parents are always initialized before children (#5343)
* Try and ensure that parents are always initialized before children

* release notes
2024-08-31 11:05:56 +10:00
nikthechampiongr
656835e7fa Change EntityRenamedEvents arguments and make it broadcast (#5413) 2024-08-31 11:04:44 +10:00
Pieter-Jan Briers
26c87b5858 Make tests run parallelizable (#5412)
Hope this won't cause issues.

Massively improves test speed.
2024-08-31 11:04:21 +10:00
Pieter-Jan Briers
be36001ab8 Add thread check assert to core entity mutation commands. (#5411)
* Add thread check assert to core entity mutation commands.

Creation of entities and components is now checked to happen from the main thread.

This is already catching multiple buggy integration tests, these will be addressed in separate commits.

* Fix broken tests directly mutating entities from wrong thread.
2024-08-31 11:04:02 +10:00
Pieter-Jan Briers
2002402af8 Version script now supports dash versions 2024-08-29 12:52:52 +02:00
metalgearsloth
f659b2b58c Version: 232.0.0 2024-08-29 12:55:51 +10:00
metalgearsloth
b1e13f5b13 Fix BUI interfaces not deep copying (#5410)
* Fix BUI interfaces not deep copying

Didn't think I'd need to on a getstate but client state moment.

* less shitcodey
2024-08-29 12:47:32 +10:00
SlamBamActionman
e5995d4edc Add ObjectSerializer, AppearanceComponent.AppearanceDataInit, and AppearanceSystem.AppendData (#5324)
* V1 commit

* V2 Commit, ObjectSerializer

* Make sure write for objects have the !type:<T> set

* Added AppearanceDataInit

* Change to AppearanceDataInit setting to AppearanceData the moment it itself gets set; ComponentInit is too late. Forgive me sloth.

* RELEASE-NOTES.md

* Fix release notes

* Fix release-notes for realsies
2024-08-28 22:43:58 +10:00
Winkarst
6eb080a277 Add Robust.Xaml.csproj to the solution (#5408) 2024-08-28 13:49:42 +02:00
metalgearsloth
b0cb41e94a Version: 231.1.1 2024-08-28 12:23:04 +10:00
Leon Friedrich
23a23f7c22 Misc toolshed fixes (#5340)
* Prevent map/emplace command errors from locking up the server

* Fix EmplaceCommand

* Fix sort commands

* Fix JoinCommand

* changelog

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2024-08-28 12:22:47 +10:00
Pieter-Jan Briers
ec3a74d268 Version: 231.1.0 2024-08-27 17:47:25 +02:00
Pieter-Jan Briers
12b0bc4e0a Add way for content to write arbitrary files into replay. (#5405)
Added a new RecordingStopped2 event that receives a IReplayFileWriter object that can be used to write arbitrary files into the replay zip file.

Fixes #5261
2024-08-27 17:38:48 +02:00
metalgearsloth
903041dfd1 Add storage BUI bandaid (#5401) 2024-08-27 17:36:54 +02:00
metalgearsloth
b96419f0b2 Add mapmanager query tests (#5403)
Sanity
2024-08-28 00:24:24 +10:00
metalgearsloth
fe33ad2652 Add physicshull tests (#5404) 2024-08-27 23:24:23 +10:00
metalgearsloth
057a68b366 Minor allocs reductions (#5330)
* Minor allocs reductions

Added a poly struct with the intention of replacing the existing one whenever I finish box2c port.

* fix merges

* Revert some stuff

* Poly tests
2024-08-27 22:58:42 +10:00
metalgearsloth
1a2c9008fe Add Box matrix tests (#5402)
Thought we had but apparently not.
2024-08-27 22:21:48 +10:00
metalgearsloth
cd95929ebe Heavily optimise entitylookup (#5400)
* Heavily optimise entitylookup

Previously I made it so MOST of entitylookup goes through the same 4 or 5 codepaths and uses shapes. The downside was some codepaths were made much slower in the process.

This fixes most of the going up and down lookups that some codepaths did. It should also be faster than the pre-shapes version because GetLocalPhysicsTransform is being used for the non-approx queries and most entities are parented directly to their broadphase.

* Tests and confidence

* code

* dang
2024-08-27 21:32:50 +10:00
Nyeogmi
6396ec472d XAML hot reloading (#5350)
* Move RobustXaml to a shared package

In a near-future change, I'll make it possible to optionally link to
this from Robust.Client, which will allow JIT compiling XAML.

Also upgrade it to a version of .NET that supports nullability
annotations.

* Re-namespace packages

* Add a JIT compiler, plus hooks that call into it

In Debug, after this change, all XAML will be hot reloaded once every
time an assembly is reloaded.

The new code is compiled with SRE and is _not_ sandboxed -- this is not
suitable to run against prod.

In Release, the hot reload path is totally skipped, using the same trick
as SmugLeaf used in an earlier attempt to implement this functionality.

* Hot reload: watcher

This is a bit of a horror, but there's not in-engine support for
identifying the source tree or the XAML files in it.

* Put everything dangerous behind conditional comp

* Code cleanup, docs

* Fix a bad comment

* Deal a little better with crashes in the watcher

* Make reload failures Info, since they're expected

They were previously causing the integration tests to flag, even though
"a few types fail hot reloading because they're internal" is expected
behavior.

* Fix an unnecessary null check

I removed the ability for CompileCore to return null.

* injectors: null! strings, default primitives

* Tidy documentation (thanks, PJB!)

* Reinstate netstandard2.0, abolish Pidgin

* Internal-ize all of Robust.Xaml

* Add a cautionary note to Sandbox.yml

* Shuffle around where conditional compilation occurs

* Privatize fields in XamlImplementationStorage

* Internalize XamlJitDelegate

* Inline some remarks. No cond. comp in Robust.Xaml

* Use file-scoped namespaces

They aren't allowed at Language Level 8.0. (which I arbitrarily picked
for Robust.Xaml because it's the oldest one that would work)

* Bump language level for R.Xaml, file namespaces

* Force hot reloading off for integration tests

* Fix bizarre comment/behavior in XamlImplementationStorage

* Consistently use interfaces, even in generated code

* Update Robust.Client/ClientIoC.cs

---------

Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2024-08-27 02:16:57 +02:00
Stalen
d7aa5daf6a Add decimal type to sandbox whitelist (#5396) 2024-08-27 01:35:42 +02:00
metalgearsloth
e3819f8245 Network interfacedata (#5399)
If UIs are dynamically changed this fixes it.
2024-08-26 18:48:15 +10:00
metalgearsloth
57f133b742 Version: 231.0.1 2024-08-26 14:41:40 +10:00
metalgearsloth
04344ffe19 Make PVS exception log better (#5397) 2024-08-26 14:31:05 +10:00
metalgearsloth
f2ee9a43f9 Version: 231.0.0 2024-08-25 22:48:51 +10:00
metalgearsloth
8d5ebd830a Add CompRegistry methods to EntManager / CompFac (#5379)
* Add CompRegistry methods to EntManager / CompFac

CompRegistries are nice to use and this just makes it a bit easier to extend functionality.

* fix bad pull
2024-08-25 21:37:14 +10:00
metalgearsloth
4d265b2210 Add methods to get entity sprite position (#5381)
* Add methods to get entity sprite position

No easy way to get this in world-terms and I want a control to track it.

* invalid
2024-08-25 21:24:37 +10:00
metalgearsloth
e04caf7eb4 Add OpenScreenAt for windows (#5387)
If I want to open it at a particular position. Takes in clyde ref so not every single screen needs to keep the ref.
2024-08-25 20:32:28 +10:00
metalgearsloth
a4c54d3602 Make pointlight setting use an attempt event (#5378)
Makes it easy for content to add functionality if multiple things try to set it without having to funnel every piece of code through a content system.
2024-08-25 20:27:58 +10:00
metalgearsloth
43fd6bc764 Add FixturesChangeComponent (#5383)
* Add FixturesChangeComponent

Adds / removes fixtures. Useful when used in conjunction with EntProtoId to dynamically add / remove fixtures.

* Move to system

* Fix allcomps test
2024-08-25 20:25:19 +10:00
metalgearsloth
ff056552fe Don't spam BUI closing in state handling (#5382)
We just do what content does and defer it until update. Saves performance + we don't have some BUIs that do special logic on open re-running it constantly (e.g. open on mouse position).
2024-08-25 20:08:19 +10:00
metalgearsloth
3014d9880e Fix prototype flag add not actually working (#5376)
tryindex was inverted and causing issues with tools.
2024-08-25 20:03:09 +10:00
metalgearsloth
679c31199d Add comments to sermanager attributes (#5384)
I always forget which is which.
2024-08-25 20:02:31 +10:00
metalgearsloth
0bc3c51707 Contact QOL stuff (#5385)
* Contact QOL stuff

Only just made the enumerator version need to test with AI branch had an IEnumerable before.

* Fix
2024-08-25 11:54:05 +10:00
metalgearsloth
140767c262 Move viewsubscriber to shared + handle eye targets (#5362)
* Move viewsubscriber to shared + handle eye targets

Need this stuff for AI.

* Fix dumb

* review
2024-08-23 18:29:57 +10:00
metalgearsloth
36a5b672e5 Version: 230.2.0 2024-08-23 14:36:00 +10:00
metalgearsloth
1eb63cb616 Stop inheriting IThreadPoolWorkitem (#5377)
More annoying with internal changes.
2024-08-23 14:33:36 +10:00
metalgearsloth
c14689f233 Add more directions for Vector2i (#5386)
Convenient.
2024-08-23 14:33:08 +10:00
Pieter-Jan Briers
f03c006129 Version: 230.1.0 2024-08-22 01:49:43 +02:00
qwerltaz
0d53c5e329 add bool[] support to shaders (#5373)
* Add bool array support to shaders

* better setUniform

* less unsafe

* stackalloc, less pointer
2024-08-21 22:36:03 +02:00
metalgearsloth
5cb1901870 Fix local tile enlargement (#5349)
* Fix local tile enlargement

Not used.

* release notes

---------

Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2024-08-21 02:52:41 +02:00
Pieter-Jan Briers
d46885b96d Fix LocalizedEntityCommands breaking content unit tests. (#5375)
They are now not loaded inside content unit tests.

Fixes #5374
2024-08-21 02:43:46 +02:00
DrSmugleaf
0553600c9a Add cvar to limit entities passed into nearby command (#5355)
* Add cvar to limit entities passed into nearby command

* Fix double enumeration
2024-08-21 02:43:19 +02:00
DrSmugleaf
580dd5f1a6 Fix RichTextLabel.Text property not setting _message if null (#5361) 2024-08-21 02:40:50 +02:00
metalgearsloth
d47d488ce7 Broadphase init fixes (#5367)
1 for replays 1 for loadmap.
The replay one is kinda sussy but physicamap is supposed to get dumped at some point so.
2024-08-21 02:39:23 +02:00
Pieter-Jan Briers
d584e51de6 Revert LocalizedCommands Loc change.
This is what I get for ragecoding at 1 AM.
2024-08-21 02:03:16 +02:00
Pieter-Jan Briers
2f85b94ea2 Use new LocalizedCommands.Loc property in engine
Also made BaseReplayCommand.Loc an explicit hide of the base property.
2024-08-21 01:23:25 +02:00
Pieter-Jan Briers
046f7a2e55 Add "Loc" property to LocalizedCommands
Intended to match the localization manager in EntitySystem, much more convenient than the existing one.
2024-08-21 01:16:43 +02:00
c4llv07e
5f2881e3e4 Add completion support for the change state command (#5368) 2024-08-20 22:38:28 +02:00
DrSmugleaf
cdb94748c8 Make resetting contacts on the client only set is touching if it is true (#5372) 2024-08-20 19:35:14 +10:00
Stalen
53516d6389 Fixed client crash on devwindow inspect control's property which throws exception (#5370)
* Fixed client crash on devwindow inspect control property which throws exception

* Display inner exception only in case of TargetInvocationException
2024-08-19 00:55:04 +02:00
metalgearsloth
efa3e010a6 Add Flip method to SplitContainer (#5333) 2024-08-14 22:59:20 +02:00
faint
4b12ff8574 fix loadprototype (#5359) 2024-08-14 14:52:09 +02:00
Pieter-Jan Briers
59ed76c66f Remove obsolete usages of *Variant prototype manager functions
Replaced with *Kind
2024-08-13 11:45:40 +02:00
Tayrtahn
9781405f5e Better location reporting for DataField analyzers (#5344)
* Better location reporting for DataField analyzers

* Update test

* Use const string in both methods
2024-08-13 11:40:23 +02:00
Pieter-Jan Briers
2178707937 Version: 230.0.1 2024-08-11 19:49:23 +02:00
Pieter-Jan Briers
0284eb0430 Use absolute path for explorer.exe
frick me
2024-08-11 19:48:48 +02:00
Pieter-Jan Briers
2c3cc070a6 Fix oopsie from me using version.py on an existing version 2024-08-11 16:33:00 +02:00
Pieter-Jan Briers
6599f9565e Version: 230.0.0 2024-08-11 16:26:47 +02:00
Pieter-Jan Briers
85abcff5ea Version: 223.0.0 2024-08-11 16:26:32 +02:00
Pieter-Jan Briers
5b5894e2d5 Release notes 2024-08-11 16:26:25 +02:00
Pieter-Jan Briers
7d778248ee Security updates (#5353)
* Fix security bug in WritableDirProvider.OpenOsWindow()

Reported by @NarryG and @nyeogmi

* Sandbox updates

* Update ImageSharp again
2024-08-11 16:21:54 +02:00
DrSmugleaf
672819d525 Add missing return calls for positions and angles in SolveIsland (#5327) 2024-08-10 11:15:02 +10:00
Nemanja
99e4910440 Fix TimedDespawnComponent causing a crash if spawning another entity with TimedDespawnComponent (#5345) 2024-08-10 11:12:44 +10:00
Leon Friedrich
b503390837 Add InterpolatedStringHandlerArgumentAttribute to sandbox whitelist (#5339) 2024-08-08 19:10:23 +02:00
Repo
87725f27c3 Add a copy to clipboard button on alert popups. (#5336)
* Add a copy button to clipboard on Alert Popups.

* ButtonFlag and better formatting.

* Localization and style cleanup
2024-08-08 18:56:32 +02:00
metalgearsloth
49c831b48d Version: 229.1.2 2024-08-08 12:15:46 +10:00
Leon Friedrich
60a29933d8 Try fix broadphase bug (#5342)
* Try fix broadphase

* I love initialization pasta
2024-08-07 20:07:57 +10:00
metalgearsloth
5729e8eb19 Version: 229.1.1 2024-08-07 10:56:07 +10:00
Leon Friedrich
42da4b1287 Fix replay teleportation command exception (#5337) 2024-08-06 20:56:20 +10:00
metalgearsloth
3342e1272f Add audio filename to entity name (#5338)
Will make debugging tests easier.
2024-08-06 20:54:17 +10:00
metalgearsloth
5c0ce43e6c Version: 229.1.0 2024-08-05 14:54:28 +10:00
metalgearsloth
0717b1fced Avoid resolve in VV prop editor (#5335) 2024-08-05 14:53:55 +10:00
Pieter-Jan Briers
68c03196e6 Fix IPv6-only hosts in HappyEyeballsHttp
Copy paste xd
2024-08-05 00:32:33 +02:00
Pieter-Jan Briers
31292fe4b8 Do network message encryption concurrently. (#5328)
In profiles of RMC-14, encrypting network messages accounted for ~8% of main thread time. That's a lot.

Each NetChannel has an "encryption channel" which gets processed on the thread pool.
2024-08-03 15:21:54 +02:00
Pieter-Jan Briers
865348550f Fix warnings in ClientOccluderSystem.cs
PROJECT ZERO WARNINGS
2024-08-02 15:48:38 +02:00
Pieter-Jan Briers
7372233782 Fix client crash if networking handshake fails
MapManager would get an NRE access its sawmill during client reset because it depends on the uninitialized entity system.
2024-08-02 15:18:50 +02:00
Vasilis
7ebfc82dd6 Reduce the default TPS (#5326)
It is our suggestion for a long while to keep the TPS at 30 for servers. However the default was always 60.

I believe its better to have it as a default.
2024-08-02 00:27:46 +10:00
metalgearsloth
807e7e888a Fix chunkenumerator allocs (#5325)
* Fix chunkenumerator allocs

This was number 2 to pathfinding sitting afk on a server. I thought the property would cache it but apparently not. Ref struct is just nicety and it's internal and not exposed to content anyway so.

* also dis
2024-08-01 14:06:22 +02:00
Stalen
39fefcb9c8 Fixed data race in ParallelTracker (#5311)
* Fixed data race in ParallelTracker

* Added ParallelTracker fix release note
2024-07-30 15:08:58 +10:00
Tayrtahn
b6548c870c Add analyzer/fixer for replacing ProtoId<EntityPrototype> with EntProtoId (#5312)
* Add PreferOtherTypeAttribute, analyzer, and test.

* nullable enable

* Add nuget package for CodeFix verifier

* Add fixer for PreferOtherType

* Rename arguments

* Adjust diagnostic message

* Move attribute lookup
2024-07-23 19:01:43 +02:00
Pieter-Jan Briers
cf230b3454 Warning fixes centered around Clyde
Pulling entity systems into direct fields in Clyde to make it now painful. This required adding an event to ClientEntityManager when these become available, as they are only available when the client is in a server/single player.
2024-07-23 17:49:56 +02:00
Pieter-Jan Briers
16a93e86f6 Add obsoletion warning on control dispose
this shouldn't be used anymore
2024-07-21 01:45:24 +02:00
metalgearsloth
2e4275a7f3 Version: 229.0.0 2024-07-20 15:38:53 +10:00
metalgearsloth
176ca6c578 Add window helper for BUIs (#5183)
* Add window helper for BUIs

Automatically does OnClose and just makes content slightly nicer.

* more

* Add prototype reload helper

* Add Box2i Center

* weh
2024-07-20 14:50:15 +10:00
metalgearsloth
2664061993 Make PhysicsHull a ref struct (#5297)
* Make PhysicsHull a ref struct

First time I've used it but seemed like a good candidate considering it's temporary.

* weh

---------

Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2024-07-15 17:43:33 +02:00
Pieter-Jan Briers
033699d7d6 Fix spawn menu breaking on larger entities
Fixes #5304
2024-07-15 16:23:25 +02:00
metalgearsloth
f696edaa0c Clamp audio tickrate (#5296)
* Clamp audio tickrate

I am reasonably sure I saw a recommended 30TPS figure somewhere but I cannot find it again. At any rate I can't notice this but imagine it provides significant benefits for people on 144hz+ monitors.

* rn

---------

Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2024-07-13 20:09:49 +02:00
SlamBamActionman
4920ecaa64 Add AppearanceSystem Data dictionaries and RemoveData (#5288)
* Improved Appearance

* PR changes
2024-07-13 15:33:05 +10:00
Pieter-Jan Briers
b8924a04cf Fix RaisePredictiveEvent prediction checks (#5294)
RaisePredictiveEvent was made to not check whether prediction is enabled in #3534. This doesn't make much sense to me and is causing various SS14 game logic to erroneously run when prediction is disabled.

Here's the fix PR. Also fixes the assert to actually work (checking Connected is wrong, it should've been InGame) and makes the new check also account for SinglePlayerGame.
2024-07-13 15:30:20 +10:00
Plykiya
be11cb4bca Update GridSplit_Tests.cs to not use Component.Owner (#5300)
Co-authored-by: plykiya <plykiya@protonmail.com>
2024-07-13 15:28:47 +10:00
Plykiya
eafe395273 Update PlayerManager.cs to not use Component.Owner (#5299)
Co-authored-by: plykiya <plykiya@protonmail.com>
2024-07-13 15:28:02 +10:00
Pieter-Jan Briers
05cdb99252 Warning fixes around IMapManager.GetMapEntityId (#5298)
* Add MapSystem.GetMapOrInvalid

This is effectively the same exact behavior as IMapManager.GetMapEntityId. Adding this so I don't have to consider whether warning fixes using MapSystem.GetMap() instead would change behavior.

* Warning fixes around IMapManager.GetMapEntityId

* Fix tests
2024-07-13 15:27:32 +10:00
Plykiya
d4c6b4a828 Update MapGrid_Tests to use MapSystem functions (#5301)
* Update MapGrid_Tests.cs

* missed one

* remove unused entman

---------

Co-authored-by: plykiya <plykiya@protonmail.com>
2024-07-13 14:30:19 +10:00
metalgearsloth
fc1cca4f48 Version: 228.0.0 2024-07-12 21:50:15 +10:00
Pieter-Jan Briers
3657b0a424 Strongly order network prototypes and resources. (#5293)
* Strongly order network prototypes and resources.

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

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

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

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

Fixes #5291

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

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

* Robust.Client warning fixes

* Fix test failure

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

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

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

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

---------

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

* Add enum flag selection buttons

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

* Add name to toolshed usage help

* Better formatting

* Localize toolshed command usage

* Remove unnecessary call

* Cleanup

* Add release notes

---------

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

* Release notes

* More comment

* Fix release note

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

* Use properties to fetch data from component

* Comp1

* Vector2

* I sure love an analyzer that doesn't work half the time
2024-07-06 17:34:50 +10:00
Amy
ad329a6b58 whitelist (#5285)
Co-authored-by: amylizzle <amylizzle@users.noreply.github.com>
2024-07-04 15:29:03 +02:00
Guillaume E
4deba4b866 Darken SnapgridCenter placement grid (#5279)
In SS14, the bright blue placement grid was making other game objects
difficult to see in low lighting conditions.
2024-07-04 09:55:46 +10:00
deathride58
4c31083186 Replaces the entity spawn window's bespoke method of object icon rendering with entityprototypeview (#5277) 2024-07-03 21:37:18 +10:00
DrSmugleaf
d31e7ccb55 Add Text property to RichTextLabel (#5280) 2024-07-03 13:02:41 +02:00
metalgearsloth
a9aea7027f Version: 227.0.0 2024-07-01 15:54:45 +10:00
metalgearsloth
2a49c2d9b8 Add loop support for SpriteSystem.GetFrame (#5265)
For Ftl I just want it played once.
2024-07-01 15:50:49 +10:00
metalgearsloth
a0c069f1ea Add LocalTilesIntersecting for circles (#5262)
* Add LocalTilesIntersecting for circles

* Update Robust.Shared/GameObjects/Systems/SharedMapSystem.Grid.cs

Co-authored-by: Tayrtahn <tayrtahn@gmail.com>

---------

Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
2024-06-29 14:57:06 +10:00
Pieter-Jan Briers
2c6fb95e53 Add EntityManager dependency to base LocalizedEntityCommands 2024-06-28 17:00:14 +02:00
Nemanja
afe337644e Make spin box controls disable buttons that can't be pressed (#5221)
* spin box changes

* make SpinboxButton private

---------

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2024-06-28 17:53:10 +10:00
Plykiya
b8924f3ddf Removes obsolete visibility system functions (#5209)
* Removes obsolete visibility system functions

* guh, forgot to add the test

---------

Co-authored-by: plykiya <plykiya@protonmail.com>
2024-06-28 17:30:02 +10:00
Pieter-Jan Briers
08970e745b Entity console commands system. (#5267)
* Entity console commands system.

This adds a new base type, LocalizedEntityCommands, which is able to import entity systems as dependencies. This is done by only registering these while the entity system is active.

Handling registration separately like this required a bit of changes around ConsoleHost to make it more suitable for this purpose:

You can now directly register command instances, and also have a system to suppress `UpdateAvailableCommands` on the client so there's no bad O(N*M) behavior.

* Convert TeleportCommands.cs to new entity commands.

Removes some obsoletion warnings without pain from having to manually import transform system.

* Fix RobustServerSimulation dependency issue.

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2024-06-28 17:29:24 +10:00
Leon Friedrich
0ba4a66787 Always process networked events via the priority queue (#5205) 2024-06-28 17:02:14 +10:00
Pieter-Jan Briers
75b3431ee6 New "must call base" analyzer. (#5266)
* New "must call base" analyzer.

This enforces that you actually call base when overriding stuff. This is intended for base methods like entity system's, where server/client systems overriding shared ones SHOULD call Initialize() and such.

* Add MustCallBase to entity system methods
2024-06-28 14:44:49 +10:00
geraeumig
c0ef976588 Make PvsSystem consider offset and zoom from EyeComponent (#5228)
* Make PvsSystem consider offset and zoom from EyeComponent

* Just use PvsScale float

* float.IsFinite

---------

Co-authored-by: geraeumig <alfenos@proton.me>
Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
2024-06-28 14:24:22 +10:00
Pieter-Jan Briers
fe5cdf9e3c Fix loading of replays if string package is compressed in zip.
This happened when I had to re-compress a recovered replay from a server crash, and then loaded it up in a dev environment.
2024-06-27 16:07:49 +02:00
Morb
450349188b Dispose memory stream after deserialization exception (#4840)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2024-06-26 23:16:56 +02:00
metalgearsloth
897ad998d9 Add option for left or right-aligned checkboxes (#4739)
* Add option for left or right-aligned checkboxes

I think right-aligned is better but this is less of a breaking change.

* Cleanup
2024-06-26 23:11:17 +02:00
metalgearsloth
635ae3c353 Remove IGameTiming from TransformComponent (#5273) 2024-06-26 17:10:34 +02:00
Pieter-Jan Briers
a4ea5a4620 Add AnimationCompletedEvent "Finished" boolean.
Content has multiple cases where AnimationCompletedEvent is used to loop an animation. #5238 broke some of these by making this event raised even when manually removed.

Luckily most cases in content tie the animation looping to the presence of a component, so the component getting removed means there's nothing to refresh the loop. LightBehavior is not as fortunate however, causing bugs like https://github.com/space-wizards/space-station-14/issues/29144

This boolean allows looping code to properly distinguish the event, so it won't try to restart an animation after removing it directly.
2024-06-25 15:35:53 +02:00
Pieter-Jan Briers
90e87526d0 Quote tab completions containing spaces. 2024-06-24 16:05:00 +02:00
metalgearsloth
cd6576ddf9 Mark EntityCoordinates.Offset as pure (#5264)
Doesn't do anything just being called and sometimes I forget.
2024-06-24 10:53:41 +02:00
Leon Friedrich
e2cf4ee3db SIMD Colour multiplication (#5251)
* color simd

* removed wrong one

* A

* Use Unsafe.BitCast

* Color4 -> Color

* remove constructor

* remove `in`
2024-06-22 16:42:40 +02:00
metalgearsloth
860c9af2bf Version: 226.3.0 2024-06-22 14:10:43 +10:00
Pieter-Jan Briers
87bb29408a Try to report method source of sandboxing issues. 2024-06-21 00:31:47 +02:00
Pieter-Jan Briers
738cfbe992 Add non-generic IList and ICollection to sandbox.
Used by collection expressions in some cases.
2024-06-21 00:31:47 +02:00
wixoa
90edc02259 Add style property overrides to ContainerButton and TabContainer (#5222)
* Add style box override properties to ContainerButton and TabContainer

* Add background panel to TabContainer, and add text color overrides

* Undo background panel
You can achieve the same by instead putting the TabContainer in a PanelContainer

* Add BackgroundColor property to StyleBoxTexture

* Remove BackgroundColor from StyleBoxTexture
2024-06-20 20:50:51 +02:00
metalgearsloth
da5416a2da Version: 226.2.0 2024-06-20 17:28:11 +10:00
metalgearsloth
021845d956 Add some System.Random methods (#5177)
* Add some System.Random methods

* weh
2024-06-20 17:23:47 +10:00
Leon Friedrich
7fab9f3b8d Fix ContainerSystem debug assert (#5254) 2024-06-20 17:23:38 +10:00
Pieter-Jan Briers
69c1161562 FormattedMessage/DebugConsole performance improvements (#5244)
* Add VisibilityChanged virtual to Control

* Defer updating invisible OutputPanels on UIScale change

DebugConsole falls under this when not hidden, and it significantly improves perf of e.g. resizing the window when there's a lot of stuff in there.

* Avoid redundant UI Scale updates on window resize.

Window resizing can change the UI scale, due to the auto-scaling system. This system had multiple perf issues:

UI scale was set and propagated even if it didn't change (system disabled, not effective, etc). This was just wasted processing.

UI scale was updated for every window resize event. When the game is lagging (due to the aforementioned UI scale updates being expensive...) this means multiple window resize events in a single frame ALL cause a UI scale update, which is useless.

UI scale updates from resizing now avoid doing *nothing* and are deferred until later in the frame for natural batching.

* Reduce allocations/memory usage of various rich-text related things

Just allocate a buncha dictionaries what could possibly go wrong.

I kept to non-breaking-changes which means this couldn't as effective as it should be.

There's some truly repulsive stuff here. Ugh.

* Cap debug console content size.

It's a CVar.

OutputPanel has been switched to use a new RingBufferList datastructure to make removal of the oldest entry efficient.

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2024-06-20 17:22:12 +10:00
metalgearsloth
095fe9d60f Turn broadphase contacts into a job (#5245)
Okay when I said no more physics this was a low-hanging fruit as we can get rid of the mapmanager getmapentityid for every contact so.
2024-06-20 17:19:26 +10:00
Leon Friedrich
14138fbcc2 Separate PVS serialization from compression & sending (#5246) 2024-06-20 17:18:51 +10:00
Pieter-Jan Briers
48ce24e98b Remove race condition invoking ThreadPool.SetMinThreads call
For some reason we call ThreadPool.SetMinThreads on startup of the game server. Calling this function this early seems to put us at high risk of triggering the following deadlock bug in the .NET runtime: https://github.com/dotnet/runtime/issues/93175

Given I have zero trust in whether this manual ThreadPool fuckery is even helpful, I'm just gonna nuke it and call it a day.
2024-06-20 03:12:01 +02:00
Pieter-Jan Briers
9cde21a7b3 Lower default MTU again.
Yet more reports of people running into issues with the current default.
2024-06-20 00:15:27 +02:00
Pieter-Jan Briers
ae1051e813 Cache non-existence of ResourceCache TryGetResource.
Many patterns (both in engine and content) make use of regular TryGetResource returning null. The problem is that if the resource doesn't exist, it won't be cached and the code attempts to load it from disk *every single time*.

For example, opening an inventory in SS14 would hang the client for ages on some UI themes due to the UITheme texture fallback system constantly trying to load a texture that doesn't exist.
2024-06-19 22:50:09 +02:00
Leon Friedrich
a3f80ac7dd Increase default value of res.rsi_atlas_size (#5250) 2024-06-19 22:09:39 +02:00
CaasGit
f98ef78a21 Update LoaderApi to the latest commit. (#5256) 2024-06-19 19:52:49 +02:00
metalgearsloth
bf8054b181 Version: 226.1.0 2024-06-18 21:50:18 +10:00
metalgearsloth
6b875e6676 Add local entities APIs (#5178)
Need for some vgroid stuff
2024-06-18 21:41:38 +10:00
Vasilis
a687c0a6c0 Change "to" to "from" on advert error (#5247)
It's a message FROM the hub

Currently, if you get "You are banned from the hub, if you believe this is an error contact us" it may confuse someone that they have to visit the hub URL where they will be met with a 404 because it's not an actual website. Seems it looks like "contact us to website"

Similarly, with "Failed to contact status address" makes it look like it's an error message coming from robust failing to connect to the hub server. When it's actually coming from the hub, telling you probably don't have your ports open.

I believe changing it to "from" will get the message acros that this is a message from the HUB and not robust.
2024-06-17 15:15:30 +02:00
Pieter-Jan Briers
0580cf3ff7 Drop SQL exporter in Robust.Benchmarks to fix compilation.
It was using an old Npgsql version, which broke compilation. Updating it breaks some of the custom JSON mapping code.

Comment out the entire thing, it's not being used anymore anyways.
2024-06-17 02:00:11 +02:00
Pieter-Jan Briers
590964d5bf Update SpaceWizards.HttpListener to 0.1.1
This fixes an EXTREMELY RARE crash on server startup due to a race condition. Yes, it did cause a crash in practice that's how I noticed it.
2024-06-16 21:34:15 +02:00
Pieter-Jan Briers
ceda39813d Fix MsgPlayerList being capped to 255
WHY WAS THIS A BYTE.

This prevented having more than 255 people on a server, beyond that the game might get stuck as people's player states wouldn't necessarily get sent.
2024-06-16 21:31:57 +02:00
metalgearsloth
a3a8912f42 Version: 226.0.0 2024-06-17 01:50:04 +10:00
metalgearsloth
b40973157d Animation player fixes (#5238)
Ensures the event always goes out even if the animation is stopped.
2024-06-17 01:47:31 +10:00
Leon Friedrich
1de8731465 Reduce uses of IComponentFactory.GetIndex(Type) (#5242)
* Update `RaiseComponentEvent` & component lifestatge methods

* Fix ComponentNetworkGenerator

* a

* A
2024-06-17 01:46:51 +10:00
Leon Friedrich
3a479cb5f4 Add ComponentEventAttribute to AfterAutoHandleStateEvent (#5243) 2024-06-15 17:32:19 +02:00
slarticodefast
76eeebf439 Allow RequestScreenTexture to be set in overlays (#5234) 2024-06-15 23:35:10 +10:00
metalgearsloth
2fa83181e2 Version: 225.0.0 2024-06-15 16:46:54 +10:00
Leon Friedrich
36f02b4a18 Fix IComponentFactory mock in tests (#5240) 2024-06-15 16:38:05 +10:00
metalgearsloth
e842142dd7 Minor API niceties (#5219)
* Minor API niceties

* weh
2024-06-15 16:26:01 +10:00
Leon Friedrich
2eb740cea8 Try prevent eventbus loops (#5166)
* Add test

* Try prevent event bus linked list loops

* Eh, add an upper limit anyways
2024-06-15 12:20:48 +10:00
metalgearsloth
a044f04e3b Remove CompIdx locks (#5231)
* Remove CompIdx locks

So GetComponentState in PVS calls RaiseComponentEvent which in turn calls this. When you start getting a significant number of players it seems to run into lock contention considering every single compstate get will lock this.

Instead we'll just update the dictionary whenever RegisterClass is called instead.

* Fix thread-safety issues
2024-06-15 01:30:45 +10:00
Leon Friedrich
a4723d1f62 Avoid read lock in GetEntityQuery (#5236) 2024-06-15 01:19:29 +10:00
Pieter-Jan Briers
627c1eb054 Rewrite HappyEyeballsHttp
This makes the game use HTTPS more when available.

Implementation is just taken from my work on the launcher, nothing special here.
2024-06-14 11:27:34 +02:00
Pieter-Jan Briers
836aec0b87 Changelog for Toolshed ent change
Forgot this in 5c83678c78. Oops.
2024-06-14 03:03:33 +02:00
Pieter-Jan Briers
9116e64291 Implement info query ?can_skip_build=1
The hub has been adding this parameter for a while, instructing the game server that it doesn't need to run ACZ. This fixes the (relatively common) issue where the first publish fails because ACZ takes longer than the hub status timeout.

I apparently already committed some code for this once on accident. Whoops.
2024-06-14 03:02:12 +02:00
metalgearsloth
a6bfb5f557 Fix lookupflags oversight (#5233)
The ONE codepath CM-14 used and I forgot to add it.
2024-06-14 09:59:47 +10:00
Pieter-Jan Briers
5c83678c78 Fix "ent" toolshed command
Makes it use NetEntity instead of EntityUid.
2024-06-13 00:22:22 +02:00
Pieter-Jan Briers
eac94b1032 Allow Eye position to be set directly.
Eye is not a well-designed API, but we've got it so here we go. It was originally designed to have some form of support for non-entity eyes through the FixedEye type, by overriding the Position property in a child type. #1016 broke this however.

This PR just makes the property writable so this is possible again.

Co-authored-by: moonheart08 <moony@hellomouse.net>
2024-06-12 23:56:29 +02:00
metalgearsloth
efd870d070 Mark System<T> as pure (#5225) 2024-06-11 03:43:20 +02:00
Leon Friedrich
94f98073b0 Make PrototypeManager.TryIndex log errors when using invalid id structs (#5203)
* Make `PrototypeManager.TryIndex` log errors when using id structs

* A
2024-06-08 22:15:21 +10:00
DrSmugleaf
5aa9378de0 Add an overload of TerminatingOrDeleted with a nullable EntityUid (#5214) 2024-06-08 20:51:05 +10:00
Leon Friedrich
850e9ab695 Try optimize NetEntities console completion helper (#5217)
* Try optimize `NetEntities` completion options

* Actually just remove it

* a
2024-06-08 20:44:21 +10:00
Tayrtahn
7319f3a241 Raise an event when an entity's name is changed (#5216) 2024-06-08 10:45:28 +10:00
DrSmugleaf
b6252c9e4f Make Entity<T> work as a loc parameter (#5215) 2024-06-07 15:48:00 +02:00
ElectroJr
fcd507d1f9 Version: 224.1.1 2024-06-06 00:58:26 +12:00
Leon Friedrich
1eb874f4c3 Fix storage key-not-found exception (#5213) 2024-06-05 22:56:50 +10:00
ElectroJr
a628d31c4b Version: 224.1.0 2024-06-05 20:19:18 +12:00
Leon Friedrich
2b0ecd7166 Fix cvar type errors (#5212) 2024-06-05 18:18:49 +10:00
Tom Leys
bde650689b Perf: Avoid a copy of ComponentChanges every tick within Checkpoints (#5146)
* Perf: Avoid a copy of ComponentChanges every tick within Checkpoints

- Also remove temporary Dictionary created every tick * every change
- Reduces GC load, 6GB less temporary allocations on typical replays.

* perf: Checkpoints: Apply state changes in-place when possible

- Avoids >1GB of gas tile allocations.

* Revert "perf: Checkpoints: Apply state changes in-place when possible"

This reverts commit 1a478944a6.

* Fix delta state merge issues

---------

Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
2024-06-05 18:06:38 +10:00
Tom Leys
87d8d74d8c Perf: Improve replay playback responsiveness (#5152)
* Perf: Improve replay playback responsiveness

- new CVAR ReplayMaxScrubTime
- There is a time budget when applying replay ticks updates of only 10 ms
- Ensure we don't apply checkpoints that move us backwards in time by accident
- Prevent double-lookup of checkpoints.

* Fix merge error

* Fix it again, but for real this time

---------

Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
2024-06-05 17:38:36 +10:00
Nemanja
dddf13a19a EntityPrototypeView (#5185)
* ent proto view

* pee jay bee rahvew

* Fix EnteredTree() not respawning the entity

---------

Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
2024-06-05 17:04:49 +10:00
Leon Friedrich
75626a86a3 Add dummy sessions for integration tests (#5202)
* Add dummy sessions

* if FULL_RELEASE
2024-06-05 16:50:06 +10:00
Tornado Tech
3e3cd0e257 Fixed incmd command (#5192)
* Fixed incmd command

* Change `HandleInputCommand` argument type

* Localize console errors

* Why is input code even like this
2024-06-05 16:32:56 +10:00
deltanedas
a3a90154a4 add SetUi to shared ui system (#5092)
* re-add AddUi

* rename to SetUi, add if missing

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
2024-06-05 15:25:49 +10:00
Ygg01
9240c94e59 Write Errors when a duplicate localization key is found. (#4885)
* Update Linguini to v0.8.1

* Add tests and verify desired behavior has been reached.

* Remove duplicate messages.

* Minor fix to message output. Add Wrapper for Fluent errors.

* Restart the test pipeline.

* Restart the test pipeline.

* Make so test don't do an early bailout.

* Ensure all errors get written rather than bailing on first.

* Fix text breakage.

* Remove obsolete // TODO LINGUINI

* line wrapping conventions

---------

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
2024-06-05 15:23:41 +10:00
ShadowCommander
a95ba9f181 Fix Toolshed EnumTypeParse on non-lowercase enum values (#5211) 2024-06-05 15:22:02 +10:00
Leon Friedrich
074a4faa92 Try fix client-side BUI error spam (#5208) 2024-06-05 15:21:27 +10:00
metalgearsloth
6b4d74f46e Maybe fix bad resolve logging (#5207)
I'm not entirely sure what happens, I couldn't repro it locally even when I tried to force it to use threadpool threads. The only info I have is it happens and no other info has been provided so.
2024-06-05 09:00:41 +10:00
ElectroJr
f648218756 Version: 224.0.1 2024-06-03 02:57:09 +12:00
Leon Friedrich
b497efb0c0 Try fix IPrototypeManager.ResolveResults() error (#5200)
* Try fix `IPrototypeManager.ResolveResults()` error

* A

* I love test IoC

* I love test init logic
2024-06-03 00:52:27 +10:00
Leon Friedrich
d8f2b917b4 Fix buis not closing properly on entity deletion (#5198) 2024-06-02 22:12:39 +10:00
Leon Friedrich
6dd6b79db6 Fix PVS exception (#5196) 2024-06-02 21:58:48 +10:00
ElectroJr
ff4548f108 Version: 224.0.0 2024-06-02 16:24:12 +12:00
ElectroJr
8f41405b31 Update release notes 2024-06-02 16:23:06 +12:00
Leon Friedrich
f285c62674 Rework entity prototype categories (#5061)
* Improve entity categories

* A
2024-06-02 14:10:11 +10:00
eoineoineoin
56c30edf04 Replace Matrix3 with System.Numerics.Matrix3x2 (#5078)
* Delete Matrix3. Replace with System.Numerics.Matrix3x2

* Feedback

* release notes
2024-06-02 14:08:47 +10:00
Nemanja
783d529ec4 more placement manager fixes (#5186)
* more placement manager fixes

* Update Robust.Shared/GameObjects/EntityManager.cs

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

---------

Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
2024-06-01 10:13:52 -07:00
Pieter-Jan Briers
895bfb8ec0 Add Array.Clear(Array) to sandbox
API added in .NET 6, overload that took explicit array bounds was already in sandbox.
2024-06-01 14:17:28 +02:00
Leon Friedrich
6ef67cf513 Add stack trace to some error logs and remove some audio error logs (#5188)
* Add stack trace to some error logs

* Remove terminating entity audio error logs
2024-05-31 13:16:47 -07:00
Leon Friedrich
15a2f6702c Add try-catch to EnsureClientBui() (#5189)
* Add `try-catch` to `EnsureClientBui()`

* Better comment

* Uneccesary !

* a
2024-05-31 18:01:29 +10:00
Leon Friedrich
c5c2c2022a Ignore invalid entityuids in bui system update method. (#5187) 2024-05-31 10:47:55 +10:00
Pieter-Jan Briers
3c378640dd Add cvar_subs command
Dumb little thing, just wanted to test something.
2024-05-31 02:00:53 +02:00
metalgearsloth
0a149fa91c Expand PVS BUIs (#5179)
Mainly happens to aghosts who go out of range. Shouldn't be a huge perf impact as the User component is added / removed as BUIs get opened.
2024-05-31 09:51:11 +10:00
metalgearsloth
fe8d1d9422 Fix BUI state getting stuck (#5180) 2024-05-30 11:02:44 +10:00
metalgearsloth
c89c529ba4 Version: 223.3.0 2024-05-29 17:35:10 +10:00
metalgearsloth
dd56de70b7 Fix grid-based audio (#5087)
* Fix grid-based audio

- Fixes parenting issues.
- Add SetGridAudio as an easy way to set it up and apply the override too.

* No more global

* Rejig it all

* mergew

* review

* Minor optimisation

* Revert "Minor optimisation"

This reverts commit d0cdac7690.
2024-05-29 16:14:37 +10:00
Nemanja
710408c613 Fix placement manager rotation jank (#5176) 2024-05-29 12:32:14 +10:00
metalgearsloth
2461cd94dd Better parallel exception logging (#5175) 2024-05-29 12:31:46 +10:00
Kara
721408bb37 Version: 223.2.0 2024-05-27 17:50:28 -05:00
Leon Friedrich
8b42c1dd46 Improve FormattedMessage exception handling (#5170)
* Improve FormattedMessage exception handling

* comments
2024-05-27 15:40:29 -07:00
deltanedas
688b0b0458 make EntityPrototype.Categories use ProtoId (#5171)
Co-authored-by: deltanedas <@deltanedas:kde.org>
2024-05-27 15:38:51 -07:00
Nemanja
5fa49b5689 Fix rotation not being passed in properly in entitymanager methods (#5174) 2024-05-27 15:37:20 -07:00
Leon Friedrich
1f7a9bdf0a Remove container IoC resolves (#5172) 2024-05-26 13:19:52 +10:00
ElectroJr
796abe1230 Version: 223.1.2 2024-05-25 18:33:46 +12:00
KIBORG04
6c2cf26250 Sync LastTileModifiedTick in MapGridComponent with the client (#5169)
* i think

* forgot

* Add lastTileModifiedTick to MapGridComponentDeltaState

* A
2024-05-25 11:05:40 +10:00
Vasilis
ce262d5ff8 Include a bat to launch the server (#5167) 2024-05-24 18:32:26 +02:00
ElectroJr
c250010dad Version: 223.1.1 2024-05-24 18:58:03 +12:00
ElectroJr
709c7bc808 Fix cvar type cast 2024-05-24 18:57:46 +12:00
ElectroJr
37918da73c Version: 223.1.0 2024-05-24 18:44:51 +12:00
Leon Friedrich
6cc2083b09 Move some EntityCoordinates methods to TransformSystem (#5136)
* Move `EntityCoordinate` methods to `TransformSystem`

* TryGetInterfaceData

* Update IsInSameOrParentContainer

* Don't broadcast BoundUserInterfaceCheckRangeEvent

* Changelog

* Defer fetching component

* Re-add obsoleted methods

* Add obsolete container methods

* update release notes

* Add InRange()

* Make error logging optional
2024-05-24 16:44:17 +10:00
ElectroJr
6a6bfe33ca Version: 223.0.0 2024-05-24 16:10:00 +12:00
Leon Friedrich
9737a4249c Rework delta-states (#5149)
* Remove full "delta" states

* Update MapGridComponentState

* abstract ComponentState

* Release notes

* Fix tests

* Fix nullable errors

* A

* typo

* Turns out testing my own PRs is a good idea

* too many warnings
2024-05-24 14:08:41 +10:00
Leon Friedrich
a48a353939 Add IConfigurationManager.OnCvarValueChanged event (#5161)
* Add `IConfigurationManager.OnCvarValueChanged` event

* Prevent CVars from changing type

* Allow double registrations?

* Turn debug asserts into exceptions

* We should really just start using generics if we can

* Re-use CVarChangeInfo

* Explicit old value

* Rename `OnCvarValueChanged` to `OnCVarValueChanged`

* internal constructor
2024-05-24 14:04:56 +10:00
DrSmugleaf
f0b45d95cb Fix serialization source generator error when multiple partials of the same definition are user-defined (#5160) 2024-05-23 22:48:40 +02:00
Amy
d69c5500f2 better compat getpixel (#5162)
Co-authored-by: amylizzle <amylizzle@users.noreply.github.com>
2024-05-23 22:47:55 +02:00
Pieter-Jan Briers
cf133ca341 Update more URLs to new infra.
Mostly auth but also a reference to the old hub URL.
2024-05-23 17:40:43 +02:00
Tom Leys
b0922b8e0e perf: Budget less memory for Replay Checkpoints (#28052) (#5145)
* perf: Replays use less memory for checkpoints (#28052)

- Simple change of the CVars and some stats
- Based on a Lizard replay, checkpoints move from on average every 70 ticks to every 350.

* Set a minimum number of ticks that must pass between checkpoints

* Fix stat collection, split _checkpointMinInterval, more CheckpointState

* update release notes
2024-05-23 15:35:10 +10:00
AJCM-git
512ebd8422 LineEdit placeholder tweaks (#5153)
* LineEdit focus tweaks

* Doing it the correct way

* Reviews
2024-05-21 22:34:45 +02:00
Leon Friedrich
85f74c3ba3 Fix GetWorldViewbounds() and GetWorldViewport() (#5060)
* Fix GetWorldViewbounds() and GetWorldViewport()

* Remove some uses of `CurrentMap` and `CurrentEye`
2024-05-19 10:47:04 +10:00
Tayrtahn
da7abc6580 Add analyzer and fixer for redundant DataField tag arguments (#5134)
* Add analyzer and fixer for redundant DataField tag arguments

* Share Tag autogeneration logic
2024-05-17 07:44:03 +02:00
Vasilis
b1329d30bf Dont print watchdog token eletric boogaloo (#5143) 2024-05-17 07:15:30 +02:00
Джексон Миссиссиппи
12808d073e Make CVar RenderFOVColor settable by server only (#5142)
* | CVar.SERVER

* Update CVars.cs
2024-05-17 07:15:17 +02:00
Pieter-Jan Briers
ec794ce4e4 Version: 222.4.0 2024-05-17 02:51:44 +02:00
metalgearsloth
6b13475842 Revert "Add physics delta states (#5116)" (#5144)
This reverts commit 1189613908.
2024-05-17 02:21:05 +02:00
Pieter-Jan Briers
b48ee22800 Add more System.Numerics types to sandbox. 2024-05-16 22:25:13 +02:00
Pieter-Jan Briers
0b95a4edeb Version: 222.3.0 2024-05-16 20:14:37 +02:00
Pieter-Jan Briers
ed359481b4 We can't expect god to do the release notes. 2024-05-16 20:14:18 +02:00
metalgearsloth
1189613908 Add physics delta states (#5116)
* Add physics delta states

Significantly cuts down on data being sent + should make client state handling faster.

* Update Robust.Shared/Physics/Components/PhysicsComponentState.cs
2024-05-16 20:09:25 +02:00
DrSmugleaf
30907d8415 Fix ordered subscriptions not working when targeting a parent system type (#5135)
* Fix ordered subscriptions not working when targeting a parent system type

* Fix missing usages of expand ordering

* Extract method
2024-05-16 20:00:15 +02:00
Leon Friedrich
7f2da4d4f3 Fix paused entities not updating on prototype reload (#5128) 2024-05-16 19:06:11 +02:00
Ed
e30e963623 Hidden tiles (#5102)
* hidden tiles

* Update TileSpawningUIController.cs

* Update TileSpawningUIController.cs

* Update ITileDefinition.cs

* Update TileSpawningUIController.cs

* Move EditorHidden where clause out

* Make EditorHidden a DIM

So there's no breaking change

* Release notes.

---------

Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2024-05-16 19:05:39 +02:00
metalgearsloth
b056caeed7 Fix cross-map BUIs (#5115)
Even the ignore range bit is going to break with pvs but uhh not sure on that one unless we do overrides or something.
2024-05-16 19:00:11 +02:00
Leon Friedrich
fbc8086335 Don't iterate over component events when removing components (#5138)
* Don't iterate over component events when removing components

* Welp nevermind, forgot about tests

* A

* AAAAAA

* AAAA
2024-05-16 18:53:33 +02:00
Pieter-Jan Briers
799702b814 Work against .NET SDK update ManagePackageVersionsCentrally change
.NET SDK 8.0.300 changed ManagePackageVersionsCentrally to be implicitly set if Directory.Packages.props exists. We do not want this, as we intentionally have some projects that have it disabled.

We now explicitly unset the value in the Directory.Packages.props file to get the old behavior back.

See https://github.com/dotnet/core/issues/9309
2024-05-15 21:02:35 +02:00
ElectroJr
63df90f86f Version: 222.2.0 2024-05-14 23:01:41 +12:00
Vasilis
51f0c60bd3 Do not log wrong and correct watchdog token into info logs (#5133)
* Lets not do this?

* Webedit 2
2024-05-14 02:12:24 +02:00
metalgearsloth
a9ed53f47b Run BUI range checks in parallel (#5118)
These still take almost half-ms in server tick time on live as it has to do a raycast for everyone that has storage or their PDA open or whatever. Haven't benchmarked with a lot of clients but easiest way to tell is just check grafanaTM and I'm not sure how to check this locally.
2024-05-14 09:03:26 +10:00
Amy
41c40f1a94 Fix checking wrong property in TryGetVariableType() (#5120)
Co-authored-by: amylizzle <amylizzle@users.noreply.github.com>
2024-05-14 08:44:19 +10:00
deltanedas
6e61c35d35 add missing Comp inline to EntityQuery (#5123)
Co-authored-by: deltanedas <@deltanedas:kde.org>
2024-05-14 08:43:03 +10:00
ShadowCommander
aae0a8bc51 Add doc comments to CreateEntityUninitialized (#5131) 2024-05-14 08:42:34 +10:00
DrSmugleaf
cb543240c6 Fix clients mispredicting a character's gender (#5119)
* Fix clients mispredicting a character's gender

* Allow nullable value in set
2024-05-12 22:20:21 -07:00
metalgearsloth
1654ab06f5 Revert "Add audio stream name to entity name" (#5127)
This reverts commit d2a2afe82e.
2024-05-13 10:53:30 +10:00
Brandon Li
211245215e remove XAMLIL after generating populate method (#5126) 2024-05-13 01:34:32 +02:00
ShadowCommander
10aaaa65c5 Add editorconfig wrapping settings (#5125) 2024-05-12 17:50:19 +02:00
ShadowCommander
d2a2afe82e Add audio stream name to entity name (#5121) 2024-05-10 17:58:38 +02:00
Pieter-Jan Briers
025d90d281 Change build upload server to Suns 2024-05-09 09:48:49 +02:00
metalgearsloth
c229f2e312 Fix valuelist ensurecapacity(0) throwing (#5113)
_items is still null so.
2024-05-08 20:46:45 +02:00
metalgearsloth
fe051a3577 Minor bui thing (#5114) 2024-05-08 19:59:13 +10:00
DrSmugleaf
51a0ef1e60 Fix error when JointRelayTargetComponent shuts down while applying state (#5110) 2024-05-08 19:21:55 +10:00
DrSmugleaf
702dfef5fc Version: 222.1.1 2024-05-07 22:28:07 -07:00
DrSmugleaf
a0c1ad246f Fix never setting BoundUserInterface.State (#5111)
* Fix never setting BoundUserInterface.State

* Make setter internal
2024-05-07 20:51:26 -07:00
metalgearsloth
1153888bd1 Add truncate for filesaving (#5098)
* Add truncate for filesaving

If I expose it to content I pretty much always want truncate to be honest.

* Update Robust.Client/UserInterface/FileDialogManager.cs

---------

Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2024-05-07 00:58:57 +02:00
Amy
ccbb6ddec7 Add method for getting type of var (#5070)
Co-authored-by: amylizzle <amylizzle@users.noreply.github.com>
2024-05-06 20:39:32 +02:00
metalgearsloth
970da5f717 Version: 222.1.0 2024-05-06 13:43:11 +10:00
Pieter-Jan Briers
4d528dd577 Analyzer to ban uncached regexes (#5107)
Using static Regex functions that take in a pattern is bad, because they constantly have to be re-parsed. Cache the Regex instance.
2024-05-06 10:30:31 +10:00
Pieter-Jan Briers
c83720b163 Update Lidgren to v0.3.1 2024-05-06 01:55:05 +02:00
Pieter-Jan Briers
bd87a805d4 Add CVars to turn Lidgren's error/warning logs off.
Combined with upcoming Lidgren changes, this should make DDoS-induced warning log spam not cause huge server perf issues anymore.
2024-05-06 01:47:27 +02:00
Leon Friedrich
fff42fb2b4 Partially fix UI assert (#5100)
* Partially fix UI assert

* Avoid breaking change in BoundKeyEventArgs

This is a public constructor, as much as it maybe shouldn't be. Adding this parameter is a breaking change.

* Replace .Disposed checks with ! .VisibleInTree

Control disposal should not be used anymore.

* Release notes

---------

Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2024-05-06 01:29:34 +02:00
metalgearsloth
4500669f65 Version: 222.0.0 2024-05-06 08:54:19 +10:00
Pieter-Jan Briers
7d19ea9338 Fix compiler error from merges
EntProtoId PR was incompatible with the PR to change EntityPrototype methods to require IComponentFactory passed in
2024-05-06 00:32:54 +02:00
Leon Friedrich
2dc610907d Make IComponentFactory argument in EntityPrototype mandatory (#5101) 2024-05-05 23:00:10 +02:00
DrSmugleaf
beb1c4b1fb Add EntProtoId<T> (#5097)
* Add EntProtoId<T>

* Fix error messages

* Shorten error messages

* Make services non-optional
2024-05-05 22:59:45 +02:00
metalgearsloth
7e331eaa75 Defer clientside BUI opens (#5073)
* Defer clientside BUI opens

Needs content fix first as storage UI breaks.

* tweaks

* Re-revert this because it seems needed
2024-05-03 12:58:19 +10:00
Leon Friedrich
caf9e45ad9 Fix PVS iterating over duplicate chunks when a a client has multiple viewers/eyes (#5094) 2024-05-03 05:52:56 +10:00
metalgearsloth
7cb3aeccc2 Version: 221.2.0 2024-05-02 12:20:54 +10:00
metalgearsloth
ae83e606d6 Add SetWorldRotNoLerp method (#5091)
* Add SetWorldRotNoLerp method

I neeeeed it.

* Also this one

* dum
2024-05-02 12:14:27 +10:00
metalgearsloth
d9d5ef7471 Add audio helpers for map-based audio (#5086)
Doesn't need to be a flag because we just set it as global, whereas gridaudio cares about stuff every frame.
2024-05-02 09:51:14 +10:00
Pieter-Jan Briers
0f97f366a6 Copy CopyToShaderParameters in SpriteComponent.CopyFrom.
Fixes dragging displacement-mapped mobs in SS14 making the displacement map visible.
2024-05-01 23:45:58 +02:00
Jezithyr
35ab0b8cc8 Version: 221.1.0 2024-04-30 12:51:22 -07:00
metalgearsloth
5a14e939bf TileChangedEvent bool (#5089)
Shows whether IsEmpty is different, useful in circumstances.

Also NotNullWhen null handling consistency.
2024-04-30 07:28:29 -07:00
T-Stalker
ccba6b5d1c Reduce default sound range to 15 (#5085) 2024-04-30 15:41:00 +10:00
DrSmugleaf
254a5987c7 Fix Array.Resize sandbox signature (#5084) 2024-04-30 02:14:56 +02:00
metalgearsloth
8550056e68 Version: 221.0.0 2024-04-29 18:46:57 +10:00
Leon Friedrich
25211e3781 Improve transform & state handling exception tolerance (#5081)
* Improve transform & state exception tolerance

* release notes

* Fix pvs assert

* Fix velocity conservation
2024-04-29 18:42:05 +10:00
Leon Friedrich
3500abfd47 Add IUserInterfaceManager.UpdateHovered() (#5083)
* Add `IUserInterfaceManager.UpdateHovered()`

* Try fix tests
2024-04-29 18:37:52 +10:00
Leon Friedrich
7d1915096a Use more entity queries in physics systems & entity manager (#5082) 2024-04-29 13:46:10 +10:00
Nemanja
4504731588 Add a method in SharedTransformSystem for swapping the position of two entities (#4988)
* swap pos method

* no forcing

* Sluth review

* weh
2024-04-29 13:45:12 +10:00
Leon Friedrich
701fa95a82 Temporarily disable macos tests (#5079) 2024-04-29 02:35:04 +10:00
ShadowCommander
40a9048704 Add margin input value order as a comment (#5067)
* Add margin input value order as a comment

* Make a better comment and move value to remark
2024-04-27 20:17:11 +02:00
Leon Friedrich
cee8d42776 Improve MergeImplicitData exception tolerance (#5075) 2024-04-28 02:23:56 +10:00
metalgearsloth
3330d96177 Version: 220.2.0 2024-04-27 16:05:51 +10:00
Pieter-Jan Briers
4033d96327 Engine changes for displacement maps. (#5023)
* Add load parameter support to RSIs.

Currently only supports turning sRGB off. RSIs with custom load parameters are not thrown into the meta-atlas.

As part of this, TextureLoadParameters and TextureSampleParameters has been made to support equality.

* Add UV2 channel to vertices.

This is a bad hack to make displacement maps work in Robust. The UV2 channel goes from 0 -> 1 across the draw and can therefore be used by displacement maps to map a separate displacement map layer on top of the regular meta-atlas RSI texture.

This creates float inaccuracy issues but they weren't bad enough to completely void the feature. I'm thinking I learn from this experience and completely re-do how UVs work with the renderer rewrite, so that hopefully won't happen anymore.

This required dumping the optimized PadVerticesV2 because the changed struct size made it impractical. RIP.

I don't like this approach at all but the renderer is slated for a rewrite anyways, and all shaders will need to be rewritten regardless.

* Add CopyToShaderParameters for sprite layers.

This effectively allows copying the parameters of a sprite layer into another layer's shader parameters. The use case is to copy texture coordinates for displacement maps, as the exact map used changes depending on orientation. It also enables animations to be used though I didn't use that personally.
2024-04-27 16:03:35 +10:00
metalgearsloth
6e0205d1a8 Version: 220.1.0 2024-04-27 12:33:45 +10:00
ShadowCommander
7cd95351c3 Remove IP address and HWId from ViewVariables (#5062)
* Remove IP address from ViewVariables

* Remove HWId from ViewVariables
2024-04-27 12:30:34 +10:00
Leon Friedrich
2a102f048f Fix client-side replay exception (#5068)
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2024-04-27 12:30:00 +10:00
metalgearsloth
16bab1bc03 Close UIs on disconnect (#5071)
Engine handles it fine but content does not as the state gets handled before all comps are initialized.
2024-04-27 12:21:46 +10:00
metalgearsloth
123d0ae6ac Version: 220.0.0 2024-04-26 18:15:47 +10:00
metalgearsloth
d72de032fa Predicted BUIs (#5059)
* Add TryGetOpenBUI

Avoids having to get the component and openinterfaces separately.

* Couple more helpers

* entityquery

* reviews

* Shared BUIs

* zawehdo

* More boilerplate

* Bunch more work

* Building

* Stuff

* More state handling

* API cleanup

* Slight tweak

* Tweaks

* gabriel

* Disposies

* Active UI support

* Lots of fixes

- Fix states not applying properly, fix predicted messages, remove redundant message type, add RaiseUiMessage for an easy way to do it from shared, add the old BUI state change events back.

* Fix test failures

* weh

* Remove unncessary closes.

* release note
2024-04-26 18:12:55 +10:00
Tayrtahn
0fdba836ee Remove debug assert for Fixture.Owner equality (#5066)
* Removed debug assert for Fixture owner equality

* Blah
2024-04-26 14:47:09 +10:00
1135 changed files with 64023 additions and 30212 deletions

View File

@@ -7,6 +7,18 @@ indent_size = 4
trim_trailing_whitespace = true
charset = utf-8
max_line_length = 120
# ReSharper properties
resharper_csharp_max_line_length = 120
resharper_csharp_wrap_after_declaration_lpar = true
resharper_csharp_wrap_arguments_style = chop_if_long
resharper_csharp_wrap_parameters_style = chop_if_long
resharper_keep_existing_attribute_arrangement = true
resharper_place_field_attribute_on_same_line = if_owner_is_single_line
resharper_wrap_chained_binary_patterns = chop_if_long
resharper_wrap_chained_method_calls = chop_if_long
[*.{csproj,xml,yml,dll.config,targets,props}]
indent_size = 2

View File

@@ -5,30 +5,30 @@ on:
- cron: "0 0 * * 0"
jobs:
docfx:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.6.0
with:
submodules: true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup .NET Core
uses: actions/setup-dotnet@v3.2.0
with:
dotnet-version: 8.0.x
- name: Setup .NET Core
uses: actions/setup-dotnet@v4.1.0
with:
dotnet-version: 9.0.x
- name: Install dependencies
run: dotnet restore
- name: Install dependencies
run: dotnet restore
- name: Build Project
run: dotnet build --no-restore /p:WarningsAsErrors=nullable
- name: Build Project
run: dotnet build --no-restore /p:WarningsAsErrors=nullable
- name: Build DocFX
uses: nikeee/docfx-action@v1.0.0
with:
args: Robust.Docfx/docfx.json
- name: Build DocFX
uses: nikeee/docfx-action@v1.0.0
with:
args: Robust.Docfx/docfx.json
- name: Publish Docfx Documentation on GitHub Pages
uses: maxheld83/ghpages@master
env:
BUILD_DIR: Robust.Docfx/_robust-site
GH_PAT: ${{ secrets.GH_PAT }}
- name: Publish Docfx Documentation on GitHub Pages
uses: maxheld83/ghpages@master
env:
BUILD_DIR: Robust.Docfx/_robust-site
GH_PAT: ${{ secrets.GH_PAT }}

View File

@@ -2,33 +2,32 @@ name: Build & Test
on:
push:
branches: [ master ]
branches: [master]
pull_request:
branches: [ master ]
branches: [master]
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, windows-latest] # , macos-latest] - temporarily disabled due to libfreetype.dll errors.
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3.6.0
with:
submodules: true
- name: Setup .NET Core
uses: actions/setup-dotnet@v3.2.0
with:
dotnet-version: 8.0.x
- name: Install dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore /p:WarningsAsErrors=nullable
- name: Robust.UnitTesting
run: dotnet test --no-build Robust.UnitTesting/Robust.UnitTesting.csproj -- NUnit.ConsoleOut=0
- name: Robust.Analyzers.Tests
run: dotnet test --no-build Robust.Analyzers.Tests/Robust.Analyzers.Tests.csproj -- NUnit.ConsoleOut=0
- uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup .NET Core
uses: actions/setup-dotnet@v4.1.0
with:
dotnet-version: 9.0.x
- name: Install dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore /p:WarningsAsErrors=nullable
- name: Robust.UnitTesting
run: dotnet test --no-build Robust.UnitTesting/Robust.UnitTesting.csproj -- NUnit.ConsoleOut=0
- name: Robust.Analyzers.Tests
run: dotnet test --no-build Robust.Analyzers.Tests/Robust.Analyzers.Tests.csproj -- NUnit.ConsoleOut=0

View File

@@ -11,14 +11,8 @@
#
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:
workflow_dispatch
jobs:
analyze:
@@ -28,50 +22,50 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ 'csharp' ]
language: ["csharp"]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v3.6.0
with:
submodules: true
- name: Checkout repository
uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup .NET Core
uses: actions/setup-dotnet@v3.2.0
with:
dotnet-version: 7.0.x
- name: Setup .NET Core
uses: actions/setup-dotnet@v4.1.0
with:
dotnet-version: 7.0.x
- name: Build
run: dotnet build
- name: Build
run: dotnet build
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@@ -3,51 +3,50 @@
on:
push:
tags:
- 'v*'
- "v*"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Parse version
id: parse_version
shell: pwsh
run: |
$ver = [regex]::Match($env:GITHUB_REF, "refs/tags/v?(.+)").Groups[1].Value
echo ("::set-output name=version::{0}" -f $ver)
- name: Parse version
id: parse_version
shell: pwsh
run: |
$ver = [regex]::Match($env:GITHUB_REF, "refs/tags/v?(.+)").Groups[1].Value
echo ("::set-output name=version::{0}" -f $ver)
- uses: actions/checkout@v3.6.0
with:
submodules: true
- uses: actions/checkout@v4.2.2
with:
submodules: true
- name: Setup .NET Core
uses: actions/setup-dotnet@v3.2.0
with:
dotnet-version: 8.0.x
- name: Setup .NET Core
uses: actions/setup-dotnet@v4.1.0
with:
dotnet-version: 9.0.x
- name: Package client
run: Tools/package_client_build.py -p windows mac linux
- name: Package client
run: Tools/package_client_build.py -p windows mac linux
- name: Shuffle files around
run: |
mkdir "release/${{ steps.parse_version.outputs.version }}"
mv release/*.zip "release/${{ steps.parse_version.outputs.version }}"
- name: Shuffle files around
run: |
mkdir "release/${{ steps.parse_version.outputs.version }}"
mv release/*.zip "release/${{ steps.parse_version.outputs.version }}"
- name: Upload files to centcomm
uses: appleboy/scp-action@master
with:
host: centcomm.spacestation14.io
username: robust-build-push
key: ${{ secrets.CENTCOMM_ROBUST_BUILDS_PUSH_KEY }}
source: "release/${{ steps.parse_version.outputs.version }}"
target: "/var/lib/robust-builds/builds/"
strip_components: 1
- name: Update manifest JSON
uses: appleboy/ssh-action@master
with:
host: centcomm.spacestation14.io
username: robust-build-push
key: ${{ secrets.CENTCOMM_ROBUST_BUILDS_PUSH_KEY }}
script: /home/robust-build-push/push.ps1 ${{ steps.parse_version.outputs.version }}
- name: Upload files to Suns
uses: appleboy/scp-action@master
with:
host: suns.spacestation14.com
username: robust-build-push
key: ${{ secrets.CENTCOMM_ROBUST_BUILDS_PUSH_KEY }}
source: "release/${{ steps.parse_version.outputs.version }}"
target: "/var/lib/robust-builds/builds/"
strip_components: 1
- name: Update manifest JSON
uses: appleboy/ssh-action@master
with:
host: suns.spacestation14.com
username: robust-build-push
key: ${{ secrets.CENTCOMM_ROBUST_BUILDS_PUSH_KEY }}
script: /home/robust-build-push/push.ps1 ${{ steps.parse_version.outputs.version }}

View File

@@ -2,40 +2,39 @@ name: Test content master against engine
on:
push:
branches: [ master ]
branches: [master]
pull_request:
branches: [ master ]
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out content
uses: actions/checkout@v3.6.0
with:
repository: space-wizards/space-station-14
submodules: recursive
- name: Check out content
uses: actions/checkout@v4.2.2
with:
repository: space-wizards/space-station-14
submodules: recursive
- name: Setup .NET Core
uses: actions/setup-dotnet@v3.2.0
with:
dotnet-version: 8.0.x
- name: Disable submodule autoupdate
run: touch BuildChecker/DISABLE_SUBMODULE_AUTOUPDATE
- name: Setup .NET Core
uses: actions/setup-dotnet@v4.1.0
with:
dotnet-version: 9.0.x
- name: Disable submodule autoupdate
run: touch BuildChecker/DISABLE_SUBMODULE_AUTOUPDATE
- name: Check out engine version
run: |
cd RobustToolbox
git fetch origin ${{ github.sha }}
git checkout FETCH_HEAD
git submodule update --init --recursive
- name: Install dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Tools --no-restore
- name: Content.Tests
run: dotnet test --no-build Content.Tests/Content.Tests.csproj -v n
- name: Content.IntegrationTests
run: COMPlus_gcServer=1 dotnet test --no-build Content.IntegrationTests/Content.IntegrationTests.csproj -v n
- name: Check out engine version
run: |
cd RobustToolbox
git fetch origin ${{ github.sha }}
git checkout FETCH_HEAD
git submodule update --init --recursive
- name: Install dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Tools --no-restore
- name: Content.Tests
run: dotnet test --no-build Content.Tests/Content.Tests.csproj -v n
- name: Content.IntegrationTests
run: COMPlus_gcServer=1 dotnet test --no-build Content.IntegrationTests/Content.IntegrationTests.csproj -v n

View File

@@ -1,64 +1,78 @@
<Project>
<PropertyGroup>
<!--
We actually set ManagePackageVersionsCentrally manually in another import file.
Since .NET SDK 8.0.300, ManagePackageVersionsCentrally is automatically set if Directory.Packages.props exists.
https://github.com/NuGet/NuGet.Client/pull/5572
We actively negate this here, as we have some packages in tree we don't want such automatic behavior for.
We use Directory.Build.props to get copy the state *after* our MSBuild config but before Nuget's config.
-->
<ManagePackageVersionsCentrally />
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="BenchmarkDotNet" Version="0.13.12" />
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" />
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
<PackageVersion Include="ILReader.Core" Version="1.0.0.4" />
<PackageVersion Include="JetBrains.Annotations" Version="2023.3.0" />
<PackageVersion Include="JetBrains.Profiler.Api" Version="1.4.0" />
<PackageVersion Include="Linguini.Bundle" Version="0.1.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzer.Testing" Version="1.1.1"/>
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.NUnit" Version="1.1.1"/>
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Features" Version="4.8.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.8.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.8.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="4.8.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.8.0" />
<PackageVersion Include="Microsoft.CodeCoverage" Version="17.8.0" />
<PackageVersion Include="Microsoft.Data.Sqlite.Core" Version="8.0.0" />
<PackageVersion Include="JetBrains.Annotations" Version="2024.3.0" />
<PackageVersion Include="JetBrains.Profiler.Api" Version="1.4.8" />
<PackageVersion Include="Linguini.Bundle" Version="0.8.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzer.Testing" Version="1.1.2" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing" Version="1.1.2" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing" Version="1.1.2" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Features" Version="4.12.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.12.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.12.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="4.12.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.12.0" />
<PackageVersion Include="Microsoft.CodeCoverage" Version="17.12.0" />
<PackageVersion Include="Microsoft.Data.Sqlite.Core" Version="9.0.0" />
<PackageVersion Include="Microsoft.DotNet.RemoteExecutor" Version="8.0.0-beta.24059.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Primitives" Version="8.0.0" />
<PackageVersion Include="Microsoft.ILVerification" Version="8.0.0" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
<PackageVersion Include="Microsoft.NET.ILLink.Tasks" Version="8.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Primitives" Version="9.0.0" />
<PackageVersion Include="Microsoft.ILVerification" Version="9.0.0" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
<PackageVersion Include="Microsoft.NET.ILLink.Tasks" Version="9.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageVersion Include="Moq" Version="4.20.70" />
<PackageVersion Include="NUnit" Version="4.0.1" />
<PackageVersion Include="NUnit.Analyzers" Version="3.10.0" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageVersion Include="Moq" Version="4.20.72" />
<PackageVersion Include="NUnit" Version="4.3.2" />
<PackageVersion Include="NUnit.Analyzers" Version="4.5.0" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageVersion Include="Nett" Version="0.15.0" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.4" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.2" />
<PackageVersion Include="OpenTK.OpenAL" Version="4.7.7" />
<PackageVersion Include="OpenToolkit.Graphics" Version="4.0.0-pre9.1" />
<PackageVersion Include="Pidgin" Version="3.2.2" />
<PackageVersion Include="Pidgin" Version="3.3.0" />
<PackageVersion Include="Robust.Natives" Version="0.1.1" />
<PackageVersion Include="Robust.Natives.Cef" Version="120.1.9" />
<PackageVersion Include="Robust.Natives.Cef" Version="131.3.5" />
<PackageVersion Include="Robust.Shared.AuthLib" Version="0.1.2" />
<PackageVersion Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.7" />
<PackageVersion Include="SQLitePCLRaw.provider.sqlite3" Version="2.1.7" />
<PackageVersion Include="Serilog" Version="3.1.1" />
<PackageVersion Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.10" />
<PackageVersion Include="SQLitePCLRaw.provider.sqlite3" Version="2.1.10" />
<PackageVersion Include="Serilog" Version="4.2.0" />
<PackageVersion Include="Serilog.Sinks.Loki" Version="4.0.0-beta3" />
<PackageVersion Include="SharpZstd.Interop" Version="1.5.2-beta2" />
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.5" />
<PackageVersion Include="SpaceWizards.HttpListener" Version="0.1.0" />
<PackageVersion Include="SpaceWizards.NFluidsynth" Version="0.1.1" />
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.7" />
<PackageVersion Include="SpaceWizards.HttpListener" Version="0.1.1" />
<PackageVersion Include="SpaceWizards.NFluidsynth" Version="0.2.2" />
<PackageVersion Include="SpaceWizards.SharpFont" Version="1.0.2" />
<PackageVersion Include="SpaceWizards.Sodium" Version="0.2.1" />
<PackageVersion Include="System.Numerics.Vectors" Version="4.5.0" />
<PackageVersion Include="System.Memory" Version="4.5.5" />
<PackageVersion Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
<PackageVersion Include="TerraFX.Interop.Windows" Version="10.0.22621.5" />
<PackageVersion Include="TerraFX.Interop.Windows" Version="10.0.26100.1" />
<PackageVersion Include="TerraFX.Interop.Xlib" Version="6.4.0" />
<PackageVersion Include="VorbisPizza" Version="1.3.0" />
<PackageVersion Include="YamlDotNet" Version="13.7.1" />
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
<PackageVersion Include="prometheus-net" Version="8.2.1" />
<PackageVersion Include="prometheus-net.DotNetRuntime" Version="4.4.0" />
<PackageVersion Include="PolySharp" Version="1.14.1" />
<PackageVersion Include="PolySharp" Version="1.15.0" />
<!-- Transitive deps that we need to pin versions for to avoid NuGet warnings. -->
<PackageVersion Include="System.Formats.Asn1" Version="9.0.0" />
<PackageVersion Include="System.Reflection.Metadata" Version="9.0.0" />
<PackageVersion Include="System.Text.Json" Version="9.0.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.12.0" />
</ItemGroup>
</Project>

View File

@@ -12,7 +12,7 @@
<SkipRobustAnalyzer>true</SkipRobustAnalyzer>
<Nullable>enable</Nullable>
<LangVersion>12.0</LangVersion>
<LangVersion>13.0</LangVersion>
</PropertyGroup>
<ItemGroup>

View File

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

View File

@@ -1,8 +1,8 @@
<Project>
<!-- Engine-specific properties. Content should not use this file. -->
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>12</LangVersion>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>13</LangVersion>
<Nullable>enable</Nullable>
<WarningsAsErrors>nullable</WarningsAsErrors>
</PropertyGroup>

View File

@@ -3,7 +3,7 @@
<!-- Import this at the end of any project files in Robust and Content. -->
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>

View File

@@ -71,6 +71,6 @@
</PropertyGroup>
<Exec
Condition="'$(_RobustUseExternalMSBuild)' == 'true'"
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"/>
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 /p:IntermediateOutputPath=&quot;$(IntermediateOutputPath.TrimEnd('\'))/&quot;"/>
</Target>
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -2,4 +2,7 @@
id: Audio
name: Audio
description: Audio entity used by engine
save: false
save: false
components:
- type: Transform
gridTraversal: false

View File

@@ -1,7 +1,7 @@
- type: entity
id: debugRotation
abstract: true
categories: [ debug ]
categories: [ Debug ]
components:
- type: Sprite
netsync: false

View File

@@ -4,6 +4,12 @@
kind: canvas
light_mode: unshaded
# Simple mix blend
- type: shader
id: Mix
kind: canvas
blend_mode: Mix
- type: shader
id: shaded
kind: canvas

View File

@@ -1,17 +1,26 @@
# debug related entities
- type: entityCategory
id: debug
id: Debug
name: entity-category-name-debug
description: entity-category-desc-debug
suffix: entity-category-suffix-debug
# entities that spawn other entities
- type: entityCategory
id: spawner
id: Spawner
name: entity-category-name-spawner
description: entity-category-desc-spawner
# entities that should be hidden from the spawn menu
# simple category that just exists to hide prototypes in spawn menus
- type: entityCategory
id: hideSpawnMenu
id: HideSpawnMenu
name: entity-category-name-hide
description: entity-category-desc-hide
hideSpawnMenu: true
inheritable: false
# Entity prototypes added by the fork. With CVar you can hide all entities without this category
- type: entityCategory
id: ForkFiltered
name: entity-category-name-fork
description: entity-category-desc-fork

View File

@@ -20,6 +20,15 @@ zzzz-object-pronoun = { GENDER($ent) ->
*[neuter] it
}
# Used internally by the DAT-OBJ() function.
# Not used in en-US. Created for supporting other languages.
zzzz-dat-object = { GENDER($ent) ->
[male] him
[female] her
[epicene] them
*[neuter] it
}
# Used internally by the POSS-PRONOUN() function.
zzzz-possessive-pronoun = { GENDER($ent) ->
[male] his

View File

@@ -1,5 +1,7 @@
### Localization for engine console commands
cmd-hint-float = [float]
## generic command errors
cmd-invalid-arg-number-error = Invalid number of arguments.
@@ -9,7 +11,9 @@ cmd-parse-failure-float = {$arg} is not a valid float.
cmd-parse-failure-bool = {$arg} is not a valid bool.
cmd-parse-failure-uid = {$arg} is not a valid entity UID.
cmd-parse-failure-mapid = {$arg} is not a valid MapId.
cmd-parse-failure-enum = {$arg} is not a {$enum} Enum.
cmd-parse-failure-grid = {$arg} is not a valid grid.
cmd-parse-failure-cultureinfo = "{$arg}" is not valid CultureInfo.
cmd-parse-failure-entity-exist = UID {$arg} does not correspond to an existing entity.
cmd-parse-failure-session = There is no session with username: {$username}
@@ -43,6 +47,13 @@ cmd-cvar-compl-list = List available CVars
cmd-cvar-arg-name = <name | ?>
cmd-cvar-value-hidden = <value hidden>
## 'cvar_subs' command
cmd-cvar_subs-desc = Lists the OnValueChanged subscriptions for a CVar.
cmd-cvar_subs-help = Usage: cvar_subs <name>
cmd-cvar_subs-invalid-args = Must provide exactly one argument.
cmd-cvar_subs-arg-name = <name>
## 'list' command
cmd-list-desc = Lists available commands, with optional search filter
cmd-list-help = Usage: list [filter]
@@ -148,6 +159,7 @@ cmd-savemap-not-exist = Target map does not exist.
cmd-savemap-init-warning = Attempted to save a post-init map without forcing the save.
cmd-savemap-attempt = Attempting to save map {$mapId} to {$path}.
cmd-savemap-success = Map successfully saved.
cmd-savemap-error = Could not save map! See server log for details.
cmd-hint-savemap-id = <MapID>
cmd-hint-savemap-path = <Path>
cmd-hint-savemap-force = [bool]
@@ -245,9 +257,6 @@ cmd-bind-arg-command = <InputCommand>
cmd-net-draw-interp-desc = Toggles the debug drawing of the network interpolation.
cmd-net-draw-interp-help = Usage: net_draw_interp
cmd-net-draw-interp-desc = Toggles the debug drawing of the network interpolation.
cmd-net-draw-interp-help = Usage: net_draw_interp
cmd-net-watch-ent-desc = Dumps all network updates for an EntityId to the console.
cmd-net-watch-ent-help = Usage: net_watchent <0|EntityUid>
@@ -288,7 +297,7 @@ cmd-lsgrid-desc = Lists grids.
cmd-lsgrid-help = lsgrid
cmd-addmap-desc = Adds a new empty map to the round. If the mapID already exists, this command does nothing.
cmd-addmap-help = addmap <mapID> [initialize]
cmd-addmap-help = addmap <mapID> [pre-init]
cmd-rmmap-desc = Removes a map from the world. You cannot remove nullspace.
cmd-rmmap-help = rmmap <mapId>
@@ -299,16 +308,9 @@ cmd-savegrid-help = savegrid <gridID> <Path>
cmd-testbed-desc = Loads a physics testbed on the specified map.
cmd-testbed-help = testbed <mapid> <test>
cmd-saveconfig-desc = Saves the client configuration to the config file.
cmd-saveconfig-help = saveconfig
## 'flushcookies' command
# Note: the flushcookies command is from Robust.Client.WebView, it's not in the main engine code.
cmd-flushcookies-desc = Flush CEF cookie storage to disk
cmd-flushcookies-help = This ensure cookies are properly saved to disk in the event of unclean shutdowns.
Note that the actual operation is asynchronous.
## 'addcomp' command
cmd-addcomp-desc = Adds a component to an entity.
cmd-addcomp-help = addcomp <uid> <componentName>
@@ -384,9 +386,9 @@ cmd-tp-desc = Teleports a player to any location in the round.
cmd-tp-help = tp <x> <y> [<mapID>]
cmd-tpto-desc = Teleports the current player or the specified players/entities to the location of the first player/entity.
cmd-tpto-help = tpto <username|uid> [username|uid]...
cmd-tpto-destination-hint = destination (uid or username)
cmd-tpto-victim-hint = entity to teleport (uid or username)
cmd-tpto-help = tpto <username|uid> [username|NetEntity]...
cmd-tpto-destination-hint = destination (NetEntity or username)
cmd-tpto-victim-hint = entity to teleport (NetEntity or username)
cmd-tpto-parse-error = Cant resolve entity or player: {$str}
cmd-listplayers-desc = Lists all players currently connected.
@@ -429,11 +431,20 @@ cmd-entfo-help = Usage: entfo <entityuid>
The entity UID can be prefixed with 'c' to convert it to a client entity UID.
cmd-fuck-desc = Throws an exception
cmd-fuck-help = Throws an exception
cmd-fuck-help = Usage: fuck
cmd-showpos-desc = Enables debug drawing over all entity positions in the game.
cmd-showpos-desc = Show the position of all entities on the screen.
cmd-showpos-help = Usage: showpos
cmd-showrot-desc = Show the rotation of all entities on the screen.
cmd-showrot-help = Usage: showrot
cmd-showvel-desc = Show the local velocity of all entites on the screen.
cmd-showvel-help = Usage: showvel
cmd-showangvel-desc = Show the angular velocity of all entities on the screen.
cmd-showangvel-help = Usage: showangvel
cmd-sggcell-desc = Lists entities on a snap grid cell.
cmd-sggcell-help = Usage: sggcell <gridID> <vector2i>\nThat vector2i param is in the form x<int>,y<int>.
@@ -446,9 +457,6 @@ cmd-showanchored-help = Usage: showanchored
cmd-dmetamem-desc = Dumps a type's members in a format suitable for the sandbox configuration file.
cmd-dmetamem-help = Usage: dmetamem <type>
cmd-dmetamem-desc = Displays chunk bounds for the purposes of rendering.
cmd-dmetamem-help = Usage: showchunkbb <type>
cmd-launchauth-desc = Load authentication tokens from launcher data to aid in testing of live servers.
cmd-launchauth-help = Usage: launchauth <account name>
@@ -515,9 +523,6 @@ cmd-profsnap-help = Usage: profsnap
cmd-devwindow-desc = Dev Window
cmd-devwindow-help = Usage: devwindow
cmd-devwindow-desc = Open file
cmd-devwindow-help = Usage: testopenfile
cmd-scene-desc = Immediately changes the UI scene/state.
cmd-scene-help = Usage: scene <className>
@@ -528,14 +533,11 @@ cmd-hwid-desc = Returns the current HWID (HardWare ID).
cmd-hwid-help = Usage: hwid
cmd-vvread-desc = Retrieve a path's value using VV (View Variables).
cmd-vvread-desc = Usage: vvread <path>
cmd-vvread-help = Usage: vvread <path>
cmd-vvwrite-desc = Modify a path's value using VV (View Variables).
cmd-vvwrite-help = Usage: vvwrite <path>
cmd-vv-desc = Opens View Variables (VV).
cmd-vv-help = Usage: vv <path|entity ID|guihover>
cmd-vvinvoke-desc = Invoke/Call a path with arguments using VV.
cmd-vvinvoke-help = Usage: vvinvoke <path> [arguments...]
@@ -573,3 +575,8 @@ cmd-pvs-override-info-desc = Prints information about any PVS overrides associat
cmd-pvs-override-info-empty = Entity {$nuid} has no PVS overrides.
cmd-pvs-override-info-global = Entity {$nuid} has a global override.
cmd-pvs-override-info-clients = Entity {$nuid} has a session override for {$clients}.
cmd-localization_set_culture-desc = Set DefaultCulture for the client LocalizationManager
cmd-localization_set_culture-help = Usage: localization_set_culture <cultureName>
cmd-localization_set_culture-culture-name = <cultureName>
cmd-localization_set_culture-changed = Localization changed to { $code } ({ $nativeName } / { $englishName })

View File

@@ -4,9 +4,21 @@ entity-spawn-window-title = Entity Spawn Panel
entity-spawn-window-search-bar-placeholder = search
entity-spawn-window-clear-button = Clear
entity-spawn-window-replace-button-text = Replace
entity-spawn-window-erase-button-text = Erase Mode
entity-spawn-window-override-menu-tooltip = Override placement
## TileSpawnWindow
tile-spawn-window-title = Place Tiles
tile-spawn-window-mirror-button-text = Mirror Tiles
## Console
console-line-edit-placeholder = Command Here
## OutputPanel
output-panel-scroll-down-button-text = Scroll Down
## Common Used
window-erase-button-text = Erase Mode

View File

@@ -0,0 +1,10 @@
## "Textures" dev window tab
dev-window-tab-textures-title = Textures
dev-window-tab-textures-reload = Reload
dev-window-tab-textures-filter = Filter
dev-window-tab-textures-summary = Total (est): { $bytes }
dev-window-tab-textures-info = Width: { $width } Height: { $height }
PixelType: { $pixelType } sRGB: { $srgb }
Name: { $name }
Est. memory usage: { $bytes }

View File

@@ -1,8 +1,12 @@
entity-category-name-debug = Debug
entity-category-desc-debug = Entity prototypes intended for debugging & testing.
entity-category-suffix-debug = Debug
entity-category-name-spawner = Spawner
entity-category-desc-spawner = Entity prototypes that spawn other entities.
entity-category-name-hide = Hidden
entity-category-desc-hide = Entity prototypes that should be hidden from the spawn menu
entity-category-desc-hide = Entity prototypes that should be hidden from entity spawn menus
entity-category-name-fork = Fork Filtered
entity-category-desc-fork = Entity prototypes added by the fork. With CVar you can hide all entities without this category

View File

@@ -1,4 +1,8 @@
command-description-tpto =
command-help-usage =
Usage:
command-help-invertible =
The behaviour of this command can be inverted using the "not" prefix.
command-description-tpto =
Teleport the given entities to some target entity.
command-description-player-list =
Returns a list of all player sessions.
@@ -19,7 +23,7 @@ command-description-buildinfo =
command-description-cmd-list =
Returns a list of all commands, for this side.
command-description-explain =
Explains the given expression, providing command descriptions and signatures.
Explains the given expression, providing command descriptions and signatures. This only works for valid expressions, it can't explain commands that it fails to parse.
command-description-search =
Searches through the input for the provided value.
command-description-stopwatch =
@@ -38,8 +42,7 @@ command-description-as =
command-description-count =
Counts the amount of entries in it's input, returning an integer.
command-description-map =
Maps the input over the given block, with the provided expected return type.
This command may be modified to not need an explicit return type in the future.
Maps the input over the given block.
command-description-select =
Selects N objects or N% of objects from the input.
One can additionally invert this command with not to make it select everything except N objects instead.
@@ -53,10 +56,8 @@ command-description-entities =
Returns all entities on the server.
command-description-paused =
Filters the input entities by whether or not they are paused.
This command can be inverted with not.
command-description-with =
Filters the input entities by whether or not they have the given component.
This command can be inverted with not.
command-description-fuck =
Throws an exception.
command-description-ecscomp-listty =
@@ -95,6 +96,8 @@ command-description-vars =
Provides a list of all variables set in this session.
command-description-any =
Returns true if there's any values in the input, otherwise false.
command-description-contains =
Returns whether the input enumerable contains the specified value.
command-description-ArrowCommand =
Assigns the input to a variable.
command-description-isempty =
@@ -119,6 +122,8 @@ command-description-splat =
"Splats" a block, value, or variable, creating N copies of it in a list.
command-description-val =
Casts the given value, block, or variable to the given type. This is mostly a workaround for current limitations of variables.
command-description-var =
Returns the contents of the given variable. This will attempt to automatically infer a variables type. Compound commands that modify a variable may need to use the 'val' command instead.
command-description-actor-controlled =
Filters entities by whether or not they're actively controlled.
command-description-actor-session =
@@ -143,7 +148,7 @@ command-description-max =
Returns the maximum of two values.
command-description-BitAndCommand =
Performs bitwise AND.
command-description-BitOrCommand =
command-description-bitor =
Performs bitwise OR.
command-description-BitXorCommand =
Performs bitwise XOR.
@@ -197,11 +202,11 @@ command-description-mappos =
command-description-pos =
Returns an entity's coordinates.
command-description-tp-coords =
Teleports the target to the given coordinates.
Teleports the given entities to the target coordinates.
command-description-tp-to =
Teleports the target to the given other entity.
Teleports the given entities to the target entity.
command-description-tp-into =
Teleports the target "into" the given other entity, attaching it at (0 0) relative to it.
Teleports the given entities "into" the target entity, attaching it at (0 0) relative to it.
command-description-comp-get =
Gets the given component from the given entity.
command-description-comp-add =
@@ -219,9 +224,9 @@ command-description-MulVecCommand =
command-description-DivVecCommand =
Divides every element in the input by a scalar (single value).
command-description-rng-to =
Returns a number from its input to its argument (i.e. n..m inclusive)
Returns a number between the input (inclusive) and the argument (exclusive).
command-description-rng-from =
Returns a number to its input from its argument (i.e. m..n inclusive)
Returns a number between the argument (inclusive) and the input (exclusive))
command-description-rng-prob =
Returns a boolean based on the input probability/chance (from 0 to 1)
command-description-sum =
@@ -271,7 +276,7 @@ command-description-ModVecCommand =
Performs the modulus operation over the input with the given constant right-hand value.
command-description-BitAndNotCommand =
Performs bitwise AND-NOT over the input.
command-description-BitOrNotCommand =
command-description-bitornot =
Performs bitwise OR-NOT over the input.
command-description-BitXnorCommand =
Performs bitwise XNOR over the input.

View File

@@ -0,0 +1,2 @@
popup-copy-button = Copy
popup-title = Alert!

View File

@@ -136,6 +136,7 @@ cmd-savemap-not-exist = O mapa de destino não existe.
cmd-savemap-init-warning = Tentativa de salvar um mapa pós-inicialização sem forçar o salvamento.
cmd-savemap-attempt = Tentando salvar o mapa {$mapId} em {$path}.
cmd-savemap-success = Mapa salvo com sucesso.
cmd-savemap-error = Não foi possível salvar o mapa! Consulte o log do servidor para obter detalhes.
cmd-hint-savemap-id = <MapID>
cmd-hint-savemap-path = <Path>
cmd-hint-savemap-force = [bool]

View File

@@ -1,12 +1,8 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.CodeAnalysis.Testing.Verifiers;
using NUnit.Framework;
using Robust.Analyzers;
using VerifyCS = Microsoft.CodeAnalysis.CSharp.Testing.NUnit.AnalyzerVerifier<Robust.Analyzers.AccessAnalyzer>;
using static Microsoft.CodeAnalysis.Testing.DiagnosticResult;
using VerifyCS = Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Robust.Analyzers.AccessAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
namespace Robust.Analyzers.Tests;
@@ -16,7 +12,7 @@ public sealed class AccessAnalyzer_Test
{
public Task Verifier(string code, params DiagnosticResult[] expected)
{
var test = new CSharpAnalyzerTest<AccessAnalyzer, NUnitVerifier>()
var test = new CSharpAnalyzerTest<AccessAnalyzer, DefaultVerifier>()
{
TestState =
{

View File

@@ -0,0 +1,114 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using NUnit.Framework;
using VerifyCS =
Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Robust.Analyzers.ByRefEventAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
namespace Robust.Analyzers.Tests;
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
[TestFixture, TestOf(typeof(ByRefEventAnalyzer))]
public sealed class ByRefEventAnalyzerTest
{
private const string EventBusDef = """
namespace Robust.Shared.GameObjects;
public readonly struct EntityUid;
public sealed class EntitySystem
{
public void RaiseLocalEvent<TEvent>(EntityUid uid, ref TEvent args, bool broadcast = false)
where TEvent : notnull { }
public void RaiseLocalEvent<TEvent>(EntityUid uid, TEvent args, bool broadcast = false)
where TEvent : notnull { }
}
public sealed class EntityEventBus
{
public void RaiseLocalEvent<TEvent>(EntityUid uid, ref TEvent args, bool broadcast = false)
where TEvent : notnull { }
public void RaiseLocalEvent<TEvent>(EntityUid uid, TEvent args, bool broadcast = false)
where TEvent : notnull { }
}
""";
private static Task Verifier(string code, params DiagnosticResult[] expected)
{
var test = new CSharpAnalyzerTest<ByRefEventAnalyzer, DefaultVerifier>()
{
TestState =
{
Sources = { code }
},
};
TestHelper.AddEmbeddedSources(
test.TestState,
"Robust.Shared.GameObjects.EventBusAttributes.cs"
);
test.TestState.Sources.Add(("EntityEventBus.cs", EventBusDef));
// ExpectedDiagnostics cannot be set, so we need to AddRange here...
test.TestState.ExpectedDiagnostics.AddRange(expected);
return test.RunAsync();
}
[Test]
public async Task TestSuccess()
{
const string code = """
using Robust.Shared.GameObjects;
[ByRefEvent]
public readonly struct RefEvent;
public readonly struct ValueEvent;
public static class Foo
{
public static void Bar(EntityEventBus bus)
{
bus.RaiseLocalEvent(default(EntityUid), new ValueEvent());
var refEv = new RefEvent();
bus.RaiseLocalEvent(default(EntityUid), ref refEv);
}
}
""";
await Verifier(code);
}
[Test]
public async Task TestWrong()
{
const string code = """
using Robust.Shared.GameObjects;
[ByRefEvent]
public readonly struct RefEvent;
public readonly struct ValueEvent;
public static class Foo
{
public static void Bar(EntityEventBus bus)
{
bus.RaiseLocalEvent(default(EntityUid), new RefEvent());
var valueEv = new ValueEvent();
bus.RaiseLocalEvent(default(EntityUid), ref valueEv);
}
}
""";
await Verifier(
code,
// /0/Test0.cs(11,49): error RA0015: Tried to raise a by-ref event 'RefEvent' by value
VerifyCS.Diagnostic(ByRefEventAnalyzer.ByRefEventRaisedByValueRule).WithSpan(11, 49, 11, 63).WithArguments("RefEvent"),
// /0/Test0.cs(13,49): error RA0016: Tried to raise a value event 'ValueEvent' by-ref
VerifyCS.Diagnostic(ByRefEventAnalyzer.ByValueEventRaisedByRefRule).WithSpan(13, 49, 13, 60).WithArguments("ValueEvent")
);
}
}

View File

@@ -66,6 +66,7 @@ public sealed class ComponentPauseGeneratorTest
public partial class FooComponent
{
[RobustAutoGenerated]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public sealed class FooComponent_AutoPauseSystem : EntitySystem
{
public override void Initialize()
@@ -106,6 +107,7 @@ public sealed class ComponentPauseGeneratorTest
public partial class FooComponent
{
[RobustAutoGenerated]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public sealed class FooComponent_AutoPauseSystem : EntitySystem
{
public override void Initialize()
@@ -147,6 +149,7 @@ public sealed class ComponentPauseGeneratorTest
public partial class FooComponent
{
[RobustAutoGenerated]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public sealed class FooComponent_AutoPauseSystem : EntitySystem
{
public override void Initialize()
@@ -188,6 +191,7 @@ public sealed class ComponentPauseGeneratorTest
public partial class FooComponent
{
[RobustAutoGenerated]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public sealed class FooComponent_AutoPauseSystem : EntitySystem
{
public override void Initialize()

View File

@@ -0,0 +1,174 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using NUnit.Framework;
using VerifyCS =
Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Robust.Analyzers.DataDefinitionAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
namespace Robust.Analyzers.Tests;
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
[TestFixture]
public sealed class DataDefinitionAnalyzerTest
{
private static Task Verifier(string code, params DiagnosticResult[] expected)
{
var test = new CSharpAnalyzerTest<DataDefinitionAnalyzer, DefaultVerifier>()
{
TestState =
{
Sources = { code }
},
};
test.TestState.Sources.Add(("TestTypeDefs.cs", TestTypeDefs));
// ExpectedDiagnostics cannot be set, so we need to AddRange here...
test.TestState.ExpectedDiagnostics.AddRange(expected);
return test.RunAsync();
}
private const string TestTypeDefs = """
using System;
namespace Robust.Shared.ViewVariables
{
public sealed class ViewVariablesAttribute : Attribute
{
public readonly VVAccess Access = VVAccess.ReadOnly;
public ViewVariablesAttribute() { }
public ViewVariablesAttribute(VVAccess access)
{
Access = access;
}
}
public enum VVAccess : byte
{
ReadOnly = 0,
ReadWrite = 1,
}
}
namespace Robust.Shared.Serialization.Manager.Attributes
{
public class DataFieldBaseAttribute : Attribute;
public class DataFieldAttribute : DataFieldBaseAttribute;
public sealed class DataDefinitionAttribute : Attribute;
public sealed class NotYamlSerializableAttribute : Attribute;
}
""";
[Test]
public async Task NoVVReadOnlyTest()
{
const string code = """
using Robust.Shared.ViewVariables;
using Robust.Shared.Serialization.Manager.Attributes;
[DataDefinition]
public sealed partial class Foo
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public int Bad;
[DataField]
public int Good;
[DataField, ViewVariables]
public int Good2;
[DataField, ViewVariables(VVAccess.ReadOnly)]
public int Good3;
[ViewVariables]
public int Good4;
}
""";
await Verifier(code,
// /0/Test0.cs(7,17): info RA0028: Data field Bad in data definition Foo has ViewVariables attribute with ReadWrite access, which is redundant
VerifyCS.Diagnostic(DataDefinitionAnalyzer.DataFieldNoVVReadWriteRule).WithSpan(7, 17, 7, 50).WithArguments("Bad", "Foo")
);
}
[Test]
public async Task ReadOnlyFieldTest()
{
const string code = """
using Robust.Shared.Serialization.Manager.Attributes;
[DataDefinition]
public sealed partial class Foo
{
[DataField]
public readonly int Bad;
[DataField]
public int Good;
}
""";
await Verifier(code,
// /0/Test0.cs(7,12): error RA0019: Data field Bad in data definition Foo is readonly
VerifyCS.Diagnostic(DataDefinitionAnalyzer.DataFieldWritableRule).WithSpan(7, 12, 7, 20).WithArguments("Bad", "Foo")
);
}
[Test]
public async Task ReadOnlyPropertyTest()
{
const string code = """
using Robust.Shared.Serialization.Manager.Attributes;
[DataDefinition]
public sealed partial class Foo
{
[DataField]
public int Bad { get; }
[DataField]
public int Good { get; private set; }
}
""";
await Verifier(code,
// /0/Test0.cs(7,20): error RA0020: Data field property Bad in data definition Foo does not have a setter
VerifyCS.Diagnostic(DataDefinitionAnalyzer.DataFieldPropertyWritableRule).WithSpan(7, 20, 7, 28).WithArguments("Bad", "Foo")
);
}
[Test]
public async Task NotYamlSerializableTest()
{
const string code = """
using Robust.Shared.Serialization.Manager.Attributes;
[NotYamlSerializable]
public sealed class NotSerializableClass { }
[DataDefinition]
public sealed partial class Foo
{
[DataField]
public NotSerializableClass BadField;
[DataField]
public NotSerializableClass BadProperty { get; set; }
public NotSerializableClass GoodField; // Not a DataField, not a problem
public NotSerializableClass GoodProperty { get; set; } // Not a DataField, not a problem
}
""";
await Verifier(code,
// /0/Test0.cs(10,12): error RA0033: Data field BadField in data definition Foo is type NotSerializableClass, which is not YAML serializable
VerifyCS.Diagnostic(DataDefinitionAnalyzer.DataFieldYamlSerializableRule).WithSpan(10, 12, 10, 32).WithArguments("BadField", "Foo", "NotSerializableClass"),
// /0/Test0.cs(13,12): error RA0033: Data field BadProperty in data definition Foo is type NotSerializableClass, which is not YAML serializable
VerifyCS.Diagnostic(DataDefinitionAnalyzer.DataFieldYamlSerializableRule).WithSpan(13, 12, 13, 32).WithArguments("BadProperty", "Foo", "NotSerializableClass")
);
}
}

View File

@@ -1,10 +1,9 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.CodeAnalysis.Testing.Verifiers;
using NUnit.Framework;
using VerifyCS =
Microsoft.CodeAnalysis.CSharp.Testing.NUnit.AnalyzerVerifier<Robust.Analyzers.DependencyAssignAnalyzer>;
Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Robust.Analyzers.DependencyAssignAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
namespace Robust.Analyzers.Tests;
@@ -14,7 +13,7 @@ public sealed class DependencyAssignAnalyzerTest
{
private static Task Verifier(string code, params DiagnosticResult[] expected)
{
var test = new CSharpAnalyzerTest<DependencyAssignAnalyzer, NUnitVerifier>()
var test = new CSharpAnalyzerTest<DependencyAssignAnalyzer, DefaultVerifier>()
{
TestState =
{

View File

@@ -0,0 +1,62 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using NUnit.Framework;
using VerifyCS =
Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Robust.Analyzers.DuplicateDependencyAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
namespace Robust.Analyzers.Tests;
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
[TestFixture]
[TestOf(typeof(DuplicateDependencyAnalyzer))]
public sealed class DuplicateDependencyAnalyzerTest
{
private static Task Verifier(string code, params DiagnosticResult[] expected)
{
var test = new CSharpAnalyzerTest<DuplicateDependencyAnalyzer, DefaultVerifier>()
{
TestState =
{
Sources = { code }
},
};
TestHelper.AddEmbeddedSources(
test.TestState,
"Robust.Shared.IoC.DependencyAttribute.cs"
);
// ExpectedDiagnostics cannot be set, so we need to AddRange here...
test.TestState.ExpectedDiagnostics.AddRange(expected);
return test.RunAsync();
}
[Test]
public async Task Test()
{
const string code = """
using Robust.Shared.IoC;
public sealed class Foo
{
[Dependency]
private object? Field;
[Dependency]
private object? Field2;
[Dependency]
private string? DifferentField;
private string? NonDependency1;
private string? NonDependency2;
}
""";
await Verifier(code,
// /0/Test0.cs(9,21): warning RA0032: Another [Dependency] field of type 'object?' already exists in this type as field 'Field'
VerifyCS.Diagnostic().WithSpan(9, 21, 9, 27).WithArguments("object?", "Field"));
}
}

View File

@@ -0,0 +1,189 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using NUnit.Framework;
using VerifyCS =
Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Robust.Analyzers.ForbidLiteralAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
namespace Robust.Analyzers.Tests;
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
[TestFixture]
public sealed class ForbidLiteralAnalyzerTest
{
private static Task Verifier(string code, params DiagnosticResult[] expected)
{
var test = new CSharpAnalyzerTest<ForbidLiteralAnalyzer, DefaultVerifier>()
{
TestState =
{
Sources = { code },
},
};
TestHelper.AddEmbeddedSources(
test.TestState,
"Robust.Shared.Analyzers.ForbidLiteralAttribute.cs"
);
test.TestState.Sources.Add(("TestTypeDefs.cs", TestTypeDefs));
// ExpectedDiagnostics cannot be set, so we need to AddRange here...
test.TestState.ExpectedDiagnostics.AddRange(expected);
return test.RunAsync();
}
private const string TestTypeDefs = """
using System.Collections.Generic;
using Robust.Shared.Analyzers;
public sealed class TestClass
{
public static void OneParameterForbidden([ForbidLiteral] string value) { }
public static void TwoParametersFirstForbidden([ForbidLiteral] string first, string second) { }
public static void TwoParametersBothForbidden([ForbidLiteral] string first, [ForbidLiteral] string second) { }
public static void ListParameterForbidden([ForbidLiteral] List<string> values) { }
public static void ParamsListParameterForbidden([ForbidLiteral] params List<string> values) { }
}
public record struct StringWrapper(string value)
{
private readonly string _value = value;
public static implicit operator string(StringWrapper wrapper)
{
return wrapper._value;
}
}
""";
[Test]
public async Task TestOneParameter()
{
const string code = """
public sealed class Tester
{
private const string _constValue = "foo";
private static readonly string StaticValue = "bar";
private static readonly StringWrapper WrappedValue = new("biz");
public void Test()
{
TestClass.OneParameterForbidden(_constValue);
TestClass.OneParameterForbidden(StaticValue);
TestClass.OneParameterForbidden(WrappedValue);
TestClass.OneParameterForbidden("baz");
}
}
""";
await Verifier(code,
// /0/Test0.cs(12,41): error RA0033: The "value" parameter of OneParameterForbidden forbids literal values
VerifyCS.Diagnostic().WithSpan(12, 41, 12, 46).WithArguments("value", "OneParameterForbidden")
);
}
[Test]
public async Task TestTwoParametersFirstForbidden()
{
const string code = """
public sealed class Tester
{
private const string _constValue = "foo";
public void Test()
{
TestClass.TwoParametersFirstForbidden(_constValue, "whatever");
TestClass.TwoParametersFirstForbidden(_constValue, _constValue);
TestClass.TwoParametersFirstForbidden("foo", "whatever");
}
}
""";
await Verifier(code,
// /0/Test0.cs(9,47): error RA0033: The "first" parameter of TwoParametersFirstForbidden forbids literal values
VerifyCS.Diagnostic().WithSpan(9, 47, 9, 52).WithArguments("first", "TwoParametersFirstForbidden")
);
}
[Test]
public async Task TestTwoParametersBothForbidden()
{
const string code = """
public sealed class Tester
{
private const string _constValue = "foo";
private static readonly string StaticValue = "bar";
public void Test()
{
TestClass.TwoParametersBothForbidden(_constValue, _constValue);
TestClass.TwoParametersBothForbidden(_constValue, StaticValue);
TestClass.TwoParametersBothForbidden(_constValue, "whatever");
TestClass.TwoParametersBothForbidden("whatever", _constValue);
}
}
""";
await Verifier(code,
// /0/Test0.cs(10,59): error RA0033: The "second" parameter of TwoParametersBothForbidden forbids literal values
VerifyCS.Diagnostic().WithSpan(10, 59, 10, 69).WithArguments("second", "TwoParametersBothForbidden"),
// /0/Test0.cs(11,46): error RA0033: The "first" parameter of TwoParametersBothForbidden forbids literal values
VerifyCS.Diagnostic().WithSpan(11, 46, 11, 56).WithArguments("first", "TwoParametersBothForbidden")
);
}
[Test]
public async Task TestListParameter()
{
const string code = """
public sealed class Tester
{
private const string _constValue = "foo";
private static readonly string StaticValue = "bar";
private static readonly StringWrapper WrappedValue = new("biz");
public void Test()
{
TestClass.ListParameterForbidden([_constValue, StaticValue, WrappedValue]);
TestClass.ListParameterForbidden(["foo", _constValue, "bar"]);
}
}
""";
await Verifier(code,
// /0/Test0.cs(10,43): warning RA0033: The "values" parameter of ListParameterForbidden forbids literal values
VerifyCS.Diagnostic().WithSpan(10, 43, 10, 48).WithArguments("values", "ListParameterForbidden"),
// /0/Test0.cs(10,63): warning RA0033: The "values" parameter of ListParameterForbidden forbids literal values
VerifyCS.Diagnostic().WithSpan(10, 63, 10, 68).WithArguments("values", "ListParameterForbidden")
);
}
[Test]
public async Task TestParamsListParameter()
{
const string code = """
public sealed class Tester
{
private const string _constValue = "foo";
private static readonly string StaticValue = "bar";
private static readonly StringWrapper WrappedValue = new("biz");
public void Test()
{
TestClass.ParamsListParameterForbidden(_constValue, StaticValue, WrappedValue);
TestClass.ParamsListParameterForbidden("foo", _constValue, "bar");
}
}
""";
await Verifier(code,
// /0/Test0.cs(10,48): warning RA0033: The "values" parameter of ParamsListParameterForbidden forbids literal values
VerifyCS.Diagnostic().WithSpan(10, 48, 10, 53).WithArguments("values", "ParamsListParameterForbidden"),
// /0/Test0.cs(10,68): warning RA0033: The "values" parameter of ParamsListParameterForbidden forbids literal values
VerifyCS.Diagnostic().WithSpan(10, 68, 10, 73).WithArguments("values", "ParamsListParameterForbidden")
);
}
}

View File

@@ -0,0 +1,91 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using NUnit.Framework;
using VerifyCS =
Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Robust.Analyzers.MustCallBaseAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
namespace Robust.Analyzers.Tests;
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
[TestFixture]
public sealed class MustCallBaseAnalyzerTest
{
private static Task Verifier(string code, params DiagnosticResult[] expected)
{
var test = new CSharpAnalyzerTest<MustCallBaseAnalyzer, DefaultVerifier>()
{
TestState =
{
Sources = { code }
},
};
TestHelper.AddEmbeddedSources(
test.TestState,
"Robust.Shared.IoC.MustCallBaseAttribute.cs"
);
// ExpectedDiagnostics cannot be set, so we need to AddRange here...
test.TestState.ExpectedDiagnostics.AddRange(expected);
return test.RunAsync();
}
[Test]
public async Task Test()
{
const string code = """
using Robust.Shared.Analyzers;
public class Foo
{
[MustCallBase]
public virtual void Function()
{
}
[MustCallBase(true)]
public virtual void Function2()
{
}
}
public class Bar : Foo
{
public override void Function()
{
}
public override void Function2()
{
}
}
public class Baz : Foo
{
public override void Function()
{
base.Function();
}
}
public class Bal : Bar
{
public override void Function2()
{
}
}
""";
await Verifier(code,
// /0/Test0.cs(20,26): warning RA0028: Overriders of this function must always call the base function
VerifyCS.Diagnostic().WithSpan(20, 26, 20, 34),
// /0/Test0.cs(41,26): warning RA0028: Overriders of this function must always call the base function
VerifyCS.Diagnostic().WithSpan(41, 26, 41, 35));
}
}

View File

@@ -0,0 +1,56 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using NUnit.Framework;
using VerifyCS =
Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Robust.Analyzers.NoUncachedRegexAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
namespace Robust.Analyzers.Tests;
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
[TestFixture]
public sealed class NoUncachedRegexAnalyzerTest
{
private static Task Verifier(string code, params DiagnosticResult[] expected)
{
var test = new CSharpAnalyzerTest<NoUncachedRegexAnalyzer, DefaultVerifier>()
{
TestState =
{
Sources = { code }
},
};
// ExpectedDiagnostics cannot be set, so we need to AddRange here...
test.TestState.ExpectedDiagnostics.AddRange(expected);
return test.RunAsync();
}
[Test]
public async Task Test()
{
const string code = """
using System.Text.RegularExpressions;
public static class Foo
{
public static void Bad()
{
Regex.Replace("foo", "bar", "baz");
}
public static void Good()
{
var r = new Regex("bar");
r.Replace("foo", "baz");
}
}
""";
await Verifier(code,
// /0/Test0.cs(7,9): warning RA0026: Usage of a static Regex function that takes in a pattern string. This can cause constant re-parsing of the pattern.
VerifyCS.Diagnostic().WithSpan(7, 9, 7, 43)
);
}
}

View File

@@ -0,0 +1,86 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using NUnit.Framework;
using VerifyCS =
Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Robust.Analyzers.ObsoleteInheritanceAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
namespace Robust.Analyzers.Tests;
/// <summary>
/// Analyzer that implements <c>[ObsoleteInheritance]</c> checking, to give obsoletion warnings for inheriting types
/// that should never have been virtual.
/// </summary>
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
[TestFixture]
public sealed class ObsoleteInheritanceAnalyzerTest
{
private static Task Verifier(string code, params DiagnosticResult[] expected)
{
var test = new CSharpAnalyzerTest<ObsoleteInheritanceAnalyzer, DefaultVerifier>()
{
TestState =
{
Sources = { code },
},
};
TestHelper.AddEmbeddedSources(
test.TestState,
"Robust.Shared.Analyzers.ObsoleteInheritanceAttribute.cs"
);
// ExpectedDiagnostics cannot be set, so we need to AddRange here...
test.TestState.ExpectedDiagnostics.AddRange(expected);
return test.RunAsync();
}
[Test]
public async Task TestBasic()
{
const string code = """
using Robust.Shared.Analyzers;
[ObsoleteInheritance]
public class Base;
public class NotAllowed : Base;
""";
await Verifier(code,
// /0/Test0.cs(6,14): warning RA0034: Type 'NotAllowed' inherits from 'Base', which has obsoleted inheriting from itself
VerifyCS.Diagnostic(ObsoleteInheritanceAnalyzer.Rule).WithSpan(6, 14, 6, 24).WithArguments("NotAllowed", "Base")
);
}
[Test]
public async Task TestMessage()
{
const string code = """
using Robust.Shared.Analyzers;
[ObsoleteInheritance("Sus")]
public class Base;
public class NotAllowed : Base;
""";
await Verifier(code,
// /0/Test0.cs(6,14): warning RA0034: Type 'NotAllowed' inherits from 'Base', which has obsoleted inheriting from itself: "Sus"
VerifyCS.Diagnostic(ObsoleteInheritanceAnalyzer.RuleWithMessage).WithSpan(6, 14, 6, 24).WithArguments("NotAllowed", "Base", "Sus")
);
}
[Test]
public async Task TestNormal()
{
const string code = """
public class Base;
public class AllowedAllowed : Base;
""";
await Verifier(code);
}
}

View File

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

View File

@@ -0,0 +1,61 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using NUnit.Framework;
using VerifyCS =
Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Robust.Analyzers.PreferOtherTypeAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
namespace Robust.Analyzers.Tests;
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
[TestFixture]
public sealed class PreferOtherTypeAnalyzerTest
{
private static Task Verifier(string code, params DiagnosticResult[] expected)
{
var test = new CSharpAnalyzerTest<PreferOtherTypeAnalyzer, DefaultVerifier>()
{
TestState =
{
Sources = { code },
},
};
TestHelper.AddEmbeddedSources(
test.TestState,
"Robust.Shared.Analyzers.PreferOtherTypeAttribute.cs"
);
// ExpectedDiagnostics cannot be set, so we need to AddRange here...
test.TestState.ExpectedDiagnostics.AddRange(expected);
return test.RunAsync();
}
[Test]
public async Task Test()
{
const string code = """
using Robust.Shared.Analyzers;
public class EntityPrototype { };
public class EntProtoId { };
public class ReagentPrototype { };
[PreferOtherType(typeof(EntityPrototype), typeof(EntProtoId))]
public class ProtoId<T> { };
public class Test
{
public ProtoId<EntityPrototype> Bad = new();
public ProtoId<ReagentPrototype> Good = new();
}
""";
await Verifier(code,
// /0/Test0.cs(12,12): warning RA0031: Use the specific type EntProtoId instead of ProtoId when the type argument is EntityPrototype
VerifyCS.Diagnostic().WithSpan(12, 12, 12, 48).WithArguments("EntProtoId", "ProtoId", "EntityPrototype")
);
}
}

View File

@@ -0,0 +1,80 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using NUnit.Framework;
using VerifyCS =
Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Robust.Analyzers.PreferOtherTypeAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
namespace Robust.Analyzers.Tests;
public sealed class PreferOtherTypeFixerTest
{
private static Task Verifier(string code, string fixedCode, params DiagnosticResult[] expected)
{
var test = new CSharpCodeFixTest<PreferOtherTypeAnalyzer, PreferOtherTypeFixer, DefaultVerifier>()
{
TestState =
{
Sources = { code },
},
FixedState =
{
Sources = { fixedCode },
}
};
TestHelper.AddEmbeddedSources(
test.TestState,
"Robust.Shared.Analyzers.PreferOtherTypeAttribute.cs"
);
TestHelper.AddEmbeddedSources(
test.FixedState,
"Robust.Shared.Analyzers.PreferOtherTypeAttribute.cs"
);
test.TestState.ExpectedDiagnostics.AddRange(expected);
return test.RunAsync();
}
[Test]
public async Task Test()
{
const string code = """
using Robust.Shared.Analyzers;
public class EntityPrototype { };
public class EntProtoId { };
public class ReagentPrototype { };
[PreferOtherType(typeof(EntityPrototype), typeof(EntProtoId))]
public class ProtoId<T> { };
public class Test
{
public ProtoId<EntityPrototype> Foo = new();
}
""";
const string fixedCode = """
using Robust.Shared.Analyzers;
public class EntityPrototype { };
public class EntProtoId { };
public class ReagentPrototype { };
[PreferOtherType(typeof(EntityPrototype), typeof(EntProtoId))]
public class ProtoId<T> { };
public class Test
{
public EntProtoId Foo = new();
}
""";
await Verifier(code, fixedCode,
// /0/Test0.cs(12,12): error RA0031: Use the specific type EntProtoId instead of ProtoId when the type argument is EntityPrototype
VerifyCS.Diagnostic().WithSpan(12, 12, 12, 48).WithArguments("EntProtoId", "ProtoId", "EntityPrototype"));
}
}

View File

@@ -10,7 +10,13 @@
<ItemGroup>
<EmbeddedResource Include="..\Robust.Shared\Analyzers\AccessAttribute.cs" LogicalName="Robust.Shared.Analyzers.AccessAttribute.cs" LinkBase="Implementations" />
<EmbeddedResource Include="..\Robust.Shared\Analyzers\AccessPermissions.cs" LogicalName="Robust.Shared.Analyzers.AccessPermissions.cs" LinkBase="Implementations" />
<EmbeddedResource Include="..\Robust.Shared\Analyzers\MustCallBaseAttribute.cs" LogicalName="Robust.Shared.IoC.MustCallBaseAttribute.cs" LinkBase="Implementations" />
<EmbeddedResource Include="..\Robust.Shared\Analyzers\PreferNonGenericVariantForAttribute.cs" LogicalName="Robust.Shared.Analyzers.PreferNonGenericVariantForAttribute.cs" LinkBase="Implementations" />
<EmbeddedResource Include="..\Robust.Shared\Analyzers\PreferOtherTypeAttribute.cs" LogicalName="Robust.Shared.Analyzers.PreferOtherTypeAttribute.cs" LinkBase="Implementations" />
<EmbeddedResource Include="..\Robust.Shared\Analyzers\ForbidLiteralAttribute.cs" LogicalName="Robust.Shared.Analyzers.ForbidLiteralAttribute.cs" LinkBase="Implementations" />
<EmbeddedResource Include="..\Robust.Shared\Analyzers\ObsoleteInheritanceAttribute.cs" LogicalName="Robust.Shared.Analyzers.ObsoleteInheritanceAttribute.cs" LinkBase="Implementations" />
<EmbeddedResource Include="..\Robust.Shared\IoC\DependencyAttribute.cs" LogicalName="Robust.Shared.IoC.DependencyAttribute.cs" LinkBase="Implementations" />
<EmbeddedResource Include="..\Robust.Shared\GameObjects\EventBusAttributes.cs" LogicalName="Robust.Shared.GameObjects.EventBusAttributes.cs" LinkBase="Implementations" />
</ItemGroup>
<PropertyGroup>
@@ -24,12 +30,17 @@
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzer.Testing"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.NUnit"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing"/>
<PackageReference Include="NUnit"/>
<PackageReference Include="NUnit3TestAdapter"/>
<PackageReference Include="NUnit.Analyzers"/>
<PackageReference Include="Microsoft.NET.Test.Sdk"/>
<!-- Needed to fix transitive dependency versions -->
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" />
<PackageReference Include="System.Formats.Asn1" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,4 +1,4 @@
#nullable enable
#nullable enable
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
@@ -24,7 +24,7 @@ public sealed class ByRefEventAnalyzer : DiagnosticAnalyzer
"Make sure that methods subscribing to a ref event have the ref keyword for the event argument."
);
private static readonly DiagnosticDescriptor ByRefEventRaisedByValueRule = new(
public static readonly DiagnosticDescriptor ByRefEventRaisedByValueRule = new(
Diagnostics.IdByRefEventRaisedByValue,
"By-ref event raised by value",
"Tried to raise a by-ref event '{0}' by value",
@@ -34,7 +34,7 @@ public sealed class ByRefEventAnalyzer : DiagnosticAnalyzer
"Make sure to use the ref keyword when raising ref events."
);
private static readonly DiagnosticDescriptor ByValueEventRaisedByRefRule = new(
public static readonly DiagnosticDescriptor ByValueEventRaisedByRefRule = new(
Diagnostics.IdValueEventRaisedByRef,
"Value event raised by-ref",
"Tried to raise a value event '{0}' by-ref",
@@ -54,32 +54,44 @@ public sealed class ByRefEventAnalyzer : DiagnosticAnalyzer
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
context.EnableConcurrentExecution();
context.RegisterOperationAction(CheckEventRaise, OperationKind.Invocation);
context.RegisterCompilationStartAction(compilationContext =>
{
var raiseMethods = compilationContext.Compilation
.GetTypeByMetadataName("Robust.Shared.GameObjects.EntitySystem")?
.GetMembers()
.Where(m => m.Name.Contains("RaiseLocalEvent") && m.Kind == SymbolKind.Method)
.Cast<IMethodSymbol>();
var busRaiseMethods = compilationContext.Compilation
.GetTypeByMetadataName("Robust.Shared.GameObjects.EntityEventBus")?
.GetMembers()
.Where(m => m.Name.Contains("RaiseLocalEvent") && m.Kind == SymbolKind.Method)
.Cast<IMethodSymbol>();
if (raiseMethods == null)
return;
if (busRaiseMethods != null)
raiseMethods = raiseMethods.Concat(busRaiseMethods);
var raiseMethodsArray = raiseMethods.ToArray();
compilationContext.RegisterOperationAction(
ctx => CheckEventRaise(ctx, raiseMethodsArray),
OperationKind.Invocation);
});
}
private void CheckEventRaise(OperationAnalysisContext context)
private static void CheckEventRaise(
OperationAnalysisContext context,
IReadOnlyCollection<IMethodSymbol> raiseMethods)
{
if (context.Operation is not IInvocationOperation operation)
return;
var raiseMethods = context.Compilation
.GetTypeByMetadataName("Robust.Shared.GameObjects.EntitySystem")?
.GetMembers()
.Where(m => m.Name.Contains("RaiseLocalEvent") && m.Kind == SymbolKind.Method)
.Cast<IMethodSymbol>();
var busRaiseMethods = context.Compilation
.GetTypeByMetadataName("Robust.Shared.GameObjects.EntityEventBus")?
.GetMembers()
.Where(m => m.Name.Contains("RaiseLocalEvent") && m.Kind == SymbolKind.Method)
.Cast<IMethodSymbol>();
if (raiseMethods == null)
if (!operation.TargetMethod.Name.Contains("RaiseLocalEvent"))
return;
if (busRaiseMethods != null)
raiseMethods = raiseMethods.Concat(busRaiseMethods);
if (!raiseMethods.Any(m => m.Equals(operation.TargetMethod.OriginalDefinition, Default)))
{
// If you try to do this normally by concatenating like busRaiseMethods above

View File

@@ -6,6 +6,8 @@ using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Robust.Roslyn.Shared;
using Robust.Shared.Serialization.Manager.Definition;
using Robust.Shared.ViewVariables;
namespace Robust.Analyzers;
@@ -15,6 +17,10 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
private const string DataDefinitionNamespace = "Robust.Shared.Serialization.Manager.Attributes.DataDefinitionAttribute";
private const string ImplicitDataDefinitionNamespace = "Robust.Shared.Serialization.Manager.Attributes.ImplicitDataDefinitionForInheritorsAttribute";
private const string DataFieldBaseNamespace = "Robust.Shared.Serialization.Manager.Attributes.DataFieldBaseAttribute";
private const string ViewVariablesNamespace = "Robust.Shared.ViewVariables.ViewVariablesAttribute";
private const string NotYamlSerializableName = "Robust.Shared.Serialization.Manager.Attributes.NotYamlSerializableAttribute";
private const string DataFieldAttributeName = "DataField";
private const string ViewVariablesAttributeName = "ViewVariables";
private static readonly DiagnosticDescriptor DataDefinitionPartialRule = new(
Diagnostics.IdDataDefinitionPartial,
@@ -36,7 +42,7 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
"Make sure to mark any type containing a nested data definition as partial."
);
private static readonly DiagnosticDescriptor DataFieldWritableRule = new(
public static readonly DiagnosticDescriptor DataFieldWritableRule = new(
Diagnostics.IdDataFieldWritable,
"Data field must not be readonly",
"Data field {0} in data definition {1} is readonly",
@@ -46,7 +52,7 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
"Make sure to remove the readonly modifier."
);
private static readonly DiagnosticDescriptor DataFieldPropertyWritableRule = new(
public static readonly DiagnosticDescriptor DataFieldPropertyWritableRule = new(
Diagnostics.IdDataFieldPropertyWritable,
"Data field property must have a setter",
"Data field property {0} in data definition {1} does not have a setter",
@@ -56,8 +62,39 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
"Make sure to add a setter."
);
private static readonly DiagnosticDescriptor DataFieldRedundantTagRule = new(
Diagnostics.IdDataFieldRedundantTag,
"Data field has redundant tag specified",
"Data field {0} in data definition {1} has an explicitly set tag that matches autogenerated tag",
"Usage",
DiagnosticSeverity.Info,
true,
"Make sure to remove the tag string from the data field attribute."
);
public static readonly DiagnosticDescriptor DataFieldNoVVReadWriteRule = new(
Diagnostics.IdDataFieldNoVVReadWrite,
"Data field has VV ReadWrite",
"Data field {0} in data definition {1} has ViewVariables attribute with ReadWrite access, which is redundant",
"Usage",
DiagnosticSeverity.Info,
true,
"Make sure to remove the ViewVariables attribute."
);
public static readonly DiagnosticDescriptor DataFieldYamlSerializableRule = new(
Diagnostics.IdDataFieldYamlSerializable,
"Data field type is not YAML serializable",
"Data field {0} in data definition {1} is type {2}, which is not YAML serializable",
"Usage",
DiagnosticSeverity.Error,
true,
"Make sure to use a type that is YAML serializable."
);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(
DataDefinitionPartialRule, NestedDataDefinitionPartialRule, DataFieldWritableRule, DataFieldPropertyWritableRule
DataDefinitionPartialRule, NestedDataDefinitionPartialRule, DataFieldWritableRule, DataFieldPropertyWritableRule,
DataFieldRedundantTagRule, DataFieldNoVVReadWriteRule, DataFieldYamlSerializableRule
);
public override void Initialize(AnalysisContext context)
@@ -123,7 +160,33 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
if (IsReadOnlyDataField(type, fieldSymbol))
{
context.ReportDiagnostic(Diagnostic.Create(DataFieldWritableRule, context.Node.GetLocation(), fieldSymbol.Name, type.Name));
TryGetModifierLocation(field, SyntaxKind.ReadOnlyKeyword, out var location);
context.ReportDiagnostic(Diagnostic.Create(DataFieldWritableRule, location, fieldSymbol.Name, type.Name));
}
if (HasRedundantTag(fieldSymbol))
{
TryGetAttributeLocation(field, DataFieldAttributeName, out var location);
context.ReportDiagnostic(Diagnostic.Create(DataFieldRedundantTagRule, location, fieldSymbol.Name, type.Name));
}
if (HasVVReadWrite(fieldSymbol))
{
TryGetAttributeLocation(field, ViewVariablesAttributeName, out var location);
context.ReportDiagnostic(Diagnostic.Create(DataFieldNoVVReadWriteRule, location, fieldSymbol.Name, type.Name));
}
if (context.SemanticModel.GetSymbolInfo(field.Declaration.Type).Symbol is not ITypeSymbol fieldTypeSymbol)
continue;
if (IsNotYamlSerializable(fieldSymbol, fieldTypeSymbol))
{
context.ReportDiagnostic(Diagnostic.Create(DataFieldYamlSerializableRule,
(context.Node as FieldDeclarationSyntax)?.Declaration.Type.GetLocation(),
fieldSymbol.Name,
type.Name,
fieldTypeSymbol.MetadataName
));
}
}
}
@@ -147,7 +210,33 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
if (IsReadOnlyDataField(type, propertySymbol))
{
context.ReportDiagnostic(Diagnostic.Create(DataFieldPropertyWritableRule, context.Node.GetLocation(), propertySymbol.Name, type.Name));
var location = property.AccessorList != null ? property.AccessorList.GetLocation() : property.GetLocation();
context.ReportDiagnostic(Diagnostic.Create(DataFieldPropertyWritableRule, location, propertySymbol.Name, type.Name));
}
if (HasRedundantTag(propertySymbol))
{
TryGetAttributeLocation(property, DataFieldAttributeName, out var location);
context.ReportDiagnostic(Diagnostic.Create(DataFieldRedundantTagRule, location, propertySymbol.Name, type.Name));
}
if (HasVVReadWrite(propertySymbol))
{
TryGetAttributeLocation(property, ViewVariablesAttributeName, out var location);
context.ReportDiagnostic(Diagnostic.Create(DataFieldNoVVReadWriteRule, location, propertySymbol.Name, type.Name));
}
if (context.SemanticModel.GetSymbolInfo(property.Type).Symbol is not ITypeSymbol propertyTypeSymbol)
return;
if (IsNotYamlSerializable(propertySymbol, propertyTypeSymbol))
{
context.ReportDiagnostic(Diagnostic.Create(DataFieldYamlSerializableRule,
(context.Node as PropertyDeclarationSyntax)?.Type.GetLocation(),
propertySymbol.Name,
type.Name,
propertyTypeSymbol.Name
));
}
}
@@ -217,6 +306,38 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
return false;
}
private static bool TryGetAttributeLocation(MemberDeclarationSyntax syntax, string attributeName, out Location location)
{
foreach (var attributeList in syntax.AttributeLists)
{
foreach (var attribute in attributeList.Attributes)
{
if (attribute.Name.ToString() != attributeName)
continue;
location = attribute.GetLocation();
return true;
}
}
// Default to the declaration syntax's location
location = syntax.GetLocation();
return false;
}
private static bool TryGetModifierLocation(MemberDeclarationSyntax syntax, SyntaxKind modifierKind, out Location location)
{
foreach (var modifier in syntax.Modifiers)
{
if (modifier.IsKind(modifierKind))
{
location = modifier.GetLocation();
return true;
}
}
location = syntax.GetLocation();
return false;
}
private static bool IsReadOnlyMember(ITypeSymbol type, ISymbol member)
{
if (member is IFieldSymbol field)
@@ -248,6 +369,65 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
return false;
}
private static bool HasRedundantTag(ISymbol symbol)
{
if (!IsDataField(symbol, out var _, out var attribute))
return false;
// No args, no problem
if (attribute.ConstructorArguments.Length == 0)
return false;
// If a tag is explicitly specified, it will be the first argument...
var tagArgument = attribute.ConstructorArguments[0];
// ...but the first arg could also something else, since tag is optional
// so we make sure that it's a string
if (tagArgument.Value is not string explicitName)
return false;
// Get the name that sourcegen would provide
var automaticName = DataDefinitionUtility.AutoGenerateTag(symbol.Name);
// If the explicit name matches the sourcegen name, we have a redundancy
return explicitName == automaticName;
}
private static bool HasVVReadWrite(ISymbol symbol)
{
if (!IsDataField(symbol, out _, out _))
return false;
// Make sure it has ViewVariablesAttribute
AttributeData? viewVariablesAttribute = null;
foreach (var attr in symbol.GetAttributes())
{
if (attr.AttributeClass?.ToDisplayString() == ViewVariablesNamespace)
{
viewVariablesAttribute = attr;
}
}
if (viewVariablesAttribute == null)
return false;
// Default is ReadOnly, which is fine
if (viewVariablesAttribute.ConstructorArguments.Length == 0)
return false;
var accessArgument = viewVariablesAttribute.ConstructorArguments[0];
if (accessArgument.Value is not byte accessByte)
return false;
return (VVAccess)accessByte == VVAccess.ReadWrite;
}
private static bool IsNotYamlSerializable(ISymbol field, ITypeSymbol type)
{
if (!IsDataField(field, out _, out _))
return false;
return HasAttribute(type, NotYamlSerializableName);
}
private static bool IsImplicitDataDefinition(ITypeSymbol type)
{
if (HasAttribute(type, ImplicitDataDefinitionNamespace))

View File

@@ -1,8 +1,5 @@
#nullable enable
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
@@ -16,8 +13,13 @@ namespace Robust.Analyzers;
[ExportCodeFixProvider(LanguageNames.CSharp)]
public sealed class DefinitionFixer : CodeFixProvider
{
private const string DataFieldAttributeName = "DataField";
private const string ViewVariablesAttributeName = "ViewVariables";
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(
IdDataDefinitionPartial, IdNestedDataDefinitionPartial, IdDataFieldWritable, IdDataFieldPropertyWritable
IdDataDefinitionPartial, IdNestedDataDefinitionPartial, IdDataFieldWritable, IdDataFieldPropertyWritable,
IdDataFieldRedundantTag, IdDataFieldNoVVReadWrite
);
public override Task RegisterCodeFixesAsync(CodeFixContext context)
@@ -34,6 +36,10 @@ public sealed class DefinitionFixer : CodeFixProvider
return RegisterDataFieldFix(context, diagnostic);
case IdDataFieldPropertyWritable:
return RegisterDataFieldPropertyFix(context, diagnostic);
case IdDataFieldRedundantTag:
return RegisterRedundantTagFix(context, diagnostic);
case IdDataFieldNoVVReadWrite:
return RegisterVVReadWriteFix(context, diagnostic);
}
}
@@ -72,6 +78,110 @@ public sealed class DefinitionFixer : CodeFixProvider
return document.WithSyntaxRoot(root);
}
private static async Task RegisterRedundantTagFix(CodeFixContext context, Diagnostic diagnostic)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
var span = diagnostic.Location.SourceSpan;
var token = root?.FindToken(span.Start).Parent?.AncestorsAndSelf().OfType<MemberDeclarationSyntax>().First();
if (token == null)
return;
// Find the DataField attribute
AttributeSyntax? dataFieldAttribute = null;
foreach (var attributeList in token.AttributeLists)
{
foreach (var attribute in attributeList.Attributes)
{
if (attribute.Name.ToString() == DataFieldAttributeName)
{
dataFieldAttribute = attribute;
break;
}
}
if (dataFieldAttribute != null)
break;
}
if (dataFieldAttribute == null)
return;
context.RegisterCodeFix(CodeAction.Create(
"Remove explicitly set tag",
c => RemoveRedundantTag(context.Document, dataFieldAttribute, c),
"Remove explicitly set tag"
), diagnostic);
}
private static async Task<Document> RemoveRedundantTag(Document document, AttributeSyntax syntax, CancellationToken cancellation)
{
var root = (CompilationUnitSyntax?) await document.GetSyntaxRootAsync(cancellation);
if (syntax.ArgumentList == null)
return document;
AttributeSyntax? newSyntax;
if (syntax.ArgumentList.Arguments.Count == 1)
{
// If this is the only argument, delete the ArgumentList so we don't leave empty parentheses
newSyntax = syntax.RemoveNode(syntax.ArgumentList, SyntaxRemoveOptions.KeepNoTrivia);
}
else
{
// Remove the first argument, which is the tag
var newArgs = syntax.ArgumentList.Arguments.RemoveAt(0);
var newArgList = syntax.ArgumentList.WithArguments(newArgs);
// Construct a new attribute with the tag removed
newSyntax = syntax.WithArgumentList(newArgList);
}
root = root!.ReplaceNode(syntax, newSyntax!);
return document.WithSyntaxRoot(root);
}
private static async Task RegisterVVReadWriteFix(CodeFixContext context, Diagnostic diagnostic)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
var span = diagnostic.Location.SourceSpan;
var token = root?.FindToken(span.Start).Parent?.AncestorsAndSelf().OfType<MemberDeclarationSyntax>().First();
if (token == null)
return;
context.RegisterCodeFix(CodeAction.Create(
"Remove ViewVariables attribute",
c => RemoveVVAttribute(context.Document, token, c),
"Remove ViewVariables attribute"
), diagnostic);
}
private static async Task<Document> RemoveVVAttribute(Document document, MemberDeclarationSyntax syntax, CancellationToken cancellation)
{
var root = (CompilationUnitSyntax?) await document.GetSyntaxRootAsync(cancellation);
var newLists = new SyntaxList<AttributeListSyntax>();
foreach (var attributeList in syntax.AttributeLists)
{
var attributes = new SeparatedSyntaxList<AttributeSyntax>();
foreach (var attribute in attributeList.Attributes)
{
if (attribute.Name.ToString() != ViewVariablesAttributeName)
{
attributes = attributes.Add(attribute);
}
}
// Don't add empty lists []
if (attributes.Count > 0)
newLists = newLists.Add(attributeList.WithAttributes(attributes));
}
var newSyntax = syntax.WithAttributeLists(newLists);
root = root!.ReplaceNode(syntax, newSyntax);
return document.WithSyntaxRoot(root);
}
private static async Task RegisterDataFieldFix(CodeFixContext context, Diagnostic diagnostic)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);

View File

@@ -0,0 +1,126 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Robust.Roslyn.Shared;
namespace Robust.Analyzers;
#nullable enable
/// <summary>
/// Analyzer that detects duplicate <c>[Dependency]</c> fields inside a single type.
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class DuplicateDependencyAnalyzer : DiagnosticAnalyzer
{
private const string DependencyAttributeType = "Robust.Shared.IoC.DependencyAttribute";
private static readonly DiagnosticDescriptor Rule = new(
Diagnostics.IdDuplicateDependency,
"Duplicate dependency field",
"Another [Dependency] field of type '{0}' already exists in this type with field '{1}'",
"Usage",
DiagnosticSeverity.Warning,
true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterCompilationStartAction(compilationContext =>
{
var dependencyAttributeType = compilationContext.Compilation.GetTypeByMetadataName(DependencyAttributeType);
if (dependencyAttributeType == null)
return;
compilationContext.RegisterSymbolStartAction(symbolContext =>
{
var typeSymbol = (INamedTypeSymbol)symbolContext.Symbol;
// Only deal with non-static classes, doesn't make sense to have dependencies in anything else.
if (typeSymbol.TypeKind != TypeKind.Class || typeSymbol.IsStatic)
return;
var state = new AnalyzerState(dependencyAttributeType);
symbolContext.RegisterSyntaxNodeAction(state.AnalyzeField, SyntaxKind.FieldDeclaration);
symbolContext.RegisterSymbolEndAction(state.End);
},
SymbolKind.NamedType);
});
}
private sealed class AnalyzerState(INamedTypeSymbol dependencyAttributeType)
{
private readonly Dictionary<ITypeSymbol, List<IFieldSymbol>> _dependencyFields = new(SymbolEqualityComparer.Default);
public void AnalyzeField(SyntaxNodeAnalysisContext context)
{
var field = (FieldDeclarationSyntax)context.Node;
if (field.AttributeLists.Count == 0)
return;
if (context.ContainingSymbol is not IFieldSymbol fieldSymbol)
return;
// Can't have [Dependency]s for non-reference types.
if (!fieldSymbol.Type.IsReferenceType)
return;
if (!IsDependency(context.ContainingSymbol))
return;
lock (_dependencyFields)
{
if (!_dependencyFields.TryGetValue(fieldSymbol.Type, out var dependencyFields))
{
dependencyFields = [];
_dependencyFields.Add(fieldSymbol.Type, dependencyFields);
}
dependencyFields.Add(fieldSymbol);
}
}
private bool IsDependency(ISymbol symbol)
{
foreach (var attributeData in symbol.GetAttributes())
{
if (SymbolEqualityComparer.Default.Equals(attributeData.AttributeClass, dependencyAttributeType))
return true;
}
return false;
}
public void End(SymbolAnalysisContext context)
{
lock (_dependencyFields)
{
foreach (var pair in _dependencyFields)
{
var fieldType = pair.Key;
var fields = pair.Value;
if (fields.Count <= 1)
continue;
// Sort so we can have deterministic order to skip reporting for a single field.
// Whichever sorts first doesn't get reported.
fields.Sort(static (a, b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal));
// Start at index 1 to skip first field.
var firstField = fields[0];
for (var i = 1; i < fields.Count; i++)
{
var field = fields[i];
context.ReportDiagnostic(
Diagnostic.Create(Rule, field.Locations[0], fieldType.ToDisplayString(), firstField.Name));
}
}
}
}
}
}

View File

@@ -0,0 +1,101 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using Robust.Roslyn.Shared;
namespace Robust.Analyzers;
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class ForbidLiteralAnalyzer : DiagnosticAnalyzer
{
private const string ForbidLiteralType = "Robust.Shared.Analyzers.ForbidLiteralAttribute";
public static DiagnosticDescriptor ForbidLiteralRule = new(
Diagnostics.IdForbidLiteral,
"Parameter forbids literal values",
"The {0} parameter of {1} forbids literal values",
"Usage",
DiagnosticSeverity.Warning,
true,
"Pass in a validated wrapper type like ProtoId, or a const or static value."
);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [ForbidLiteralRule];
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
context.EnableConcurrentExecution();
context.RegisterOperationAction(AnalyzeOperation, OperationKind.Invocation);
}
private void AnalyzeOperation(OperationAnalysisContext context)
{
if (context.Operation is not IInvocationOperation invocationOperation)
return;
// Check each parameter of the method invocation
foreach (var argumentOperation in invocationOperation.Arguments)
{
// Check for our attribute on the parameter
if (!AttributeHelper.HasAttribute(argumentOperation.Parameter, ForbidLiteralType, out _))
continue;
// Handle parameters using the params keyword
if (argumentOperation.Syntax is InvocationExpressionSyntax subExpressionSyntax)
{
// Check each param value
foreach (var subArgument in subExpressionSyntax.ArgumentList.Arguments)
{
CheckArgumentSyntax(context, argumentOperation, subArgument);
}
continue;
}
// Not params, so just check the single parameter
if (argumentOperation.Syntax is not ArgumentSyntax argumentSyntax)
continue;
CheckArgumentSyntax(context, argumentOperation, argumentSyntax);
}
}
private void CheckArgumentSyntax(OperationAnalysisContext context, IArgumentOperation operation, ArgumentSyntax argumentSyntax)
{
// Handle collection types
if (argumentSyntax.Expression is CollectionExpressionSyntax collectionExpressionSyntax)
{
// Check each value of the collection
foreach (var elementSyntax in collectionExpressionSyntax.Elements)
{
if (elementSyntax is not ExpressionElementSyntax expressionSyntax)
continue;
// Check if a literal was passed in
if (expressionSyntax.Expression is not LiteralExpressionSyntax)
continue;
context.ReportDiagnostic(Diagnostic.Create(ForbidLiteralRule,
expressionSyntax.GetLocation(),
operation.Parameter.Name,
(context.Operation as IInvocationOperation).TargetMethod.Name
));
}
return;
}
// Not a collection, just a single value to check
// Check if it's a literal
if (argumentSyntax.Expression is not LiteralExpressionSyntax)
return;
context.ReportDiagnostic(Diagnostic.Create(ForbidLiteralRule,
argumentSyntax.GetLocation(),
operation.Parameter.Name,
(context.Operation as IInvocationOperation).TargetMethod.Name
));
}
}

View File

@@ -0,0 +1,111 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Robust.Roslyn.Shared;
namespace Robust.Analyzers;
#nullable enable
/// <summary>
/// Enforces <c>MustCallBaseAttribute</c>.
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class MustCallBaseAnalyzer : DiagnosticAnalyzer
{
private const string Attribute = "Robust.Shared.Analyzers.MustCallBaseAttribute";
private static readonly DiagnosticDescriptor Rule = new(
Diagnostics.IdMustCallBase,
"No base call in overriden function",
"Overriders of this function must always call the base function",
"Usage",
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.Method);
}
private static void AnalyzeSymbol(SymbolAnalysisContext context)
{
if (context.Symbol is not IMethodSymbol { IsOverride: true } method)
return;
var attrSymbol = context.Compilation.GetTypeByMetadataName(Attribute);
if (attrSymbol == null)
return;
if (DoesMethodOverriderHaveAttribute(method, attrSymbol) is not { } data)
return;
if (data is { onlyOverrides: true, depth: < 2 })
return;
var syntax = (MethodDeclarationSyntax) method.DeclaringSyntaxReferences[0].GetSyntax();
if (HasBaseCall(syntax))
return;
var diag = Diagnostic.Create(Rule, syntax.Identifier.GetLocation());
context.ReportDiagnostic(diag);
}
private static (int depth, bool onlyOverrides)? DoesMethodOverriderHaveAttribute(
IMethodSymbol method,
INamedTypeSymbol attributeSymbol)
{
var depth = 0;
while (method.OverriddenMethod != null)
{
depth += 1;
method = method.OverriddenMethod;
if (GetAttribute(method, attributeSymbol) is not { } attribute)
continue;
var onlyOverrides = attribute.ConstructorArguments is [{Kind: TypedConstantKind.Primitive, Value: true}];
return (depth, onlyOverrides);
}
return null;
}
private static bool HasBaseCall(MethodDeclarationSyntax syntax)
{
return syntax.Accept(new BaseCallLocator());
}
private static AttributeData? GetAttribute(ISymbol namedTypeSymbol, INamedTypeSymbol attrSymbol)
{
return namedTypeSymbol.GetAttributes()
.SingleOrDefault(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attrSymbol));
}
private sealed class BaseCallLocator : CSharpSyntaxVisitor<bool>
{
public override bool VisitBaseExpression(BaseExpressionSyntax node)
{
return true;
}
public override bool DefaultVisit(SyntaxNode node)
{
foreach (var childNode in node.ChildNodes())
{
if (childNode is not CSharpSyntaxNode cSharpSyntax)
continue;
if (cSharpSyntax.Accept(this))
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,66 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using Robust.Roslyn.Shared;
namespace Robust.Analyzers;
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class NoUncachedRegexAnalyzer : DiagnosticAnalyzer
{
private const string RegexTypeName = "Regex";
private const string RegexType = $"System.Text.RegularExpressions.{RegexTypeName}";
private static readonly DiagnosticDescriptor Rule = new (
Diagnostics.IdUncachedRegex,
"Use of uncached static Regex function",
"Usage of a static Regex function that takes in a pattern string. This can cause constant re-parsing of the pattern.",
"Usage",
DiagnosticSeverity.Warning,
true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
public static readonly HashSet<string> BadFunctions =
[
"Count",
"EnumerateMatches",
"IsMatch",
"Match",
"Matches",
"Replace",
"Split"
];
public override void Initialize(AnalysisContext context)
{
context.EnableConcurrentExecution();
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.RegisterOperationAction(CheckInvocation, OperationKind.Invocation);
}
private static void CheckInvocation(OperationAnalysisContext context)
{
if (context.Operation is not IInvocationOperation invocation)
return;
// All Regex functions we care about are static.
var targetMethod = invocation.TargetMethod;
if (!targetMethod.IsStatic)
return;
// Bail early.
if (targetMethod.ContainingType.Name != "Regex")
return;
var regexType = context.Compilation.GetTypeByMetadataName(RegexType);
if (!SymbolEqualityComparer.Default.Equals(regexType, targetMethod.ContainingType))
return;
if (!BadFunctions.Contains(targetMethod.Name))
return;
context.ReportDiagnostic(Diagnostic.Create(Rule, invocation.Syntax.GetLocation()));
}
}

View File

@@ -0,0 +1,75 @@
#nullable enable
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Robust.Roslyn.Shared;
namespace Robust.Analyzers;
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class ObsoleteInheritanceAnalyzer : DiagnosticAnalyzer
{
private const string Attribute = "Robust.Shared.Analyzers.ObsoleteInheritanceAttribute";
public static readonly DiagnosticDescriptor Rule = new(
Diagnostics.IdObsoleteInheritance,
"Parent type has obsoleted inheritance",
"Type '{0}' inherits from '{1}', which has obsoleted inheriting from itself",
"Usage",
DiagnosticSeverity.Warning,
true);
public static readonly DiagnosticDescriptor RuleWithMessage = new(
Diagnostics.IdObsoleteInheritanceWithMessage,
"Parent type has obsoleted inheritance",
"Type '{0}' inherits from '{1}', which has obsoleted inheriting from itself: \"{2}\"",
"Usage",
DiagnosticSeverity.Warning,
true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Rule, RuleWithMessage];
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterSymbolAction(CheckClass, SymbolKind.NamedType);
}
private static void CheckClass(SymbolAnalysisContext context)
{
if (context.Symbol is not INamedTypeSymbol typeSymbol)
return;
if (typeSymbol.IsValueType || typeSymbol.BaseType is not { } baseType)
return;
if (!AttributeHelper.HasAttribute(baseType, Attribute, out var data))
return;
var location = context.Symbol.Locations[0];
if (GetMessageFromAttributeData(data) is { } message)
{
context.ReportDiagnostic(Diagnostic.Create(
RuleWithMessage,
location,
[typeSymbol.Name, baseType.Name, message]));
}
else
{
context.ReportDiagnostic(Diagnostic.Create(
Rule,
location,
[typeSymbol.Name, baseType.Name]));
}
}
private static string? GetMessageFromAttributeData(AttributeData data)
{
if (data.ConstructorArguments is not [var message, ..])
return null;
return message.Value as string;
}
}

View File

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

View File

@@ -0,0 +1,75 @@
#nullable enable
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Robust.Roslyn.Shared;
namespace Robust.Analyzers;
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class PreferOtherTypeAnalyzer : DiagnosticAnalyzer
{
private const string AttributeType = "Robust.Shared.Analyzers.PreferOtherTypeAttribute";
private static readonly DiagnosticDescriptor PreferOtherTypeDescriptor = new(
Diagnostics.IdPreferOtherType,
"Use the specific type",
"Use the specific type {0} instead of {1} when the type argument is {2}",
"Usage",
DiagnosticSeverity.Error,
true,
"Use the specific type.");
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(
PreferOtherTypeDescriptor
);
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.ReportDiagnostics | GeneratedCodeAnalysisFlags.Analyze);
context.EnableConcurrentExecution();
context.RegisterSyntaxNodeAction(AnalyzeField, SyntaxKind.VariableDeclaration);
}
private void AnalyzeField(SyntaxNodeAnalysisContext context)
{
if (context.Node is not VariableDeclarationSyntax node)
return;
// Get the type of the generic being used
if (node.Type is not GenericNameSyntax genericName)
return;
var genericSyntax = genericName.TypeArgumentList.Arguments[0];
if (context.SemanticModel.GetSymbolInfo(genericSyntax).Symbol is not { } genericType)
return;
// Look for the PreferOtherTypeAttribute
var symbolInfo = context.SemanticModel.GetSymbolInfo(node.Type);
if (symbolInfo.Symbol?.GetAttributes() is not { } attributes)
return;
var preferOtherTypeAttribute = context.Compilation.GetTypeByMetadataName(AttributeType);
foreach (var attribute in attributes)
{
if (!SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, preferOtherTypeAttribute))
continue;
// See if the generic type argument matches the type the attribute specifies
if (attribute.ConstructorArguments[0].Value is not ITypeSymbol checkedType)
return;
if (!SymbolEqualityComparer.Default.Equals(checkedType, genericType))
continue;
if (attribute.ConstructorArguments[1].Value is not ITypeSymbol replacementType)
continue;
context.ReportDiagnostic(Diagnostic.Create(PreferOtherTypeDescriptor,
context.Node.GetLocation(),
replacementType.Name,
symbolInfo.Symbol.Name,
genericType.Name));
}
}
}

View File

@@ -0,0 +1,97 @@
#nullable enable
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Robust.Roslyn.Shared.Diagnostics;
namespace Robust.Analyzers;
[ExportCodeFixProvider(LanguageNames.CSharp)]
public sealed class PreferOtherTypeFixer : CodeFixProvider
{
private const string PreferOtherTypeAttributeName = "PreferOtherTypeAttribute";
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(
IdPreferOtherType
);
public override FixAllProvider GetFixAllProvider()
{
return WellKnownFixAllProviders.BatchFixer;
}
public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
foreach (var diagnostic in context.Diagnostics)
{
switch (diagnostic.Id)
{
case IdPreferOtherType:
return RegisterReplaceType(context, diagnostic);
}
}
return Task.CompletedTask;
}
private static async Task RegisterReplaceType(CodeFixContext context, Diagnostic diagnostic)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
var span = diagnostic.Location.SourceSpan;
var token = root?.FindToken(span.Start).Parent?.AncestorsAndSelf().OfType<VariableDeclarationSyntax>().First();
if (token == null)
return;
context.RegisterCodeFix(CodeAction.Create(
"Replace type",
c => ReplaceType(context.Document, token, c),
"Replace type"
), diagnostic);
}
private static async Task<Document> ReplaceType(Document document, VariableDeclarationSyntax syntax, CancellationToken cancellation)
{
var root = (CompilationUnitSyntax?) await document.GetSyntaxRootAsync(cancellation);
var model = await document.GetSemanticModelAsync(cancellation);
if (model == null)
return document;
if (syntax.Type is not GenericNameSyntax genericNameSyntax)
return document;
var genericTypeSyntax = genericNameSyntax.TypeArgumentList.Arguments[0];
if (model.GetSymbolInfo(genericTypeSyntax).Symbol is not {} genericTypeSymbol)
return document;
var symbolInfo = model.GetSymbolInfo(syntax.Type);
if (symbolInfo.Symbol?.GetAttributes() is not { } attributes)
return document;
foreach (var attribute in attributes)
{
if (attribute.AttributeClass?.Name != PreferOtherTypeAttributeName)
continue;
if (attribute.ConstructorArguments[0].Value is not ITypeSymbol checkedTypeSymbol)
continue;
if (!SymbolEqualityComparer.Default.Equals(checkedTypeSymbol, genericTypeSymbol))
continue;
if (attribute.ConstructorArguments[1].Value is not ITypeSymbol replacementTypeSymbol)
continue;
var replacementIdentifier = SyntaxFactory.IdentifierName(replacementTypeSymbol.Name);
var replacementSyntax = syntax.WithType(replacementIdentifier);
root = root!.ReplaceNode(syntax, replacementSyntax);
return document.WithSyntaxRoot(root);
}
return document;
}
}

View File

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

View File

@@ -26,7 +26,8 @@ public sealed class DefaultSQLConfig : IConfig
public IEnumerable<IExporter> GetExporters()
{
yield return SQLExporter.Default;
//yield return SQLExporter.Default;
yield break;
}
public IEnumerable<IColumnProvider> GetColumnProviders() => DefaultConfig.Instance.GetColumnProviders();

View File

@@ -0,0 +1,96 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;
using JetBrains.Annotations;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.UnitTesting.Server;
namespace Robust.Benchmarks.EntityManager;
[Virtual]
public partial class HasComponentBenchmark
{
private static readonly Consumer Consumer = new();
private ISimulation _simulation = default!;
private IEntityManager _entityManager = default!;
private ComponentRegistration _compReg = default!;
private A _dummyA = new();
[UsedImplicitly]
[Params(1, 10, 100, 1000)]
public int N;
[GlobalSetup]
public void GlobalSetup()
{
_simulation = RobustServerSimulation
.NewSimulation()
.RegisterComponents(f => f.RegisterClass<A>())
.InitializeInstance();
_entityManager = _simulation.Resolve<IEntityManager>();
var map = _simulation.CreateMap().Uid;
var coords = new EntityCoordinates(map, default);
_compReg = _entityManager.ComponentFactory.GetRegistration(typeof(A));
for (var i = 0; i < N; i++)
{
var uid = _entityManager.SpawnEntity(null, coords);
_entityManager.AddComponent<A>(uid);
}
}
[Benchmark]
public void HasComponentGeneric()
{
for (var i = 2; i <= N+1; i++)
{
var uid = new EntityUid(i);
var result = _entityManager.HasComponent<A>(uid);
Consumer.Consume(result);
}
}
[Benchmark]
public void HasComponentCompReg()
{
for (var i = 2; i <= N+1; i++)
{
var uid = new EntityUid(i);
var result = _entityManager.HasComponent(uid, _compReg);
Consumer.Consume(result);
}
}
[Benchmark]
public void HasComponentType()
{
for (var i = 2; i <= N+1; i++)
{
var uid = new EntityUid(i);
var result = _entityManager.HasComponent(uid, typeof(A));
Consumer.Consume(result);
}
}
[Benchmark]
public void HasComponentGetType()
{
for (var i = 2; i <= N+1; i++)
{
var uid = new EntityUid(i);
var type = _dummyA.GetType();
var result = _entityManager.HasComponent(uid, type);
Consumer.Consume(result);
}
}
[ComponentProtoName("A")]
public sealed partial class A : Component
{
}
}

View File

@@ -15,11 +15,10 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Npgsql;
using Npgsql.Internal;
using Npgsql.Internal.TypeHandlers;
using Npgsql.Internal.TypeHandling;
namespace Robust.Benchmarks.Exporters;
/*
public sealed class SQLExporter : IExporter
{
private static readonly JsonSerializerOptions JsonSerializerOptions = new JsonSerializerOptions
@@ -98,7 +97,9 @@ public sealed class SQLExporter : IExporter
public string Name => "sql";
}
*/
/*
// https://github.com/npgsql/efcore.pg/issues/1107#issuecomment-945126627
class JsonOverrideTypeHandlerResolverFactory : TypeHandlerResolverFactory
{
@@ -138,6 +139,7 @@ class JsonOverrideTypeHandlerResolverFactory : TypeHandlerResolverFactory
=> null; // Let the built-in resolver do this
}
}
*/
public sealed class DesignTimeContextFactoryPostgres : IDesignTimeDbContextFactory<BenchmarkContext>
{

View File

@@ -0,0 +1,96 @@
using System;
using System.Numerics;
using BenchmarkDotNet.Attributes;
using Microsoft.Extensions.Configuration;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Physics.Systems;
using Robust.UnitTesting.Server;
namespace Robust.Benchmarks.Physics;
[Virtual]
[MediumRunJob]
public class PhysicsBoxStackBenchmark
{
private ISimulation _sim = default!;
[GlobalSetup]
public void Setup()
{
_sim = RobustServerSimulation.NewSimulation().InitializeInstance();
var entManager = _sim.Resolve<IEntityManager>();
entManager.System<SharedMapSystem>().CreateMap(out var mapId);
SetupTumbler(entManager, mapId);
for (var i = 0; i < 30; i++)
{
entManager.TickUpdate(0.016f, false);
}
}
[Benchmark]
public void BoxStack()
{
var entManager = _sim.Resolve<IEntityManager>();
for (var i = 0; i < 10000; i++)
{
entManager.TickUpdate(0.016f, false);
}
}
private void SetupTumbler(IEntityManager entManager, MapId mapId)
{
var physics = entManager.System<SharedPhysicsSystem>();
var fixtures = entManager.System<FixtureSystem>();
var groundUid = entManager.SpawnEntity(null, new MapCoordinates(0, 0, mapId));
var ground = entManager.AddComponent<PhysicsComponent>(groundUid);
var horizontal = new EdgeShape(new Vector2(-40, 0), new Vector2(40, 0));
fixtures.CreateFixture(groundUid, "fix1", new Fixture(horizontal, 2, 2, true), body: ground);
var vertical = new EdgeShape(new Vector2(10, 0), new Vector2(10, 10));
fixtures.CreateFixture(groundUid, "fix2", new Fixture(vertical, 2, 2, true), body: ground);
var xs = new[]
{
0.0f, -10.0f, -5.0f, 5.0f, 10.0f
};
var columnCount = 1;
var rowCount = 15;
PolygonShape shape;
for (var j = 0; j < columnCount; j++)
{
for (var i = 0; i < rowCount; i++)
{
var x = 0.0f;
var boxUid = entManager.SpawnEntity(null,
new MapCoordinates(new Vector2(xs[j] + x, 0.55f + 1.1f * i), mapId));
var box = entManager.AddComponent<PhysicsComponent>(boxUid);
physics.SetBodyType(boxUid, BodyType.Dynamic, body: box);
shape = new PolygonShape();
shape.SetAsBox(0.5f, 0.5f);
physics.SetFixedRotation(boxUid, false, body: box);
fixtures.CreateFixture(boxUid, "fix1", new Fixture(shape, 2, 2, true), body: box);
physics.WakeBody(boxUid, body: box);
physics.SetSleepingAllowed(boxUid, box, false);
}
}
physics.WakeBody(groundUid, body: ground);
}
}

View File

@@ -0,0 +1,92 @@
using System.Numerics;
using BenchmarkDotNet.Attributes;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Physics.Systems;
using Robust.UnitTesting.Server;
namespace Robust.Benchmarks.Physics;
[Virtual]
public class PhysicsCircleStackBenchmark
{
private ISimulation _sim = default!;
[GlobalSetup]
public void Setup()
{
_sim = RobustServerSimulation.NewSimulation().InitializeInstance();
var entManager = _sim.Resolve<IEntityManager>();
entManager.System<SharedMapSystem>().CreateMap(out var mapId);
SetupTumbler(entManager, mapId);
for (var i = 0; i < 30; i++)
{
entManager.TickUpdate(0.016f, false);
}
}
[Benchmark]
public void CircleStack()
{
var entManager = _sim.Resolve<IEntityManager>();
for (var i = 0; i < 10000; i++)
{
entManager.TickUpdate(0.016f, false);
}
}
private void SetupTumbler(IEntityManager entManager, MapId mapId)
{
var physics = entManager.System<SharedPhysicsSystem>();
var fixtures = entManager.System<FixtureSystem>();
var groundUid = entManager.SpawnEntity(null, new MapCoordinates(0, 0, mapId));
var ground = entManager.AddComponent<PhysicsComponent>(groundUid);
var horizontal = new EdgeShape(new Vector2(-40, 0), new Vector2(40, 0));
fixtures.CreateFixture(groundUid, "fix1", new Fixture(horizontal, 2, 2, true), body: ground);
var vertical = new EdgeShape(new Vector2(20, 0), new Vector2(20, 20));
fixtures.CreateFixture(groundUid, "fix2", new Fixture(vertical, 2, 2, true), body: ground);
var xs = new[]
{
0.0f, -10.0f, -5.0f, 5.0f, 10.0f
};
var columnCount = 1;
var rowCount = 15;
PhysShapeCircle shape;
for (var j = 0; j < columnCount; j++)
{
for (var i = 0; i < rowCount; i++)
{
var x = 0.0f;
var boxUid = entManager.SpawnEntity(null,
new MapCoordinates(new Vector2(xs[j] + x, 0.55f + 2.1f * i), mapId));
var box = entManager.AddComponent<PhysicsComponent>(boxUid);
physics.SetBodyType(boxUid, BodyType.Dynamic, body: box);
shape = new PhysShapeCircle(0.5f);
physics.SetFixedRotation(boxUid, false, body: box);
// TODO: Need to detect shape and work out if we need to use fixedrotation
fixtures.CreateFixture(boxUid, "fix1", new Fixture(shape, 2, 2, true, 5f));
physics.WakeBody(boxUid, body: box);
physics.SetSleepingAllowed(boxUid, box, false);
}
}
physics.WakeBody(groundUid, body: ground);
}
}

View File

@@ -0,0 +1,91 @@
using System;
using System.Numerics;
using BenchmarkDotNet.Attributes;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Physics.Systems;
using Robust.UnitTesting.Server;
namespace Robust.Benchmarks.Physics;
[Virtual]
public class PhysicsPyramidBenchmark
{
private ISimulation _sim = default!;
[GlobalSetup]
public void Setup()
{
_sim = RobustServerSimulation.NewSimulation().InitializeInstance();
var entManager = _sim.Resolve<IEntityManager>();
entManager.System<SharedMapSystem>().CreateMap(out var mapId);
SetupTumbler(entManager, mapId);
for (var i = 0; i < 300; i++)
{
entManager.TickUpdate(0.016f, false);
}
}
[Benchmark]
public void Pyramid()
{
var entManager = _sim.Resolve<IEntityManager>();
for (var i = 0; i < 5000; i++)
{
entManager.TickUpdate(0.016f, false);
}
}
private void SetupTumbler(IEntityManager entManager, MapId mapId)
{
const byte count = 20;
// Setup ground
var physics = entManager.System<SharedPhysicsSystem>();
var fixtures = entManager.System<FixtureSystem>();
var groundUid = entManager.SpawnEntity(null, new MapCoordinates(0, 0, mapId));
var ground = entManager.AddComponent<PhysicsComponent>(groundUid);
var horizontal = new EdgeShape(new Vector2(40, 0), new Vector2(-40, 0));
fixtures.CreateFixture(groundUid, "fix1", new Fixture(horizontal, 2, 2, true), body: ground);
physics.WakeBody(groundUid, body: ground);
// Setup boxes
float a = 0.5f;
PolygonShape shape = new();
shape.SetAsBox(a, a);
var x = new Vector2(-7.0f, 0.75f);
Vector2 y;
Vector2 deltaX = new Vector2(0.5625f, 1.25f);
Vector2 deltaY = new Vector2(1.125f, 0.0f);
for (var i = 0; i < count; ++i)
{
y = x;
for (var j = i; j < count; ++j)
{
var boxUid = entManager.SpawnEntity(null, new MapCoordinates(y, mapId));
var box = entManager.AddComponent<PhysicsComponent>(boxUid);
physics.SetBodyType(boxUid, BodyType.Dynamic, body: box);
fixtures.CreateFixture(boxUid, "fix1", new Fixture(shape, 2, 2, true, 5f), body: box);
y += deltaY;
physics.WakeBody(boxUid, body: box);
physics.SetSleepingAllowed(boxUid, box, false);
}
x += deltaX;
}
}
}

View File

@@ -0,0 +1,108 @@
using System;
using System.Numerics;
using BenchmarkDotNet.Attributes;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Physics.Systems;
using Robust.UnitTesting.Server;
namespace Robust.Benchmarks.Physics;
[Virtual]
public class PhysicsTumblerBenchmark
{
private ISimulation _sim = default!;
[GlobalSetup]
public void Setup()
{
_sim = RobustServerSimulation.NewSimulation().InitializeInstance();
var entManager = _sim.Resolve<IEntityManager>();
var physics = entManager.System<SharedPhysicsSystem>();
var fixtures = entManager.System<FixtureSystem>();
var mapUid = entManager.System<SharedMapSystem>().CreateMap(out var mapId);
SetupTumbler(entManager, mapId);
for (var i = 0; i < 300; i++)
{
entManager.TickUpdate(0.016f, false);
var boxUid = entManager.SpawnEntity(null, new MapCoordinates(0f, 10f, mapId));
var box = entManager.AddComponent<PhysicsComponent>(boxUid);
physics.SetBodyType(boxUid, BodyType.Dynamic, body: box);
physics.SetFixedRotation(boxUid, false, body: box);
var shape = new PolygonShape();
shape.SetAsBox(0.125f, 0.125f);
fixtures.CreateFixture(boxUid, "fix1", new Fixture(shape, 2, 2, true, 0.0625f), body: box);
physics.WakeBody(boxUid, body: box);
physics.SetSleepingAllowed(boxUid, box, false);
}
if (entManager.TryGetComponent(mapUid, out BroadphaseComponent? mapBroadphase))
entManager.System<SharedBroadphaseSystem>().RebuildBottomUp(mapBroadphase);
}
[Benchmark]
public void Tumbler()
{
var entManager = _sim.Resolve<IEntityManager>();
for (var i = 0; i < 1000; i++)
{
entManager.TickUpdate(0.016f, false);
}
}
private void SetupTumbler(IEntityManager entManager, MapId mapId)
{
var physics = entManager.System<SharedPhysicsSystem>();
var fixtures = entManager.System<FixtureSystem>();
var joints = entManager.System<SharedJointSystem>();
var groundUid = entManager.SpawnEntity(null, new MapCoordinates(0f, 0f, mapId));
var ground = entManager.AddComponent<PhysicsComponent>(groundUid);
// Due to lookup changes fixtureless bodies are invalid, so
var cShape = new PhysShapeCircle(1f);
fixtures.CreateFixture(groundUid, "fix1", new Fixture(cShape, 0, 0, false));
var bodyUid = entManager.SpawnEntity(null, new MapCoordinates(0f, 10f, mapId));
var body = entManager.AddComponent<PhysicsComponent>(bodyUid);
physics.SetBodyType(bodyUid, BodyType.Dynamic, body: body);
physics.SetSleepingAllowed(bodyUid, body, false);
physics.SetFixedRotation(bodyUid, false, body: body);
// TODO: Box2D just deref, bleh shape structs someday
var shape1 = new PolygonShape();
shape1.SetAsBox(0.5f, 10.0f, new Vector2(10.0f, 0.0f), 0.0f);
fixtures.CreateFixture(bodyUid, "fix1", new Fixture(shape1, 2, 0, true, 20f));
var shape2 = new PolygonShape();
shape2.SetAsBox(0.5f, 10.0f, new Vector2(-10.0f, 0.0f), 0f);
fixtures.CreateFixture(bodyUid, "fix2", new Fixture(shape2, 2, 0, true, 20f));
var shape3 = new PolygonShape();
shape3.SetAsBox(10.0f, 0.5f, new Vector2(0.0f, 10.0f), 0f);
fixtures.CreateFixture(bodyUid, "fix3", new Fixture(shape3, 2, 0, true, 20f));
var shape4 = new PolygonShape();
shape4.SetAsBox(10.0f, 0.5f, new Vector2(0.0f, -10.0f), 0f);
fixtures.CreateFixture(bodyUid, "fix4", new Fixture(shape4, 2, 0, true, 20f));
physics.WakeBody(groundUid, body: ground);
physics.WakeBody(bodyUid, body: body);
var revolute = joints.CreateRevoluteJoint(groundUid, bodyUid);
revolute.LocalAnchorA = new Vector2(0f, 10f);
revolute.LocalAnchorB = new Vector2(0f, 0f);
revolute.ReferenceAngle = 0f;
revolute.MotorSpeed = 0.05f * MathF.PI;
revolute.MaxMotorTorque = 100000000f;
revolute.EnableMotor = true;
}
}

View File

@@ -19,6 +19,10 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
<!-- Needed to pin transitive dependency versions. -->
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" />
<PackageReference Include="System.Formats.Asn1" />
</ItemGroup>
<Import Project="..\MSBuild\Robust.Properties.targets" />

View File

@@ -42,8 +42,8 @@ public class RecursiveMoveBenchmark : RobustIntegrationTest
public void GlobalSetup()
{
ProgramShared.PathOffset = "../../../../";
var server = StartServer();
var client = StartClient();
var server = StartServer(new() {Pool = false});
var client = StartClient(new() {Pool = false});
Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync()).Wait();

View File

@@ -1,8 +1,8 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.Build.Framework;
using Robust.Xaml;
namespace Robust.Build.Tasks
{
@@ -37,10 +37,12 @@ namespace Robust.Build.Tasks
var msg = $"CompileRobustXamlTask -> AssemblyFile:{AssemblyFile}, ProjectDirectory:{ProjectDirectory}, OutputPath:{OutputPath}";
BuildEngine.LogMessage(msg, MessageImportance.High);
var res = XamlCompiler.Compile(BuildEngine, input,
var res = XamlAotCompiler.Compile(
BuildEngine, input,
File.ReadAllLines(ReferencesFilePath).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray(),
ProjectDirectory, OutputPath,
(SignAssembly && !DelaySign) ? AssemblyOriginatorKeyFile : null);
OutputPath,
(SignAssembly && !DelaySign) ? AssemblyOriginatorKeyFile : null
);
if (!res.success)
return false;
if (!res.writtentofile)
@@ -65,22 +67,24 @@ namespace Robust.Build.Tasks
return true;
}
// PYREX NOTE: This project was comically null-unsafe before I touched it. I'm just marking what it did accurately
[Required]
public string ReferencesFilePath { get; set; }
public string ReferencesFilePath { get; set; } = null!;
[Required]
public string ProjectDirectory { get; set; }
public string ProjectDirectory { get; set; } = null!;
[Required]
public string AssemblyFile { get; set; }
public string AssemblyFile { get; set; } = null!;
[Required]
public string OriginalCopyPath { get; set; }
public string? OriginalCopyPath { get; set; } = null;
public string OutputPath { get; set; }
public string UpdateBuildIndicator { get; set; }
public string? OutputPath { get; set; }
public string UpdateBuildIndicator { get; set; } = null!;
public string AssemblyOriginatorKeyFile { get; set; }
public string AssemblyOriginatorKeyFile { get; set; } = null!;
public bool SignAssembly { get; set; }
public bool DelaySign { get; set; }
@@ -95,7 +99,7 @@ namespace Robust.Build.Tasks
return rv;
}
public IBuildEngine BuildEngine { get; set; }
public ITaskHost HostObject { get; set; }
public IBuildEngine BuildEngine { get; set; } = null!;
public ITaskHost HostObject { get; set; } = null!;
}
}

View File

@@ -1,37 +0,0 @@
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

@@ -55,9 +55,11 @@ namespace Robust.Build.Tasks
public bool BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties,
IDictionary targetOutputs) => throw new NotSupportedException();
public bool ContinueOnError { get; }
public int LineNumberOfTaskNode { get; }
public int ColumnNumberOfTaskNode { get; }
public string ProjectFileOfTaskNode { get; }
// PYREX NOTE: This project was extremely null-unsafe before I touched it. I'm just marking what it did already
// Here's the broken interface of IBuildEngine that we started with
public bool ContinueOnError => default;
public int LineNumberOfTaskNode => default;
public int ColumnNumberOfTaskNode => default;
public string ProjectFileOfTaskNode => null!;
}
}

View File

@@ -1,17 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\MSBuild\Robust.Engine.props" />
<!--
PJB3005 (2024-08-24)
So the reason that Robust.Client.Injectors is NS2.0 is that Visual Studio
still ships a .NET FX based MSBuild for some godforsaken reason. This means
that when having Robust.Client.Injectors loaded directly by the main MSBuild
process... that would break.
Except we don't do that anyways right now due to file locking issues, so maybe
it's fine to give up on that. Whatever.
-->
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<TargetFramework>netstandard2.0</TargetFramework>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build.Framework" Version="17.8.3" />
<PackageReference Include="Mono.Cecil" Version="0.11.5" />
<PackageReference Include="Pidgin" Version="2.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\XamlX\src\XamlX.IL.Cecil\XamlX.IL.Cecil.csproj" />
<ProjectReference Include="..\Robust.Xaml\Robust.Xaml.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,388 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
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;
using XamlX.IL;
using XamlX.Parsers;
using XamlX.Transform;
using XamlX.TypeSystem;
namespace Robust.Build.Tasks
{
/// <summary>
/// Based on https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
/// Adjusted for our UI-Framework
/// </summary>
public partial class XamlCompiler
{
public static (bool success, bool writtentofile) Compile(IBuildEngine engine, string input, string[] references,
string projectDirectory, string output, string strongNameKey)
{
var typeSystem = new CecilTypeSystem(references
.Where(r => !r.ToLowerInvariant().EndsWith("robust.build.tasks.dll"))
.Concat(new[] { input }), input);
var asm = typeSystem.TargetAssemblyDefinition;
if (asm.MainModule.GetType("CompiledRobustXaml", "XamlIlContext") != null)
{
// If this type exists, the assembly has already been processed by us.
// Do not run again, it would corrupt the file.
// This *shouldn't* be possible due to Inputs/Outputs dependencies in the build system,
// but better safe than sorry eh?
engine.LogWarningEvent(new BuildWarningEventArgs("XAMLIL", "", "", 0, 0, 0, 0, "Ran twice on same assembly file; ignoring.", "", ""));
return (true, false);
}
var compileRes = CompileCore(engine, typeSystem);
if (compileRes == null)
return (true, false);
if (compileRes == false)
return (false, false);
var writerParameters = new WriterParameters { WriteSymbols = asm.MainModule.HasSymbols };
if (!string.IsNullOrWhiteSpace(strongNameKey))
writerParameters.StrongNameKeyBlob = File.ReadAllBytes(strongNameKey);
asm.Write(output, writerParameters);
return (true, true);
}
static bool? CompileCore(IBuildEngine engine, CecilTypeSystem typeSystem)
{
var asm = typeSystem.TargetAssemblyDefinition;
var embrsc = new EmbeddedResources(asm);
if (embrsc.Resources.Count(CheckXamlName) == 0)
// Nothing to do
return null;
var xamlLanguage = new XamlLanguageTypeMappings(typeSystem)
{
XmlnsAttributes =
{
typeSystem.GetType("Avalonia.Metadata.XmlnsDefinitionAttribute"),
},
ContentAttributes =
{
typeSystem.GetType("Avalonia.Metadata.ContentAttribute")
},
UsableDuringInitializationAttributes =
{
typeSystem.GetType("Robust.Client.UserInterface.XAML.UsableDuringInitializationAttribute")
},
DeferredContentPropertyAttributes =
{
typeSystem.GetType("Robust.Client.UserInterface.XAML.DeferredContentAttribute")
},
RootObjectProvider = typeSystem.GetType("Robust.Client.UserInterface.XAML.ITestRootObjectProvider"),
UriContextProvider = typeSystem.GetType("Robust.Client.UserInterface.XAML.ITestUriContext"),
ProvideValueTarget = typeSystem.GetType("Robust.Client.UserInterface.XAML.ITestProvideValueTarget"),
};
var emitConfig = new XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult>
{
ContextTypeBuilderCallback = (b,c) => EmitNameScopeField(xamlLanguage, typeSystem, b, c)
};
var transformerconfig = new TransformerConfiguration(
typeSystem,
typeSystem.TargetAssembly,
xamlLanguage,
XamlXmlnsMappings.Resolve(typeSystem, xamlLanguage), CustomValueConverter);
var contextDef = new TypeDefinition("CompiledRobustXaml", "XamlIlContext",
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
asm.MainModule.Types.Add(contextDef);
var contextClass = XamlILContextDefinition.GenerateContextClass(typeSystem.CreateTypeBuilder(contextDef), typeSystem,
xamlLanguage, emitConfig);
var compiler =
new RobustXamlILCompiler(transformerconfig, emitConfig, true);
bool CompileGroup(IResourceGroup group)
{
var typeDef = new TypeDefinition("CompiledRobustXaml", "!" + group.Name, TypeAttributes.Class,
asm.MainModule.TypeSystem.Object);
//typeDef.CustomAttributes.Add(new CustomAttribute(ed));
asm.MainModule.Types.Add(typeDef);
var builder = typeSystem.CreateTypeBuilder(typeDef);
foreach (var res in group.Resources.Where(CheckXamlName))
{
try
{
engine.LogMessage($"XAMLIL: {res.Name} -> {res.Uri}", MessageImportance.Low);
var xaml = new StreamReader(new MemoryStream(res.FileContents)).ReadToEnd();
var parsed = XDocumentXamlParser.Parse(xaml);
var initialRoot = (XamlAstObjectNode) parsed.Root;
var classDirective = initialRoot.Children.OfType<XamlAstXmlDirective>()
.FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Class");
string classname;
if (classDirective != null && classDirective.Values[0] is XamlAstTextNode tn)
{
classname = tn.Text;
}
else
{
classname = res.Name.Replace(".xaml","");
}
var classType = typeSystem.TargetAssembly.FindType(classname);
if (classType == null)
throw new Exception($"Unable to find type '{classname}'");
compiler.Transform(parsed);
var populateName = $"Populate:{res.Name}";
var buildName = $"Build:{res.Name}";
var classTypeDefinition = typeSystem.GetTypeReference(classType).Resolve();
var populateBuilder = typeSystem.CreateTypeBuilder(classTypeDefinition);
compiler.Compile(parsed, contextClass,
compiler.DefinePopulateMethod(populateBuilder, parsed, populateName,
classTypeDefinition == null),
compiler.DefineBuildMethod(builder, parsed, buildName, true),
null,
(closureName, closureBaseType) =>
populateBuilder.DefineSubType(closureBaseType, closureName, false),
res.Uri, res
);
//add compiled populate method
var compiledPopulateMethod = typeSystem.GetTypeReference(populateBuilder).Resolve().Methods
.First(m => m.Name == populateName);
const string TrampolineName = "!XamlIlPopulateTrampoline";
var trampoline = new MethodDefinition(TrampolineName,
MethodAttributes.Static | MethodAttributes.Private, asm.MainModule.TypeSystem.Void);
trampoline.Parameters.Add(new ParameterDefinition(classTypeDefinition));
classTypeDefinition.Methods.Add(trampoline);
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Call, compiledPopulateMethod));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
var foundXamlLoader = false;
// Find RobustXamlLoader.Load(this) and replace it with !XamlIlPopulateTrampoline(this)
foreach (var method in classTypeDefinition.Methods
.Where(m => !m.Attributes.HasFlag(MethodAttributes.Static)))
{
var i = method.Body.Instructions;
for (var c = 1; c < i.Count; c++)
{
if (i[c].OpCode == OpCodes.Call)
{
var op = i[c].Operand as MethodReference;
if (op != null
&& op.Name == TrampolineName)
{
foundXamlLoader = true;
break;
}
if (op != null
&& op.Name == "Load"
&& op.Parameters.Count == 1
&& op.Parameters[0].ParameterType.FullName == "System.Object"
&& op.DeclaringType.FullName == "Robust.Client.UserInterface.XAML.RobustXamlLoader")
{
if (MatchThisCall(i, c - 1))
{
i[c].Operand = trampoline;
foundXamlLoader = true;
}
}
}
}
}
if (!foundXamlLoader)
{
var ctors = classTypeDefinition.GetConstructors()
.Where(c => !c.IsStatic).ToList();
// We can inject xaml loader into default constructor
if (ctors.Count == 1 && ctors[0].Body.Instructions.Count(o=>o.OpCode != OpCodes.Nop) == 3)
{
var i = ctors[0].Body.Instructions;
var retIdx = i.IndexOf(i.Last(x => x.OpCode == OpCodes.Ret));
i.Insert(retIdx, Instruction.Create(OpCodes.Call, trampoline));
i.Insert(retIdx, Instruction.Create(OpCodes.Ldarg_0));
}
else
{
throw new InvalidProgramException(
$"No call to RobustXamlLoader.Load(this) call found anywhere in the type {classType.FullName} and type seems to have custom constructors.");
}
}
}
catch (Exception e)
{
engine.LogErrorEvent(new BuildErrorEventArgs("XAMLIL", "", res.FilePath, 0, 0, 0, 0,
$"{res.FilePath}: {e.Message}", "", "CompileRobustXaml"));
}
}
return true;
}
if (embrsc.Resources.Count(CheckXamlName) != 0)
{
if (!CompileGroup(embrsc))
return false;
}
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)
{
var nameScopeType = typeSystem.FindType("Robust.Client.UserInterface.XAML.NameScope");
var field = typeBuilder.DefineField(nameScopeType,
ContextNameScopeFieldName, true, false);
constructor
.Ldarg_0()
.Newobj(nameScopeType.GetConstructor())
.Stfld(field);
}
}
interface IResource : IFileSource
{
string Uri { get; }
string Name { get; }
void Remove();
}
interface IResourceGroup
{
string Name { get; }
IEnumerable<IResource> Resources { get; }
}
}

View File

@@ -15,6 +15,9 @@ using XamlX.Transform;
using XamlX.Transform.Transformers;
using XamlX.TypeSystem;
// Yes dude I know this source generator isn't incremental, I'll fix it eventually.
#pragma warning disable RS1035
namespace Robust.Client.NameGenerator
{
/// <summary>

View File

@@ -64,6 +64,8 @@ internal abstract class BaseRobustCefClient : CefClient
string title,
string defaultFilePath,
string[] acceptFilters,
string[] acceptExtensions,
string[] acceptDescriptions,
CefFileDialogCallback callback)
{
callback.Cancel();

View File

@@ -6,7 +6,7 @@ using Xilium.CefGlue;
namespace Robust.Client.WebView.Cef
{
public static class Program
internal static class Program
{
// This was supposed to be the main entry for the subprocess program... It doesn't work.
public static int Main(string[] args)

View File

@@ -44,6 +44,8 @@ namespace Robust.Client.WebView.Cef
//commandLine.AppendSwitch("--disable-gpu-compositing");
//commandLine.AppendSwitch("--in-process-gpu");
commandLine.AppendSwitch("--off-screen-rendering-enabled");
commandLine.AppendSwitch("disable-threaded-scrolling", "1");
commandLine.AppendSwitch("disable-features", "TouchpadAndWheelScrollLatching,AsyncWheelEvents");

View File

@@ -23,6 +23,7 @@ namespace Robust.Client.WebView.Cef
var info = CefWindowInfo.Create();
info.Bounds = new CefRectangle(0, 0, createParams.Width, createParams.Height);
info.SetAsPopup(mainHWnd, "ss14cef");
info.RuntimeStyle = CefRuntimeStyle.Alloy;
var impl = new WebViewWindowImpl(this);

View File

@@ -484,27 +484,27 @@ namespace Robust.Client.WebView.Cef
public void FocusEntered()
{
if (_textInputActive)
_clyde.TextInputStart();
Owner.Root?.Window?.TextInputStart();
}
public void FocusExited()
{
if (_textInputActive)
_clyde.TextInputStop();
Owner.Root?.Window?.TextInputStop();
}
public void TextInputStart()
{
_textInputActive = true;
if (Owner.HasKeyboardFocus())
_clyde.TextInputStart();
Owner.Root?.Window?.TextInputStart();
}
public void TextInputStop()
{
_textInputActive = false;
if (Owner.HasKeyboardFocus())
_clyde.TextInputStop();
Owner.Root?.Window?.TextInputStop();
}
private sealed class LiveData
@@ -587,8 +587,11 @@ namespace Robust.Client.WebView.Cef
}
}
protected override void OnAcceleratedPaint(CefBrowser browser, CefPaintElementType type,
CefRectangle[] dirtyRects, IntPtr sharedHandle)
protected override void OnAcceleratedPaint(
CefBrowser browser,
CefPaintElementType type,
CefRectangle[] dirtyRects,
in CefAcceleratedPaintInfo info)
{
// Unused, but we're forced to implement it so.. NOOP.
}

View File

@@ -5,6 +5,7 @@ using System.Net;
using System.Reflection;
using System.Text;
using Robust.Client.Console;
using Robust.Client.Utility;
using Robust.Shared.Configuration;
using Robust.Shared.ContentPack;
using Robust.Shared.IoC;
@@ -24,6 +25,7 @@ namespace Robust.Client.WebView.Cef
[Dependency] private readonly IDependencyCollection _dependencyCollection = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IGameControllerInternal _gameController = default!;
[Dependency] private readonly IResourceManagerInternal _resourceManager = default!;
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
@@ -61,7 +63,10 @@ namespace Robust.Client.WebView.Cef
var cachePath = "";
if (_resourceManager.UserData is WritableDirProvider userData)
cachePath = userData.GetFullPath(new ResPath("/cef_cache"));
{
var rootDir = UserDataDir.GetRootUserDataDir(_gameController);
cachePath = Path.Combine(rootDir, "cef_cache", "0");
}
var settings = new CefSettings()
{

View File

@@ -5,6 +5,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputType>WinExe</OutputType>
<ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
<CETCompat>false</CETCompat>
</PropertyGroup>
<ItemGroup>

View File

@@ -40,11 +40,7 @@ namespace Robust.Client.Animations
var keyFrame = KeyFrames[keyFrameIndex];
var audioParams = keyFrame.AudioParamsFunc.Invoke();
var audio = new SoundPathSpecifier(keyFrame.Resource)
{
Params = audioParams
};
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>().PlayEntity(audio, Filter.Local(), entity, true);
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>().PlayEntity(keyFrame.Specifier, Filter.Local(), entity, true, audioParams);
}
return (keyFrameIndex, playingTime);
@@ -55,7 +51,7 @@ namespace Robust.Client.Animations
/// <summary>
/// The RSI state to play when this keyframe gets triggered.
/// </summary>
public readonly string Resource;
public readonly ResolvedSoundSpecifier Specifier;
/// <summary>
/// A function that returns the audio parameter to be used.
@@ -69,9 +65,9 @@ namespace Robust.Client.Animations
/// </summary>
public readonly float KeyTime;
public KeyFrame(string resource, float keyTime, Func<AudioParams>? audioParams = null)
public KeyFrame(ResolvedSoundSpecifier specifier, float keyTime, Func<AudioParams>? audioParams = null)
{
Resource = resource;
Specifier = specifier;
KeyTime = keyTime;
AudioParamsFunc = audioParams ?? (() => AudioParams.Default);
}

View File

@@ -13,7 +13,7 @@ namespace Robust.Client.Animations
/// </summary>
public abstract class AnimationTrackProperty : AnimationTrack
{
public List<KeyFrame> KeyFrames { get; protected set; } = new();
public List<KeyFrame> KeyFrames { get; set; } = new();
/// <summary>
/// How to interpolate values when between two keyframes.

View File

@@ -84,6 +84,19 @@ internal partial class AudioManager
AL.Listener(ALListenerfv.Orientation, ref at, ref up);
}
void IAudioInternal.Remove(AudioStream stream)
{
if (stream.ClydeHandle == null)
return;
if (!_audioSampleBuffers.Remove(stream.BufferId))
{
return;
}
AL.DeleteBuffer(stream.BufferId);
}
/// <inheritdoc/>
public AudioStream LoadAudioOggVorbis(Stream stream, string? name = null)
{
@@ -120,9 +133,9 @@ internal partial class AudioManager
_checkAlError();
var handle = new ClydeHandle(_audioSampleBuffers.Count);
_audioSampleBuffers.Add(new LoadedAudioSample(buffer));
_audioSampleBuffers.Add(buffer, new LoadedAudioSample(buffer));
var length = TimeSpan.FromSeconds(vorbis.TotalSamples / (double) vorbis.SampleRate);
return new AudioStream(handle, length, (int) vorbis.Channels, name, vorbis.Title, vorbis.Artist);
return new AudioStream(this, buffer, handle, length, (int) vorbis.Channels, name, vorbis.Title, vorbis.Artist);
}
/// <inheritdoc/>
@@ -179,9 +192,9 @@ internal partial class AudioManager
_checkAlError();
var handle = new ClydeHandle(_audioSampleBuffers.Count);
_audioSampleBuffers.Add(new LoadedAudioSample(buffer));
_audioSampleBuffers.Add(buffer, new LoadedAudioSample(buffer));
var length = TimeSpan.FromSeconds(wav.Data.Length / (double) wav.BlockAlign / wav.SampleRate);
return new AudioStream(handle, length, wav.NumChannels, name);
return new AudioStream(this, buffer, handle, length, wav.NumChannels, name);
}
/// <inheritdoc/>
@@ -210,8 +223,8 @@ internal partial class AudioManager
var handle = new ClydeHandle(_audioSampleBuffers.Count);
var length = TimeSpan.FromSeconds((double) samples.Length / channels / sampleRate);
_audioSampleBuffers.Add(new LoadedAudioSample(buffer));
return new AudioStream(handle, length, channels, name);
_audioSampleBuffers.Add(buffer, new LoadedAudioSample(buffer));
return new AudioStream(this, buffer, handle, length, channels, name);
}
public void SetMasterGain(float newGain)
@@ -293,7 +306,7 @@ internal partial class AudioManager
// ReSharper disable once PossibleInvalidOperationException
// TODO: This really shouldn't be indexing based on the ClydeHandle...
AL.Source(source, ALSourcei.Buffer, _audioSampleBuffers[(int) stream.ClydeHandle!.Value].BufferHandle);
AL.Source(source, ALSourcei.Buffer, _audioSampleBuffers[stream.BufferId].BufferHandle);
var audioSource = new AudioSource(this, source, stream);
_audioSources.Add(source, new WeakReference<BaseAudioSource>(audioSource));
@@ -302,7 +315,7 @@ internal partial class AudioManager
}
/// <inheritdoc/>
IBufferedAudioSource? IAudioInternal.CreateBufferedAudioSource(int buffers, bool floatAudio=false)
IBufferedAudioSource? IAudioInternal.CreateBufferedAudioSource(int buffers, bool floatAudio)
{
var source = AL.GenSource();
@@ -370,5 +383,12 @@ internal partial class AudioManager
}
_bufferedAudioSources.Clear();
foreach (var buffer in _audioSampleBuffers.Values)
{
DeleteAudioBufferOnMainThread(buffer.BufferHandle);
}
_audioSampleBuffers.Clear();
}
}

View File

@@ -5,6 +5,7 @@ using System.Threading;
using OpenTK.Audio.OpenAL;
using OpenTK.Audio.OpenAL.Extensions.Creative.EFX;
using Robust.Client.Audio.Sources;
using Robust.Client.ResourceManagement;
using Robust.Shared;
using Robust.Shared.Audio;
using Robust.Shared.Configuration;
@@ -17,13 +18,15 @@ internal sealed partial class AudioManager : IAudioInternal
{
[Shared.IoC.Dependency] private readonly IConfigurationManager _cfg = default!;
[Shared.IoC.Dependency] private readonly ILogManager _logMan = default!;
[Shared.IoC.Dependency] private readonly IReloadManager _reload = default!;
[Shared.IoC.Dependency] private readonly IResourceCache _cache = default!;
private Thread? _gameThread;
private ALDevice _openALDevice;
private ALContext _openALContext;
private readonly List<LoadedAudioSample> _audioSampleBuffers = new();
private readonly Dictionary<int, LoadedAudioSample> _audioSampleBuffers = new();
private readonly Dictionary<int, WeakReference<BaseAudioSource>> _audioSources =
new();
@@ -116,6 +119,22 @@ internal sealed partial class AudioManager : IAudioInternal
IsEfxSupported = HasAlDeviceExtension("ALC_EXT_EFX");
_cfg.OnValueChanged(CVars.AudioMasterVolume, SetMasterGain, true);
_reload.Register("/Audio", "*.ogg");
_reload.Register("/Audio", "*.wav");
_reload.OnChanged += OnReload;
}
private void OnReload(ResPath args)
{
if (args.Extension != "ogg" &&
args.Extension != "wav")
{
return;
}
_cache.ReloadResource<AudioResource>(args);
}
internal bool IsMainThread()
@@ -140,15 +159,19 @@ internal sealed partial class AudioManager : IAudioInternal
}
}
internal void LogError(string message)
{
OpenALSawmill.Error(message);
}
/// <summary>
/// Like _checkAlError but allows custom data to be passed in as relevant.
/// </summary>
internal void LogALError(string message, [CallerMemberName] string callerMember = "", [CallerLineNumber] int callerLineNumber = -1)
internal void LogALError(ALErrorInterpolatedStringHandler message, [CallerMemberName] string callerMember = "", [CallerLineNumber] int callerLineNumber = -1)
{
var error = AL.GetError();
if (error != ALError.NoError)
if (message.Error != ALError.NoError)
{
OpenALSawmill.Error("[{0}:{1}] AL error: {2}, {3}. Stacktrace is {4}", callerMember, callerLineNumber, error, message, Environment.StackTrace);
OpenALSawmill.Error("[{0}:{1}] AL error: {2}, {3}. Stacktrace is {4}", callerMember, callerLineNumber, message.Error, message.ToStringAndClear(), Environment.StackTrace);
}
}
@@ -170,4 +193,32 @@ internal sealed partial class AudioManager : IAudioInternal
BufferHandle = bufferHandle;
}
}
[InterpolatedStringHandler]
internal ref struct ALErrorInterpolatedStringHandler
{
private DefaultInterpolatedStringHandler _handler;
public ALError Error;
public ALErrorInterpolatedStringHandler(int literalLength, int formattedCount, out bool shouldAppend)
{
Error = AL.GetError();
if (Error == ALError.NoError)
{
shouldAppend = false;
_handler = default;
}
else
{
shouldAppend = true;
_handler = new DefaultInterpolatedStringHandler(literalLength, formattedCount);
}
}
public string ToStringAndClear() => _handler.ToStringAndClear();
public override string ToString() => _handler.ToString();
public void AppendLiteral(string value) => _handler.AppendLiteral(value);
public void AppendFormatted<T>(T value) => _handler.AppendFormatted(value);
public void AppendFormatted<T>(T value, string? format) => _handler.AppendFormatted(value, format);
}
}

View File

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

View File

@@ -6,8 +6,15 @@ namespace Robust.Client.Audio;
/// <summary>
/// Has the metadata for a particular audio stream as well as the relevant internal handle to it.
/// </summary>
public sealed class AudioStream
public sealed class AudioStream : IDisposable
{
private IAudioInternal _audio;
/// <summary>
/// Buffer ID for this audio in AL.
/// </summary>
internal int BufferId { get; }
public TimeSpan Length { get; }
internal IClydeHandle? ClydeHandle { get; }
public string? Name { get; }
@@ -15,8 +22,10 @@ public sealed class AudioStream
public string? Artist { get; }
public int ChannelCount { get; }
internal AudioStream(IClydeHandle? handle, TimeSpan length, int channelCount, string? name = null, string? title = null, string? artist = null)
internal AudioStream(IAudioInternal internalAudio, int bufferId, IClydeHandle? handle, TimeSpan length, int channelCount, string? name = null, string? title = null, string? artist = null)
{
_audio = internalAudio;
BufferId = bufferId;
ClydeHandle = handle;
Length = length;
ChannelCount = channelCount;
@@ -24,4 +33,9 @@ public sealed class AudioStream
Title = title;
Artist = artist;
}
public void Dispose()
{
_audio.Remove(this);
}
}

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using OpenTK.Audio.OpenAL;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
@@ -37,11 +38,10 @@ public sealed partial class AudioSystem : SharedAudioSystem
[Dependency] private readonly IReplayRecordingManager _replayRecording = default!;
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IParallelManager _parMan = default!;
[Dependency] private readonly IRuntimeLog _runtimeLog = default!;
[Dependency] private readonly IAudioInternal _audio = default!;
[Dependency] private readonly MetaDataSystem _metadata = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;
[Dependency] private readonly SharedTransformSystem _xformSys = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
@@ -49,13 +49,16 @@ public sealed partial class AudioSystem : SharedAudioSystem
/// Per-tick cache of relevant streams.
/// </summary>
private readonly List<(EntityUid Entity, AudioComponent Component, TransformComponent Xform)> _streams = new();
private EntityUid? _listenerGrid;
private UpdateAudioJob _updateAudioJob;
private float _audioFrameTime;
private float _audioFrameTimeRemaining;
private EntityQuery<PhysicsComponent> _physicsQuery;
private float _maxRayLength;
private float _zOffset;
private float _audioEndBuffer;
public override float ZOffset
{
@@ -79,8 +82,6 @@ public sealed partial class AudioSystem : SharedAudioSystem
}
}
private float _zOffset;
/// <inheritdoc />
public override void Initialize()
{
@@ -108,13 +109,31 @@ public sealed partial class AudioSystem : SharedAudioSystem
SubscribeNetworkEvent<PlayAudioEntityMessage>(OnEntityAudio);
SubscribeNetworkEvent<PlayAudioPositionalMessage>(OnEntityCoordinates);
Subs.CVar(CfgManager, CVars.AudioEndBuffer, OnAudioBuffer, true);
Subs.CVar(CfgManager, CVars.AudioAttenuation, OnAudioAttenuation, true);
Subs.CVar(CfgManager, CVars.AudioRaycastLength, OnRaycastLengthChanged, true);
Subs.CVar(CfgManager, CVars.AudioTickRate, OnAudioTickRate, true);
InitializeLimit();
}
private void OnAudioState(EntityUid uid, AudioComponent component, ref AfterAutoHandleStateEvent args)
private void OnAudioBuffer(float value)
{
_audioEndBuffer = value;
}
private void OnAudioTickRate(int obj)
{
_audioFrameTime = 1f / obj;
_audioFrameTimeRemaining = MathF.Min(_audioFrameTimeRemaining, _audioFrameTime);
}
private void OnAudioState(Entity<AudioComponent> entity, ref AfterAutoHandleStateEvent args)
{
var component = entity.Comp;
if (component.LifeStage < ComponentLifeStage.Initialized)
return;
ApplyAudioParams(component.Params, component);
component.Source.Global = component.Global;
@@ -138,21 +157,29 @@ public sealed partial class AudioSystem : SharedAudioSystem
case AudioState.Stopped:
component.StopPlaying();
component.PlaybackPosition = 0f;
break;
return;
}
// If playback position changed then update it.
if (!string.IsNullOrEmpty(component.FileName))
{
var position = (float) ((component.PauseTime ?? Timing.CurTime) - component.AudioStart).TotalSeconds;
var currentPosition = component.Source.PlaybackPosition;
var diff = Math.Abs(position - currentPosition);
var position = (float) ((entity.Comp.PauseTime ?? Timing.CurTime) - entity.Comp.AudioStart).TotalSeconds;
var currentPosition = entity.Comp.Source.PlaybackPosition;
var diff = Math.Abs(position - currentPosition);
if (diff > 0.1f)
// Don't try to set the audio too far ahead.
if (!string.IsNullOrEmpty(entity.Comp.FileName))
{
if (position > GetAudioLengthImpl(entity.Comp.FileName).TotalSeconds - _audioEndBuffer)
{
component.PlaybackPosition = position;
entity.Comp.StopPlaying();
return;
}
}
// If the difference is minor then we'll just keep playing it.
if (diff > 0.1f)
{
entity.Comp.PlaybackPosition = position;
}
}
/// <summary>
@@ -200,6 +227,10 @@ public sealed partial class AudioSystem : SharedAudioSystem
private void SetupSource(Entity<AudioComponent> entity, AudioResource audioResource, TimeSpan? length = null)
{
var component = entity.Comp;
length ??= GetAudioLength(component.FileName);
// If audio came into range then start playback at the correct position.
var offset = ((entity.Comp.PauseTime ?? Timing.CurTime) - component.AudioStart).TotalSeconds;
if (TryAudioLimit(component.FileName))
{
@@ -216,11 +247,6 @@ public sealed partial class AudioSystem : SharedAudioSystem
}
}
if ((component.Flags & AudioFlags.GridAudio) != 0x0)
{
_metadata.SetFlag(entity.Owner, MetaDataFlags.Undetachable, true);
}
// Need to set all initial data for first frame.
ApplyAudioParams(component.Params, component);
component.Source.Global = component.Global;
@@ -228,10 +254,17 @@ public sealed partial class AudioSystem : SharedAudioSystem
// Don't play until first frame so occlusion etc. are correct.
component.Gain = 0f;
length ??= GetAudioLength(component.FileName);
// If audio came into range then start playback at the correct position.
var offset = (Timing.CurTime - component.AudioStart).TotalSeconds % length.Value.TotalSeconds;
// If the offset < buffer than just play it from the start.
if (offset < AudioDespawnBuffer)
{
offset = 0;
}
// Not enough audio to play
else if (offset > length.Value.TotalSeconds - _audioEndBuffer)
{
component.StopPlaying();
return;
}
if (offset > 0)
{
@@ -259,6 +292,13 @@ public sealed partial class AudioSystem : SharedAudioSystem
public override void FrameUpdate(float frameTime)
{
_audioFrameTimeRemaining -= frameTime;
if (_audioFrameTimeRemaining > 0f)
return;
// Clamp to 0 in case we have a really long frame.
_audioFrameTimeRemaining = MathF.Max(0f, _audioFrameTime + _audioFrameTimeRemaining);
var eye = _eyeManager.CurrentEye;
var localEntity = _playerManager.LocalEntity;
Vector2 listenerVelocity;
@@ -282,9 +322,6 @@ public sealed partial class AudioSystem : SharedAudioSystem
_streams.Add((uid, comp, xform));
}
_mapManager.TryFindGridAt(ourPos, out var gridUid, out _);
_listenerGrid = gridUid == EntityUid.Invalid ? null : gridUid;
try
{
_updateAudioJob.OurPosition = ourPos;
@@ -336,52 +373,18 @@ public sealed partial class AudioSystem : SharedAudioSystem
}
Vector2 worldPos;
var gridUid = xform.ParentUid;
component.Volume = component.Params.Volume;
// Handle grid audio differently by using nearest-edge instead of entity centre.
// Handle grid audio differently by using grid position.
if ((component.Flags & AudioFlags.GridAudio) != 0x0)
{
// It's our grid so max volume.
if (_listenerGrid == gridUid)
{
component.Volume = component.Params.Volume;
component.Occlusion = 0f;
component.Position = listener.Position;
return;
}
// TODO: Need a grid-optimised version because this is gonna be expensive.
// Just to avoid clipping on and off grid or nearestPoint changing we'll
// always set the sound to listener's pos, we'll just manually do gain ourselves.
if (_physics.TryGetNearest(gridUid, listener, out _, out var gridDistance))
{
// Out of range
if (gridDistance > component.MaxDistance)
{
component.Gain = 0f;
return;
}
var paramsGain = VolumeToGain(component.Params.Volume);
// Thought I'd never have to manually calculate gain again but this is the least
// unpleasant audio I could get at the moment.
component.Gain = paramsGain * _audio.GetAttenuationGain(
gridDistance,
component.Params.RolloffFactor,
component.Params.ReferenceDistance,
component.Params.MaxDistance);
component.Position = listener.Position;
return;
}
// Can't get nearest point so don't play anymore.
component.Gain = 0f;
return;
var parentUid = xform.ParentUid;
worldPos = _maps.GetGridPosition(parentUid);
}
else
{
worldPos = _xformSys.GetWorldPosition(entity);
}
worldPos = _xformSys.GetWorldPosition(entity);
component.Volume = component.Params.Volume;
// Max distance check
var delta = worldPos - listener.Position;
@@ -403,8 +406,15 @@ public sealed partial class AudioSystem : SharedAudioSystem
}
// Update audio occlusion
var occlusion = GetOcclusion(listener, delta, distance, entity);
component.Occlusion = occlusion;
if ((component.Flags & AudioFlags.NoOcclusion) == AudioFlags.NoOcclusion)
{
component.Occlusion = 0f;
}
else
{
var occlusion = GetOcclusion(listener, delta, distance, entity);
component.Occlusion = occlusion;
}
// Update audio positions.
component.Position = worldPos;
@@ -436,6 +446,16 @@ public sealed partial class AudioSystem : SharedAudioSystem
return occlusion;
}
private bool TryGetAudio(ResolvedSoundSpecifier specifier, [NotNullWhen(true)] out AudioResource? audio)
{
var filename = GetAudioPath(specifier);
if (_resourceCache.TryGetResource(new ResPath(filename), out audio))
return true;
Log.Error($"Server tried to play audio file {filename} which does not exist.");
return false;
}
private bool TryGetAudio(string filename, [NotNullWhen(true)] out AudioResource? audio)
{
if (_resourceCache.TryGetResource(new ResPath(filename), out audio))
@@ -454,15 +474,15 @@ public sealed partial class AudioSystem : SharedAudioSystem
return false;
}
public override (EntityUid Entity, AudioComponent Component)? PlayPvs(string? filename, EntityCoordinates coordinates,
public override (EntityUid Entity, AudioComponent Component)? PlayPvs(ResolvedSoundSpecifier? specifier, EntityCoordinates coordinates,
AudioParams? audioParams = null)
{
return PlayStatic(filename, Filter.Local(), coordinates, true, audioParams);
return PlayStatic(specifier, Filter.Local(), coordinates, true, audioParams);
}
public override (EntityUid Entity, AudioComponent Component)? PlayPvs(string? filename, EntityUid uid, AudioParams? audioParams = null)
public override (EntityUid Entity, AudioComponent Component)? PlayPvs(ResolvedSoundSpecifier? specifier, EntityUid uid, AudioParams? audioParams = null)
{
return PlayEntity(filename, Filter.Local(), uid, true, audioParams);
return PlayEntity(specifier, Filter.Local(), uid, true, audioParams);
}
/// <inheritdoc />
@@ -474,6 +494,17 @@ public sealed partial class AudioSystem : SharedAudioSystem
return null; // uhh Lets hope predicted audio never needs to somehow store the playing audio....
}
/// <inheritdoc />
public override (EntityUid Entity, AudioComponent Component)? PlayLocal(
SoundSpecifier? sound,
EntityUid source,
EntityUid? soundInitiator,
AudioParams? audioParams = null
)
{
return PlayPredicted(sound, source, soundInitiator, audioParams);
}
public override (EntityUid Entity, AudioComponent Component)? PlayPredicted(SoundSpecifier? sound, EntityCoordinates coordinates, EntityUid? user, AudioParams? audioParams = null)
{
if (Timing.IsFirstTimePredicted && sound != null)
@@ -487,21 +518,21 @@ public sealed partial class AudioSystem : SharedAudioSystem
/// </summary>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="audioParams"></param>
private (EntityUid Entity, AudioComponent Component)? PlayGlobal(string? filename, AudioParams? audioParams = null, bool recordReplay = true)
private (EntityUid Entity, AudioComponent Component)? PlayGlobal(ResolvedSoundSpecifier? specifier, AudioParams? audioParams = null, bool recordReplay = true)
{
if (string.IsNullOrEmpty(filename))
if (specifier is null)
return null;
if (recordReplay && _replayRecording.IsRecording)
{
_replayRecording.RecordReplayMessage(new PlayAudioGlobalMessage
{
FileName = filename,
Specifier = specifier,
AudioParams = audioParams ?? AudioParams.Default
});
}
return TryGetAudio(filename, out var audio) ? PlayGlobal(audio, audioParams) : default;
return TryGetAudio(specifier, out var audio) ? PlayGlobal(audio, specifier, audioParams) : default;
}
/// <summary>
@@ -509,12 +540,12 @@ public sealed partial class AudioSystem : SharedAudioSystem
/// </summary>
/// <param name="stream">The audio stream to play.</param>
/// <param name="audioParams"></param>
public (EntityUid Entity, AudioComponent Component)? PlayGlobal(AudioStream stream, AudioParams? audioParams = null)
public (EntityUid Entity, AudioComponent Component)? PlayGlobal(AudioStream stream, ResolvedSoundSpecifier? specifier, AudioParams? audioParams = null)
{
var (entity, component) = CreateAndStartPlayingStream(audioParams, stream);
var (entity, component) = CreateAndStartPlayingStream(audioParams, specifier, stream);
component.Global = true;
component.Source.Global = true;
Dirty(entity, component);
DirtyField(entity, component, nameof(AudioComponent.Global));
return (entity, component);
}
@@ -523,22 +554,22 @@ public sealed partial class AudioSystem : SharedAudioSystem
/// </summary>
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
/// <param name="entity">The entity "emitting" the audio.</param>
private (EntityUid Entity, AudioComponent Component)? PlayEntity(string? filename, EntityUid entity, AudioParams? audioParams = null, bool recordReplay = true)
private (EntityUid Entity, AudioComponent Component)? PlayEntity(ResolvedSoundSpecifier? specifier, EntityUid entity, AudioParams? audioParams = null, bool recordReplay = true)
{
if (string.IsNullOrEmpty(filename))
if (specifier is null)
return null;
if (recordReplay && _replayRecording.IsRecording)
{
_replayRecording.RecordReplayMessage(new PlayAudioEntityMessage
{
FileName = filename,
Specifier = specifier,
NetEntity = GetNetEntity(entity),
AudioParams = audioParams ?? AudioParams.Default
});
}
return TryGetAudio(filename, out var audio) ? PlayEntity(audio, entity, audioParams) : default;
return TryGetAudio(specifier, out var audio) ? PlayEntity(audio, entity, specifier, audioParams) : default;
}
/// <summary>
@@ -547,7 +578,7 @@ public sealed partial class AudioSystem : SharedAudioSystem
/// <param name="stream">The audio stream to play.</param>
/// <param name="entity">The entity "emitting" the audio.</param>
/// <param name="audioParams"></param>
public (EntityUid Entity, AudioComponent Component)? PlayEntity(AudioStream stream, EntityUid entity, AudioParams? audioParams = null)
public (EntityUid Entity, AudioComponent Component)? PlayEntity(AudioStream stream, EntityUid entity, ResolvedSoundSpecifier? specifier, AudioParams? audioParams = null)
{
if (TerminatingOrDeleted(entity))
{
@@ -555,7 +586,7 @@ public sealed partial class AudioSystem : SharedAudioSystem
return null;
}
var playing = CreateAndStartPlayingStream(audioParams, stream);
var playing = CreateAndStartPlayingStream(audioParams, specifier, stream);
_xformSys.SetCoordinates(playing.Entity, new EntityCoordinates(entity, Vector2.Zero));
return playing;
@@ -567,22 +598,22 @@ public sealed partial class AudioSystem : SharedAudioSystem
/// <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>
private (EntityUid Entity, AudioComponent Component)? PlayStatic(string? filename, EntityCoordinates coordinates, AudioParams? audioParams = null, bool recordReplay = true)
private (EntityUid Entity, AudioComponent Component)? PlayStatic(ResolvedSoundSpecifier? specifier, EntityCoordinates coordinates, AudioParams? audioParams = null, bool recordReplay = true)
{
if (string.IsNullOrEmpty(filename))
if (specifier is null)
return null;
if (recordReplay && _replayRecording.IsRecording)
{
_replayRecording.RecordReplayMessage(new PlayAudioPositionalMessage
{
FileName = filename,
Specifier = specifier,
Coordinates = GetNetCoordinates(coordinates),
AudioParams = audioParams ?? AudioParams.Default
});
}
return TryGetAudio(filename, out var audio) ? PlayStatic(audio, coordinates, audioParams) : default;
return TryGetAudio(specifier, out var audio) ? PlayStatic(audio, coordinates, specifier, audioParams) : default;
}
/// <summary>
@@ -591,7 +622,7 @@ public sealed partial class AudioSystem : SharedAudioSystem
/// <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>
public (EntityUid Entity, AudioComponent Component)? PlayStatic(AudioStream stream, EntityCoordinates coordinates, AudioParams? audioParams = null)
public (EntityUid Entity, AudioComponent Component)? PlayStatic(AudioStream stream, EntityCoordinates coordinates, ResolvedSoundSpecifier? specifier, AudioParams? audioParams = null)
{
if (TerminatingOrDeleted(coordinates.EntityId))
{
@@ -599,33 +630,33 @@ public sealed partial class AudioSystem : SharedAudioSystem
return null;
}
var playing = CreateAndStartPlayingStream(audioParams, stream);
var playing = CreateAndStartPlayingStream(audioParams, specifier, stream);
_xformSys.SetCoordinates(playing.Entity, coordinates);
return playing;
}
/// <inheritdoc />
public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(string? filename, Filter playerFilter, bool recordReplay, AudioParams? audioParams = null)
public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(ResolvedSoundSpecifier? specifier, Filter playerFilter, bool recordReplay, AudioParams? audioParams = null)
{
return PlayGlobal(filename, audioParams);
return PlayGlobal(specifier, audioParams);
}
/// <inheritdoc />
public override (EntityUid Entity, AudioComponent Component)? PlayEntity(string? filename, Filter playerFilter, EntityUid entity, bool recordReplay, AudioParams? audioParams = null)
public override (EntityUid Entity, AudioComponent Component)? PlayEntity(ResolvedSoundSpecifier? specifier, Filter playerFilter, EntityUid entity, bool recordReplay, AudioParams? audioParams = null)
{
return PlayEntity(filename, entity, audioParams);
return PlayEntity(specifier, entity, audioParams);
}
/// <inheritdoc />
public override (EntityUid Entity, AudioComponent Component)? PlayStatic(string? filename, Filter playerFilter, EntityCoordinates coordinates, bool recordReplay, AudioParams? audioParams = null)
public override (EntityUid Entity, AudioComponent Component)? PlayStatic(ResolvedSoundSpecifier? specifier, Filter playerFilter, EntityCoordinates coordinates, bool recordReplay, AudioParams? audioParams = null)
{
return PlayStatic(filename, coordinates, audioParams);
return PlayStatic(specifier, coordinates, audioParams);
}
/// <inheritdoc />
public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(string? filename, ICommonSession recipient, AudioParams? audioParams = null)
public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(ResolvedSoundSpecifier? specifier, ICommonSession recipient, AudioParams? audioParams = null)
{
return PlayGlobal(filename, audioParams);
return PlayGlobal(specifier, audioParams);
}
public override void LoadStream<T>(Entity<AudioComponent> entity, T stream)
@@ -639,47 +670,48 @@ public sealed partial class AudioSystem : SharedAudioSystem
}
/// <inheritdoc />
public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(string? filename, EntityUid recipient, AudioParams? audioParams = null)
public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(ResolvedSoundSpecifier? specifier, EntityUid recipient, AudioParams? audioParams = null)
{
return PlayGlobal(filename, audioParams);
return PlayGlobal(specifier, audioParams);
}
/// <inheritdoc />
public override (EntityUid Entity, AudioComponent Component)? PlayEntity(string? filename, ICommonSession recipient, EntityUid uid, AudioParams? audioParams = null)
public override (EntityUid Entity, AudioComponent Component)? PlayEntity(ResolvedSoundSpecifier? specifier, ICommonSession recipient, EntityUid uid, AudioParams? audioParams = null)
{
return PlayEntity(filename, uid, audioParams);
return PlayEntity(specifier, uid, audioParams);
}
/// <inheritdoc />
public override (EntityUid Entity, AudioComponent Component)? PlayEntity(string? filename, EntityUid recipient, EntityUid uid, AudioParams? audioParams = null)
public override (EntityUid Entity, AudioComponent Component)? PlayEntity(ResolvedSoundSpecifier? specifier, EntityUid recipient, EntityUid uid, AudioParams? audioParams = null)
{
return PlayEntity(filename, uid, audioParams);
return PlayEntity(specifier, uid, audioParams);
}
/// <inheritdoc />
public override (EntityUid Entity, AudioComponent Component)? PlayStatic(string? filename, ICommonSession recipient, EntityCoordinates coordinates, AudioParams? audioParams = null)
public override (EntityUid Entity, AudioComponent Component)? PlayStatic(ResolvedSoundSpecifier? specifier, ICommonSession recipient, EntityCoordinates coordinates, AudioParams? audioParams = null)
{
return PlayStatic(filename, coordinates, audioParams);
return PlayStatic(specifier, coordinates, audioParams);
}
/// <inheritdoc />
public override (EntityUid Entity, AudioComponent Component)? PlayStatic(string? filename, EntityUid recipient, EntityCoordinates coordinates, AudioParams? audioParams = null)
public override (EntityUid Entity, AudioComponent Component)? PlayStatic(ResolvedSoundSpecifier? specifier, EntityUid recipient, EntityCoordinates coordinates, AudioParams? audioParams = null)
{
return PlayStatic(filename, coordinates, audioParams);
return PlayStatic(specifier, coordinates, audioParams);
}
private (EntityUid Entity, AudioComponent Component) CreateAndStartPlayingStream(AudioParams? audioParams, AudioStream stream)
private (EntityUid Entity, AudioComponent Component) CreateAndStartPlayingStream(AudioParams? audioParams, ResolvedSoundSpecifier? specifier, AudioStream stream)
{
var audioP = audioParams ?? AudioParams.Default;
var entity = EntityManager.CreateEntityUninitialized("Audio", MapCoordinates.Nullspace);
var comp = SetupAudio(entity, null, audioP, stream.Length);
LoadStream((entity, comp), stream);
var entity = SetupAudio(specifier, audioP, initialize: false, length: stream.Length);
LoadStream(entity, stream);
EntityManager.InitializeAndStartEntity(entity);
var comp = entity.Comp;
var source = comp.Source;
// TODO clamp the offset inside of SetPlaybackPosition() itself.
var offset = audioP.PlayOffsetSeconds;
offset = Math.Clamp(offset, 0f, (float) stream.Length.TotalSeconds - 0.01f);
var maxOffset = Math.Max((float) stream.Length.TotalSeconds - 0.01f, 0f);
offset = Math.Clamp(offset, 0f, maxOffset);
source.PlaybackPosition = offset;
// For server we will rely on the adjusted one but locally we will have to adjust it ourselves.
@@ -703,17 +735,17 @@ public sealed partial class AudioSystem : SharedAudioSystem
private void OnEntityCoordinates(PlayAudioPositionalMessage ev)
{
PlayStatic(ev.FileName, GetCoordinates(ev.Coordinates), ev.AudioParams, false);
PlayStatic(ev.Specifier, GetCoordinates(ev.Coordinates), ev.AudioParams, false);
}
private void OnEntityAudio(PlayAudioEntityMessage ev)
{
PlayEntity(ev.FileName, GetEntity(ev.NetEntity), ev.AudioParams, false);
PlayEntity(ev.Specifier, GetEntity(ev.NetEntity), ev.AudioParams, false);
}
private void OnGlobalAudio(PlayAudioGlobalMessage ev)
{
PlayGlobal(ev.FileName, ev.AudioParams, false);
PlayGlobal(ev.Specifier, ev.AudioParams, false);
}
protected override TimeSpan GetAudioLengthImpl(string filename)

View File

@@ -13,6 +13,8 @@ namespace Robust.Client.Audio;
/// </summary>
internal sealed class HeadlessAudioManager : IAudioInternal
{
private int _audioBuffer;
/// <inheritdoc />
public void InitializePostWindowing()
{
@@ -65,6 +67,11 @@ internal sealed class HeadlessAudioManager : IAudioInternal
{
}
/// <inheritdoc />
public void Remove(AudioStream stream)
{
}
/// <inheritdoc />
public void StopAllAudio()
{
@@ -101,11 +108,11 @@ internal sealed class HeadlessAudioManager : IAudioInternal
public AudioStream LoadAudioRaw(ReadOnlySpan<short> samples, int channels, int sampleRate, string? name = null)
{
var length = TimeSpan.FromSeconds((double) samples.Length / channels / sampleRate);
return new AudioStream(null, length, channels, name);
return new AudioStream(this, _audioBuffer++, null, length, channels, name);
}
private static AudioStream AudioStreamFromMetadata(AudioMetadata metadata, string? name)
private AudioStream AudioStreamFromMetadata(AudioMetadata metadata, string? name)
{
return new AudioStream(null, metadata.Length, metadata.ChannelCount, name, metadata.Title, metadata.Artist);
return new AudioStream(this, _audioBuffer++, null, metadata.Length, metadata.ChannelCount, name, metadata.Title, metadata.Artist);
}
}

View File

@@ -44,6 +44,8 @@ internal interface IAudioInternal : IAudioManager
void SetAttenuation(Attenuation attenuation);
void Remove(AudioStream stream);
/// <summary>
/// Stops all audio from playing.
/// </summary>

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using Robust.Client.Audio.Sources;
using Robust.Shared.Audio.Sources;
namespace Robust.Client.Audio;
@@ -11,7 +10,7 @@ namespace Robust.Client.Audio;
public interface IAudioManager
{
IAudioSource? CreateAudioSource(AudioStream stream);
AudioStream LoadAudioOggVorbis(Stream stream, string? name = null);
AudioStream LoadAudioWav(Stream stream, string? name = null);

View File

@@ -33,12 +33,6 @@ public interface IMidiRenderer : IDisposable
/// </summary>
bool LoopMidi { get; set; }
/// <summary>
/// This increases all note on velocities to 127.
/// </summary>
[Obsolete($"Use {nameof(VelocityOverride)} instead, you can set it to 127 to achieve the same effect.")]
bool VolumeBoost { get; set; }
/// <summary>
/// The midi program (instrument) the renderer is using.
/// </summary>

View File

@@ -205,14 +205,6 @@ internal sealed class MidiRenderer : IMidiRenderer
}
}
[ViewVariables(VVAccess.ReadWrite)]
[Obsolete($"Use {nameof(VelocityOverride)} instead, you can set it to 127 to achieve the same effect.")]
public bool VolumeBoost
{
get => VelocityOverride == 127;
set => VelocityOverride = value ? 127 : null;
}
[ViewVariables(VVAccess.ReadWrite)]
public EntityUid? TrackingEntity { get; set; } = null;
@@ -234,6 +226,9 @@ internal sealed class MidiRenderer : IMidiRenderer
if (value == _master)
return;
if (CheckMasterCycle(value))
throw new InvalidOperationException("Tried to set master to a child of this renderer!");
if (_master is { Disposed: false })
{
try
@@ -737,4 +732,22 @@ internal sealed class MidiRenderer : IMidiRenderer
_synth?.Dispose();
_player?.Dispose();
}
/// <summary>
/// Check that a given renderer is not already a child of this renderer, i.e. it would introduce a cycle if set as master of this renderer.
/// </summary>
private bool CheckMasterCycle(IMidiRenderer? otherRenderer)
{
// Doesn't inside drift, cringe.
while (otherRenderer != null)
{
if (otherRenderer == this)
return true;
otherRenderer = otherRenderer.Master;
}
return false;
}
}

View File

@@ -13,7 +13,7 @@ internal sealed class AudioSource : BaseAudioSource
/// <summary>
/// Underlying stream to the audio.
/// </summary>
private readonly AudioStream _sourceStream;
internal readonly AudioStream SourceStream;
#if DEBUG
private bool _didPositionWarning;
@@ -21,7 +21,7 @@ internal sealed class AudioSource : BaseAudioSource
public AudioSource(AudioManager master, int sourceHandle, AudioStream sourceStream) : base(master, sourceHandle)
{
_sourceStream = sourceStream;
SourceStream = sourceStream;
}
/// <inheritdoc />
@@ -47,13 +47,13 @@ internal sealed class AudioSource : BaseAudioSource
#if DEBUG
// OpenAL doesn't seem to want to play stereo positionally.
// Log a warning if people try to.
if (_sourceStream.ChannelCount > 1 && !_didPositionWarning)
if (SourceStream.ChannelCount > 1 && !_didPositionWarning)
{
_didPositionWarning = true;
Master.OpenALSawmill.Warning("Attempting to set position on audio source with multiple audio channels! Stream: '{0}'. Make sure the audio is MONO, not stereo.",
_sourceStream.Name);
SourceStream.Name);
// warning isn't enough, people just ignore it :(
DebugTools.Assert(false, $"Attempting to set position on audio source with multiple audio channels! Stream: '{_sourceStream.Name}'. Make sure the audio is MONO, not stereo.");
DebugTools.Assert(false, $"Attempting to set position on audio source with multiple audio channels! Stream: '{SourceStream.Name}'. Make sure the audio is MONO, not stereo.");
}
#endif

View File

@@ -208,6 +208,12 @@ public abstract class BaseAudioSource : IAudioSource
}
set
{
if (float.IsNaN(value))
{
Master.LogError($"Tried to set NaN gain, setting audio source to 0f: {Environment.StackTrace}");
value = 0f;
}
_checkDisposed();
var priorOcclusion = 1f;
if (!IsEfxSupported)

View File

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

View File

@@ -88,10 +88,10 @@ namespace Robust.Client
{
if (GameInfo != null)
{
GameInfo.TickRate = (byte) tickrate;
GameInfo.TickRate = (ushort) tickrate;
}
_timing.SetTickRateAt((byte) tickrate, info.TickChanged);
_timing.SetTickRateAt((ushort) tickrate, info.TickChanged);
_logger.Info($"Tickrate changed to: {tickrate} on tick {_timing.CurTick}");
}
@@ -115,10 +115,6 @@ namespace Robust.Client
/// <inheritdoc />
public void DisconnectFromServer(string reason)
{
DebugTools.Assert(RunLevel > ClientRunLevel.Initialize);
DebugTools.Assert(_net.IsConnected);
// run level changed in OnNetDisconnect()
// are both of these *really* needed?
_net.ClientDisconnect(reason);
}
@@ -395,6 +391,6 @@ namespace Robust.Client
/// </summary>
public int ServerMaxPlayers { get; set; }
public byte TickRate { get; internal set; }
public uint TickRate { get; internal set; }
}
}

View File

@@ -8,7 +8,9 @@ using Robust.Client.GameObjects;
using Robust.Client.GameStates;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Clyde;
using Robust.Client.HWId;
using Robust.Client.Input;
using Robust.Client.Localization;
using Robust.Client.Map;
using Robust.Client.Placement;
using Robust.Client.Player;
@@ -26,6 +28,7 @@ using Robust.Client.Upload;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.RichText;
using Robust.Client.UserInterface.Themes;
using Robust.Client.UserInterface.XAML.Proxy;
using Robust.Client.Utility;
using Robust.Client.ViewVariables;
using Robust.Shared;
@@ -34,6 +37,7 @@ using Robust.Shared.Console;
using Robust.Shared.ContentPack;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Physics;
@@ -44,6 +48,7 @@ using Robust.Shared.Replays;
using Robust.Shared.Serialization;
using Robust.Shared.Timing;
using Robust.Shared.Upload;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
namespace Robust.Client
@@ -100,6 +105,9 @@ namespace Robust.Client
deps.Register<ProfViewManager>();
deps.Register<IGamePrototypeLoadManager, GamePrototypeLoadManager>();
deps.Register<NetworkResourceManager>();
deps.Register<IReloadManager, ReloadManager>();
deps.Register<ILocalizationManager, ClientLocalizationManager>();
deps.Register<ILocalizationManagerInternal, ClientLocalizationManager>();
switch (mode)
{
@@ -146,7 +154,18 @@ namespace Robust.Client
deps.Register<IConfigurationManagerInternal, ClientNetConfigurationManager>();
deps.Register<IClientNetConfigurationManager, ClientNetConfigurationManager>();
deps.Register<INetConfigurationManagerInternal, ClientNetConfigurationManager>();
#if TOOLS
deps.Register<IXamlProxyManager, XamlProxyManager>();
deps.Register<IXamlHotReloadManager, XamlHotReloadManager>();
#else
deps.Register<IXamlProxyManager, XamlProxyManagerStub>();
deps.Register<IXamlHotReloadManager, XamlHotReloadManagerStub>();
#endif
deps.Register<IXamlProxyHelper, XamlProxyHelper>();
deps.Register<MarkupTagManager>();
deps.Register<IHWId, BasicHWId>();
}
}
}

View File

@@ -2,6 +2,7 @@ using System.Numerics;
using Robust.Client.GameObjects;
using Robust.Shared.ComponentTrees;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
@@ -9,25 +10,7 @@ namespace Robust.Client.ComponentTrees;
public sealed class SpriteTreeSystem : ComponentTreeSystem<SpriteTreeComponent, SpriteComponent>
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SpriteComponent, QueueSpriteTreeUpdateEvent>(OnQueueUpdate);
}
private void OnQueueUpdate(EntityUid uid, SpriteComponent component, ref QueueSpriteTreeUpdateEvent args)
=> QueueTreeUpdate(uid, component, args.Xform);
// TODO remove this when finally ECSing sprite components
[ByRefEvent]
internal readonly struct QueueSpriteTreeUpdateEvent
{
public readonly TransformComponent Xform;
public QueueSpriteTreeUpdateEvent(TransformComponent xform)
{
Xform = xform;
}
}
[Dependency] private readonly SpriteSystem _sprite = default!;
#region Component Tree Overrides
protected override bool DoFrameUpdate => true;
@@ -36,6 +19,11 @@ public sealed class SpriteTreeSystem : ComponentTreeSystem<SpriteTreeComponent,
protected override int InitialCapacity => 1024;
protected override Box2 ExtractAabb(in ComponentTreeEntry<SpriteComponent> entry, Vector2 pos, Angle rot)
=> entry.Component.CalculateRotatedBoundingBox(pos, rot, default).CalcBoundingBox();
{
// TODO SPRITE optimize this
// Because the just take the BB of the rotated BB, I'mt pretty sure we do a lot of unnecessary maths.
return _sprite.CalculateBounds((entry.Uid, entry.Component), pos, rot, default).CalcBoundingBox();
}
#endregion
}

View File

@@ -173,29 +173,51 @@ namespace Robust.Client.Console.Commands
}
}
internal sealed class ShowPositionsCommand : LocalizedCommands
internal sealed class ShowPositionsCommand : LocalizedEntityCommands
{
[Dependency] private readonly IEntitySystemManager _entitySystems = default!;
[Dependency] private readonly DebugDrawingSystem _debugDrawing = default!;
public override string Command => "showpos";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var mgr = _entitySystems.GetEntitySystem<DebugDrawingSystem>();
mgr.DebugPositions = !mgr.DebugPositions;
_debugDrawing.DebugPositions = !_debugDrawing.DebugPositions;
}
}
internal sealed class ShowRotationsCommand : LocalizedCommands
internal sealed class ShowRotationsCommand : LocalizedEntityCommands
{
[Dependency] private readonly IEntitySystemManager _entitySystems = default!;
[Dependency] private readonly DebugDrawingSystem _debugDrawing = default!;
public override string Command => "showrot";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var mgr = _entitySystems.GetEntitySystem<DebugDrawingSystem>();
mgr.DebugRotations = !mgr.DebugRotations;
_debugDrawing.DebugRotations = !_debugDrawing.DebugRotations;
}
}
internal sealed class ShowVelocitiesCommand : LocalizedEntityCommands
{
[Dependency] private readonly DebugDrawingSystem _debugDrawing = default!;
public override string Command => "showvel";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
_debugDrawing.DebugVelocities = !_debugDrawing.DebugVelocities;
}
}
internal sealed class ShowAngularVelocitiesCommand : LocalizedEntityCommands
{
[Dependency] private readonly DebugDrawingSystem _debugDrawing = default!;
public override string Command => "showangvel";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
_debugDrawing.DebugAngularVelocities = !_debugDrawing.DebugAngularVelocities;
}
}
@@ -291,9 +313,9 @@ namespace Robust.Client.Console.Commands
}
}
internal sealed class SnapGridGetCell : LocalizedCommands
internal sealed class SnapGridGetCell : LocalizedEntityCommands
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
public override string Command => "sggcell";
@@ -319,9 +341,10 @@ namespace Robust.Client.Console.Commands
return;
}
if (_entManager.TryGetComponent<MapGridComponent>(_entManager.GetEntity(gridNet), out var grid))
var gridEnt = EntityManager.GetEntity(gridNet);
if (EntityManager.TryGetComponent<MapGridComponent>(gridEnt, out var grid))
{
foreach (var entity in grid.GetAnchoredEntities(new Vector2i(
foreach (var entity in _map.GetAnchoredEntities(gridEnt, grid, new Vector2i(
int.Parse(indices.Split(',')[0], CultureInfo.InvariantCulture),
int.Parse(indices.Split(',')[1], CultureInfo.InvariantCulture))))
{
@@ -425,9 +448,9 @@ namespace Robust.Client.Console.Commands
}
}
internal sealed class GridTileCount : LocalizedCommands
internal sealed class GridTileCount : LocalizedEntityCommands
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
public override string Command => "gridtc";
@@ -440,15 +463,15 @@ namespace Robust.Client.Console.Commands
}
if (!NetEntity.TryParse(args[0], out var gridUidNet) ||
!_entManager.TryGetEntity(gridUidNet, out var gridUid))
!EntityManager.TryGetEntity(gridUidNet, out var gridUid))
{
shell.WriteLine($"{args[0]} is not a valid entity UID.");
return;
}
if (_entManager.TryGetComponent<MapGridComponent>(gridUid, out var grid))
if (EntityManager.TryGetComponent<MapGridComponent>(gridUid, out var grid))
{
shell.WriteLine(grid.GetAllTiles().Count().ToString());
shell.WriteLine(_map.GetAllTiles(gridUid.Value, grid).Count().ToString());
}
else
{
@@ -578,7 +601,20 @@ namespace Robust.Client.Console.Commands
private static string GetMemberValue(MemberInfo? member, Control control, string separator, string
wrap = "{0}")
{
var value = member?.GetValue(control);
object? value = null;
try
{
value = member?.GetValue(control);
}
catch (TargetInvocationException exception)
{
var exceptionToPrint = exception.InnerException ?? exception;
value = $"{exceptionToPrint.GetType()}: {exceptionToPrint.Message}";
}
catch (Exception exception)
{
value = $"{exception.GetType()}: {exception.Message}";
}
var o = value switch
{
ICollection<Control> controls => string.Join(separator,
@@ -680,12 +716,12 @@ namespace Robust.Client.Console.Commands
}
}
internal sealed class ChunkInfoCommand : LocalizedCommands
internal sealed class ChunkInfoCommand : LocalizedEntityCommands
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IMapManager _map = default!;
[Dependency] private readonly IEyeManager _eye = default!;
[Dependency] private readonly IInputManager _input = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
public override string Command => "chunkinfo";
@@ -699,8 +735,8 @@ namespace Robust.Client.Console.Commands
return;
}
var mapSystem = _entManager.System<SharedMapSystem>();
var chunkIndex = mapSystem.LocalToChunkIndices(gridUid, grid, grid.MapToGrid(mousePos));
var mapSystem = EntityManager.System<SharedMapSystem>();
var chunkIndex = mapSystem.LocalToChunkIndices(gridUid, grid, _mapSystem.MapToGrid(gridUid, mousePos));
var chunk = mapSystem.GetOrAddChunk(gridUid, grid, chunkIndex);
shell.WriteLine($"worldBounds: {mapSystem.CalcWorldAABB(gridUid, grid, chunk)} localBounds: {chunk.CachedBounds}");

View File

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

View File

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

View File

@@ -20,8 +20,9 @@ namespace Robust.Client.Console.Commands
{
var wantName = args.Length > 0 ? args[0] : null;
var basePath = Path.GetDirectoryName(UserDataDir.GetUserDataDir(_gameController))!;
var dbPath = Path.Combine(basePath, "launcher", "settings.db");
var basePath = UserDataDir.GetRootUserDataDir(_gameController);
var launcherDirName = Environment.GetEnvironmentVariable("SS14_LAUNCHER_APPDATA_NAME") ?? "launcher";
var dbPath = Path.Combine(basePath, launcherDirName, "settings.db");
#if USE_SYSTEM_SQLITE
SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3());

View File

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

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using JetBrains.Annotations;
using Robust.Shared.Console;
using Robust.Shared.Localization;
namespace Robust.Client.Console.Commands;
[UsedImplicitly]
internal sealed class LocalizationSetCulture : LocalizedCommands
{
private const string Name = "localization_set_culture";
private const int ArgumentCount = 1;
public override string Command => Name;
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != ArgumentCount)
{
shell.WriteError(Loc.GetString("cmd-invalid-arg-number-error"));
return;
}
CultureInfo culture;
try
{
culture = CultureInfo.GetCultureInfo(args[0], predefinedOnly: false);
}
catch (CultureNotFoundException)
{
shell.WriteError(Loc.GetString("cmd-parse-failure-cultureinfo", ("arg", args[0])));
return;
}
LocalizationManager.SetCulture(culture);
shell.WriteLine(LocalizationManager.GetString("cmd-localization_set_culture-changed",
("code", culture.Name),
("nativeName", culture.NativeName),
("englishName", culture.EnglishName)));
}
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
{
return args.Length switch
{
1 => CompletionResult.FromHintOptions(GetCultureNames(),
LocalizationManager.GetString("cmd-localization_set_culture-culture-name")),
_ => CompletionResult.Empty
};
}
private static HashSet<string> GetCultureNames()
{
var cultureInfos = CultureInfo.GetCultures(CultureTypes.AllCultures)
.Where(x => !string.IsNullOrEmpty(x.Name))
.ToArray();
var allNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
allNames.UnionWith(cultureInfos.Select(x => x.TwoLetterISOLanguageName));
allNames.UnionWith(cultureInfos.Select(x => x.Name));
return allNames;
}
}

View File

@@ -0,0 +1,18 @@
using Robust.Client.GameObjects;
using Robust.Shared.Console;
using Robust.Shared.IoC;
namespace Robust.Client.Console.Commands
{
public sealed class ShowPlayerVelocityCommand : LocalizedEntityCommands
{
[Dependency] private readonly ShowPlayerVelocityDebugSystem _system = default!;
public override string Command => "showplayervelocity";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
_system.Enabled ^= true;
}
}
}

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