Compare commits

..

901 Commits

Author SHA1 Message Date
Vera Aguilera Puerto
fdcaa83b63 AudioSystem uses TryGet for ITransformComponent. 2021-10-01 12:48:24 +02:00
metalgearsloth
cb1b93e89c Revert this because it makes contacts look like shit 2021-09-30 22:49:37 +10:00
ike709
7d271a83b1 Updates cefglue (#2083)
Co-authored-by: ike709 <ike709@github.com>
2021-09-29 21:35:08 +02:00
metalgearsloth
ebaba35e8b Aggressively sleep physics bodies (#2078)
* Aggressively sleep physics bodies

* Fix tests

* Also buff angular damping
2021-09-29 20:06:56 +10:00
Vera Aguilera Puerto
35f4a4b011 Adds OwnerUid property to components. 2021-09-29 11:23:48 +02:00
metalgearsloth
0eebfe6931 Optimise anchored entity states for PVS (#2067) 2021-09-29 10:47:30 +02:00
metalgearsloth
9dafe46552 Don't generate physics contacts for non-predicted bodies (#2070)
These are all just handled on the server anyway so it's a significant waste of performance on the client for busy scenes.
2021-09-29 10:45:43 +02:00
metalgearsloth
b5d3772ef4 Fix items getting stuck awake 2021-09-29 13:59:12 +10:00
metalgearsloth
9baa2e6469 Slight grid fixtures optimisation (#2075) 2021-09-29 00:11:20 +10:00
Vera Aguilera Puerto
87f5c059c4 Remove IComponentManager entirely. 2021-09-28 13:40:48 +02:00
Vera Aguilera Puerto
fbcdd63988 Gets rid of most ComponentManager usages. (#2076)
- Obsoletes more `ComponentManager` fields/properties.
2021-09-28 13:36:18 +02:00
Vera Aguilera Puerto
07542ff6eb Further IComponentManager warning cleanup. 2021-09-28 12:56:12 +02:00
Vera Aguilera Puerto
56dd3ff03b Clean up BaseServer slightly.
- It doesn't CullRemovedComponents twice anymore.
- Remove IComponentManager from it.
2021-09-28 12:42:25 +02:00
Vera Aguilera Puerto
15778d3af4 Fix some warnings regarding IComponentManager. 2021-09-28 12:41:49 +02:00
Vera Aguilera Puerto
0fce2e438a Add EntityUid overloads for SoundSystem, AudioSystem. 2021-09-28 11:41:15 +02:00
Vera Aguilera Puerto
7d39e130f4 Fix bug involving the MapCoordinates SpawnEntity overload.
When you tried to spawn an anchored entity, it wouldn't spawn it in the position you specified, as the entity is anchored...
Now, we forcibly disable anchoring just for moving the entity, and restore the old anchor state when we're done.
Yes, this is a bad solution. No, I don't regret it: We need to get our shit together and have a way to forcibly teleport/move entities that are anchored for things like this.
2021-09-27 20:16:23 +02:00
Vera Aguilera Puerto
85249e7be7 Add Filter overloads for EntityUid. 2021-09-27 14:59:22 +02:00
metalgearsloth
e91ce4c5ad Fix animation crash 2021-09-27 15:29:43 +10:00
metalgearsloth
09fb921f38 Fix occluder edges for grid rotation (#2054) 2021-09-27 14:53:09 +10:00
metalgearsloth
1acad96eff Optimise animations a bit (#2006)
* Optimise animations

L'il bit of ECS at the time.

* Add pointlight event too

* System methods

* Bool flag

* Fix perf problem

* Use RQ
2021-09-27 14:51:10 +10:00
metalgearsloth
3dac144bef Remie is in engine now (#2066) 2021-09-27 14:38:41 +10:00
metalgearsloth
bccda8d87c Fix deleting grid crashing 2021-09-27 09:57:07 +10:00
metalgearsloth
5af8732054 Optimise ServerMapManager GetStateData
Free 4% performance on PVS
2021-09-26 17:10:48 +10:00
metalgearsloth
6f057e0c85 Set capacity for containermanager getcompstate 2021-09-26 16:52:02 +10:00
Paul
d18743a3cc improves vectorserializer copypasta 2021-09-26 02:13:40 +02:00
ike709
c785311a74 Adds support for "1x2" Vector2i serializing (#2065) 2021-09-26 02:04:47 +02:00
Vera Aguilera Puerto
949a584325 Fix missing using directive when EXCEPTION_TOLERANCE is enabled. 2021-09-25 18:31:18 +02:00
Vera Aguilera Puerto
c7461221b9 Merge ComponentManager into EntityManager. (#2064)
* Merge ComponentManager into EntityManager.

* Obsolete IComponentManager.
2021-09-25 18:23:11 +02:00
Pieter-Jan Briers
cd2942a0da Fix splitcontainer layout calculations. 2021-09-25 18:18:33 +02:00
Vera Aguilera Puerto
0b8cb5e3b6 Add proxy methods to SharedContainerSystem. (#2061) 2021-09-25 18:18:11 +02:00
metalgearsloth
aa3992255e Use approximate bounds for sprite rendering (#2052) 2021-09-23 23:53:37 +10:00
metalgearsloth
6d0cf375d0 Hotfix centroids
Not the permanent solution given it doesn't handle offset vertices but good enough for now.
2021-09-23 13:19:38 +10:00
Pieter-Jan Briers
52ad027854 Increase display.blur_light_factor to 0.001f 2021-09-21 08:09:02 +02:00
metalgearsloth
60ac47fad7 Fix rendertexture for rotated eyes (#2053) 2021-09-20 18:19:05 +02:00
metalgearsloth
8b462cc099 Remove 2 unused field dependencies 2021-09-21 00:18:33 +10:00
metalgearsloth
e918e40cd2 Fix ShapeTest warnings 2021-09-21 00:01:49 +10:00
metalgearsloth
39656f6810 Fix fixture mass setter crash 2021-09-20 22:30:31 +10:00
metalgearsloth
68576ace72 Accurate grid bounds (#2027)
* Fright night

* Shitty bounds working

* No more fixture leak

* Optimise TryFindGridAt

Should be O(1) now instead of the previous O(n) for number of fixtures

* ambush

* Merge stuffies

* Merge to master

* Fixes I guess

* Fix client sync

* Fix grid deserialization

* Jank test

* Fix deferral shitfuckery

* Optimise and remove

* Fixes

* Just werk dam u

* Optimisations

* Bunch of fixes

* FINALLY IT'S DONE

* Fixes

* Fix

* Comment
2021-09-20 21:07:31 +10:00
Vera Aguilera Puerto
ac21e24f33 Proper xmldocs for Resolves. 2021-09-20 11:06:42 +02:00
Vera Aguilera Puerto
843b8e69ef EntitySystem Resolve helper methods. (#2047)
* EntitySystem Resolve helper methods.

* Debug assert for component ownership

* Fix assert
2021-09-20 11:03:24 +02:00
metalgearsloth
a827bbec2b Add a debug system for showing anchored ents (#2030) 2021-09-20 11:00:30 +02:00
Visne
a5be8e723e Remove some unused obsolete stuff (#2049) 2021-09-20 10:59:50 +02:00
metalgearsloth
bac3ff969b Don't sleep items parented to map (#2031) 2021-09-20 10:58:44 +02:00
Javier Guardia Fernández
bfabc8e51a Fix deleting empty containers on the client deleting their previous contents (#2036) 2021-09-20 10:58:14 +02:00
Paul Ritter
c116cd6d8b new xaml error for invalid root node type (#2038)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
2021-09-20 10:57:43 +02:00
Visne
30f39dfb66 Remove MarginContainer (#2050) 2021-09-20 10:43:12 +02:00
Pieter-Jan Briers
6b81c283f5 Light blur experiment. 2021-09-20 10:40:46 +02:00
Pieter-Jan Briers
c91170b50e Explicit GL debugger detection to fix ANGLE console spam. 2021-09-20 10:40:30 +02:00
Pieter-Jan Briers
831dd0e5bb Flush render queue after WorldSpaceBelowFOV()
Fixes FOV appearing below atmos in SS14.
2021-09-20 10:14:49 +02:00
Swept
028dea2819 Updates documentation link in comment 2021-09-20 01:25:57 +00:00
Pieter-Jan Briers
9117f8c776 These IRenderHandle APIs are going public, deal with it. 2021-09-19 23:37:47 +02:00
mirrorcult
a46c539462 Merge pull request #2048 from Visne/vbox-hbox-remove
Remove VBoxContainer/HBoxContainer completely
2021-09-19 13:03:17 -07:00
Visne
c9cbeadc9e Trigger tests 2021-09-19 21:37:42 +02:00
Visne
8f1386cb19 Remove VBoxContainer/HBoxContainer completely 2021-09-19 18:41:10 +02:00
Vera Aguilera Puerto
3b902e0557 IMetaDataComponent implements IComponent 2021-09-19 10:46:09 +02:00
ike709
3142dcbfda Adds some OpenDream things to the sandbox whitelist (#2042) 2021-09-18 22:40:22 +02:00
Vera Aguilera Puerto
29ffd07712 MapCoordinates Offset overload that takes two floats. 2021-09-18 13:01:30 +02:00
Vera Aguilera Puerto
afd687e392 Add Offset method to MapCoordinates. 2021-09-18 12:49:54 +02:00
Vera Aguilera Puerto
72341a25af VV attribute for ViewSubscriptions in PlayerSession. 2021-09-18 11:14:44 +02:00
Vera Aguilera Puerto
6d03840fbd Makes BoundUserInterfaces partially ECS. (#2033) 2021-09-18 10:41:06 +02:00
metalgearsloth
ea2d63b404 Add test for lookup anchoring (#2035)
* Add test for lookup anchoring

* Updates

* Fix test
2021-09-17 01:43:41 +10:00
metalgearsloth
42a137d106 Raise anchoring broadcasted 2021-09-17 00:06:02 +10:00
metalgearsloth
8f8c1eccc3 hotfix eyes 2021-09-16 17:42:30 +10:00
metalgearsloth
b91fa6ba75 Reduce position approx tolerance 2021-09-16 14:03:33 +10:00
metalgearsloth
e270f4f06c Reduce velocity approx tolerance 2021-09-16 13:57:18 +10:00
metalgearsloth
56b7957878 Receive testbed from content (#2034) 2021-09-16 13:02:43 +10:00
metalgearsloth
209eb5fea0 Fix 90% of grid rotation bugs (#2003)
* View box2rotated

* Changes

* Stash someday

* Sync

* Grid rotation in a commit

* SIMD comment

* Minor TryFindGridAt optimisation

* More fixes

* Optimise rays a tad

* Reduce code duplication

* Fix anchoring

* More fixes woopsie

* Eye matching parent

* Centre of mass stuffsies

* Remove TODO

* Add TODO

* Revert anchor crash

* Fix master merge-in whoopsie

* Fixes

* Woops

* Fixed viewport transform

* Re-fix rendering
2021-09-16 12:59:16 +10:00
Javier Guardia Fernández
417954e66c Simplify how some serialization expression trees return values (#2040) 2021-09-15 21:00:42 +02:00
Visne
e4fb860985 Fix licenses (#2041) 2021-09-16 00:18:51 +10:00
Pieter-Jan Briers
d70481aedd Update Linguini
This fixes several compiler warnings.
2021-09-15 16:17:52 +02:00
Pieter-Jan Briers
52eb581b56 Fix some compiler warnings. 2021-09-15 15:55:27 +02:00
Pieter-Jan Briers
918fa8e3b9 Fix handling of key names GLFW returns as null. 2021-09-15 13:37:24 +02:00
Visne
1c7f19bf67 Add OptionButton margin (#2020) 2021-09-15 01:49:49 +02:00
Javier Guardia Fernández
0cbff8dee1 Change serialization reading to only do type checks once per type (#2018)
* Change serialization reading to only do type checks once per type

* Optimize for sealed types in arrays

* Oops the context

* Fix ISelfSerialize node type and null values

* Add int read test

* Remove nullability from constructor and property of DeserializedValue

* Add clearing readers to serialization shutdown

* Fix struct populate default values
Remove some notnull constraints

* Replace robust gen with normal il generator
2021-09-13 18:14:52 +02:00
metalgearsloth
670ff54ef0 Fix SetAsBox 2021-09-13 19:46:31 +10:00
metalgearsloth
8f519c52b6 Fix multi-viewer PVS crash 2021-09-13 15:59:18 +10:00
Javier Guardia Fernández
fbd29afbd8 Fix data definitions sometimes not being found in tests (#2026) 2021-09-12 11:47:50 +02:00
Javier Guardia Fernández
2bbdb23716 Fix tests getting stuck until terminated (#2025) 2021-09-12 11:42:46 +02:00
Javier Guardia Fernández
e2dda67eef Add test for IPopulateDefaultValues (#2024) 2021-09-12 10:07:59 +02:00
metalgearsloth
699615df97 Remove Snapus Gridus (#2014) 2021-09-12 16:34:51 +10:00
Javier Guardia Fernández
e804994a5b Fix serialization manager shutdown (#2011) 2021-09-11 00:00:31 +02:00
metalgearsloth
24f7ecccc0 Remove AppearanceTestComponent (#2015) 2021-09-10 23:59:42 +02:00
Javier Guardia Fernández
21d43350f0 Add benchmark for serializing arrays of strings, ints and definitions (#2017)
* Add benchmark for serializing arrays of strings, ints and definitions

* Add sealed elements array benchmark
2021-09-10 17:57:16 +02:00
Javier Guardia Fernández
63eb7847a1 Add test for serializing nullable ints (#2016) 2021-09-10 17:50:02 +02:00
metalgearsloth
4a4f07a10c StopPlaying won't throw if already disposed (#2013) 2021-09-09 12:53:33 +02:00
Javier Guardia Fernández
1c816941ec Change serialization writing with serializers to use expression trees (#2010)
* Change serialization writing with serializers to use expression trees

* Add test
2021-09-08 13:05:34 +02:00
Javier Guardia Fernández
2143c9abc3 Change serialization reading with serializers to use expression trees (#2009)
* Change serialization reading with serializers to use expression trees

* Add test

* Eliminate lambda capture
2021-09-08 12:07:17 +02:00
Vera Aguilera Puerto
4b6ceed586 Adds FileNotFoundException to the sandbox whitelist. 2021-09-08 09:52:20 +02:00
metalgearsloth
49c6c0c9d8 Fix anchoring crashes 2021-09-08 10:55:44 +10:00
metalgearsloth
54f6143be3 Quick audio fix nothing to see here 2021-09-07 18:17:58 +10:00
metalgearsloth
b83e09c214 Add method to apply impulse from a point (#1992) 2021-09-07 08:25:28 +02:00
metalgearsloth
caa9b442d5 Use arrays for polygon vertices (#1958)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-09-07 08:24:58 +02:00
Javier Guardia Fernández
69921da034 Change serialization copying with serializers to use expression trees (#2008) 2021-09-07 08:09:26 +02:00
metalgearsloth
552893f1b7 Audio enhancements (#1997)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-09-07 08:08:49 +02:00
metalgearsloth
c5c10caaf1 Chunk streaming (#1985)
* The real lookup flags

* Don't get anchored entities for PVS query

* Finish that implementation

* Immediate anchoring changes

* Woops some anchoring slippy

* Fix stupidity

* More gradual

* Remove thread-unsafe stuff

In case anyone notices I'm stupid

* Some day I'll stash instead lol

* Fix thread issue

* Werk

* Cvar for range too

* Explanation

* More comments

* Fix merge
2021-09-07 07:59:22 +02:00
metalgearsloth
98de046977 Avoid unnecessary TransformComponent cast in PVS (#2007)
* Avoid unnecessary TransformComponent cast in PVS

Haven't profiled if it's faster but it supports EntityUid better so whenever we deprecate IEntity we would've had to do this anyway.

* Avoid unnecessary MapPosition call

LocalToChunkIndices already checks for this and saves the additional conversion from EC -> map -> EC again

* Doc fixes
2021-09-07 07:57:54 +02:00
Pieter-Jan Briers
6328bddb52 Fix GridContainer looking at Size in its ArrangeOverride()
This fixes tests.
2021-09-07 07:47:17 +02:00
Pieter-Jan Briers
003c910c66 Make some icky reflection APIs internal. 2021-09-07 07:43:24 +02:00
Pieter-Jan Briers
1d7f4b4501 Improve comments on BoxContainer a bit. 2021-09-07 02:27:56 +02:00
Pieter-Jan Briers
2f6fb22473 Remove obsolete layout APIs. 2021-09-07 01:38:13 +02:00
Pieter-Jan Briers
96d66c57c1 Comments for Control.Layout.cs. 2021-09-07 01:24:10 +02:00
metalgearsloth
35741524a3 Significantly reduce debug allocations (#2005)
* Significantly reduce debug allocations

I know it's debug but it's number 1 on entity spawning

* Nothing to see here
2021-09-06 13:32:09 +02:00
metalgearsloth
d5855fa805 Sync PointLight data between client and server. (#1995)
* Sync PointLight data

* ECS GetComponentState

* Nothing to see here
2021-09-06 17:31:06 +10:00
metalgearsloth
36a9d06381 Fix Robust tests (#2004)
Not the greatest of solutions but at least it's fixed for now.
2021-09-06 01:27:37 +10:00
Pieter-Jan Briers
3bfb3a5ef7 Fix GLES3 sRGB detection.
Forgot to set the variable, epic.
2021-09-04 21:07:20 +02:00
metalgearsloth
83b031cab4 Optimise GetTileRef (#1998)
* Optimise GetTileRef

Used in movement code a lot to check weightless and most of the time they're parented to the grid.

* More optimisations
2021-09-04 12:09:04 +02:00
Pieter-Jan Briers
6197352fca Try GLES3 anyways on compat mode. 2021-09-01 18:29:58 +02:00
Pieter-Jan Briers
0fd210481a Multithread SerializationManager initialize. 2021-09-01 13:38:34 +02:00
Pieter-Jan Briers
74eea847e2 Compact LOH on initial startup GC.
LOH gets fragmented heavily, currently, so this helps.
2021-09-01 01:29:20 +02:00
Pieter-Jan Briers
6938787863 Fix compat mode, fullscreen, more work on ANGLE swap chain. 2021-09-01 01:13:32 +02:00
Pieter-Jan Briers
4ba5654253 Allow modifying selection/cursor colors on LineEdit 2021-08-30 23:34:28 +02:00
Pieter-Jan Briers
15ff120b97 Add Control.StylePropertyDefault() helper method. 2021-08-30 23:34:14 +02:00
Pieter-Jan Briers
942a550687 Fix clearColor not being passed through by RenderInRenderTarget.
This fixes background colors for non-main WindowRoots
2021-08-30 23:24:21 +02:00
Pieter-Jan Briers
acff35f4bf Fix multi-window rendering deadlock. 2021-08-30 23:07:26 +02:00
Pieter-Jan Briers
4e7039e09b StyleBoxFlat can now draw simple rectangular borders 2021-08-30 23:01:51 +02:00
Pieter-Jan Briers
4a0b3793e4 Add IUserInterfaceManager.GetWindowRoot 2021-08-30 23:01:38 +02:00
Pieter-Jan Briers
928ae19249 Fix styling not applying to root controls. 2021-08-30 15:17:43 +02:00
Pieter-Jan Briers
a7f85b53f8 Background color for UIRoot. 2021-08-30 02:14:22 +02:00
Pieter-Jan Briers
5fac83c697 Fix GLFW_SCALE_TO_MONITOR not being specified for self-managed context windows. 2021-08-30 01:45:56 +02:00
Pieter-Jan Briers
577b2b0f62 Remove OutputPath overrides for shared.
Pretty sure this will reduce recompilation when switching between debug and release in rider, so sounds like a good idea to me.
2021-08-30 01:38:28 +02:00
Pieter-Jan Briers
cd3a7ef91e ANGLE+DXGI experiment, window/GL init rewrite (#1982) 2021-08-30 01:35:07 +02:00
Vera Aguilera Puerto
051d47f4ff Adds ComponentGetState ECS event (#1988) 2021-08-29 17:23:40 +02:00
metalgearsloth
b982b94c83 Port TestPoint from Box2D (#1991)
Rather than having the methods on the shapes themselves (whenever we eventually get them as structs) I just put them on a shapemanager instead as it seemed cleaner?
2021-08-29 17:10:46 +02:00
Vera Aguilera Puerto
84b7742656 Adds by-ref and struct event support to ComponentEvents (#1987) 2021-08-29 16:52:38 +02:00
metalgearsloth
1585cd111f Don't dirty appearance if state is identical (#1990)
Avoids unnecessary visualizer calls and bugs from duplicate animations or the likes.
2021-08-29 16:00:06 +02:00
metalgearsloth
766f6dc93d EntityLookup flags for PVS optimisations (#1983)
* The real lookup flags

* Don't get anchored entities for PVS query

* Finish that implementation

* Immediate anchoring changes

* Woops some anchoring slippy

* Address review
2021-08-29 14:03:45 +10:00
Vera Aguilera Puerto
59af9451be Various improvements to midi
- MidiEvent control is now an int
- Instead of hardcoding the channel count, we check the count on the synth itself.
- Do nothing for event 0x51
2021-08-26 15:01:34 +02:00
metalgearsloth
80e4f69f29 PVS Anchoring take 2 (#1959)
* PVS is now aware of entity anchoring.
Misc PVS perf improvements.

* Fix master merge

* Optimise chunks intersecting

* Ensure anchored entity chunks are always sent

* Remove silly pool by me

* Hotfixes?

* Chunk sending

* Optimise assert

* Assert updates

* Remove AME debug

* Fixes

* Add back in including map eye

* Update Robust.Server/GameStates/EntityViewCulling.cs

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

* Update Robust.Shared/Map/MapChunk.cs

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

Co-authored-by: Acruid <shatter66@gmail.com>
Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
2021-08-26 12:48:44 +10:00
Pieter-Jan Briers
98060f2056 Fix closing child window minimizing parent on windows. 2021-08-26 00:30:56 +02:00
Vera Aguilera Puerto
f0bfb6a69a Adds deflate compression to MsgState. (#1981) 2021-08-25 23:54:15 +02:00
Pieter-Jan Briers
ac38748280 Fix GridContraction_Test doing bad entity access and causing test failure. 2021-08-25 23:30:38 +02:00
Pieter-Jan Briers
18fe34c041 Do not send all entities on fromTick = 0.
This doesn't seem to be necessary anymore and it massively improves load performance.
2021-08-25 23:19:34 +02:00
Pieter-Jan Briers
6a0cb6a5af Rework entity storage to remove CullDeletedEntities.
Now we only use the dictionary for storing entities, similar to components.

This means creating/deleting entities while enumerating them will throw, but that's probably fine since GetEntities() is barely used nowadays, and we have QueueDelete().
2021-08-25 22:47:33 +02:00
Pieter-Jan Briers
310aebaee2 Make prediction CVars NOT ARCHIVE.
I want to disable them in OpenDream and this would make that impossible.
2021-08-25 22:47:32 +02:00
Paul Ritter
f25d67da55 dynamically adjusts divisions in worlddrawhandles drawcircle (#1980)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
2021-08-25 22:23:59 +02:00
metalgearsloth
eac36e917f Fix showrays (#1979) 2021-08-26 00:12:56 +10:00
ShadowCommander
c64fa8f2cc Fix Box2Serializer and tests 2021-08-24 22:58:43 -07:00
Vera Aguilera Puerto
63c1707581 Adds new helpful filter methods. (#1962)
- AddWhereAttachedEntity and RemoveWhereAttachedEntity methods
- AddInGrid and AddInMap methods
- BroadcastGrid and BroadcastMap static methods
2021-08-24 16:11:38 +02:00
metalgearsloth
914a7fb130 Fix box2 serializer (#1966)
There's some existing content with invalid bounds so this is going to be fun.
2021-08-24 18:30:42 +10:00
Pieter-Jan Briers
41d3495e29 Some stubs for JS execution queuing.
Definitely gonna be necessary but eeeeeeh feeling lazy.
2021-08-24 10:05:35 +02:00
Pieter-Jan Briers
2ae426b8e5 Allow file filters in save file dialogs. 2021-08-24 09:24:49 +02:00
Pieter-Jan Briers
eb45e16739 BrowserControl now allows hooking the BeforeBrowse API.
This is necessary to be able to cancel navigation (OpenDream Topic()).
2021-08-24 08:32:44 +02:00
Pieter-Jan Briers
79c952a871 Make MouseFilterMode.Stop default for BrowserControl 2021-08-24 08:01:22 +02:00
Pieter-Jan Briers
827c4b32fd Double check that CefManager is initialized in BrowserControl.
Otherwise it would throw with a nullref somewhere in CefGlue.
2021-08-24 07:35:28 +02:00
Pieter-Jan Briers
033e20cbf1 Add Closed (past tense) event to OSWindow.
Change a bunch of window event stuff up.
2021-08-24 04:49:04 +02:00
Pieter-Jan Briers
3ff46d40fa UsedImplicitly for IConsoleCommand 2021-08-24 04:42:09 +02:00
Pieter-Jan Briers
5ab6aba20b More implicit use attributes.
This means that entity systems and IoC managers should no longer need [UsedImplicitly] to suppress "object never instantiated" warnings.
2021-08-24 03:13:23 +02:00
Pieter-Jan Briers
e6be04cb83 OSWindow control to make OS windows much easier. 2021-08-24 02:05:25 +02:00
Pieter-Jan Briers
627b2f4d0d Change WindowCreateParameters.HideCloseButton to a more general purpose Styles system. 2021-08-24 02:05:25 +02:00
Pieter-Jan Briers
ffff42cc95 Add owner window parameter to window creation.
And also CenterOwner placement rule.

Currently owner windows are only implemented on Win32. Linux and macOS will need implementing still.
2021-08-24 02:05:25 +02:00
Pieter-Jan Briers
ce420ac8ab Set GLFW_SCALE_TO_MONITOR true on window creation. 2021-08-24 02:05:25 +02:00
Paul Ritter
d3cdfbe3cb ratio's rects (#1970)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
2021-08-23 20:33:38 +02:00
Paul Ritter
726bfd58f6 adds some helpers to robustrandom (#1969)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
2021-08-23 20:32:51 +02:00
Paul Ritter
05827d01d0 Datafield now implies readonly VVAccess (#1968)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
2021-08-23 20:32:25 +02:00
metalgearsloth
6cb7641c07 Fix GetEntitiesInRange
A lot of lookup needs cleaning up but this is technically brokeded.
2021-08-23 22:40:47 +10:00
metalgearsloth
d72185933a Add support for grid chunk removals (#1941)
* Add support for grid chunk removals

Also allows grids to be removed when they have no more chunks remaining.

* No more crashing pog

* Slightly better

* Minor optimisations and fix bounds

* Avoid creating new chunks for anchoring

* chucky

* comment

* Tests

* Remove some logs

* Remove another log

* Review
2021-08-23 16:00:07 +10:00
metalgearsloth
80a9a82278 Fix client-side physics bodies getting stuck awake (#1946)
* Fix client-side physics bodies getting stuck awake

Wasn't a huge perf hit but it could leak a bit. Also there's a bunch of E/C stuff in here and I'll deal with it later.

* Fix broadphase leak

* Fix robust server sim
2021-08-23 15:01:08 +10:00
metalgearsloth
99c8ce2cc8 Attach to parent before inserting into container (#1965)
tl;dr is that throwing on content needs to be able to have IsInContainer return the correct result when checking for it in EntInsertedIntoContainer
2021-08-22 21:46:20 -07:00
Pieter-Jan Briers
f137a6e3a5 Add InheritChildMeasure bool to LayoutContainer 2021-08-22 11:32:15 +02:00
Pieter-Jan Briers
73e62414a7 Update Lidgren and NetSerializer submodules 2021-08-22 11:08:43 +02:00
Pieter-Jan Briers
ef7ef3ca9f Replace usages of NET5_0 preprocessor with NET5_0_OR_GREATER 2021-08-22 11:08:05 +02:00
Pieter-Jan Briers
da26e86f5e Merge branch 'robust-client-CEF' 2021-08-22 10:51:44 +02:00
Pieter-Jan Briers
d2a1815d7b Allow GameControllerOptions to change the startup branding. 2021-08-22 10:43:41 +02:00
Pieter-Jan Briers
4894888339 Dev window has UI tab now with UI tree. 2021-08-22 02:07:42 +02:00
Pieter-Jan Briers
3fd55733bb Add child added/removed/moved events to Control.
Intended for UI dev window
2021-08-22 02:07:42 +02:00
Pieter-Jan Briers
bebd638412 Make SplitContainer properties VV. 2021-08-22 02:07:42 +02:00
Pieter-Jan Briers
328b3cc715 Add IUserInterfaceManager.OnPostDrawUIRoot.
Intended for UI dev window highlighting.
2021-08-22 02:07:42 +02:00
Pieter-Jan Briers
b523cfddb7 Fix some layout calculation bugs.
1. Fix a copy paste typo in ApplySizeConstraints().
2. Fix negative sizes passed to MeasureCore() causing exceptions.
2021-08-22 02:07:42 +02:00
Pieter-Jan Briers
4fea277541 Make some SplitContainer stuff [ViewVariables] 2021-08-22 02:07:42 +02:00
Pieter-Jan Briers
3417f00650 Give main window UI root a good name 2021-08-22 02:07:42 +02:00
Pieter-Jan Briers
db4b190498 guidump command now shows all UI roots. 2021-08-22 02:07:38 +02:00
Pieter-Jan Briers
7d2bbc2ca7 Add an OnResized event to controls 2021-08-22 01:29:24 +02:00
Pieter-Jan Briers
553278fdb3 Fix x:Class directives in XamlUI. 2021-08-22 01:29:10 +02:00
Vera Aguilera Puerto
e5013d9e3f Add support for struct directed events, add by-ref directed/broadcast events. (#1931)
* Add support for struct directed events.
- Turn transform events into readonly structs

* TransformComponent events have readonly fields.

* Reduce boxing allocations, add DirectedRegistration readonly struct.

* Use typeof in a few places instead of GetType

* Add overloads to allow passing directed events by ref.

* Raise transform events by ref.

* Fix occluder AnchorStateChangedEvent subscription

* Fix broadphase subscriptions

* Fix bug oops

* Fix transform system raising moveevents by value

* Don't reflect the test entity systems.

* Directed EventBus uses ref everywhere, internally
Deduplicates a bunch of code. Whoo!

* Add broadcast by-ref events

* Fix by-ref events bug using Unsafe, add new tests for sorted by-ref events.

* Port broadcast events to by-ref.

* Speed, more correctness, reduce generics bloat.

* Clean up subscription code some.

* Remove bad test.

Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-08-21 11:37:02 +02:00
Vera Aguilera Puerto
679f8f24c9 Cleans up EntityCoordinates, split coordinates into their own files. (#1956) 2021-08-20 15:48:43 +02:00
metalgearsloth
1a547b946c Fix anchoring parent changes
Problem was coordinates were updated first and then it was clearing the snapgrid cell.
2021-08-20 14:14:17 +10:00
metalgearsloth
5594bd7203 Revert "PVS is now aware of entity anchoring. (#1845)"
This reverts commit 820d988e0a.

# Conflicts:
#	Robust.Server/GameStates/EntityViewCulling.cs
2021-08-19 22:34:06 +10:00
metalgearsloth
8cbe48c94f Use all chunks for PVS culling
Temporary attempt at fixing the server issue with PVS.
2021-08-19 22:30:05 +10:00
metalgearsloth
b04b9fc9cd Fix timer crash 2021-08-19 22:18:31 +10:00
Acruid
820d988e0a PVS is now aware of entity anchoring. (#1845)
* PVS is now aware of entity anchoring.
Misc PVS perf improvements.

* Fix master merge

* Optimise chunks intersecting

* Ensure anchored entity chunks are always sent

* Remove silly pool by me

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2021-08-19 21:48:44 +10:00
metalgearsloth
1ad5122b5d Fix y-sorting (#1952) 2021-08-18 17:49:54 +02:00
metalgearsloth
456ac03870 Add RevoluteJoint (#1953) 2021-08-18 17:48:52 +02:00
metalgearsloth
f647d00dc4 Add short-circuit for TryDistance (#1951)
* Add short-circuit for TryDistance

90% of the uses probably have the same parent hence we can avoid the more expensive ToMap calls for these.

* InRange too
2021-08-17 08:56:16 +02:00
metalgearsloth
2fd3bbf58b Optimise TryFindGridAt (#1945) 2021-08-16 21:06:31 +02:00
metalgearsloth
5ed49d51d3 Add vertices simplifier (#1935) 2021-08-15 19:15:23 +02:00
metalgearsloth
758d5eedef Add WorldPoint to StartCollideEvent (#1943)
Some stuff may want the actual collision point.
2021-08-15 16:45:42 +02:00
metalgearsloth
96d15929e6 Optimise GetMapChunks (#1948)
Don't need to check every chunk's bounds when you can just do dictionary lookups. Should be an okay bonus for PVS and grid rendering on larger grids. Didn't make tests yet because all of the existing ones are mocked and painful to change.
2021-08-15 16:45:30 +02:00
metalgearsloth
2a062dbf53 Cleanup TimerComponent when none are running (#1949)
The ToList was showing up on a profiler.
2021-08-15 16:45:00 +02:00
metalgearsloth
6d66bc66e4 Minor grid traversal optimisation (#1950)
Avoids running duplicate events, mainly for client, but also avoids the additional GetEntity call as well.
2021-08-15 16:29:14 +02:00
Pieter-Jan Briers
5cc056100b Remove unused MsgEntity parameter packing helpers.
These were originally for when messages were passed around as an object[] args list, I believe. This isn't used so this code should just go honestly.
2021-08-12 14:35:56 +02:00
Visne
5eee22b034 Make no rotation work when eye is rotated (#1927) 2021-08-12 13:12:02 +02:00
DrSmugleaf
7f5beab259 Add the component type to the unknown component linter error message 2021-08-12 12:21:52 +02:00
metalgearsloth
46aead639b Allow VirtualControllers to be retrieved by content (#1937)
Useful in SS14 for MoverController to cache some work that SharedTileFrictionController can re-use.
2021-08-12 17:55:34 +10:00
Visne
488d060595 Fix map deletion not working because of deleted entity referencing map (#1933)
* Fix map deletion not working because of deleted entity referencing map

* Change fix

* Update Robust.Shared/GameObjects/Components/CollisionWakeComponent.cs

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2021-08-12 14:00:12 +10:00
metalgearsloth
b1bab1f38e Significantly reduce default volume range
Now it's actually unified instead of being 25 sometimes and 62.5 (the godot default) at other times.
2021-08-11 19:53:15 +10:00
metalgearsloth
feba2a23ad Fix grid collisions (#1934)
* Fix grid collisions

* Fix this silliness

* Add test for grid collisions

* Fix FlagSerializer not working with 1 << 31

Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
2021-08-10 00:04:19 +10:00
Javier Guardia Fernández
e1ff29744e Fix FlagSerializer not working with 1 << 31 (#1940) 2021-08-09 23:56:43 +10:00
Javier Guardia Fernández
f6216e63b0 Add tests for serializing flags (#1939) 2021-08-09 13:07:42 +02:00
Javier Guardia Fernández
0b3ecf2168 Add benchmarks for serializing flags (#1938)
* Add benchmarks for serializing flags

* Add type definitions
2021-08-09 13:03:24 +02:00
Vera Aguilera Puerto
9f29bf6349 Merge branch 'master' into robust-client-CEF 2021-08-09 12:02:15 +02:00
metalgearsloth
d12a238ecc Fix tests
Woops
2021-08-09 19:42:34 +10:00
Vera Aguilera Puerto
d62a64029d Merge branch 'master' into robust-client-CEF 2021-08-09 11:13:56 +02:00
metalgearsloth
ac46a7845d Fix container bounds 2021-08-09 18:46:51 +10:00
Vera Aguilera Puerto
17662aaad9 Merge branch 'master' into robust-client-CEF 2021-08-09 08:08:29 +02:00
metalgearsloth
60b526f653 Dirty physics bodies on new fixtures 2021-08-08 15:59:59 +10:00
metalgearsloth
d58e380dd9 MapManager now uses accurate bounds for grids (#1918)
* MapManager now uses accurate bounds for grids

Instead of using the old WorldBounds (which was dirty for multiple reasons) it goes through physics instead using the actual fixtures attached to the grid.

* Fix nuke

* Test time

* AABB tests

* feex

* how is this failing aaa

* feex tests

* slightly better

Co-authored-by: metalgearsloth <metalgearsloth@gmail.com>
2021-08-06 22:25:14 +10:00
Visne
96a098a0c2 Fix outline when eye is rotated (#1929) 2021-08-06 09:53:14 +02:00
Vera Aguilera Puerto
c0d4e34089 Add Friend classes to C# with the help of Analyzers and Attributes. (#1928)
* Add Friend classes to C# with the help of Analyzers and Attributes.

* Revert to netstandard2.0

* Use LINQ instead of ^1 for array

* Address review.
Oops, forgot to push.
2021-08-06 09:50:22 +02:00
ShadowCommander
e16e0f4bd0 Fix containers with entities that do not exist yet (#1892)
* Fix containers that hold entities not on client

* Delete from ExpectedEntities when entity removed

* Fix ContainerSystem not registering on the server

* Move container state to entity system
Move client code to client

* Fix removal and clean up code

* Add test

* Add more checks to test

* Remove unneeded deletion event handler

When the child is deleted, if the entity does not exist on the client,
then HandleComponentState runs. If the entity does exist, then
HandleEntityInitialized would have run. Either way HandleEntityDeleted
is not needed.

* Renamed unexpected to removedExpected
2021-08-04 19:00:14 -07:00
metalgearsloth
d31ffd2794 Update broadphase every frame on client (#1925)
There was a reason I didn't do this prior to refactor but that reason is no longer relevant soooooo
2021-08-04 00:43:32 +10:00
metalgearsloth
04d94f87fc Fix movement lerping (#1924) 2021-08-04 00:11:04 +10:00
metalgearsloth
f809375389 Cache broadphase on PhysicsMap (#1923) 2021-08-03 22:24:01 +10:00
metalgearsloth
530ea5f4e6 Remove BroadphaseMapid from physicscomp
Was made redundant in the broadphase refactor
2021-08-03 19:08:45 +10:00
Visne
590a23d540 Make it possible to set lighting per map (#1921) 2021-08-03 09:55:54 +02:00
Vera Aguilera Puerto
52351e8b11 Clyde can now render multiple viewports with different maps. (#1917)
* Clyde can now render multiple viewports with different maps.

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

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

* Actually feex

* spellcheck

* Add a test for chunk bounds

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

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

* tests

* namespace

* working

* thonk

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

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

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

* Also cache position and angle for GetWorldAABB

* Fix boogs

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

Needs several content PRs to be merged as well.

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

* Copy pasting

* Reduce bounds

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

* Stuff

* Working

* TODO

* Changes

* Which fucking madman came up with this shit

* Known gud state

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

* Shuttle jankiness

* Refactor entitylookups to be 30% more based

* Refactor gucci

* Done?

* Fix most tests

* nothing suss

* Vera single-handedly saving shuttles

* fex

* Fix renderingtreecomp for relativity

* Fix IEntityLookup

* Fixes

* Testing jank please revert some of it before merging

* Fix the remaining bugs

* Fix crash

* Fix grid physics initialization

* Shuttle collisions working

* Fixes

* Fixes

* Velocity on transfers

* Velocity on parent change

* Fixes

* world angular velocity too

* Slightly faster map velocities

* showbb revert

* Sketch grids kinda workin

* Fix PVS contact crash

* Cleanup gridfixture updates 0.1%

* Grid fixtures

* AAAAAAAAAAAAAAA

* a

* termp

* Fixes

* Test reversion reversion?

* Tests

* Fix Equals

* Slight box2i cleanup

* Better initializer

* Fix merge issues

* Shuttles go BRRT

* Remove MoveProxy from DynamicTreeBroadphase

* Optimise a shit tonne

* Approx

* fix showbb

* clean

* Slightly more optimised

* My almonds are activating

* Contact transform caching

* Avoid duplicates

* Typo

* Logger

* Jitter 1% better

* Okay shit maybe that's not it.

* Contact fixes

* Move check thingy up front

* Revert some jank caching

* Contact filtering

* Fix master merge

* Test fixes

* Re-fix MapLoaderTest

* Use proxies instead

* uhh wtf?

* Woops

* Fix collisions

* Fix grid fixture generation

* Fix deserializing

* Tile window fix

* Cleanup broadphase

* Bit more cleanup

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

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

* termp

* Fixes

* Test reversion reversion?

* Tests

* Fix Equals

* Slight box2i cleanup

* Better initializer

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

* Refactor gucci

* Done?

* Fix most tests

* nothing suss

* Vera single-handedly saving shuttles

* fex

* Copy lookup from shuttles

* sys

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

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

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

* Remove the unnecessary NetID property from ComponentState.

* Remove Component.NetworkSynchronizeExistence.

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

* Remove public usages of the Component.NetID property.

* Adds the NetIDAttribute that can be applied to components.

* Removed Component.NetID.

* Revert changes to GetComponentState and how prediction works.

* Adds component netID automatic generation.

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

* Completely remove static NetIds.

* Renamed NetIDAttribute to NetworkedComponentAttribute.

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

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

* Faster func

* Test

* lag

* uhh LAAAGGG
2021-07-11 12:25:02 +10:00
Swept
7df2d1f430 Fixes console loc string (#1858) 2021-07-09 15:13:30 +02:00
Vera Aguilera Puerto
d7ecc0883f Merge branch 'master' into robust-client-CEF 2021-07-08 10:00:46 +02:00
Vera Aguilera Puerto
d216c3a1f6 VV command can now get IoC services that don't have an interface. 2021-07-07 18:03:20 +02:00
Vera Aguilera Puerto
44b17edff6 Fix failing unit test. 2021-07-06 10:38:48 +02:00
Pieter-Jan Briers
6366c2383a Request handling API. 2021-07-06 02:07:17 +02:00
Pieter-Jan Briers
ddbbe22bda Make RobustCefApp internal. 2021-07-05 23:41:01 +02:00
Pieter-Jan Briers
6880af0d8b Lifetime management for BrowserControl
Correctly shuts down all resources when removed fromt ree.
2021-07-05 23:35:16 +02:00
Vera Aguilera Puerto
6f258b1822 Fix multi process mode on Linux. 2021-07-05 23:10:19 +02:00
Pieter-Jan Briers
2cf3ed8a70 External window lifetime management. 2021-07-05 21:58:43 +02:00
Pieter-Jan Briers
c6f10a1321 Don't make a RobustCefApp in CEF sub processes. 2021-07-05 20:26:16 +02:00
Vera Aguilera Puerto
41ab9b106f Add RobustCefApp, CefManager no longer inherits CefApp. 2021-07-05 20:22:00 +02:00
Pieter-Jan Briers
0d97569576 Implement mouse modifiers. 2021-07-05 20:18:54 +02:00
Pieter-Jan Briers
0a21d402b2 Apparently I didn't disable disable GPU properly. 2021-07-05 20:16:50 +02:00
Pieter-Jan Briers
c6827fe8ae Merge remote-tracking branch 'origin/robust-client-CEF' into robust-client-CEF 2021-07-05 18:23:05 +02:00
Pieter-Jan Briers
0c94956be1 Various degrees of work on input stuff. 2021-07-05 18:21:47 +02:00
Pieter-Jan Briers
1e7a193d5e Raise scroll speed 2021-07-05 11:44:42 +02:00
Vera Aguilera Puerto
eb4ea8aa63 Adds a few APIs to IBrowserControl and implements them where needed 2021-07-05 11:23:44 +02:00
Pieter-Jan Briers
af1a3d965d Actually shut down loaded modules on client 2021-07-05 10:27:21 +02:00
Pieter-Jan Briers
26fed40ad4 Remove fixed TODO comment 2021-07-05 10:24:10 +02:00
Pieter-Jan Briers
c6c6309eff Disable disable GPU 2021-07-05 10:05:10 +02:00
Pieter-Jan Briers
7188eeb0c8 Add external window creation API 2021-07-05 09:37:04 +02:00
Pieter-Jan Briers
d74b22a4e8 Engine API for fetching win32 HWND. 2021-07-05 09:05:59 +02:00
Pieter-Jan Briers
75de717b4e Enable CEF multi-process mode. 2021-07-05 08:00:16 +02:00
Pieter-Jan Briers
a00fc75b61 BrowserControl less inefficient rendering 2021-07-05 07:59:56 +02:00
Pieter-Jan Briers
dcbb6608df Improve clyde SetSubImage.
1. better perf.
2. code cleaned up
3. span-based API.
2021-07-05 07:55:52 +02:00
Pieter-Jan Briers
e4d0e50000 Add Robust.Client.CEF to InternalsVisibleTo 2021-07-05 07:46:59 +02:00
Pieter-Jan Briers
e5a2ab284b Merge branch 'master' into robust-client-CEF 2021-07-04 19:56:41 +02:00
metalgearsloth
986ec3ef06 Do showbb transforms in the iterator (#1847) 2021-07-04 19:52:21 +02:00
Vera Aguilera Puerto
3ac1506f17 Add correct license header to BitmapBuffer 2021-07-04 18:22:04 +02:00
metalgearsloth
60cec9cb84 Make showbb awakeness binary (#1846)
Makes it easier to spot mapping issues because otherwise it might have a massive sleep timer and not be easily visible.
2021-07-04 22:31:34 +10:00
Vera Aguilera Puerto
c06707d519 Adds ServerOptions, improve GameControllerOptions, fix engine integration tests (#1844)
* Adds ServerOptions, improve GameControllerOptions, fix engine integration tests

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

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

* Add integration test for engine integration tests working correctly

* Move cvar overrides out of content and into engine.
2021-07-03 15:19:46 +02:00
Pieter-Jan Briers
63128324ab Stop RunTicks overriding tick deltas in integration tests.
Now listens to game timing tick rate.
2021-07-03 13:06:19 +02:00
Vera Aguilera Puerto
c85bb81606 Add initial CEF integration to engine. 2021-07-02 23:31:37 +02:00
Pieter-Jan Briers
abea3024b4 Raise event when entity paused state changes. 2021-07-02 17:19:34 +02:00
Pieter-Jan Briers
07dafeb6cd Can now rotate anchored entities 2021-07-02 01:16:25 +02:00
Pieter-Jan Briers
a726d42ae3 Fix ResetPredictedEntities applying data early in some cases.
FullState was getting updated before ResetPredictedEntities ran instead of after. So ResetPredictedEntities was applying data to stuff like containers that depends on entities that hadn't been made yet.
2021-07-01 12:16:18 +02:00
metalgearsloth
d02d186a2f Fix light pop-in 2 (#1798)
* Fix light pop-in

Doh

* Uniqueness

* Refactor to be less bad

* Better perf

* Fix perf problems

* Hide debug commands under preprocessor

Can't imagine anyone using this during live-game.

* CVars
2021-06-29 22:29:47 +10:00
Vera Aguilera Puerto
a6be66949d Fix segfault when MIDI renderer is disposed.
Apparently? You need to dispose of the sequencer BEFORE the synth or a funny segfault will occur... T-Thanks libfluidsynth.
Also unregisters the sequencer clients before disposing, just for cleanliness.
2021-06-28 10:59:20 +02:00
Galactic Chimp
0dfd3b7443 #1462 extracted MapGrid's HasGravity property to separate Content component (#1835) 2021-06-27 15:01:58 +10:00
metalgearsloth
6f90e9a76e MapGridSystem for grid initialization (#1838)
* MapGridSystem for grid initialization

Doesn't seem to be a clean way to hook into grids being initialized (can't duplicate directed bus events and a few systems need to EnsureComponent) hence the event.

* Address reviews
2021-06-27 14:59:38 +10:00
Galactic Chimp
9246b88560 #1607 deprecate IEntityQuery (#1837)
* #1607 partial progress

* #1607 almost done

* #1607 small test tweak

* #1607 PR suggestions

* #1607 PR suggestions

* #1607 indentation tweaks
2021-06-27 13:40:00 +10:00
Vera Aguilera Puerto
61af9db362 Fix bug where anchored entities would be spawned at 0,0 always.
This is because the parent was attached first, and then the Entity Coordinates are set, but position doesn't change because the parent is the same and the entity is anchored.
NOTE: I only fixed the EntityCoordinates overload. Unsure if this is even a problem with MapCoordinates.
2021-06-24 21:41:39 +02:00
Vera Aguilera Puerto
5aa950e7f7 GetTilesIntersecting yield returns instead of creating, populating and returning a list of tiles. 2021-06-23 12:40:31 +02:00
Pieter-Jan Briers
b8903af52f Make public DrawingHandleScreen.DrawString helper method.
This method was copy pasted into 4 separate overlays already.
2021-06-23 01:42:47 +02:00
Pieter-Jan Briers
5b35c4e82b Fix disposed exception on client shutdown (I think?). 2021-06-23 01:26:16 +02:00
metalgearsloth
06db80780c Filter contacts for joints properly (#1836)
If you're colliding with something you obtain a joint with it should be filtered correctly now.
2021-06-21 02:27:07 +02:00
Acruid
e5fd4f5700 DependencyCollection Children (#1833)
Adds a new register function for registering a simple Type without an interface.
2021-06-21 02:15:23 +02:00
Galactic Chimp
e1a199e060 Removed old Loc.GetString() use instances (#1814)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-06-21 02:12:53 +02:00
Pieter-Jan Briers
22ac34c7a1 Are you for real, .NET CLI. 2021-06-21 02:01:55 +02:00
Pieter-Jan Briers
04fa6901b1 Fix ordering of command arguments.
Dumb CLI.
2021-06-21 01:57:09 +02:00
Pieter-Jan Briers
8f7d4211e3 Try server GC for content integration tests. 2021-06-21 01:53:40 +02:00
Pieter-Jan Briers
1147d6fd9a Do not cache injector delegates for entity system creation. 2021-06-21 01:44:36 +02:00
Pieter-Jan Briers
e4449c4901 Cache data definitions statically.
Significantly improves integration test times.
2021-06-21 01:31:13 +02:00
Pieter-Jan Briers
dc8963faa5 Use a no-op mapped string serializer in integration tests.
Serialization never happens in integration tests, so...
2021-06-21 01:29:51 +02:00
Pieter-Jan Briers
f9cf9a8fd4 Single-threaded integration tests experiment.
This didn't really seem to improve performance, so it's not enabled, but I'm not deleting the code.
2021-06-21 00:38:37 +02:00
Pieter-Jan Briers
393bdc04bc ItemList doesn't render things outside its clip region. 2021-06-20 19:48:24 +02:00
Pieter-Jan Briers
db4d787b49 use a struct enumerator for EventTables GetReferences. 2021-06-20 18:50:43 +02:00
Pieter-Jan Briers
cd802d6a66 Fix more nullrefs due to dummy sprite IEntity. 2021-06-20 18:50:29 +02:00
Pieter-Jan Briers
be2281a5b3 Remove glue code to allow components to subscribe to EventBus.
No. Just no.
2021-06-20 18:10:21 +02:00
Pieter-Jan Briers
e717396b33 MapManager uses directed remove event instead of hooking global ComponentRemoved event. 2021-06-20 18:07:24 +02:00
Pieter-Jan Briers
db0e49f5dd Defer SpriteComponent.IsInert updates.
Prevents O(n^2) behavior in many cases.
2021-06-20 17:57:45 +02:00
Pieter-Jan Briers
d3b94aa6af Fix name generator xaml file locating logic.
It would do .EndsWidth(), so DropDownDebugConsole and DebugConsole would get confused.

It now properly checks for path separators and also will report an error if there are two candidate XAML files.

Also, fixed the AXN0003 diagnostic having the wrong name.
2021-06-20 15:48:48 +02:00
Acruid
713f702064 Engine Entity Anchoring (#1829)
* Added unit tests for the new anchor system design.

* Amend ME!

* SnapGridComponent now anchors the entity when added or removed.
TransformComponent.Anchored properly replicates it's state to clients.

* Converted all SnapGridPositionChangedEvent subscriptions to AnchorStateChangedEvent.
Removed SnapGridPositionChangedEvent.
Obsoleted SnapGridComponent.

* Allows setting Transform.Anchored in prototypes.

* Changing tile to empty under anchored ents unanchors them.

* More unit testing.

* Migrated transform gamestate tests to RobustServerSimulation.

* Fixed nasty off-by-one error when sending a full server state.

* Adds lifetime stages to Component.

* More test fixing.

* Review changes.
2021-06-19 17:26:18 -07:00
Pieter-Jan Briers
d0b6a9b28c Replace usages of OperatingSystem.IsOSPlatform with OperatingSystem.IsXXX(). 2021-06-19 03:14:39 +02:00
Pieter-Jan Briers
4003781a1b Manually load libEGL.dll to fix ANGLE in dev builds. 2021-06-19 03:05:15 +02:00
Acruid
40586a8f0e Removes all engine component events. (#1832) 2021-06-18 10:44:21 +02:00
metalgearsloth
f4d427f5c5 Pre-reqs for multithreaded physics (#1784)
* Tanks off guard

* Medic

* Diamondback

* Gaming

* Gamingo

* Finalise

* Doh

* Bullet licence

* Marginal cleanup

* Physics licences

* Apply reviews
2021-06-17 16:01:41 +10:00
metalgearsloth
ce2a4282f3 Bandaid GridTileLookup containers (#1789)
* Bandaid GridTileLookup containers

I'm hoping tile entities deprecates this system but this should fix our problems for now.

* Fix stupid
2021-06-16 16:18:23 +02:00
Ygg01
0cc78c1402 Add missing types to type conversion (#1828) 2021-06-15 10:22:24 +02:00
Pieter-Jan Briers
fa0d4da6d1 Implement subscription ordering into EventBus. (#1823)
* Implement subscription ordering into EventBus.

* Topological helpers, rest of code uses shared topological sort, fix bugs.

* Fix tests.

Didn't realize that multi-subscriptions are allowed on input handlers like that??

* Improve and use topological sort helpers more.
2021-06-14 21:34:30 +02:00
Ygg01
33334d6f5c Upgrade Linguini to latest (prevents IDE issue with SG) (#1826) 2021-06-13 22:16:12 +02:00
ShadowCommander
55aba93faf Revert "Update Linguini"
This reverts commit 4f49296a94.
2021-06-13 08:38:01 -07:00
ShadowCommander
4f49296a94 Update Linguini 2021-06-13 08:34:57 -07:00
Vera Aguilera Puerto
65357ee8da ComponentHandleState event (#1778) 2021-06-12 15:50:27 +02:00
Vera Aguilera Puerto
bfcad4001b Adds public methods to ActorSystem. (#1824) 2021-06-12 15:50:01 +02:00
DrSmugleaf
5a3000febb Add directed events for player attach/detach (#1815) 2021-06-12 01:45:43 +02:00
DrSmugleaf
2d236670ab Add SetAndDirtyIfChanged extension method (#1816) 2021-06-12 01:44:28 +02:00
20kdc
796f1480a8 Add more tolerance for if player sessions are connected to dead entities (#1818)
* Add more tolerance for if some calamity causes a player session to be connected to a dead entity

* Fix build issues w/ previous commit (oops)
2021-06-10 09:29:25 +02:00
Ygg01
a8ee7be844 Add linguini loc (#1760)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2021-06-09 19:44:18 +02:00
metalgearsloth
60b506cb2a Fix GetWorldAABB again (#1802)
No weird-ass bug this time. There was also an issue where occasionally the AABB on the client would disappear if you had a bunch of objects and used showbb but I think it's fixed now.
2021-06-09 12:25:08 +10:00
metalgearsloth
66117e35ba Don't store lights in rendertree if not enabled (#1803) 2021-06-09 01:37:40 +02:00
metalgearsloth
22cfee4f01 Don't store non-visible / occluded sprites in rendertree (#1805)
Sister commit to the point-light one.
2021-06-09 01:33:24 +02:00
metalgearsloth
d9355e576f Remove PhysicsManager (#1812)
Goodnight sweet prince
2021-06-09 01:26:51 +02:00
Vera Aguilera Puerto
e54e33edb0 Client Networked event subscriptions can now take in EntitySessionEventArgs (#1817) 2021-06-09 01:22:20 +02:00
mirrorcult
25881ce343 MapInit ECS event (#1813)
* MapInit ECS event

* allocs
2021-06-08 22:33:21 +02:00
Acruid
f64197c189 Removes the map and grid entity pivot hack from clientside map networking. (#1811) 2021-06-08 02:45:02 -07:00
metalgearsloth
a7ec907f1d Remove mass from physics comp state (#1810)
Deprecated by fixtures storing mass
2021-06-07 13:56:21 +10:00
metalgearsloth
81272b0bc8 Reduce rendertree allocs (#1806) 2021-06-06 14:50:31 +02:00
metalgearsloth
25c1c6ef91 Fix rendertree updatequeued (#1804)
Woulda pushed directly but I cooked my git so ya know, nothing to see here
2021-06-06 19:25:27 +10:00
ShadowCommander
d1a83134e3 Fix SpriteView when UI is scaled 2021-06-05 19:47:26 -07:00
metalgearsloth
71c2993d20 Add joint support for CollisionWakeComponent (#1794)
* Add joint support for CollisionWakeComponent

* Less bad

* Fix heresy
2021-06-05 18:16:06 +10:00
Galactic Chimp
14fa616723 #1224 removed obsolete FloatMath class (#1800) 2021-06-03 00:11:19 +02:00
metalgearsloth
d46ea9c9ba Add gridtilelookup debugger back in (#1792)
Was reverted from the broadphase PR.
2021-06-01 11:58:44 +10:00
ShadowCommander
ea00ccb34f Fix window not calling OnMouseExited 2021-05-31 18:56:23 -07:00
Pieter-Jan Briers
8e416bb3cb Fix error in RenderingTreeSystem.
Seems related to #1754? Doesn't seem to fix it though.
2021-06-01 00:01:36 +02:00
Galactic Chimp
8e0a26073d #1765 - replaced 3 try-catch clauses with if-else clause + VS autoformat of affected files (#1796) 2021-05-31 22:49:23 +02:00
metalgearsloth
9fa24948ea Fix EntitySystemManagerOrderTest (#1793) 2021-05-31 13:20:09 +02:00
metalgearsloth
b9a9cc4b0f Revert "Immediate broadphase updates (#1687)" (#1790)
This reverts commit ee6aee57bd.
2021-05-31 20:33:29 +10:00
Pieter-Jan Briers
a67345f9bf Add debug log for runtime/OS info on game start. 2021-05-31 10:48:30 +02:00
Pieter-Jan Briers
2a022f39bd Add system for loading extra serializer strings.
"fixture-0" comes up a LOT so we load this manually now.
2021-05-31 10:48:30 +02:00
Vera Aguilera Puerto
a3ba969589 Container modified events are raised directed to the container owner. 2021-05-31 10:14:02 +02:00
metalgearsloth
21e1b75f5d Remove ICollideSpecial entirely (#1782)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-05-31 09:41:11 +02:00
metalgearsloth
1f6ddd96a6 Optimise the shit out of showpos (#1788) 2021-05-31 09:11:29 +02:00
metalgearsloth
b4d2cd26aa Named joints (#1787)
1 step closer to ECS physics.
2021-05-31 09:01:02 +02:00
metalgearsloth
ee6aee57bd Immediate broadphase updates (#1687) 2021-05-31 08:58:23 +02:00
DrSmugleaf
ac1705e41f Make NetMessage name and group virtual to remove required boilerplate (#1770) 2021-05-31 08:53:46 +02:00
metalgearsloth
196a6047f1 Use Box2D FindMaxSeparation (#1786) 2021-05-31 08:52:01 +02:00
ShadowCommander
b98b36a461 Add loglevel command line arg (#1769) 2021-05-31 08:41:34 +02:00
mirrorcult
9980a98a94 Add new fluent functions for words that change based on gender (#1775) 2021-05-31 08:41:06 +02:00
Pieter-Jan Briers
5a1a1d0420 Add component names to string serializer. 2021-05-30 22:55:33 +02:00
ShadowCommander
1c99678fe9 Change other physics awake event calls to RaiseLocalEvent 2021-05-30 12:16:17 -07:00
ShadowCommander
4049f10faa Make awake dispatch local events (#1785) 2021-05-30 21:05:16 +02:00
metalgearsloth
331c0bd43f Fix PreventCollideEvent (#1781)
With directed bus it's better to raise it both ways for a collision.
2021-05-30 18:38:28 +02:00
metalgearsloth
604cd2f93d Fix physics nullrefs (#1780)
* Fix physics nullrefs

* woops
2021-05-30 05:15:22 -07:00
Vera Aguilera Puerto
a87db2e57c EntitySystemManager uses IRuntimeLog for exception logging. 2021-05-30 12:27:36 +02:00
ShadowCommander
4c7f0a8d6b Add container helper for entity storage interaction (#1777) 2021-05-29 11:40:36 +02:00
20kdc
9eaf52886a Make RenderingTreeSystem handle parent recursion properly, fixing space-station-14#4040 and possibly other bugs (#1776) 2021-05-29 11:39:35 +02:00
Vera Aguilera Puerto
fce6f6c714 Adds ActorSystem to handle Attaching/Detaching players to/from entities sanely. (#1774) 2021-05-29 11:37:34 +02:00
DrSmugleaf
c04d51d489 Add test for YAML hot reloading (#1773)
* Add test for YAML hot reloading

* Perhaps test the event firing as well
2021-05-27 15:50:44 +02:00
Vera Aguilera Puerto
d310871aa6 CVar for MIDI volume. 2021-05-26 19:27:02 +02:00
Vera Aguilera Puerto
5fa422865f AudioSystem warning now prints audio stream name, if any. 2021-05-26 18:56:30 +02:00
Vera Aguilera Puerto
c137823355 Proper cleanup when detaching player from a deleted entity. 2021-05-26 18:44:37 +02:00
Vera Aguilera Puerto
0a0026b9ae Add formatted message newline helper method. 2021-05-26 10:18:27 +02:00
Pieter-Jan Briers
97a2a5cfae Block loading of R2R'd .NET assemblies in sandboxing. 2021-05-25 16:57:54 +02:00
Pieter-Jan Briers
a266e21d9e Add single-type IoC register call. 2021-05-24 22:05:15 +02:00
Pieter-Jan Briers
ad8bbe6401 Clyde audio improvements:
1. Allow loading audio directly from a sample buffer
2. SetVolumeDirect that takes a 0 -> 1 scale similar to OpenAL's AL_GAIN.
3. Fix OpenAL threading bugs with logging by caching the sawmill.
2021-05-23 22:58:32 +02:00
Pieter-Jan Briers
71ce4749fe Show active input context on DebugInputPanel. 2021-05-23 22:58:32 +02:00
Pieter-Jan Briers
1e33c3c843 MIDI renderer debugging code. 2021-05-23 22:58:32 +02:00
Vera Aguilera Puerto
b3f3ca9725 MIDI renderer uses NumericsHelpers to convert stereo audio to mono. 2021-05-23 13:40:06 +02:00
Vera Aguilera Puerto
33c37393ba Fixes incorrect comment in MidiRenderer.
Pain.
2021-05-23 13:15:31 +02:00
metalgearsloth
ae36529744 Emit line for mapping node exceptions (#1764)
Makes it a billion times more useful when I dun screwed up
2021-05-22 11:36:28 +02:00
20kdc
ed2be48864 Fix Coordinates setter destroying local position during a parent change by migrating parent changes to it (#1763)
This fixes computer boards going missing. (Seriously.)
2021-05-22 11:36:18 +02:00
Vera Aguilera Puerto
7ad5ce302e Directed event improvements (#1761)
* IComponentManager holds a reference to IComponentFactory.

* Directed events for a same <TComp, TEvent> can be duplicated, component references of a component are added to the entity's event tables.

* Fix tests.

* Improvements, duplicated subscriptions are no more

* Cache component factory for faster access

* when the
2021-05-21 17:38:52 -07:00
Vera Aguilera Puerto
647f1a6808 Fixes bug where deleting things causes their sprite to appear and pile on 0,0.
- Cleans up an unneeded event.
2021-05-20 21:17:20 +02:00
metalgearsloth
6c44dd9665 RenderingTreeSystem cleanup (#1759)
* RenderingTreeSystem cleanup

10% less bad but 100% still boilerplate

* Slight changies

* Even better

* New shit just got made

* Apply revews
2021-05-20 18:57:29 +10:00
Acruid
c81413b0b4 Fixes bug where the net_entityreport red PVS range square was drawn at half the actual range. 2021-05-19 15:52:44 -07:00
Vera Aguilera Puerto
88b3a557da Fixes bug with PrototypeIdListSerializer where lists wouldn't be copied at all. 2021-05-19 12:12:13 +02:00
Vera Aguilera Puerto
572eb01290 Opens SCSI window centered
- Kinda fixes it getting NaN'd on resize... This isn't a proper fix, however.
2021-05-19 11:11:35 +02:00
Vera Aguilera Puerto
9dab74c9d5 Fixes SS14Window going off-screen. 2021-05-19 10:55:41 +02:00
Paul
e1cb1e1b9c fixes xamlui nuking itself when one (1) (singular) partial declaration is missing 2021-05-18 20:19:50 +02:00
Vera Aguilera Puerto
a23da702b1 MidiManager now has a Volume property which changes the general midi volume.
- Adds VV attributes to MidiManager and MidiRenderer.
2021-05-18 20:03:20 +02:00
Vera Aguilera Puerto
ae9c2423ff Fixes EntityLookup not being restarted correctly on reconnect. 2021-05-18 17:55:24 +02:00
metalgearsloth
a6dae8e30a GridId caching (#1678)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-05-17 11:43:22 +02:00
Pieter-Jan Briers
96c0a4ae1f Automatically unsubscribe event bus registrations in entity system shutdown. (#1758)
* Automatically unsubscribe event bus registrations in entity system shutdown.

* Fix incorrect unsubscription of local events, obsolete unsubscribe methods.

That's what we got tests for.

* = null instead of .Clear()
2021-05-17 11:01:22 +02:00
Vera Aguilera Puerto
c26ebcbc78 QueueDelete method for entities (#1757) 2021-05-17 09:20:55 +02:00
Vera Aguilera Puerto
8334050411 MIDI improvements (#1756) 2021-05-16 19:28:14 +02:00
Vera Aguilera Puerto
cc67edfc2c Unsubscribe from directed event in UI System. 2021-05-15 12:40:35 +02:00
Vera Aguilera Puerto
943ea9e6c8 Shutdown and dispose of BoundUserInterfaces correctly when the UI component gets shutdown. 2021-05-14 14:25:53 +02:00
Pieter-Jan Briers
3aa5cefe03 Stop using component messages in bound UI code. 2021-05-13 03:29:38 +02:00
Pieter-Jan Briers
c5b34bab69 More obsoletions component messages. 2021-05-13 02:24:35 +02:00
Pieter-Jan Briers
e4f24ec125 Remove IPlayerSession on client. 2021-05-13 02:16:55 +02:00
Pieter-Jan Briers
250971ade7 Remove anchored APIs from physics. 2021-05-13 02:13:18 +02:00
Pieter-Jan Briers
718adf9740 Deprecate component messages harder. 2021-05-13 01:24:20 +02:00
20kdc
5d63aa8c95 Deferred Input Context Switches (fixes spawn entities menu while moving) (#1755) 2021-05-12 18:40:26 +02:00
Vera Aguilera Puerto
17af3612a5 Remove IActorComponent, rename BasicActorComponent to ActorComponent. (#1752)
Rename playerSession to PlayerSession.
2021-05-12 13:40:16 +02:00
Pieter-Jan Briers
d2ecf6b9b1 Remove CollidesOnMask
Only usage was a unit test.
2021-05-12 01:58:12 +02:00
Pieter-Jan Briers
2a1eda0d38 Fix tests 2021-05-12 01:57:03 +02:00
Pieter-Jan Briers
f0180abeb0 Missed a spot while fixing warnings. 2021-05-12 00:26:47 +02:00
Pieter-Jan Briers
720f1b1d05 Fix a bunch of compiler warnings. 2021-05-12 00:16:12 +02:00
ShadowCommander
ae45a96753 Fix error when someone else is shooting outside client PVS 2021-05-11 13:21:30 -07:00
ShadowCommander
74257c72ee Add yaml linting for entity prototype parent (#1749)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-05-11 21:54:51 +02:00
ShadowCommander
cea088f4b4 Change maxlinvelocity and maxangvelocity to take tickrate (#1746) 2021-05-11 21:53:36 +02:00
Pieter-Jan Briers
88678e7d58 Entity localization refactoring (#1753) 2021-05-11 21:52:54 +02:00
Pieter-Jan Briers
d222e25d22 Remove outdated comment. 2021-05-11 20:58:21 +02:00
Pieter-Jan Briers
f0d7fbb6f2 Allow enumeration of monitor video modes.
Basically I kept dumping debugging code for this into Clyde startup to test multi-monitor stuff with GLFW so I guess I'm making it official now.
2021-05-11 20:57:27 +02:00
Pieter-Jan Briers
adec0e71ec I can't believe Zumorica would clean up this class in the last 24 hours. 2021-05-11 13:30:38 +02:00
Pieter-Jan Briers
86d9067d62 Report error if prototype has invalid parent ID. 2021-05-11 13:24:42 +02:00
Vera Aguilera Puerto
b989c9dbee Remove unused IEntityQuery methods from EntitySystem. 2021-05-10 20:35:52 +02:00
Vera Aguilera Puerto
3101ec1985 Mark IEntityQuery and implementing classes as obsolete. 2021-05-10 20:25:54 +02:00
Vera Aguilera Puerto
9ec2da1777 PlayerSession comment cleanup. 2021-05-10 20:20:44 +02:00
Vera Aguilera Puerto
0acd28e8f4 Slight PrototypeManager cleanup. 2021-05-10 20:18:08 +02:00
Vera Aguilera Puerto
c340f50ee5 Remove unused dependencies. 2021-05-10 20:14:15 +02:00
Vera Aguilera Puerto
2b589215aa Improves the Filter API. (#1747)
- Recipients is now of type `IEnumerable<ICommonSession>`.
    - This way, people need to use the Filter API to modify the recipients, instead of being allowed to modify the underlying collection directly.
- Underlying collection is now a HashSet.
    - We want no duplicates at all. This will ensure that while being quite performant.
- Removes `IFilter`.
    - Let's face it, everyone is gonna end up using `Filter` instead as it has a much more convenient API, and nothing else will EVER implement `IFilter`. For this reason, I've just gone ahead and removed it. Every method used `Filter` already, anyway.
- Adds EntitySystem `RaiseNetworkEvent` overload that takes in a `Filter`.
    - This deduplicates a lot of code that enumerated the recipients and raised a network event per each one.
- Made AddPlayersByPvs aware of `net.pvs` and `net.maxupdaterange`, has a range multiplier parameter.
    - Now it will simply add all players to the filter if PVS is disabled, and add all players in range if it's enabled.
    - The range multiplier parameter allows us to make the PVS filter a bit more permissive, and generally better. The range is doubled by default, as it was already before.
- Adds `AddInRange` method to filters.
    - This is useful for the AudioSystem, and the PVS methods use it, too!
- Adds `RemoveByVisibility` method to filters.
    - This will remove all recipients that don't have a visibility flag in their entity's EyeComponent from the filter.
    - (This will be VERY useful for Ghost Pointing, for example)
- Adds `Clone` method to filters.
    - This is useful in cases where methods take in a filter and want to modify it without modifying the original instance. (See AudioSystem)
2021-05-08 22:27:47 +02:00
Vera Aguilera Puerto
490a567ad4 Makes some PlayerManager methods thread-safe. (#1744) 2021-05-08 22:27:26 +02:00
DrSmugleaf
32f0c49484 Fix missing Attribute suffix from some serialization attributes (#1741)
* Fix missing Attribute suffix from some serialization attributes

* Rename DataDefinition namespace to Definition
2021-05-07 14:23:21 +02:00
DrSmugleaf
61113d2434 Fix comments on serialization PropertyAndFieldDefinitionTest 2021-05-04 14:33:29 +02:00
DrSmugleaf
6ba1baa88c Add summary to seed data definition in Robust.Benchmarks 2021-05-04 14:26:07 +02:00
DrSmugleaf
07867acb9a Add serialization writing benchmark, optimize writing (#1739)
* Add serialization write benchmark

* Add baseline test and rename AddNode to Add in mapping extensions

* Optimize serialization writing

* Make reader delegate private

* Unhardcode baseline test
2021-05-04 14:25:13 +02:00
DrSmugleaf
3e28b083b9 Cleanup serialization markdown, add extensions for easier mapping node manipulation (#1738) 2021-05-04 13:01:07 +02:00
DrSmugleaf
68d9e13edf Fix nullability in ViewVariablesInstance onValueChanged tuple action 2021-05-04 12:08:53 +02:00
Pieter-Jan Briers
a0c0a722c9 Don't crash if window creation fails due to selected renderer. 2021-05-03 23:37:41 +02:00
Pieter-Jan Briers
bf4aead1e8 Fix margins on debug console background 2021-05-03 12:43:21 +02:00
Pieter-Jan Briers
39f0d2e974 Fix positioning and size handling when the game started in fullscreen and exited it later.
It now actually makes the non-fullscreen windows sized and placed sanely so it isn't placed offscreen and too big.
2021-05-02 23:30:50 +02:00
Pieter-Jan Briers
b20ae98f21 quit command now does soft exit, hardquit command added. 2021-05-02 23:30:50 +02:00
Acruid
7899780543 Unsubscribing from a directed entity event does not require a delegate argument anymore. 2021-05-02 14:23:48 -07:00
Pieter-Jan Briers
0c9e322b3e Fix macOS builds. 2021-05-02 21:48:58 +02:00
Pieter-Jan Briers
6005208285 Use Fluent localization for key names. 2021-05-02 21:48:50 +02:00
Pieter-Jan Briers
2b15831349 Fix fullscreen startup crashing. 2021-05-02 21:36:08 +02:00
Pieter-Jan Briers
1b2450d1cb Make debug.target_fps cvar for frame graph.
So 60 FPS isn't hardcoded anymore.
2021-05-02 20:55:46 +02:00
DrSmugleaf
5f31036ab2 Cleanup serialization code (#1735)
* Cleanup serialization code

* Merge fixes

* american codebase
2021-05-02 14:23:39 +02:00
Pieter-Jan Briers
8efffc471d Multi-window support (#1713) 2021-05-02 14:05:50 +02:00
DrSmugleaf
eb9e842027 Make SpecificPropertyInfo not return attributes on the backing field by default (#1734) 2021-05-02 13:47:32 +02:00
DrSmugleaf
f9cd9ac12a Add serialization copy benchmark, optimize copying and reading with IL generators (#1729)
* Create serialization copy benchmark

* Optimize copy generic method call

Before
|                             Method |         Mean |      Error |     StdDev |       Median |
|----------------------------------- |-------------:|-----------:|-----------:|-------------:|
|                   CreateCopyString |     43.54 ns |   0.918 ns |   0.859 ns |     43.74 ns |
|                  CreateCopyInteger |     19.33 ns |   0.388 ns |   0.860 ns |     19.24 ns |
| CreateCopyDataDefinitionWithString |  3,971.42 ns |  78.974 ns | 213.512 ns |  3,902.54 ns |
|       CreateCopySeedDataDefinition | 49,916.69 ns | 264.992 ns | 221.280 ns | 49,950.53 ns |

After
|                             Method |         Mean |      Error |     StdDev |
|----------------------------------- |-------------:|-----------:|-----------:|
|                   CreateCopyString |     43.15 ns |   0.917 ns |   1.766 ns |
|                  CreateCopyInteger |     17.91 ns |   0.366 ns |   0.305 ns |
| CreateCopyDataDefinitionWithString |    544.20 ns |   8.137 ns |   7.611 ns |
|       CreateCopySeedDataDefinition | 18,233.34 ns | 357.861 ns | 397.761 ns |

* Change populate delegate to use IL

|                       Method |        Mean |     Error |    StdDev |
|----------------------------- |------------:|----------:|----------:|
|                   ReadString |    190.7 ns |   3.48 ns |   5.63 ns |
|                  ReadInteger |    218.8 ns |   4.29 ns |   6.01 ns |
| ReadDataDefinitionWithString |    677.5 ns |  13.34 ns |  24.06 ns |
|       ReadSeedDataDefinition | 11,067.0 ns | 219.19 ns | 260.93 ns |

|                             Method |         Mean |      Error |     StdDev |
|----------------------------------- |-------------:|-----------:|-----------:|
|                   CreateCopyString |     42.69 ns |   0.926 ns |   1.414 ns |
|                  CreateCopyInteger |     18.02 ns |   0.268 ns |   0.237 ns |
| CreateCopyDataDefinitionWithString |    556.80 ns |  11.206 ns |  21.589 ns |
|       CreateCopySeedDataDefinition | 13,797.07 ns | 256.011 ns | 367.163 ns |

* Make copying use IL to get values

|                               Method |        Mean |      Error |     StdDev |
|------------------------------------- |------------:|-----------:|-----------:|
|                     CreateCopyString |    42.55 ns |   0.889 ns |   1.357 ns |
|                    CreateCopyInteger |    18.72 ns |   0.394 ns |   0.740 ns |
|   CreateCopyDataDefinitionWithString |   398.98 ns |   7.853 ns |  12.682 ns |
|         CreateCopySeedDataDefinition | 5,996.60 ns | 118.724 ns | 181.304 ns |
| BaselineCreateCopySeedDataDefinition |   340.85 ns |   6.811 ns |  12.281 ns |

* Rest in peace the fast path
For now

* Fix serialization copying not passing the target ref properly

* Fix field assigners for structs
2021-05-02 12:09:12 +02:00
Pieter-Jan Briers
8fd98c75a9 Fix finalizer stutter from post-process shaders. 2021-05-02 11:23:48 +02:00
Pieter-Jan Briers
7c008e857d Rewrite FileDialogManager to remove #if from it. 2021-05-02 09:35:38 +02:00
Pieter-Jan Briers
4de2e35e66 Add macOS CI for build-test 2021-05-02 09:25:26 +02:00
metalgearsloth
d4467acf93 Fix filedialogmanager 2021-05-02 17:16:27 +10:00
Silver
f3babcc39f Update FileDialogManager.cs 2021-05-01 19:30:45 -06:00
Silver
f491bb5571 Update FileDialogManager.cs 2021-05-01 19:20:40 -06:00
Pieter-Jan Briers
b201f10c76 Reduce some dictionary allocations in RSI loading. 2021-05-02 01:08:51 +02:00
Pieter-Jan Briers
a9208c0d29 Reduce allocations in RSIResource.LoadRsiMetadata somewhat.
Using stackallocs for the meta.json file.
2021-05-02 00:55:01 +02:00
Pieter-Jan Briers
b8cc01d872 Remove unecessary array allocation from ResourcePath constructor. 2021-05-02 00:16:52 +02:00
Pieter-Jan Briers
2d827890e9 Fix nullable errors reported by Rider. 2021-05-02 00:00:40 +02:00
Pieter-Jan Briers
f86d6ccd3c Remvoe unused .dll.config and app.config. 2021-05-02 00:00:04 +02:00
Vera Aguilera Puerto
967b76483a Fix rendering tree system crash involving nullspace.
Nullspace is a valid map, so we need to account for that!
2021-04-30 01:11:16 +02:00
Vera Aguilera Puerto
ef2c0ad8cf Fix the comp lifetime ComponentRemove event
Now, event tables DispatchComponent takes in the component reference directly.
2021-04-30 01:09:50 +02:00
metalgearsloth
9ae1352030 Enable nullables as errors in Robust (#1732) 2021-04-29 15:56:05 -06:00
SweptWasTaken
d8d9b271cc Updates sandbox.yml 2021-04-28 14:31:46 -07:00
Acruid
122acc5fd5 SnapGridComponent Removal (#1720)
* Removed SnapGridOffset, there is only center now.

* SnapGridComponent methods are now static.

* Removed SnapGridComponent.OnPositionChanged.

* Refactored static functions off SnapGridComponent to MapGrid.
Refactored away usages of SnapGridComponent.Position.

* Added Transform.Anchored for checking if an entity is a tile entity.
More refactoring for static MapGrid functions.

* Static snapgrid methods on MapGrid are no longer static.

* Removed IMapGrid.SnapSize, it is now always equal to the IMapGrid.TileSize.

* Add setter to ITransformComponent.Anchored.
Removed direct references to SnapGridComponent from content.

* Grid functions now deal with EntityUids instead of SnapGridComponents.
Began renaming public API functions from SnapGrid to Anchor.

* Add some unit tests.

* SnapGridComponent now anchors itself in startup, instead of Initialize (sending directed events in init is an error).
2021-04-28 10:24:11 -07:00
metalgearsloth
32dea84196 Fix physics build warnings (#1731) 2021-04-28 15:29:51 +02:00
DrSmugleaf
91d58dbca4 Make serialization work with backing fields automatically (#1727)
* Make serialization work with backing fields automatically

* Fix not taking priorities into account, make the test fail when that is the case

* Turn fieldDefs back into a list

* Format it better

* Remove GetInheritanceBehaviour, expose immutable array of base field definitions
2021-04-27 14:11:06 +02:00
MehimoNemo
c54b1572f5 Unbuckling Closes Inventory UI (#1723)
* pain

* Add test for parent changed when not at 0,0

* Fix map loading of grids

Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
2021-04-26 12:26:29 -07:00
DrSmugleaf
1fa979c0f6 Add serialization manager shutdown method and initialize benchmark (#1728) 2021-04-25 13:00:31 -07:00
metalgearsloth
760599171d Obsolete collision interfaces (#1725) 2021-04-25 12:58:30 -07:00
metalgearsloth
10d295d535 Basic Collisionmanager tests (#1722)
* Add some unit tests for CollisionManager
2021-04-25 12:49:45 -07:00
ShadowCommander
0047c5000f Fix placement of grid tiles on the edge of a grid (#1724)
* Fix placement of grid tiles on the edge of a grid
2021-04-25 12:48:26 -07:00
metalgearsloth
810a6d190f Add MapId error to tp command (#1726)
Previously it would just dump the exception
2021-04-25 04:12:28 -07:00
metalgearsloth
197227dcf6 Fix showbb
matrices momento
2021-04-25 19:03:19 +10:00
Swept
fa23ec8fc6 Updates the README.md 2021-04-23 19:23:54 +00:00
Vera Aguilera Puerto
6506171ea0 Server ContentStart.StartLibrary method.
This will skip the FULL_RELEASE check on games specifically using RobustToolbox as a library.
2021-04-23 20:37:45 +02:00
Vera Aguilera Puerto
8bd1e72e9f Adds GameController options for games using RobustToolbox as a library. (#1711) 2021-04-23 00:05:42 +02:00
Acruid
4ce6629ace RSIs fail to load if they have duplicate states defined in their JSON. (#1701) 2021-04-22 15:21:34 -06:00
Vera Aguilera Puerto
f9ef605903 Add optional AwaitEvent methods that take a Type instead of using generics. 2021-04-21 15:29:43 +02:00
Vera Aguilera Puerto
c6b74e998f Use System.Numerics in a few Box2 methods to speed them up (#1708) 2021-04-19 17:18:09 +02:00
Vera Aguilera Puerto
c4946b8466 Viewport Improvements (#1528)
Co-authored-by: 20kdc <asdd2808@gmail.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-04-19 09:47:20 +02:00
Pieter-Jan Briers
ffa908bf27 More workarounding for Rider Avalonia faking 2021-04-19 01:47:33 +02:00
Pieter-Jan Briers
0d37ff3f20 Fix reporting of fatal GLFW errors on window creation. 2021-04-19 01:44:00 +02:00
Pieter-Jan Briers
7aecdcf70a Improved soft shadows. 2021-04-19 01:42:59 +02:00
Vera Aguilera Puerto
70f82d6db8 Add directed start/end collision events. (#1710) 2021-04-17 13:08:11 +02:00
Vera Aguilera Puerto
20b7870739 PlayerSession is now correctly setup on singleplayer 2021-04-17 01:52:07 +02:00
Vera Aguilera Puerto
172639baea Fix bug where TickUpdate is never ran in singleplayer mode. 2021-04-16 13:37:01 +02:00
metalgearsloth
6038483b1e DebugDrawing for DistanceJoints (#1703) 2021-04-16 10:55:31 +02:00
Vera Aguilera Puerto
39d98d591c Adds singleplayer support (#1704) 2021-04-16 10:53:59 +02:00
Vera Aguilera Puerto
01c2fc0730 ClydeTileDefinitionManager no longer throws when uninitialized, or when there are no tile definitions. (#1705) 2021-04-16 10:53:49 +02:00
ike709
1884bb0067 Fixes DateTimeOffset sandbox whitelisting (#1706) 2021-04-16 01:39:18 +02:00
Vera Aguilera Puerto
1c368bbaa8 Remove useless debug prototypes. 2021-04-15 20:44:25 +02:00
metalgearsloth
d16078a35f Don't reset sleeptimer on building physics islands 2021-04-15 23:18:05 +10:00
Vera Aguilera Puerto
4dd04207ac Shared GameTiming no longer depends on INetManager (#1697)
Adds ClientGameTiming with prediction and local/server time methods.
2021-04-14 11:40:02 -07:00
Vera Aguilera Puerto
02af42da30 Refactors EntityManager to not do any networking. (#1695)
* Refactors EntityManager to not do any networking.
ServerEntityManager and ClientEntityManager now do the networking instead.

* Rename property for "backwards compat."

* Remove comented out code in robust server simulation
2021-04-14 11:39:21 -07:00
Vera Aguilera Puerto
2c75c8b36d Refactors MapManager to not do any networking. (#1696)
* Refactors MapManager to not do any networking.
Now, ServerMapManager and ClientMapManager handle any networking.

* it's christmas in april!

* Remove comented line

* Remove useless seal

* Fix incorrect semicolon

* Event is no longer overriden, has a protected Invoke method instead
2021-04-14 11:13:58 -07:00
Vera Aguilera Puerto
013e6f7ce4 Move INetManager dependency from PrototypeManager to Server/ClientPrototypeManager 2021-04-14 14:55:40 +02:00
Acruid
cbd7b62ad7 Component Lifetime Events (#1660)
* Events are now raised for component OnAdd/Initialize/Startup/Shutdown/OnRemove.
Code cleanup in the Component class.
2021-04-13 17:16:41 -07:00
metalgearsloth
c1396f1c50 Named fixtures (#1684)
* Add named fixtures

Useful for getting specific collisions.

* Final cleanup

* More cleanup
2021-04-13 20:47:13 +10:00
Vera Aguilera Puerto
3ec9e7a734 Remove a few (now irrelevant) comments mentioning Godot. 2021-04-12 20:10:05 +02:00
Vera Aguilera Puerto
3a1e6e84b1 Remove Unused sharer params enum from the Godot era. 2021-04-12 20:09:22 +02:00
Vera Aguilera Puerto
7224419f77 Remove unused AudioMixTarget 2021-04-12 20:03:57 +02:00
Vera Aguilera Puerto
056e4de0c1 Appearance System cleanup.
Removes a nearly 4 years old unused visualizer that had a hardcoded update method in the appearance system, for some reason.
2021-04-12 19:59:25 +02:00
Vera Aguilera Puerto
aa90f22e23 Adds abstract class for entity events that can be cancelled. (#1688) 2021-04-11 18:51:07 +02:00
metalgearsloth
071234095d Don't use linked-list for contact pooling (#1683)
Always seemed icky to me. Aether uses a linked-list (like world contacts) and Farseer just uses a Queue.
2021-04-10 18:33:01 +02:00
Vera Aguilera Puerto
5b06391159 Fix objects of a server-only type not correctly showing up as such in VV. 2021-04-10 17:32:56 +02:00
Vera Aguilera Puerto
8edd44086b AudioSystem and DebugPhysicsIslandSystem unsubscribe from events on shutdown now. 2021-04-09 16:07:44 +02:00
Vera Aguilera Puerto
ccf212e9cb GridTileLookupSystem unsubscribes from events on shutdown. 2021-04-09 13:51:12 +02:00
Vera Aguilera Puerto
493011d1f9 SnapGridSystem uses directed MoveEvent, unsubscribes on shutdown. 2021-04-09 13:24:21 +02:00
Vera Aguilera Puerto
40e193df33 Adds directed/broadcast event for SnapGrid component position change. 2021-04-09 13:21:15 +02:00
Vera Aguilera Puerto
5068294d38 Makes a bunch of TransformComponent events directed. (#1682) 2021-04-08 20:42:46 +02:00
metalgearsloth
24054b5e2f Optimise showbb some more 2021-04-08 18:37:22 +10:00
Paul Ritter
17869c16cd when the bool 2021-04-06 11:58:17 +02:00
metalgearsloth
d8aad89c2f Split entity management from entity queries (#1665)
* Split entity lookups from entitymanager

* Helps if you subscribe dingus

* Handle map changes

* Stacks instead

* Make mapchanges use a queue because it's probably better

Moves likely only care about the latest position

* IoC what you did there

* IoC refactor

* Minor optimisations

* Apply feedback

* My IQ dropped 3 sizes that day

* Rest of acruid's feedback

* final_no_actual commit

* enlightenment?

* Liftoff

* final_commit_v2_actual

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-04-06 13:29:48 +10:00
DrSmugleaf
2a349eb023 Optimize serialization reading, create benchmarks (#1679)
* Add Robust.Benchmarks and read string benchmark

* Separate serialization manager methods, use compiled lambdas to call manager read

4 us > 200 ns

* Add int and data definition with string benchmarks

* Make serialization population use expressions to create definitions

* Make benchmark classes internal and create seed data definition

* Add complex data definition read benchmark

* Create primitive serializers, remove primitive special case

|                 Method |        Mean |     Error |    StdDev |
|----------------------- |------------:|----------:|----------:|
|             ReadString |    227.1 ns |   4.47 ns |   5.65 ns |
|            ReadInteger |    245.4 ns |   4.82 ns |   6.26 ns |
|  ReadDataDefWithString |    804.7 ns |  15.27 ns |  16.34 ns |
| ReadSeedDataDefinition | 15,846.8 ns | 312.89 ns | 773.39 ns |

* Remove testing code

* Setup delegates during initialize

* Revert "Setup delegates during initialize"

This reverts commit 7ff4d4eaaa.

* Store delegates in a concurrent dictionary because I really cannot be arsed to generate them on initialize at this point
2021-04-05 14:50:33 +02:00
Vera Aguilera Puerto
47ad07b3d2 Adds directed event for when an entity's BodyType changes. (#1681)
Removes old Anchored C# event.
2021-04-05 13:17:09 +02:00
ShadowCommander
aacf6522b4 Remove NetId requirement for local event subscriptions (#1675) 2021-04-02 18:45:59 -07:00
ShadowCommander
c73d27b9ae Add RSI path to error log (#1676) 2021-04-02 16:45:21 -07:00
Vera Aguilera Puerto
f068b30a7c Adds Prototype Id Validator for Dictionaries whose keys are prototype IDs. (#1673) 2021-04-02 15:47:48 +02:00
Vera Aguilera Puerto
5400dddcfc Fix ComponentDependencies tests for debug & release 2021-04-02 13:56:42 +02:00
metalgearsloth
6cf5fdc5d6 Grid-trees for rendering (#1666) 2021-04-02 20:25:16 +11:00
Vera Aguilera Puerto
5d46663881 Fix ComponentDependencies tests 2021-03-31 22:17:55 +02:00
Acruid
8e0f227940 PVS Bugfixes 1: The Debuggening (#1671)
* Wrapped the parallel GetMail function in a try/catch.
Added a hack to the ViewCulling leave message that skips ents that don't exist.
Always send ALL map and grid entities to the client.
More info logging about adding/removing maps/grids.

* Will now still send required map critical entities even if client is not attached to an entity.
PvsEnabled and PvsRange are now writeable.
2021-03-31 21:56:11 +02:00
metalgearsloth
73a13fff9a Fix grid bounds upon deserialization 2021-03-31 19:33:19 +11:00
DrSmugleaf
de2e505a12 Make content able to choose which log level leads to test failures (#1670)
* Make content able to choose which log level leads to test failures

* Now make it make sense
2021-03-31 19:26:38 +11:00
DrSmugleaf
a9f7c7a76f Fix no HWId userdata error in integration tests (#1667) 2021-03-30 15:39:43 +02:00
Vera Aguilera Puerto
37401c26c9 Adds a custom editor for Prototypes to ViewVariables. (#1663)
Also improves VV a bit.
2021-03-30 15:33:15 +02:00
Vera Aguilera Puerto
528cd1e0e5 Fix fullscreen crash 2021-03-30 15:32:15 +02:00
Pieter-Jan Briers
2959456bec Fix integration test networking. 2021-03-30 13:28:26 +02:00
Metal Gear Sloth
8951712495 Add NaN guards to physics 2021-03-30 21:59:15 +11:00
metalgearsloth
d8612aff64 Re-implement inertia (#1652)
* Implement inertia

* actual SPEEN

* Sync mass

* bitcoin miner

* I am le dumb

* also dis

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-30 21:42:05 +11:00
Acruid
e16732eb7b Network View Bubble (#1629)
* Adds barbones culling.

* Visibility culling and recursive parent ent additions.
DebugEntityNetView improvements.
Visibility moved from session to eyecomponent.

* Multiple viewport support.

* Perf improvements.

* Removed old netbubble system from ServerEntityManager.
Supports old NaN system for entities leaving view.
Supports old SendFullMap optimization for anchored, non-updating Entities.

* Fixes size of netView box.

* Remove empty EntityManager.Update method.
Switching ViewCulling back to PLINQ.
2021-03-29 16:17:34 -07:00
Acruid
91f61bb9de Reverts component NetId storage in ComponentManager back to the way Acruid originally designed it.
Removes NetId methods from IEntity, content does not need to be messing with them.
Fixes bug in DeleteComponent where the ComponentDeleted event was not being raised if a component did not have a NetId.
2021-03-29 03:40:48 -07:00
Pieter-Jan Briers
ddc91d05ec Some work towards multi-monitor support in Clyde.
Most of this was me experimenting with GLFW, but I figured I'd still commit it.
2021-03-28 21:23:38 +02:00
Acruid
ef22842b90 Fixes bug where FirstTimePredicted was not being set properly for the first predicted frame. 2021-03-27 20:16:04 -07:00
Pieter-Jan Briers
303e2152d2 UIScale now updates dynamically.
So if you move the window between different monitors with different scaling, the game updates.
2021-03-28 01:55:35 +01:00
Vera Aguilera Puerto
37fc0d0d2a Set correct class constrains for prototype id list serializers 2021-03-27 22:47:24 +01:00
Vera Aguilera Puerto
53987e1e5d Adds prototype "Variant" helper methods to IPrototypeManager (#1662) 2021-03-27 22:40:07 +01:00
metalgearsloth
3216d7770b Fix net.rate cvar warning (#1659)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-27 02:14:45 -07:00
Acruid
3203ca2ff4 Removed Control.Update from the UI system. UI Controls have no business running code in simulation updates.
Refactored the client update loop so that the GameStateManager is in full control of the simulation update.
2021-03-26 17:46:34 -07:00
metalgearsloth
e22254cd51 Clear velocities on container insertion (#1653)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-26 22:39:11 +01:00
Acruid
7ed722f669 Visibility moved from session to EyeComponent (#1657) 2021-03-26 22:38:45 +01:00
DrSmugleaf
4864096b2a Add prototype id list serializer and tests (#1658)
* Add prototype id list serializer and tests

* Bring old .Value code back

* Paul made me do this
2021-03-26 20:52:22 +01:00
Acruid
5161385de4 Removed unused Update and Resize code from GameStates. Presenters can get resize events from the interface manager (hint: you won't ever need to), and there is no reason for a UI Presenter to do anything in simulation ticks (UI should be event driven, not polling data every frame). 2021-03-25 14:01:51 -07:00
Acruid
98e009b38f Removed the GameController dependency from Clyde.
Removed the ConfigurationManager dependency from FontManager.
2021-03-25 11:36:57 -07:00
Vera Aguilera Puerto
3863ab8f62 Adds PrototypeIdHashSetSerializer for HashSet<string> prototype ID validation (#1656)
* Adds PrototypeIdHashSetSerializer for HashSet<string> prototype ID validation

* Paul changes

* cleanup, better stuff
2021-03-25 14:26:14 +01:00
Metal Gear Sloth
f576eb5125 Optimise showbb 2021-03-25 23:32:06 +11:00
Acruid
314742ccd8 NullableHelper tests now properly set up their required DI container instead of reusing the container from whatever test was ran before it. Service Locator anti-pattern :( 2021-03-25 02:02:09 -07:00
Acruid
f9074811f9 Adds constructor injection to the IoCManager & DependencyCollection. 2021-03-25 01:16:08 -07:00
Pieter-Jan Briers
5f3e1eb378 Frame graph now shows when GCs occur. 2021-03-25 02:24:38 +01:00
Pieter-Jan Briers
3c1ee20ca1 A 2021-03-25 02:05:28 +01:00
Pieter-Jan Briers
3768f5e68e Remove allocs from ContainerSlot.ContainedEntities. 2021-03-25 01:56:06 +01:00
Pieter-Jan Briers
765a560380 Fix integer overflow breaking Lidgren metrics. 2021-03-25 01:47:45 +01:00
Metal Gear Sloth
39ae3ac653 Optimise physics do not research 2021-03-24 22:35:17 +11:00
Pieter-Jan Briers
e48f4027e5 Probably fix running Robust directly for some people. 2021-03-23 21:28:36 +01:00
ShadowCommander
2fa1e98faf Fix CopyWithTypeSerializer not copying when null (#1651) 2021-03-22 11:02:32 +01:00
Pieter-Jan Briers
cedfa0ee2f Nothing to see here. 2021-03-21 20:37:10 +01:00
Acruid
92f44b390e SoundSystem Improvements (#1649) 2021-03-21 16:35:52 +01:00
Pieter-Jan Briers
65a42f9209 Prototype reloading now fires an event. 2021-03-21 16:25:52 +01:00
Acruid
ebf53248cf TestLogHandler now fails the test if a warning or higher is logged. 2021-03-19 13:42:13 -07:00
Acruid
289f637e8a Entity Lifetime Levels (#1644)
* Added an entity lifetime levels property.
Added exception when recursively deleting an entity.

* Add a directed event 'EntityTerminatingEvent' for right before an entity is deleted.

* Added MapInit lifestage to entities.
2021-03-18 22:53:05 -07:00
metalgearsloth
d7c13f30c8 Fix showbb awake (#1632)
* Fix showbb awake

* Slight tweak

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-17 13:58:26 -07:00
Vera Aguilera Puerto
0dac17ae5e ConfigurationManager.OnValueChanged's invokeImmediately now accounts for overriden values correctly. 2021-03-17 20:22:44 +01:00
Pieter-Jan Briers
9a19a774fa Use stencil test to cull FOV-hidden lights early.
Massive shader optimization.
2021-03-17 13:16:47 +01:00
Pieter-Jan Briers
81f49d5eb2 Fix moving to the end of a textbox. 2021-03-17 01:22:45 +01:00
DrSmugleaf
4f3b4ac2d2 Changes for content server nullability (#1642) 2021-03-16 15:47:49 +01:00
Pieter-Jan Briers
e428056b52 Rldrsc now works with textures. 2021-03-16 12:39:19 +01:00
DrSmugleaf
8dc9d2989a Fix not being able to use shared entity systems in update order (#1638) 2021-03-16 12:38:31 +01:00
Paul
fd8c90dcbb reverting cringe (moved controller metrics cvar get to server) 2021-03-16 12:05:56 +01:00
Vera Aguilera Puerto
ffe4e5a8ab Add Enabled property to CollisionWake component. (#1641)
* Add Enabled property to CollisionWake component.

* Set property in HandleComponentState
2021-03-16 11:38:46 +01:00
Paul Ritter
6e5026d270 adds prometheus logging to physicscontrollers (#1640) 2021-03-16 11:32:46 +01:00
metalgearsloth
946c4166dc Move RootControl frameupdate to after queue (#1625)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-16 09:15:18 +01:00
Paul Ritter
7d2fb85a04 adds custom typeserializers (#1636)
retires DataFieldWithConstantAttribute & DataFieldWithFlagAttribute in favor of new customtypeserializers
adds prototypeidvalidation, just needs to be added to the corresponding fields
fixes some behaviour in yamllinter
2021-03-15 13:24:29 +01:00
metalgearsloth
d6ec078519 Fix static sleeping crash (#1630)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-14 12:44:49 +11:00
DrSmugleaf
32256fc4d9 Remove printing ticks in integration tests (#1627) 2021-03-13 20:12:49 +01:00
DrSmugleaf
37bbdfe7ff Fix serialization logging not printing messages (#1628) 2021-03-13 20:12:41 +01:00
metalgearsloth
c906675cdf Set collidable on CollisionWake removal (#1626)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-13 20:13:00 +11:00
DrSmugleaf
90bb5574c1 Add a CVar to disable texture preloading for tests (#1623) 2021-03-13 13:25:10 +11:00
Acruid
7b50dcd969 Removed IEntityManager.SpawnEntityNoMapInit. Every entity spawned into an uninitialized map does not have mapinit ran, so this is useless. 2021-03-11 22:17:31 -08:00
Pieter-Jan Briers
8d82f48a8f Various GLES fixes. 2021-03-11 13:06:30 +01:00
Pieter-Jan Briers
469f9fd219 Remove #line directives from shaders.
They hurt debugging more than they helped.
2021-03-11 13:06:18 +01:00
Pieter-Jan Briers
1a5783ab4e Probably fix tests 2021-03-11 11:47:58 +01:00
Clyybber
3d25886d79 Set velocity for audio sources, enabling doppler effect (#1622) 2021-03-11 11:44:01 +01:00
Pieter-Jan Briers
516b2cd372 Handle surrogate pairs correctly in LineEdit. 2021-03-10 16:55:12 +01:00
Pieter-Jan Briers
3cfcfa0be2 Render fallback character for unavailable characters. 2021-03-10 16:54:52 +01:00
Pieter-Jan Briers
69328087bd Added AsRune property to TextEventArgs 2021-03-10 16:54:13 +01:00
Pieter-Jan Briers
1bf8b2a52b Use Rune for rendering text instead of char.
Fixes crashes with surrogates.
2021-03-09 23:25:27 +01:00
Pieter-Jan Briers
fc6dc6f4e1 Add/fix Rune APIs for sandbox. 2021-03-09 23:24:33 +01:00
Pieter-Jan Briers
31c1feca4e Debug console history improvements.
No longer blows up if history cannot be read/written thanks to file locking.

Made it more async so it won't waste main thread init time.
2021-03-09 22:28:58 +01:00
Pieter-Jan Briers
3ed1eef2ab Fix build. 2021-03-09 21:44:46 +01:00
Pieter-Jan Briers
1394a017bb Fix IL verification throwing if a verifier error does not need to be formatted. 2021-03-09 21:41:50 +01:00
metalgearsloth
6b0670d5f1 Break joints on container insertion; semi-related to break pulling on container insertion (#1620)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-09 11:51:57 -08:00
metalgearsloth
f573331541 Fix physics joint disconnect spam (#1619)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-09 11:51:35 -08:00
metalgearsloth
a7218cd3b8 Make Visible a Shared Property for sprites (#1615)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-09 11:51:16 -08:00
Acruid
f7e8178736 Added new ComponentEvents system in IEventBus. (#1601)
* Added new ComponentEventBus, combined it with IEventBus.

* Removed all traces of IEntity from ComponentDependencies.
Removed IEntityManager dependency from ComponentManager.

* Added entity create/delete events to IEntityManager.

* ComponentEvents now use EntitySystemMessages instead of their custom ComponentEvent class.

* Component events are now just overloads of entity events.

* Removed obsolete EntitySystemMessage, now everything uses the base EntityEventArgs.

* Add a bool argument for if the message should be broadcast as well as directed.
Fix ordering and init issues of events in EntityManager.

* Changed names from Component/Entity events to Directed/Broadcast.

* Fix bugs and unit tests.
2021-03-09 11:02:24 -08:00
Pieter-Jan Briers
31f921e4aa Use ProfileOptimization to speed up startup. 2021-03-09 12:29:59 +01:00
Pieter-Jan Briers
aa1c25637c Allow disabling nvidia optimus via env var. 2021-03-09 12:29:59 +01:00
Pieter-Jan Briers
71f2c48463 Call GC.Collect after game init.
Cleans up any gen 2 garbage from init and the stutter shouldn't be the end of the world.
2021-03-09 12:29:59 +01:00
Pieter-Jan Briers
d65f4ca898 RSI & texture preloading.
All RSIs and textures are now loaded ahead of time in client startup. This is well threaded and is extremely fast.
2021-03-09 12:29:59 +01:00
Pieter-Jan Briers
b35568ffe5 Disable path case checks by default.
The idea was that these are Task.Run'd so don't influence performance. That was before we started threading the hell out of startup.

We're getting more stuff like YAML linting now which should hopefully be able to catch 99% of this. And louder because it was always just a warning before.
2021-03-09 12:29:59 +01:00
Acruid
a0d241e551 Removes some things that should not have been in the last PR. 2021-03-09 02:06:13 -08:00
GraniteSidewalk
33a6934582 Large number of changes to Shaders and Overlays (#1387)
* AAAAAAAAAAAAA

* Organization

* Still doesnt work

* Formatting

* It works!!

* More changes to everything

* Beginning of changes to overlays

* Makes the overlay manager GUID based (also it was very messy, still messy but i fixed some of it)

* Stencils are easy

* Questionable changes to overlays

* Minor change to HLR

* Fixed duplicate overlays when calling some commands (Like showbb)

* Fixes misleading message

* Adds a variety of worldspaces for overlays to choose from

* Caching

* Address reviews

* Merging pains

* ah.

* ahhhhh

* minor overlaymanager changes

* Work

* fix

* Merge??

* Fixes null errors

* Force update

* Delete whatever the fuck this is?

Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-03-09 01:52:16 -08:00
metalgearsloth
f237a8bbbc Optimise static body sleeping (#1618)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-09 19:47:51 +11:00
Pieter-Jan Briers
4bc775c01c RSI loader improvements:
1. Stop using NJsonSchema, it didn't do anything useful.
2. Use System.Text.Json instead of Newtonsoft.Json.
3. General cleanup of the code, using arrays instead of lists, etc...
2021-03-08 11:18:19 +01:00
Pieter-Jan Briers
93b4d81505 Optimize ImageSharp blitting. 2021-03-08 11:15:33 +01:00
Pieter-Jan Briers
0afb85a09e Fix some missing re-pooling of ImageSharp images. 2021-03-08 09:45:22 +01:00
Metal Gear Sloth
7b9315cea4 Significantly lower physics speedcap 2021-03-08 15:46:50 +11:00
Metal Gear Sloth
dc3af45096 Fix anchored message 2021-03-08 15:00:08 +11:00
metalgearsloth
00ce0179ae Allow kinematic controllers to have an impulse applied (#1612)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-08 12:10:20 +11:00
ShadowCommander
81947ba3d8 Fix buckling (#1611) 2021-03-07 15:25:11 -08:00
DrSmugleaf
49327279d0 Fix nullability errors in physics ContactHead code (#1609) 2021-03-07 23:15:55 +01:00
Metal Gear Sloth
0936cf3c7f Fix CanCollide serialization 2021-03-08 04:06:21 +11:00
Metal Gear Sloth
43b75a69c2 Fix contact overlap 2021-03-08 03:48:30 +11:00
metalgearsloth
c17c8d7a11 Physics (#1605)
* Physics worlds

* Paul's a good boy

* Build working

* Ingame and not lagging to hell

* Why didn't you commit ahhhhh

* Hard collisions working

* Solver parity

* Decent broadphase work done

* BroadPhase outline done

* BroadPhase working

* waiting for pvs

* Fix static PVS AABB

* Stop static bodies from awakening

* Optimise a bunch of stuff

* Even more broadphase stuff

* I'm fucking stupid

* Optimise fixture updates

* Collision solver start

* Building

* A is for Argumentative

* Fix contact caching island flags

* Circle shapes actually workeded

* Damping

* DS2 consumables only

* Slightly more stable

* Even slightlier more stablier

* VV your heart out

* Initial joint support

* 90% of joints I just wanted to push as I'd scream if I lost progress

* JOINT PURGATORY

* Joints barely functional lmao

* Okay these joints slightly more functional

* Remove station FrictionJoint

* Also that

* Some Box2D ports

* Cleanup mass

* Edge shape

* Active contacts

* Fix active contacts

* Optimise active contacts even more

* Boxes be stacking

* I would die for smug oh my fucking god

* In which everything is fixed

* Distance joints working LETS GO

* Remove frequency on distancejoint

* Fix some stuff and break joints

* Crashing fixed mehbeh

* ICollideSpecial and more resilience

* auto-clear

* showbb vera

* Slap that TODO in there

* Fix restartround crash

* Random fixes

* Fix fixture networking

* Add intersection method for broadphase

* Fix contacts

* Licenses done

* Optimisations

* Fix wall clips

* Config caching for island

* allocations optimisations

* Optimise casts

* Optimise events queue for physics

* Contact manager optimisations

* Optimise controllers

* Sloth joint or something idk

* Controller graph

* Remove content cvar

* Random cleanup

* Finally remove VirtualController

* Manifold structs again

* Optimise this absolute retardation

* Optimise

* fix license

* Cleanup physics interface

* AHHHHHHHHHHHHH

* Fix collisions again

* snivybus

* Fix potential nasty manifold bug

* Tests go snivy

* Disable prediction for now

* Spans

* Fix ShapeTypes

* fixes

* ch ch changeesss

* Kinematic idea

* Prevent static bodies from waking

* Pass WorldAABB to MoveEvent

* Fix collisions

* manifold structs fucking WOOORRKKKINNGGG

* Better pushing

* Fix merge ickies

* Optimise MoveEvents

* Use event for collisions performance

* Fix content tests

* Do not research tests

* Fix most conflicts

* Paul's trying to kill me

* Maybe collisions work idk

* Make us whole again

* Smug is also trying to kill me

* nani

* shitty collisions

* Settling

* Do not research collisions

* SHIP IT

* Fix joints

* PVS moment

* Fix other assert

* Fix locker collisions

* serializable sleeptime

* Aether2D contacts

* Physics is no longer crashing (and burning)

* Add to the TODO list

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-08 03:19:01 +11:00
Paul
223fd8126f copy fix 2021-03-06 14:47:44 +01:00
Paul
1d5559be4a makes typevalidator its own interface 2021-03-05 15:02:03 +01:00
Paul
0b749ff8bb makes prototypeinheritance opt in 2021-03-05 11:13:00 +01:00
Paul
069fa89fcb adds Try variants to FirstOrNull & FirstOrDefault
fixes ientity serialization when loading the map
2021-03-05 10:07:18 +01:00
Paul Ritter
80f9f24243 Serialization v3 aka constant suffering (#1606)
* oops

* fixes serialization il

* copytest

* typo & misc fixes

* 139 moment

* boxing

* mesa dum

* stuff

* goodbye bad friend

* last commit before the big (4) rewrite

* adds datanodes

* kills yamlobjserializer in favor of the new system

* adds more serializers, actually implements them & removes most of the last of the old system

* changed yamlfieldattribute namespace

* adds back iselfserialize

* refactors consts&flags

* renames everything to data(field/definition)

* adds afterserialization

* help

* dataclassgen

* fuggen help me mannen

* Fix most errors on content

* Fix engine errors except map loader

* maploader & misc fix

* misc fixes

* thing

* help

* refactors datanodes

* help me mannen

* Separate ITypeSerializer into reader and writer

* Convert all type serializers

* priority

* adds alot

* il fixes

* adds robustgen

* argh

* adds array & enum serialization

* fixes dataclasses

* adds vec2i / misc fixes

* fixes inheritance

* a very notcursed todo

* fixes some custom dataclasses

* push dis

* Remove data classes

* boutta box

* yes

* Add angle and regex serializer tests

* Make TypeSerializerTest abstract

* sets up ioc etc

* remove pushinheritance

* fixes

* Merge fixes, fix yaml hot reloading

* General fixes2

* Make enum serialization ignore case

* Fix the tag not being copied in data nodes

* Fix not properly serializing flag enums

* Fix component serialization on startup

* Implement ValueDataNode ToString

* Serialization IL fixes, fix return and string equality

* Remove async from prototype manager

* Make serializing unsupported node as enum exception more descriptive

* Fix serv3 tryread casting to serializer instead of reader

* Add constructor for invalid node type exception

* Temporary fix for SERV3: Turn populate delegate into regular code

* Fix not copying the data of non primitive types

* Fix not using the data definition found in copying

* Make ISerializationHooks require explicit implementations

* Add test for serialization inheritance

* Improve IsOverridenIn method

* Fix error message when a data definition is null

* Add method to cast a read value in Serv3Manager

* Rename IServ3Manager to ISerializationManager

* Rename usages of serv3manager, add generic copy method

* Fix IL copy method lookup

* Rename old usages of serv3manager

* Add ITypeCopier

* resistance is futile

* we will conquer this codebase

* Add copy method to all serializers

* Make primitive mismatch error message more descriptive

* bing bong im going to freacking heck

* oopsie moment

* hello are you interested in my wares

* does generic serializers under new architecture

* Convert every non generic serializer to the new format, general fixes

* Update usgaes of generic serializers, cleanup

* does some pushinheritance logic

* finishes pushinheritance FRAMEWORK

* shed

* Add box2, color and component registry serializer tests

* Create more deserialized types and store prototypes with their deserialized results

* Fixes and serializer updates

* Add serialization manager extensions

* adds pushinheritance

* Update all prototypes to have a parent and have consistent id/parent properties

* Fix grammar component serialization

* Add generic serializer tests

* thonk

* Add array serializer test

* Replace logger warning calls with exceptions

* fixes

* Move redundant methods to serialization manager extensions, cleanup

* Add array serialization

* fixes context

* more fixes

* argh

* inheritance

* this should do it

* fixes

* adds copiers & fixes some stuff

* copiers use context v1

* finishing copy context

* more context fixes

* Test fixes

* funky maps

* Fix server user interface component serialization

* Fix value tuple serialization

* Add copying for value types and arrays. Fix copy internal for primitives, enums and strings

* fixes

* fixes more stuff

* yes

* Make abstract/interface skips debugs instead of warnings

* Fix typo

* Make some dictionaries readonly

* Add checks for the serialization manager initializing and already being initialized

* Add base type required and usage for MeansDataDefinition and ImplicitDataDefinitionForInheritorsAttribute

* copy by ref

* Fix exception wording

* Update data field required summary with the new forbidden docs

* Use extension in map loader

* wanna erp

* Change serializing to not use il temporarily

* Make writing work with nullable types

* pushing

* check

* cuddling slaps HARD

* Add serialization priority test

* important fix

* a serialization thing

* serializer moment

* Add validation for some type serializers

* adds context

* moar context

* fixes

* Do the thing for appearance

* yoo lmao

* push haha pp

* Temporarily make copy delegate regular c# code

* Create deserialized component registry to handle not inheriting conflicting references

* YAML LINTER BABY

* ayes

* Fix sprite component norot not being default true like in latest master

* Remove redundant todos

* Add summary doc to every ISerializationManager method

* icon fixes

* Add skip hook argument to readers and copiers

* Merge fixes

* Fix ordering of arguments in read and copy reflection call

* Fix user interface components deserialization

* pew pew

* i am going to HECK

* Add MustUseReturnValue to copy-over methods

* Make serialization log calls use the same sawmill

* gamin

* Fix doc errors in ISerializationManager.cs

* goodbye brave soldier

* fixes

* WIP merge fixes and entity serialization

* aaaaaaaaaaaaaaa

* aaaaaaaaaaaaaaa

* adds inheritancebehaviour

* test/datafield fixes

* forgot that one

* adds more verbose validation

* This fixes the YAML hot reloading

* Replace yield break with Enumerable.Empty

* adds copiers

* aaaaaaaaaaaaa

* array fix
priority fix
misc fixes

* fix(?)

* fix.

* funny map serialization (wip)

* funny map serialization (wip)

* Add TODO

* adds proper info the validation

* Make yaml linter 5 times faster (~80% less execution time)

* Improves the error message for missing fields in the linter

* Include component name in unknown component type error node

* adds alwaysrelevant usa

* fixes mapsaving

* moved surpressor to analyzers proj

* warning cleanup & moves surpressor

* removes old msbuild targets

* Revert "Make yaml linter 5 times faster (~80% less execution time)"

This reverts commit 2ee4cc2c26.

* Add serialization to RobustServerSimulation and mock reflection methods
Fixes container tests

* Fix nullability warnings

* Improve yaml linter message feedback

* oops moment

* Add IEquatable, IComparable, ToString and operators to DataPosition
Rename it to NodeMark
Make it a readonly struct

* Remove try catch from enum parsing

* Make dependency management in serialization less bad

* Make dependencies an argument instead of a property on the serialization manager

* Clean up type serializers

* Improve validation messages and resourc epath checking

* Fix sprite error message

* reached perfection

Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
Co-authored-by: Vera Aguilera Puerto <zddm@outlook.es>
2021-03-04 15:59:14 -08:00
Pieter-Jan Briers
93018c9843 Silence localization warnings on client again. 2021-03-03 16:02:30 +01:00
Pieter-Jan Briers
e2675271d0 Parallelize assembly sandbox checking harder. 2021-03-03 16:02:12 +01:00
Pieter-Jan Briers
d1f7edecef Use Directory.EnumerateFiles in PathHelpers.GetFiles.
Significant improvement in startup time.
2021-03-03 10:52:05 +01:00
Pieter-Jan Briers
b5a3c0b988 Do not load files under Locale/ not ending with .ftl.
Will ignore stuff like .DS_Store/.directory/thumbs.db
2021-03-02 21:22:44 +01:00
Acruid
06e62b031a SoundSystem (#1604)
* Adds the SoundSystem static proxy class for the AudioSystem.
Added a shared IAudioSystem interface for the future.

* Moved ConnectedClient property from IPlayerSession down to ICommonSession.

* Connected up the SoundSystem to the client/server AudioSystems.

* Converted client calls over to the new system.

* Marked the old serverside functions to play sound obsolete, use the new ones from the IAudioSystem.

* Added ISharedPlayerManager to the IoC registration.
2021-03-01 20:22:28 -08:00
Acruid
24707b7385 Shared Containers (#1579)
* Added a basic server simulation framework for help with tests.

* Moved as much as possible to Robust.Shared/Containers.
Moved ContainerSlot from content to engine.

* Moved ClientContainer to shared.

* Merged client/server ContainerManagerComponents into a single shared version.

* ContainerManagerComponent is now implicitly registered with the attributes.

* Migrated to 2021 serialization technology.

* Existing Unit Tests work.

* More tests coverage.
Fixed bug with transferring items between containers.

* Container Type info is now sent over the network.

* Merge client/server container systems.

* Code cleanup.

* Attempted to fix dictionary serialization.
Logs warning when trying to check if an unknown GridId is paused.

* Remove OldCode.
2021-03-01 15:19:59 -08:00
Pieter-Jan Briers
ab95f39f9f Localize SS14Window 2021-03-01 00:45:36 +01:00
Pieter-Jan Briers
cdd38abab5 Fix two shutdown crashes by removing IDisposable managers. 2021-02-28 23:10:03 +01:00
Pieter-Jan Briers
d751c0b3ab Revert "Physics (#1602)"
This reverts commit fefcc7cba3.
2021-02-28 18:45:18 +01:00
Pieter-Jan Briers
2ace0e9e5a Expose Patreon tier info from auth server. 2021-02-28 18:45:01 +01:00
Pieter-Jan Briers
31716f5104 Work around Roslyn scripting bug with ref structs. 2021-02-28 18:45:01 +01:00
metalgearsloth
fefcc7cba3 Physics (#1602)
* Physics worlds

* Paul's a good boy

* Build working

* Ingame and not lagging to hell

* Why didn't you commit ahhhhh

* Hard collisions working

* Solver parity

* Decent broadphase work done

* BroadPhase outline done

* BroadPhase working

* waiting for pvs

* Fix static PVS AABB

* Stop static bodies from awakening

* Optimise a bunch of stuff

* Even more broadphase stuff

* I'm fucking stupid

* Optimise fixture updates

* Collision solver start

* Building

* A is for Argumentative

* Fix contact caching island flags

* Circle shapes actually workeded

* Damping

* DS2 consumables only

* Slightly more stable

* Even slightlier more stablier

* VV your heart out

* Initial joint support

* 90% of joints I just wanted to push as I'd scream if I lost progress

* JOINT PURGATORY

* Joints barely functional lmao

* Okay these joints slightly more functional

* Remove station FrictionJoint

* Also that

* Some Box2D ports

* Cleanup mass

* Edge shape

* Active contacts

* Fix active contacts

* Optimise active contacts even more

* Boxes be stacking

* I would die for smug oh my fucking god

* In which everything is fixed

* Distance joints working LETS GO

* Remove frequency on distancejoint

* Fix some stuff and break joints

* Crashing fixed mehbeh

* ICollideSpecial and more resilience

* auto-clear

* showbb vera

* Slap that TODO in there

* Fix restartround crash

* Random fixes

* Fix fixture networking

* Add intersection method for broadphase

* Fix contacts

* Licenses done

* Optimisations

* Fix wall clips

* Config caching for island

* allocations optimisations

* Optimise casts

* Optimise events queue for physics

* Contact manager optimisations

* Optimise controllers

* Sloth joint or something idk

* Controller graph

* Remove content cvar

* Random cleanup

* Finally remove VirtualController

* Manifold structs again

* Optimise this absolute retardation

* Optimise

* fix license

* Cleanup physics interface

* AHHHHHHHHHHHHH

* Fix collisions again

* snivybus

* Fix potential nasty manifold bug

* Tests go snivy

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-01 03:09:36 +11:00
Paul
30df989e8d Merge branch 'serialization_v3_nodataclasses' of https://github.com/PaulRitter/RobustToolbox into master 2021-02-28 15:55:26 +01:00
Acruid
86bfea6bd4 ICommonSession Improvements + Player Filter (#1600)
* Removed IBaseSession, pushed all members down to ICommonSession.

* Pulled all members of client IPlayerSession into ICommonSession.
Marked client IPlayerSession as obsolete, use the base ICommonSession.

* Restricted setter access for properties in ICommonSession, only engine should be setting them.

* Fixed ping implementation on server.

* Moved AttachedEntityUid to ICommonSession.

* Added a shared IPlayerManager and pulled some common properties down to it.

* Added a shared player Filter class that holds a set of recipients in a networked call. Very useful for selecting recipients in a shared context.
2021-02-27 20:42:54 -08:00
Paul
d890f168c2 Spawner windows remember positions - engine commit 2021-02-27 12:27:46 +01:00
Paul
f888a810bf fixes that pesky warning 2021-02-27 11:58:51 +01:00
tmtmtl30
16249a4dde doubles default gain value (#1593) 2021-02-26 20:54:43 -08:00
Manel Navola
e33488ba55 Implemented erasing rectangular areas (#1419)
* Added support for erasing rectangular areas

* Apply suggestions from code review

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

* Switched sending start coordinate + end coordinate to sending start coordinate + rect selection size for preventing different parented positions, general code improvements

* Rewritten certain code part so the checks pass

* Added unshaded shader to rect erasing

* Tweaked alpha of erasing rectangle for better visualizing

Co-authored-by: Manel Navola <ManelNavola@users.noreply.github.com>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2021-02-26 20:52:12 -08:00
RemieRichards
bfe6eeddb1 Localization Fixes. Stop double-localizing localizationID-sourced names, PROPER returning "True" or "False" instead of "true" or "false" 2021-02-27 01:04:04 +00:00
RemieRichards
7f540e741c Add myself to CODEOWNERS for fluent translations. 2021-02-25 20:30:57 +00:00
Pieter-Jan Briers
b7855f5af5 Fix reloading localizations. 2021-02-25 20:47:17 +01:00
Pieter-Jan Briers
91391e1205 Update NetSerializer submodule 2021-02-25 12:06:28 +01:00
Pieter-Jan Briers
d5199ec459 Update NuGet packages. 2021-02-25 12:06:05 +01:00
Vera Aguilera Puerto
e1e6f4fd10 ContainerHelpers EmptyContainer now has an argument to attach removed entities to grid or map 2021-02-25 11:43:09 +01:00
Leo
e5b6fccf67 Add a scroll speed property to ScrollContainer (#1590)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-02-25 10:39:53 +00:00
RemberBL
95a912c329 Adds args.Handle(); into UI code for scrolling (#1595) 2021-02-25 11:08:19 +01:00
Pieter-Jan Briers
2b4833fc4e Allow content to read assembly versions in sandbox. 2021-02-24 12:18:44 +01:00
Pieter-Jan Briers
b814fc851a Fix more scrollbar DPI scaling bugs. 2021-02-24 12:18:29 +01:00
Pieter-Jan Briers
e87863203b Use DataFieldCached for AppearanceComponent.
What could go wrong?
2021-02-23 23:56:41 +01:00
Pieter-Jan Briers
33b66d9e18 Fix OpenCentered and OpenToLeft window methods. 2021-02-23 23:24:58 +01:00
Pieter-Jan Briers
fd406f7897 Selector-based VV windows have correct size.
Fixes #1594.
2021-02-23 23:10:58 +01:00
Pieter-Jan Briers
7a836d1018 Work around broken nullability.
Revert "Fix nullability errors"

This reverts commit a7f31f9ebf.

Revert "NotNullWhen()"

This reverts commit b332644d48.

Work around broken nullability.
2021-02-23 23:07:19 +01:00
Alex Evgrashin
393c15c44a Post shader will use real sprite bounding box (#1536)
Co-authored-by: Alex Evgrashin <evgrashin.adl@gmail.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-02-23 22:54:48 +01:00
Pieter-Jan Briers
a7f31f9ebf Fix nullability errors 2021-02-23 22:53:38 +01:00
RemieRichards
b332644d48 NotNullWhen() 2021-02-23 21:40:33 +00:00
RemieRichards
510f7c0e7c Merge branch 'master' of https://github.com/space-wizards/RobustToolbox into localization_grammar 2021-02-23 21:33:06 +00:00
RemieRichards
fdd05e3d3a Fix GrammarComponent gender parsing, Add tests for GENDER() function (which covers custom types (Enum) and custom functions (GENDER)) 2021-02-23 21:31:13 +00:00
Pieter-Jan Briers
6d41958853 Fix nullability of TryIndex<T>. 2021-02-23 22:25:48 +01:00
Pieter-Jan Briers
cecc4dfcf2 Improve SharedTransformSystem:
Do not fire events for deleted entities.
Optimize to remove allocations & LINQ.
2021-02-23 22:05:49 +01:00
Pieter-Jan Briers
4ac40f2e90 Make norot on sprites default for the time being.
To band aid the pulling issues.
2021-02-23 21:32:00 +01:00
Pieter-Jan Briers
3e12d44173 Bool/enum/entity handling for localization parameters. 2021-02-23 20:59:21 +01:00
RemieRichards
a42b39bd84 Adds GENDER(), PROPER() and ATTRIB() localization functions, GrammarComponent. 2021-02-23 19:53:56 +00:00
DrSmugleaf
22affccf24 Add individual layer offset (#1583)
* Add individual layer offset

* Fix error message

* Bring back layer offsetting
2021-02-23 12:55:45 +01:00
Pieter-Jan Briers
028724c47b Localization improvements:
*Allow content to define localization functions.
* Add rldloc command to reload localizations.
* Doc comments
* Error handling
* Parallelize loading of localization files, since I can only assume we'll have a lot eventually.
* Type system stuff to allow content to pass custom data types into fluent.
* Code cleanup.
2021-02-23 11:35:54 +01:00
Pieter-Jan Briers
0114bff2fc Add IFormattable to sandbox whitelist. 2021-02-23 11:27:51 +01:00
Pieter-Jan Briers
4ddbd644eb Add helper method to set up logging inside unit tests. 2021-02-23 11:27:42 +01:00
Pieter-Jan Briers
f0366531ef Inject the csi directly into my master. 2021-02-23 01:39:33 +01:00
Pieter-Jan Briers
6bd5814f4a Automatically fetch names and descs from loc. 2021-02-22 11:11:11 +01:00
Pieter-Jan Briers
78c132fdab Mute loc warnings for the time being. 2021-02-22 08:57:30 +01:00
Remie Richards
460cf57d7c Fluent Localization (#1584) 2021-02-22 00:36:02 +01:00
Pieter-Jan Briers
a3190a8aca Improvements to SpriteComponent for new angle changes: (#1589)
1. Fixes CopyFrom with new rotation parameters.
2. Adds a couple APIs for ClickableComponent content side.
2021-02-22 00:30:16 +01:00
Pieter-Jan Briers
6921fb2fbf Make UserInterfaceManager not dispose root control on game shutdown.
No real reason to do this and it only risks breaking something.
2021-02-21 23:52:09 +01:00
Fortune117
9954d571de Fix for Crash Caused by the Entity Spawn Menu (#1588) 2021-02-21 20:16:01 +01:00
Pieter-Jan Briers
17fe000a1e Fix math tests due to angle/direction changes. 2021-02-21 20:06:39 +01:00
Pieter-Jan Briers
fba415e765 Bit of work to make Direction.South == Angle.Zero.
This makes Direction no longer follow a cartesian trig circle but oh well. Also helper methods to work with this.

Math tests currently fail, pushing this so Acruid can see about fixing SpriteComponent.
2021-02-21 19:47:42 +01:00
Pieter-Jan Briers
583b7ebf38 WPF layout (#1581) 2021-02-21 12:28:13 +01:00
Acruid
771a256925 Fixes bug with an exception being throw when trying to overwrite a deleted Component. (#1587)
Entity now uses constructor injection instead of property injection.
2021-02-20 23:30:09 -08:00
Acruid
ae79e89347 Added a shared PointLightComponent interface. (#1585)
* Added a shared PointLightComponent interface.

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

* Added a rotation debug entity.

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

* Directional RSIs and Sprite Smoothing work.

* Remove the Directional flag usages.

* Supports layers with different numbers of directions.

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

* Implement automatic prototype hot-reloading

* Merge fixes

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

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

* Remove reload command

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

* Fix errors

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

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

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

* Moved ITimerManager from Timers to Timing.

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

* Fix up names

* Make addcomp and rmcomp give better feedback

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

* cancel token on close

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

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

* #272 ability to apply style class to child

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

* #272 allow escaping right angle bracket in formatted message

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

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

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

* Fix nulls in tests

* Fix null in tests maybe

* Return to type tags

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

NetChannel is now a nested class of NetManager.

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

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

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

* GetAllComponents

* Fix shell commands

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

* Lots of refactoring into a shared context.

* Removed ICommonSession from server concmd Execute.

* Added argStr parameter to concmd execute.

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

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

* Finally move shells and commands into shared.

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

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

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

* Repair rebase damage.

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

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

* Re-add main viewport in a different place

* Move screen/map translation into ViewportContainer

* Support for viewport resolution

* Fix postfx, add WorldToScreen to Viewport

* Remove useless cast

* Some cleanup.

* Fix incorrect worldBounds when rendering viewports

* nullability

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

* Change TryCastValue to be more generic

* Add notnull constraing for TKey to TryCastValue

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

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

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

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

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

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

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

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

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

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

So, to fix this...

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

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

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

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

* I blame Remie

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

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

On windows default path to dotnet are `C:\Program Files`. Without quoting the
the command if it contains a space, it's going to break Windows builds that
install in `C:\Program Files`.
2021-01-08 13:53:42 +01:00
Paul
9b92bcf911 intermediate fix to garantuee people with dotnet in path to launch commpilerobustxaml 2021-01-05 12:15:03 +01:00
metalgearsloth
86e34ea27b Fix enum caching (#1485)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-01-05 16:17:20 +11:00
Clyybber
62cf778958 Fix build when dotnet is not in the PATH (#1483) 2021-01-04 20:25:43 +01:00
py01
5d667e44c3 Replaces AnchoredChanged C# event with a ComponentMessage (#1482)
Co-authored-by: py01 <pyronetics01@gmail.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-01-04 10:16:05 +01:00
metalgearsloth
6d84b8741c Cache enum references (#1480)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-01-03 03:45:02 +01:00
DrSmugleaf
d08ca59b75 Make RobustUnitTest register content cvars and set _isServer (#1481) 2021-01-03 03:44:12 +01:00
Pieter-Jan Briers
f06b046c1c Fix Content-Type not being set for status API. 2021-01-03 03:42:21 +01:00
Vera Aguilera Puerto
bb412a6906 Entity Timer SpawnTimer throws if entity is deleted. 2021-01-01 15:45:13 +01:00
Radrark
1baee3004c Adds new keybind property: AllowSubCombs (#1473)
Co-authored-by: Radrark <null>
2020-12-29 15:59:34 +01:00
Pieter-Jan Briers
f18068c13a Update NetSerializer submodule to improve build times 2020-12-29 15:59:13 +01:00
Pieter-Jan Briers
0ba00a1845 Gcf command to mess with LOH compaction. 2020-12-29 14:10:15 +01:00
Pieter-Jan Briers
28caf0d74c Reduce allocations 2020-12-29 03:58:16 +01:00
Pieter-Jan Briers
ecbb32b70b Clean up various cases of failing to dispose file streams. 2020-12-29 03:58:16 +01:00
Pieter-Jan Briers
8e2a9cc597 Font atlasses are now dynamic and can render all glyphs in the font file. 2020-12-29 03:58:16 +01:00
Vera Aguilera Puerto
a7eb8201c9 Fix MIDI soundfont load error on non-rooted paths. 2020-12-26 22:05:17 +01:00
Pieter-Jan Briers
1f95fe6782 Fix XamlIL problems when publishing 2020-12-25 18:34:19 +01:00
DrSmugleaf
07c1f9e1af Replace MaybeNullWhen(false) with NotNullWhen(true) in AppearanceComponent (#1461) 2020-12-25 15:17:54 +01:00
Vera Aguilera Puerto
826dce6659 Fix custom MIDI soundfont loading when mounting content from zip
Fixes #1466
2020-12-24 03:54:06 +01:00
Vera Aguilera Puerto
cdf714f3ba Fix stereo ogg audio not playing correctly.
Only half of the samples were being read.
2020-12-23 16:21:42 +01:00
Pieter-Jan Briers
671ca7959c Throw debug info if the RichTextEntry assert fails. 2020-12-23 15:12:47 +01:00
Pieter-Jan Briers
b7a1345d3a XAML compilation improvements.
Prevent double XAML-ifying causing corrupt dlls.

Use MSBuild dependencies to reduce unecessary xamlil builds.
2020-12-23 12:01:35 +01:00
Pieter-Jan Briers
835b6ebdba Probably fix build forgetting that nuget exists. 2020-12-21 12:14:28 +01:00
Pieter-Jan Briers
0ecabd6553 Fix XamlIL locking build. 2020-12-21 12:13:45 +01:00
Pieter-Jan Briers
feaa69f825 Fix build of injector. 2020-12-21 04:05:34 +01:00
Pieter-Jan Briers
857904a3d9 Update dependencies of name generator. 2020-12-21 04:05:25 +01:00
Pieter-Jan Briers
0b37418477 Fix injectors UsingTask. 2020-12-21 03:31:11 +01:00
Pieter-Jan Briers
f234ecb2c3 Make Robust.Client.Injectors NS2.0
So that it works out of the box with Framework MSBuild.
2020-12-21 03:16:13 +01:00
Pieter-Jan Briers
b449959865 Clean up bad project reference in Robust.Server 2020-12-21 03:15:45 +01:00
Pieter-Jan Briers
8f870403d2 Managed implementation of HttpListener. (#1460) 2020-12-21 02:51:04 +01:00
Paul Ritter
d94f702601 Xaml UI (#1446)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-12-20 23:52:36 +01:00
DrSmugleaf
e78ab8f922 Add YamlObjectSerializer.NodeToType with generic argument (#1456) 2020-12-20 20:46:56 +01:00
20kdc
6972000293 Make the "softness" of soft shadows adjustible per-light. (#1454)
Note: Thanks to the nature of YAML properties in RobustToolbox, this commit is only an API blocker if the Softness property is directly manipulated from code, which is unlikely.
2020-12-19 21:44:47 +01:00
1345 changed files with 77893 additions and 30964 deletions

17
.github/CODEOWNERS vendored
View File

@@ -1,14 +1,7 @@
# Lines starting with '#' are comments.
# Each line is a file pattern followed by one or more owners.
# Last match in file takes precedence.
# These owners will be the default owners for everything in the repo.
# * @defunkt
* @Acruid @PJB3005 @Silvertorch5
# Be they Fluent translations or Freemarker templates, I know them both!
*.ftl @RemieRichards
# Order is important. The last matching pattern has the most precedence.
# So if a pull request only touches javascript files, only these owners
# will be requested to review.
# *.js @octocat @github/js
# You can also use email addresses if you prefer.
# docs/* docs@example.com
# Ping for all PRs
* @Acruid @PJB3005 @Silvertorch5

View File

@@ -10,7 +10,7 @@ jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}

View File

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

View File

@@ -38,4 +38,4 @@ jobs:
- name: Content.Tests
run: dotnet test --no-build Content.Tests/Content.Tests.csproj -v n
- name: Content.IntegrationTests
run: dotnet test --no-build Content.IntegrationTests/Content.IntegrationTests.csproj -v n
run: COMPlus_gcServer=1 dotnet test --no-build Content.IntegrationTests/Content.IntegrationTests.csproj -v n

12
.gitmodules vendored
View File

@@ -4,6 +4,18 @@
[submodule "Lidgren.Network"]
path = Lidgren.Network/Lidgren.Network
url = https://github.com/space-wizards/lidgren-network-gen3.git
[submodule "XamlX"]
path = XamlX
url = https://github.com/space-wizards/XamlX
[submodule "Robust.LoaderApi"]
path = Robust.LoaderApi
url = https://github.com/space-wizards/Robust.LoaderApi.git
[submodule "ManagedHttpListener"]
path = ManagedHttpListener
url = https://github.com/space-wizards/ManagedHttpListener.git
[submodule "Linguini"]
path = Linguini
url = https://github.com/space-wizards/Linguini
[submodule "cefglue"]
path = cefglue
url = https://gitlab.com/xiliumhq/chromiumembedded/cefglue/

View File

@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
</Project>

2
Avalonia.Base/README.md Normal file
View File

@@ -0,0 +1,2 @@
See `Robust.Client/UserInterface/XAML/RiderNotes.md` for why this project exists.
We are not actually using Avalonia (yet).

1
Linguini Submodule

Submodule Linguini added at b3c05c2f31

View File

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

View File

@@ -4,5 +4,6 @@
<TargetFramework>net5.0</TargetFramework>
<LangVersion>9</LangVersion>
<Nullable>enable</Nullable>
<WarningsAsErrors>nullable</WarningsAsErrors>
</PropertyGroup>
</Project>

View File

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

65
MSBuild/XamlIL.targets Normal file
View File

@@ -0,0 +1,65 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
<PropertyGroup>
<!-- Avoid MSBuild adding a None entry for XAML files because they'd show up TWICE in the project view. -->
<DefaultItemExcludes>**/*.xaml</DefaultItemExcludes>
<RobustUseExternalMSBuild>true</RobustUseExternalMSBuild>
<_RobustUseExternalMSBuild>$(RobustUseExternalMSBuild)</_RobustUseExternalMSBuild>
<_RobustUseExternalMSBuild Condition="'$(_RobustForceInternalMSBuild)' == 'true'">false</_RobustUseExternalMSBuild>
</PropertyGroup>
<ItemGroup>
<Compile Update="**\*.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<EmbeddedResource Include="**\*.xaml"/>
<AdditionalFiles Include="**\*.xaml"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\Robust.Client.NameGenerator\Robust.Client.NameGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\Robust.Client.Injectors\Robust.Client.Injectors.csproj" ReferenceOutputAssembly="false"/>
</ItemGroup>
<UsingTask
Condition="'$(_RobustUseExternalMSBuild)' != 'true' And $(DesignTimeBuild) != true"
TaskName="CompileRobustXamlTask"
AssemblyFile="$(MSBuildThisFileDirectory)\..\Robust.Client.Injectors\bin\$(Configuration)\netstandard2.0\Robust.Client.Injectors.dll"/>
<Target
Name="CompileRobustXaml"
Condition="Exists('@(IntermediateAssembly)')"
AfterTargets="AfterCompile"
Inputs="@(IntermediateAssembly);@(ReferencePathWithRefAssemblies)"
Outputs="$(IntermediateOutputPath)XAML/doot">
<PropertyGroup>
<RobustXamlReferencesTemporaryFilePath Condition="'$(RobustXamlReferencesTemporaryFilePath)' == ''">$(IntermediateOutputPath)XAML/references</RobustXamlReferencesTemporaryFilePath>
<RobustXamlOriginalCopyFilePath Condition="'$(RobustXamlOriginalCopyFilePath)' == ''">$(IntermediateOutputPath)XAML/original.dll</RobustXamlOriginalCopyFilePath>
</PropertyGroup>
<WriteLinesToFile
Condition="'$(_RobustForceInternalMSBuild)' != 'true'"
File="$(RobustXamlReferencesTemporaryFilePath)"
Lines="@(ReferencePathWithRefAssemblies)"
Overwrite="true"/>
<!--
UpdateBuildIndicator is done so that we can use MSBuild Inputs and Outputs on the target
to avoid unecessary execution of this target
Saves compile time if e.g. ONLY Robust.Client changes (Content.Client doesn't have to re-xaml).
-->
<CompileRobustXamlTask
Condition="'$(_RobustUseExternalMSBuild)' != 'true'"
AssemblyFile="@(IntermediateAssembly)"
ReferencesFilePath="$(RobustXamlReferencesTemporaryFilePath)"
OriginalCopyPath="$(RobustXamlOriginalCopyFilePath)"
ProjectDirectory="$(MSBuildProjectDirectory)"
AssemblyOriginatorKeyFile="$(AssemblyOriginatorKeyFile)"
SignAssembly="$(SignAssembly)"
DelaySign="$(DelaySign)"
UpdateBuildIndicator="$(IntermediateOutputPath)XAML/doot"/>
<PropertyGroup>
<DOTNET_HOST_PATH Condition="'$(DOTNET_HOST_PATH)' == ''">dotnet</DOTNET_HOST_PATH>
</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"/>
</Target>
</Project>

1
ManagedHttpListener Submodule

Submodule ManagedHttpListener added at f2aa590fec

View File

@@ -129,5 +129,7 @@ namespace OpenToolkit.GraphicsLibraryFramework
/// for controlling sRGB rendering and a created OpenGL ES context will always have sRGB rendering enabled.
/// </summary>
SrgbCapable = 0x0002100E,
ScaleToMonitor = 0x0002200C,
}
}

View File

@@ -5551,5 +5551,15 @@ namespace OpenToolkit.GraphicsLibraryFramework
{
return glfwGetX11Window(window);
}
public static unsafe IntPtr GetX11Display(Window* window)
{
return glfwGetX11Display(window);
}
public static unsafe IntPtr GetWin32Window(Window* window)
{
return glfwGetWin32Window(window);
}
}
}

View File

@@ -17,17 +17,18 @@ namespace OpenToolkit.GraphicsLibraryFramework
// On net472, we rely on Mono's DllMap for this. See the .dll.config file.
NativeLibrary.SetDllImportResolver(typeof(GLFWNative).Assembly, (name, assembly, path) =>
{
// Please keep in sync with what Robust.Shared/DllMapHelper.cs does.
if (name != "glfw3.dll")
{
return IntPtr.Zero;
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
if (OperatingSystem.IsLinux())
{
return NativeLibrary.Load("libglfw.so.3", assembly, path);
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
if (OperatingSystem.IsMacOS())
{
return NativeLibrary.Load("libglfw.3.dylib", assembly, path);
}
@@ -405,5 +406,11 @@ namespace OpenToolkit.GraphicsLibraryFramework
[DllImport(LibraryName)]
public static extern uint glfwGetX11Window(Window* window);
[DllImport(LibraryName)]
public static extern IntPtr glfwGetX11Display(Window* window);
[DllImport(LibraryName)]
public static extern IntPtr glfwGetWin32Window(Window* window);
}
}

View File

@@ -14,12 +14,6 @@
<PackageReference Condition="'$(TargetFramework)' == 'net472'" Include="System.Memory" Version="4.5.3" />
</ItemGroup>
<ItemGroup>
<Content Include="OpenToolkit.GraphicsLibraryFramework.dll.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Robust.Shared\Robust.Shared.csproj" />
</ItemGroup>

View File

@@ -1,5 +0,0 @@
<configuration>
<!-- I actually have no idea whether this works on FreeBSD but it can't hurt to set it as such. -->
<dllmap os="linux,freebsd" dll="glfw3.dll" target="glfw.so.3" />
<dllmap os="osx" dll="glfw3.dll" target="glfw.3.dylib" />
</configuration>

View File

@@ -1,25 +1,16 @@
![Robust Toolbox](https://raw.githubusercontent.com/space-wizards/asset-dump/3dd3078e49e3a7e06709a6e0fc6e3223d8d44ca2/robust.png)
[![Build status](https://ci.appveyor.com/api/projects/status/ygb7t8hsj3wt7pnm/branch/master?svg=true)](https://ci.appveyor.com/project/Silvertorch5/space-station-14/branch/master)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=ss14&metric=coverage)](https://sonarcloud.io/dashboard?id=ss14)
Robust Toolbox is an engine primarily being developed for [Space Station 14](https://github.com/space-wizards/space-station-14), although we're working on making it usable for both [singleplayer](https://github.com/space-wizards/RobustToolboxTemplateSingleplayer) and [multiplayer](https://github.com/space-wizards/RobustToolboxTemplate) projects.
Robust Toolbox is a client/server backend for [Space Station 14](https://github.com/space-wizards/space-station-14).
Use the [content repo](https://github.com/space-wizards/space-station-14) for actual development, even if you're modifying the engine itself.
### *This repository is the *engine* section of SS14. This is the base engine all SS14 servers will be built on. As such, it does not start on its own: it needs the [content repo](https://github.com/space-wizards/space-station-14). Use said repo for actual development, even if you're modifying the engine itself. Think of Robust Toolbox as BYOND in the context of Spacestation 13.*
## Project Links
## Getting in Touch
[Website](https://spacestation14.io/) | [Discord](https://discord.gg/t2jac3p) | [Forum](https://forum.spacestation14.io/) | [Steam](https://store.steampowered.com/app/1255460/Space_Station_14/) | [Standalone Download](https://spacestation14.io/about/nightlies/)
* Website: [spacestation14.io](https://spacestation14.io/)
* Discord: [Invite Link](https://discord.gg/t2jac3p)
* IRC: `irc.rizon.net#spacebus`
* Code Analysis: [Sonar Cloud](https://sonarcloud.io/dashboard?id=ss14)
* Automatic Content Builds: [builds.spacestation14.io](https://builds.spacestation14.io/jenkins/)
## Documentation/Wiki
The IRC is setup to relay back and forth to the Discord server so [IRC nerds](https://xkcd.com/1782/) will not be left out.
## Documentation
We have various technical documentation articles on the [HackMD Wiki](https://hackmd.io/@ss14/docs/%2F%40ss14%2Ftechnical-documentation-overview).
The [HackMD Wiki](https://hackmd.io/@ss14/docs/wiki) has documentation on SS14s content, engine, game design and more. We also have lots of resources for new contributors to the project.
## Contributing
@@ -27,8 +18,8 @@ We are happy to accept contributions from anybody. Get in Discord or IRC if you
## Building
**In practice, you usually don't build this repository directly.**
This repository is the **engine** part of SS14. It's the base engine all SS14 servers will be built on. As such, it does not start on its own: it needs the [content repo](https://github.com/space-wizards/space-station-14). Think of Robust Toolbox as BYOND in the context of Spacestation 13.
## Legal Info
See `legal.md` for licenses and copyright.
See [legal.md](https://github.com/space-wizards/RobustToolbox/blob/master/legal.md) for licenses and copyright.

View File

@@ -23,6 +23,48 @@
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- name: Box2D
license: |
MIT License
Copyright (c) 2019 Erin Catto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- name: Bullet Physics SDK
license: |
The files in this repository are licensed under the zlib license, except for the files under 'Extras' and examples/ThirdPartyLibs.
Bullet Continuous Collision Detection and Physics Library
http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
- name: Castle Core
license: |
Copyright 2004-2016 Castle Project - http://www.castleproject.org/
@@ -317,6 +359,43 @@
See the License for the specific language governing permissions and
limitations under the License.
- name: Farseer Physics Engine
license: |
Microsoft Permissive License (Ms-PL)
This license governs use of the accompanying software.
If you use the software, you accept this license.
If you do not accept the license, do not use the software.
1. Definitions
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.
A "contribution" is the original software, or any additions or changes to the software.
A "contributor" is any person that distributes its contribution under this license.
"Licensed patents" are a contributor's patent claims that read directly on its contribution.
2. Grant of Rights
(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution,
prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to
make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or
derivative works of the contribution in the software.
3. Conditions and Limitations
(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software,
your patent license from such contributor to the software ends automatically.
(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark,
and attribution notices that are present in the software.
(D) If you distribute any portion of the software in source code form, you may do so only under this license by
including a complete copy of this license with your distribution. If you distribute any portion of the software in
compiled or object code form, you may only do so under a license that complies with this license.
(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties,
guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change.
To the extent permitted under your local laws, the contributors exclude the implied warranties of
merchantability, fitness for a particular purpose and non-infringement.
- name: Mono.Cecil
license: |
Copyright (c) 2008 - 2015 Jb Evain
@@ -574,29 +653,22 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- name: NGetText
- name: Fluent.Net
license: |
The MIT License (MIT)
blushingpenguin and Contributors
Copyright (c) 2012 Vitaly Zilnik
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
http://www.apache.org/licenses/LICENSE-2.0
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
- name: NetSerializer
license: |

View File

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

View File

@@ -0,0 +1,54 @@
input-key-Escape = Escape
input-key-Control = Control
input-key-Shift = Shift
input-key-Alt = Alt
input-key-Menu = Menu
input-key-F1 = F1
input-key-F2 = F2
input-key-F3 = F3
input-key-F4 = F4
input-key-F5 = F5
input-key-F6 = F6
input-key-F7 = F7
input-key-F8 = F8
input-key-F9 = F9
input-key-F10 = F10
input-key-F11 = F11
input-key-F12 = F12
input-key-F13 = F13
input-key-F14 = F14
input-key-F15 = F15
input-key-Pause = Pause
input-key-Left = Left
input-key-Up = Up
input-key-Down = Down
input-key-Right = Right
input-key-Space = Space
input-key-Return = Return
input-key-NumpadEnter = Num Enter
input-key-BackSpace = Backspace
input-key-Tab = Tab
input-key-PageUp = Page Up
input-key-PageDown = Page Down
input-key-End = End
input-key-Home = Home
input-key-Insert = Insert
input-key-Delete = Delete
input-key-MouseLeft = Mouse Left
input-key-MouseRight = Mouse Right
input-key-MouseMiddle = Mouse Middle
input-key-MouseButton4 = Mouse 4
input-key-MouseButton5 = Mouse 5
input-key-MouseButton6 = Mouse 6
input-key-MouseButton7 = Mouse 7
input-key-MouseButton8 = Mouse 8
input-key-MouseButton9 = Mouse 9
input-key-LSystem-win = Left Win
input-key-RSystem-win = Right Win
input-key-LSystem-mac = Left Cmd
input-key-RSystem-mac = Right Cmd
input-key-LSystem-linux = Left Meta
input-key-RSystem-linux = Right Meta
input-key-unknown = <unknown key>

View File

@@ -0,0 +1 @@
ss14window-placeholder-title = Exemplary Window Title Here

View File

@@ -0,0 +1 @@
tab-container-not-tab-title-provided = No title

View File

@@ -0,0 +1,11 @@
## ViewVariablesInstanceEntity
view-variable-instance-entity-server-components-add-component-button-placeholder = Add Component
view-variable-instance-entity-client-variables-tab-title = Client Variables
view-variable-instance-entity-client-components-tab-title = Client Components
view-variable-instance-entity-server-variables-tab-title = Server Variables
view-variable-instance-entity-server-components-tab-title = Server Components
view-variable-instance-entity-client-components-search-bar-placeholder = Search
view-variable-instance-entity-server-components-search-bar-placeholder = Search
view-variable-instance-entity-add-window-server-components = Add Component [S]
view-variable-instance-entity-add-window-client-components = Add Component [C]

View File

@@ -28,5 +28,10 @@ void fragment()
highp float occlusion = ChebyshevUpperBound(occlDist, ourDist);
if (occlusion >= 1.0)
{
discard;
}
COLOR = vec4(0.0, 0.0, 0.0, 1.0 - occlusion);
}

View File

@@ -0,0 +1,41 @@
preset raw;
uniform highp vec2 direction;
uniform highp vec2 size;
uniform highp float radius;
varying highp vec2 pos;
varying highp vec4 blurPos1;
varying highp vec4 blurPos2;
void vertex()
{
highp float aspect = size.y / size.x;
highp float horRadius = aspect * radius;
highp vec2 offset = vec2(horRadius, radius) * direction;
VERTEX = apply_mvp(VERTEX);
pos = (VERTEX + vec2(1.0)) / 2.0;
blurPos1.xy = pos + offset;
blurPos1.zw = pos - offset;
blurPos2.xy = pos + offset * 2.0;
blurPos2.zw = pos - offset * 2.0;
}
void fragment()
{
// Very simple gaussian blur.
highp vec4 sum = zTexture(pos) * 0.375;
sum += zTexture(blurPos1.xy) * 0.25;
sum += zTexture(blurPos1.zw) * 0.25;
sum += zTexture(blurPos2.xy) * 0.0625;
sum += zTexture(blurPos2.zw) * 0.0625;
COLOR = sum;
}

View File

@@ -1,5 +1,11 @@
#include "/Shaders/Internal/light_shared.swsl"
highp vec4 calcGaussianWeights(highp float sigma, highp vec4 offset)
{
highp vec4 eExp = offset * offset / (2.0 * sigma * sigma);
return exp(-eExp) / (sigma * sqrt(2.0 * PI));
}
highp float createOcclusion(highp vec2 diff)
{
// Calculate vector perpendicular to light vector.
@@ -8,23 +14,57 @@ highp float createOcclusion(highp vec2 diff)
highp float ourDist = length(diff);
highp vec2 occlDist = occludeDepth(diff, shadowMap, lightIndex);
// Sample 7 points on a line perpendicular to the light source.
// Depending on the closest point, we change the gaussian weights down below
// to change the "narrowness" of the samples.
perpendicular *= lightSoftness * 1.5;
// Get all the samples we need.
highp vec2 sample1 = occludeDepth(diff, shadowMap, lightIndex);
highp vec2 sample2 = occludeDepth(diff + perpendicular, shadowMap, lightIndex);
highp vec2 sample3 = occludeDepth(diff - perpendicular, shadowMap, lightIndex);
highp vec2 sample4 = occludeDepth(diff + perpendicular * 2.0, shadowMap, lightIndex);
highp vec2 sample5 = occludeDepth(diff - perpendicular * 2.0, shadowMap, lightIndex);
highp vec2 sample6 = occludeDepth(diff + perpendicular * 3.0, shadowMap, lightIndex);
highp vec2 sample7 = occludeDepth(diff - perpendicular * 3.0, shadowMap, lightIndex);
highp float mindist =
min(sample1.x,
min(sample2.x,
min(sample3.x,
min(sample4.x,
min(sample5.x,
min(sample6.x,
sample7.x))))));
mindist = max(0.001, mindist);
// Change soft shadow size based on distance from primary occluder.
highp float distRatio = (ourDist - occlDist.x) / occlDist.x / 2.0;
highp float distRatio = (ourDist - mindist);
perpendicular *= distRatio;
// Sigma can never be zero so make sure to clamp.
// TODO: Scaling the dist ratio here in a more sane way might make shadows look better buuuut I'm lazy.
// Shadows look pretty nice already.
highp float sigma = max(0.001, distRatio * 0.75);
highp vec4 weights = calcGaussianWeights(sigma, vec4(0.0, 1.0, 2.0, 3.0));
// Totally not hacky PCF on top of VSM.
highp float occlusion = smoothstep(0.1, 1.0, ChebyshevUpperBound(occlDist, ourDist));
// Calculation of gaussian weights here is broken because it doesn't add up to 1.
// Fixing this is hard and if I had to guess too expensive for GPU shaders.
// So instead we add up the total weights and scale the result with that,
// so that we still end up with 0-1.
highp float totalWeigths = weights.x + weights.y * 2.0 + weights.z * 2.0 + weights.w * 2.0;
occlusion += shadowContrib(diff + perpendicular);
occlusion += shadowContrib(diff - perpendicular);
occlusion += shadowContrib(diff + perpendicular * 2.0);
occlusion += shadowContrib(diff - perpendicular * 2.0);
occlusion += shadowContrib(diff + perpendicular * 3.0);
occlusion += shadowContrib(diff - perpendicular * 3.0);
highp float occlusion = 0.0;
return occlusion / 7.0;
// Calculate actual occlusion with new weights.
occlusion += ChebyshevUpperBound(sample1, ourDist) * weights.x;
occlusion += ChebyshevUpperBound(sample2, ourDist) * weights.y;
occlusion += ChebyshevUpperBound(sample3, ourDist) * weights.y;
occlusion += ChebyshevUpperBound(sample4, ourDist) * weights.z;
occlusion += ChebyshevUpperBound(sample5, ourDist) * weights.z;
occlusion += ChebyshevUpperBound(sample6, ourDist) * weights.w;
occlusion += ChebyshevUpperBound(sample7, ourDist) * weights.w;
return occlusion / totalWeigths;
}

View File

@@ -13,6 +13,7 @@ uniform highp vec4 lightColor;
uniform highp vec2 lightCenter;
uniform highp float lightRange;
uniform highp float lightPower;
uniform highp float lightSoftness;
uniform highp float lightIndex;
uniform sampler2D shadowMap;

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

View File

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

Binary file not shown.

View File

@@ -0,0 +1,10 @@
using Microsoft.CodeAnalysis;
namespace Robust.Generators
{
public static class Diagnostics
{
public static SuppressionDescriptor MeansImplicitAssignment =>
new SuppressionDescriptor("RADC1000", "CS0649", "Marked as implicitly assigned.");
}
}

View File

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

View File

@@ -0,0 +1,107 @@
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Robust.Analyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class FriendAnalyzer : DiagnosticAnalyzer
{
const string FriendAttribute = "Robust.Shared.Analyzers.FriendAttribute";
public const string DiagnosticId = "RA0002";
private const string Title = "Tried to access friend-only member";
private const string MessageFormat = "Tried to access member \"{0}\" in class \"{1}\" which can only be accessed by friend classes";
private const string Description = "Make sure to specify the accessing class in the friends attribute.";
private const string Category = "Usage";
[SuppressMessage("ReSharper", "RS2008")]
private static readonly DiagnosticDescriptor Rule = new (DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, true, Description);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
context.EnableConcurrentExecution();
context.RegisterSyntaxNodeAction(CheckFriendship, SyntaxKind.SimpleMemberAccessExpression);
}
private void CheckFriendship(SyntaxNodeAnalysisContext context)
{
if (context.Node is not MemberAccessExpressionSyntax memberAccess)
return;
// We only do something if our parent is one of a few types.
switch (context.Node.Parent)
{
// If we're being assigned...
case AssignmentExpressionSyntax assignParent:
{
if (assignParent.Left != memberAccess)
return;
break;
}
// If we're being invoked...
case InvocationExpressionSyntax:
break;
// Otherwise, do nothing.
default:
return;
}
// Get the friend attribute
var friendAttr = context.Compilation.GetTypeByMetadataName(FriendAttribute);
// Get the type that is containing this expression, or, the class where this is happening.
if (context.ContainingSymbol?.ContainingType is not { } containingType)
return;
// We check all of our children and get only the identifiers.
foreach (var identifier in memberAccess.ChildNodes().Select(node => node as IdentifierNameSyntax))
{
if (identifier == null) continue;
// Get the type info of the identifier, so we can check the attributes...
if (context.SemanticModel.GetTypeInfo(identifier).ConvertedType is not { } type)
continue;
// Same-type access is always fine.
if (SymbolEqualityComparer.Default.Equals(type, containingType))
continue;
// Finally, get all attributes of the type, to check if we have any friend classes.
foreach (var attribute in type.GetAttributes())
{
// If the attribute isn't the friend attribute, continue.
if (!SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, friendAttr))
continue;
// Check all types allowed in the friend attribute. (We assume there's only one constructor arg.)
foreach (var constant in attribute.ConstructorArguments[0].Values)
{
// Check if the value is a type...
if (constant.Value is not INamedTypeSymbol t)
continue;
// If we find that the containing class is specified in the attribute, return! All is good.
if (SymbolEqualityComparer.Default.Equals(containingType, t))
return;
}
// Not in a friend class! Report an error.
context.ReportDiagnostic(
Diagnostic.Create(Rule, context.Node.GetLocation(),
$"{context.Node.ToString().Split('.').LastOrDefault()}", $"{type.Name}"));
}
}
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Robust.Generators;
namespace Robust.Analyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class MeansImplicitAssigmentSuppressor : DiagnosticSuppressor
{
const string MeansImplicitAssignmentAttribute = "Robust.Shared.MeansImplicitAssignmentAttribute";
public override void ReportSuppressions(SuppressionAnalysisContext context)
{
var implAttr = context.Compilation.GetTypeByMetadataName(MeansImplicitAssignmentAttribute);
foreach (var reportedDiagnostic in context.ReportedDiagnostics)
{
if(reportedDiagnostic.Id != Diagnostics.MeansImplicitAssignment.SuppressedDiagnosticId) continue;
var node = reportedDiagnostic.Location.SourceTree?.GetRoot(context.CancellationToken).FindNode(reportedDiagnostic.Location.SourceSpan);
if (node == null) continue;
var symbol = context.GetSemanticModel(reportedDiagnostic.Location.SourceTree).GetDeclaredSymbol(node);
if (symbol == null || !symbol.GetAttributes().Any(a =>
a.AttributeClass?.GetAttributes().Any(attr =>
SymbolEqualityComparer.Default.Equals(attr.AttributeClass, implAttr)) == true))
{
continue;
}
context.ReportSuppression(Suppression.Create(
Diagnostics.MeansImplicitAssignment,
reportedDiagnostic));
}
}
public override ImmutableArray<SuppressionDescriptor> SupportedSuppressions => ImmutableArray.Create(Diagnostics.MeansImplicitAssignment);
}
}

View File

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

View File

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

View File

@@ -0,0 +1,28 @@
using BenchmarkDotNet.Attributes;
namespace Robust.Benchmarks.NumericsHelpers
{
public class AddBenchmark
{
[Params(32, 128)]
public int N { get; set; }
private float[] _inputA = default!;
private float[] _inputB = default!;
private float[] _output = default!;
[GlobalSetup]
public void Setup()
{
_inputA = new float[N];
_inputB = new float[N];
_output = new float[N];
}
[Benchmark]
public void Bench()
{
Shared.Maths.NumericsHelpers.Add(_inputA, _inputB, _output);
}
}
}

View File

@@ -0,0 +1,14 @@
using BenchmarkDotNet.Running;
namespace Robust.Benchmarks
{
internal class Program
{
// --allCategories=ctg1,ctg2
// --anyCategories=ctg1,ctg2
public static void Main(string[] args)
{
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
}
}
}

View File

@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\MSBuild\Robust.Properties.targets" />
<Import Project="..\MSBuild\Robust.Engine.props" />
<PropertyGroup>
<IsPackable>false</IsPackable>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<OutputPath>../bin/Benchmarks</OutputPath>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Robust.Server\Robust.Server.csproj" />
<ProjectReference Include="..\Robust.Shared\Robust.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
</ItemGroup>
<Import Project="..\MSBuild\Robust.Engine.targets" />
</Project>

View File

@@ -0,0 +1,40 @@
using System.Globalization;
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
namespace Robust.Benchmarks.Serialization
{
public class BenchmarkIntSerializer : ITypeSerializer<int, ValueDataNode>
{
public ValidationNode Validate(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, ISerializationContext? context = null)
{
return int.TryParse(node.Value, out _)
? new ValidatedValueNode(node)
: new ErrorNode(node, $"Failed parsing int value: {node.Value}");
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
{
return new DeserializedValue<int>(int.Parse(node.Value, CultureInfo.InvariantCulture));
}
public DataNode Write(ISerializationManager serializationManager, int value, bool alwaysWrite = false,
ISerializationContext? context = null)
{
return new ValueDataNode(value.ToString(CultureInfo.InvariantCulture));
}
public int Copy(ISerializationManager serializationManager, int source, int target, bool skipHook,
ISerializationContext? context = null)
{
return source;
}
}
}

View File

@@ -0,0 +1,151 @@
using System.IO;
using System.Linq;
using BenchmarkDotNet.Attributes;
using Robust.Benchmarks.Serialization.Definitions;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Robust.Benchmarks.Serialization.Copy
{
[MemoryDiagnoser]
public class SerializationCopyBenchmark : SerializationBenchmark
{
public SerializationCopyBenchmark()
{
InitializeSerialization();
DataDefinitionWithString = new DataDefinitionWithString {StringField = "ABC"};
var yamlStream = new YamlStream();
yamlStream.Load(new StringReader(SeedDataDefinition.Prototype));
var seedMapping = yamlStream.Documents[0].RootNode.ToDataNodeCast<SequenceDataNode>().Cast<MappingDataNode>(0);
Seed = SerializationManager.ReadValueOrThrow<SeedDataDefinition>(seedMapping);
}
private const string String = "ABC";
private const int Integer = 1;
private DataDefinitionWithString DataDefinitionWithString { get; }
private SeedDataDefinition Seed { get; }
private BenchmarkFlagsEnum FlagZero = BenchmarkFlagsEnum.Zero;
private BenchmarkFlagsEnum FlagThirtyOne = BenchmarkFlagsEnum.ThirtyOne;
[Benchmark]
public string? CreateCopyString()
{
return SerializationManager.CreateCopy(String);
}
[Benchmark]
public int? CreateCopyInteger()
{
return SerializationManager.CreateCopy(Integer);
}
[Benchmark]
public DataDefinitionWithString? CreateCopyDataDefinitionWithString()
{
return SerializationManager.CreateCopy(DataDefinitionWithString);
}
[Benchmark]
public SeedDataDefinition? CreateCopySeedDataDefinition()
{
return SerializationManager.CreateCopy(Seed);
}
[Benchmark]
public SeedDataDefinition BaselineCreateCopySeedDataDefinition()
{
// ReSharper disable once UseObjectOrCollectionInitializer
var copy = new SeedDataDefinition();
copy.ID = Seed.ID;
copy.Name = Seed.Name;
copy.SeedName = Seed.SeedName;
copy.SeedNoun = Seed.SeedNoun;
copy.DisplayName = Seed.DisplayName;
copy.RoundStart = Seed.RoundStart;
copy.Mysterious = Seed.Mysterious;
copy.Immutable = Seed.Immutable;
copy.ProductPrototypes = Seed.ProductPrototypes.ToList();
copy.Chemicals = Seed.Chemicals.ToDictionary(p => p.Key, p => p.Value);
copy.ConsumeGasses = Seed.ConsumeGasses.ToDictionary(p => p.Key, p => p.Value);
copy.ExudeGasses = Seed.ExudeGasses.ToDictionary(p => p.Key, p => p.Value);
copy.NutrientConsumption = Seed.NutrientConsumption;
copy.WaterConsumption = Seed.WaterConsumption;
copy.IdealHeat = Seed.IdealHeat;
copy.HeatTolerance = Seed.HeatTolerance;
copy.IdealLight = Seed.IdealLight;
copy.LightTolerance = Seed.LightTolerance;
copy.ToxinsTolerance = Seed.ToxinsTolerance;
copy.LowPressureTolerance = Seed.LowPressureTolerance;
copy.HighPressureTolerance = Seed.HighPressureTolerance;
copy.PestTolerance = Seed.PestTolerance;
copy.WeedTolerance = Seed.WeedTolerance;
copy.Endurance = Seed.Endurance;
copy.Yield = Seed.Yield;
copy.Lifespan = Seed.Lifespan;
copy.Maturation = Seed.Maturation;
copy.Production = Seed.Production;
copy.GrowthStages = Seed.GrowthStages;
copy.HarvestRepeat = Seed.HarvestRepeat;
copy.Potency = Seed.Potency;
copy.Ligneous = Seed.Ligneous;
copy.PlantRsi = Seed.PlantRsi == null
? null!
: new ResourcePath(Seed.PlantRsi.ToString(), Seed.PlantRsi.Separator);
copy.PlantIconState = Seed.PlantIconState;
copy.Bioluminescent = Seed.Bioluminescent;
copy.BioluminescentColor = Seed.BioluminescentColor;
copy.SplatPrototype = Seed.SplatPrototype;
return copy;
}
[Benchmark]
[BenchmarkCategory("flag")]
public object? CopyFlagZero()
{
return SerializationManager.CopyWithTypeSerializer(
typeof(FlagSerializer<BenchmarkFlags>),
(int) FlagZero,
(int) FlagZero);
}
[Benchmark]
[BenchmarkCategory("flag")]
public object? CopyFlagThirtyOne()
{
return SerializationManager.CopyWithTypeSerializer(
typeof(FlagSerializer<BenchmarkFlags>),
(int) FlagThirtyOne,
(int) FlagThirtyOne);
}
[Benchmark]
[BenchmarkCategory("customTypeSerializer")]
public object? CopyIntegerCustomSerializer()
{
return SerializationManager.CopyWithTypeSerializer(
typeof(BenchmarkIntSerializer),
Integer,
Integer);
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
using Robust.Shared.Serialization;
namespace Robust.Benchmarks.Serialization.Definitions
{
public class BenchmarkFlags
{
public const int Zero = 1 << 0;
public const int ThirtyOne = 1 << 31;
}
[Flags]
[FlagsFor(typeof(BenchmarkFlags))]
public enum BenchmarkFlagsEnum
{
Zero = BenchmarkFlags.Zero,
ThirtyOne = BenchmarkFlags.ThirtyOne
}
}

View File

@@ -0,0 +1,11 @@
using Robust.Shared.Serialization.Manager.Attributes;
namespace Robust.Benchmarks.Serialization.Definitions
{
[DataDefinition]
public class DataDefinitionWithString
{
[DataField("string")]
public string StringField { get; init; } = default!;
}
}

View File

@@ -0,0 +1,11 @@
using Robust.Shared.Serialization.Manager.Attributes;
namespace Robust.Benchmarks.Serialization.Definitions
{
[DataDefinition]
public sealed class SealedDataDefinitionWithString
{
[DataField("string")]
public string StringField { get; init; } = default!;
}
}

View File

@@ -0,0 +1,119 @@
using System.Collections.Generic;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Utility;
namespace Robust.Benchmarks.Serialization.Definitions
{
/// <summary>
/// Arbitrarily large data definition for benchmarks.
/// Taken from content.
/// </summary>
[Prototype("seed")]
public class SeedDataDefinition : IPrototype
{
public const string Prototype = @"
- type: seed
id: tobacco
name: tobacco
seedName: tobacco
displayName: tobacco plant
productPrototypes:
- LeavesTobacco
harvestRepeat: Repeat
lifespan: 75
maturation: 5
production: 5
yield: 2
potency: 20
growthStages: 3
idealLight: 9
idealHeat: 298
chemicals:
chem.Nicotine:
Min: 1
Max: 10
PotencyDivisor: 10";
[DataField("id", required: true)] public string ID { get; set; } = default!;
#region Tracking
[DataField("name")] public string Name { get; set; } = string.Empty;
[DataField("seedName")] public string SeedName { get; set; } = string.Empty;
[DataField("seedNoun")] public string SeedNoun { get; set; } = "seeds";
[DataField("displayName")] public string DisplayName { get; set; } = string.Empty;
[DataField("roundStart")] public bool RoundStart { get; set; } = true;
[DataField("mysterious")] public bool Mysterious { get; set; }
[DataField("immutable")] public bool Immutable { get; set; }
#endregion
#region Output
[DataField("productPrototypes")]
public List<string> ProductPrototypes { get; set; } = new();
[DataField("chemicals")]
public Dictionary<string, SeedChemQuantity> Chemicals { get; set; } = new();
[DataField("consumeGasses")]
public Dictionary<Gas, float> ConsumeGasses { get; set; } = new();
[DataField("exudeGasses")]
public Dictionary<Gas, float> ExudeGasses { get; set; } = new();
#endregion
#region Tolerances
[DataField("nutrientConsumption")] public float NutrientConsumption { get; set; } = 0.25f;
[DataField("waterConsumption")] public float WaterConsumption { get; set; } = 3f;
[DataField("idealHeat")] public float IdealHeat { get; set; } = 293f;
[DataField("heatTolerance")] public float HeatTolerance { get; set; } = 20f;
[DataField("idealLight")] public float IdealLight { get; set; } = 7f;
[DataField("lightTolerance")] public float LightTolerance { get; set; } = 5f;
[DataField("toxinsTolerance")] public float ToxinsTolerance { get; set; } = 4f;
[DataField("lowPressureTolerance")] public float LowPressureTolerance { get; set; } = 25f;
[DataField("highPressureTolerance")] public float HighPressureTolerance { get; set; } = 200f;
[DataField("pestTolerance")] public float PestTolerance { get; set; } = 5f;
[DataField("weedTolerance")] public float WeedTolerance { get; set; } = 5f;
#endregion
#region General traits
[DataField("endurance")] public float Endurance { get; set; } = 100f;
[DataField("yield")] public int Yield { get; set; }
[DataField("lifespan")] public float Lifespan { get; set; }
[DataField("maturation")] public float Maturation { get; set; }
[DataField("production")] public float Production { get; set; }
[DataField("growthStages")] public int GrowthStages { get; set; } = 6;
[DataField("harvestRepeat")] public HarvestType HarvestRepeat { get; set; } = HarvestType.NoRepeat;
[DataField("potency")] public float Potency { get; set; } = 1f;
[DataField("ligneous")] public bool Ligneous { get; set; }
#endregion
#region Cosmetics
[DataField("plantRsi", required: true)] public ResourcePath PlantRsi { get; set; } = default!;
[DataField("plantIconState")] public string PlantIconState { get; set; } = "produce";
[DataField("bioluminescent")] public bool Bioluminescent { get; set; }
[DataField("bioluminescentColor")] public Color BioluminescentColor { get; set; } = Color.White;
[DataField("splatPrototype")] public string? SplatPrototype { get; set; }
#endregion
}
public enum HarvestType
{
NoRepeat,
Repeat
}
public enum Gas
{
}
[DataDefinition]
public struct SeedChemQuantity
{
[DataField("Min")]
public int Min;
[DataField("Max")]
public int Max;
[DataField("PotencyDivisor")]
public int PotencyDivisor;
}
}

View File

@@ -0,0 +1,22 @@
using BenchmarkDotNet.Attributes;
using Robust.Shared.Serialization.Manager;
namespace Robust.Benchmarks.Serialization.Initialize
{
[MemoryDiagnoser]
public class SerializationInitializeBenchmark : SerializationBenchmark
{
[IterationCleanup]
public void IterationCleanup()
{
SerializationManager.Shutdown();
}
[Benchmark]
public ISerializationManager Initialize()
{
InitializeSerialization();
return SerializationManager;
}
}
}

View File

@@ -0,0 +1,96 @@
using System.IO;
using BenchmarkDotNet.Attributes;
using Robust.Benchmarks.Serialization.Definitions;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
using YamlDotNet.RepresentationModel;
namespace Robust.Benchmarks.Serialization.Read
{
[MemoryDiagnoser]
public class SerializationReadBenchmark : SerializationBenchmark
{
public SerializationReadBenchmark()
{
InitializeSerialization();
StringDataDefNode = new MappingDataNode();
StringDataDefNode.Add(new ValueDataNode("string"), new ValueDataNode("ABC"));
var yamlStream = new YamlStream();
yamlStream.Load(new StringReader(SeedDataDefinition.Prototype));
SeedNode = yamlStream.Documents[0].RootNode.ToDataNodeCast<SequenceDataNode>().Cast<MappingDataNode>(0);
}
private ValueDataNode StringNode { get; } = new("ABC");
private ValueDataNode IntNode { get; } = new("1");
private MappingDataNode StringDataDefNode { get; }
private MappingDataNode SeedNode { get; }
private ValueDataNode FlagZero { get; } = new("Zero");
private ValueDataNode FlagThirtyOne { get; } = new("ThirtyOne");
[Benchmark]
public string? ReadString()
{
return SerializationManager.ReadValue<string>(StringNode);
}
[Benchmark]
public int? ReadInteger()
{
return SerializationManager.ReadValue<int>(IntNode);
}
[Benchmark]
public DataDefinitionWithString? ReadDataDefinitionWithString()
{
return SerializationManager.ReadValue<DataDefinitionWithString>(StringDataDefNode);
}
[Benchmark]
public SeedDataDefinition? ReadSeedDataDefinition()
{
return SerializationManager.ReadValue<SeedDataDefinition>(SeedNode);
}
[Benchmark]
[BenchmarkCategory("flag")]
public DeserializationResult ReadFlagZero()
{
return SerializationManager.ReadWithTypeSerializer(
typeof(int),
typeof(FlagSerializer<BenchmarkFlags>),
FlagZero);
}
[Benchmark]
[BenchmarkCategory("flag")]
public DeserializationResult ReadThirtyOne()
{
return SerializationManager.ReadWithTypeSerializer(
typeof(int),
typeof(FlagSerializer<BenchmarkFlags>),
FlagThirtyOne);
}
[Benchmark]
[BenchmarkCategory("customTypeSerializer")]
public DeserializationResult ReadIntegerCustomSerializer()
{
return SerializationManager.ReadWithTypeSerializer(
typeof(int),
typeof(BenchmarkIntSerializer),
IntNode);
}
}
}

View File

@@ -0,0 +1,127 @@
using BenchmarkDotNet.Attributes;
using Robust.Benchmarks.Serialization.Definitions;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Value;
namespace Robust.Benchmarks.Serialization
{
[MemoryDiagnoser]
public class SerializationArrayBenchmark : SerializationBenchmark
{
public SerializationArrayBenchmark()
{
InitializeSerialization();
OneStringDefNode = new SequenceDataNode();
OneStringDefNode.Add(new MappingDataNode
{
["string"] = new ValueDataNode("ABC")
});
TenStringDefsNode = new SequenceDataNode();
for (var i = 0; i < 10; i++)
{
TenStringDefsNode.Add(new MappingDataNode
{
["string"] = new ValueDataNode("ABC")
});
}
}
private SequenceDataNode EmptyNode { get; } = new();
private SequenceDataNode OneIntNode { get; } = new("1");
private SequenceDataNode TenIntsNode { get; } = new("1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
private SequenceDataNode OneStringDefNode { get; }
private SequenceDataNode TenStringDefsNode { get; }
[Benchmark]
[BenchmarkCategory("read")]
public string[]? ReadEmptyString()
{
return SerializationManager.ReadValue<string[]>(EmptyNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public string[]? ReadOneString()
{
return SerializationManager.ReadValue<string[]>(OneIntNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public string[]? ReadTenStrings()
{
return SerializationManager.ReadValue<string[]>(TenIntsNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public int[]? ReadEmptyInt()
{
return SerializationManager.ReadValue<int[]>(EmptyNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public int[]? ReadOneInt()
{
return SerializationManager.ReadValue<int[]>(OneIntNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public int[]? ReadTenInts()
{
return SerializationManager.ReadValue<int[]>(TenIntsNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public DataDefinitionWithString[]? ReadEmptyStringDataDef()
{
return SerializationManager.ReadValue<DataDefinitionWithString[]>(EmptyNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public DataDefinitionWithString[]? ReadOneStringDataDef()
{
return SerializationManager.ReadValue<DataDefinitionWithString[]>(OneStringDefNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public DataDefinitionWithString[]? ReadTenStringDataDefs()
{
return SerializationManager.ReadValue<DataDefinitionWithString[]>(TenStringDefsNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public SealedDataDefinitionWithString[]? ReadEmptySealedStringDataDef()
{
return SerializationManager.ReadValue<SealedDataDefinitionWithString[]>(EmptyNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public SealedDataDefinitionWithString[]? ReadOneSealedStringDataDef()
{
return SerializationManager.ReadValue<SealedDataDefinitionWithString[]>(OneStringDefNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public SealedDataDefinitionWithString[]? ReadTenSealedStringDataDefs()
{
return SerializationManager.ReadValue<SealedDataDefinitionWithString[]>(TenStringDefsNode);
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
using Robust.Server;
using Robust.Shared.Configuration;
using Robust.Shared.ContentPack;
using Robust.Shared.IoC;
using Robust.Shared.Reflection;
using Robust.Shared.Serialization.Manager;
namespace Robust.Benchmarks.Serialization
{
public abstract class SerializationBenchmark
{
public SerializationBenchmark()
{
IoCManager.InitThread();
ServerIoC.RegisterIoC();
IoCManager.BuildGraph();
var assemblies = new[]
{
AppDomain.CurrentDomain.GetAssemblyByName("Robust.Shared"),
AppDomain.CurrentDomain.GetAssemblyByName("Robust.Server"),
AppDomain.CurrentDomain.GetAssemblyByName("Robust.Benchmarks")
};
foreach (var assembly in assemblies)
{
IoCManager.Resolve<IConfigurationManagerInternal>().LoadCVarsFromAssembly(assembly);
}
IoCManager.Resolve<IReflectionManager>().LoadAssemblies(assemblies);
SerializationManager = IoCManager.Resolve<ISerializationManager>();
}
protected ISerializationManager SerializationManager { get; }
public void InitializeSerialization()
{
SerializationManager.Initialize();
}
}
}

View File

@@ -0,0 +1,134 @@
using System.Globalization;
using System.IO;
using BenchmarkDotNet.Attributes;
using Robust.Benchmarks.Serialization.Definitions;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
using YamlDotNet.RepresentationModel;
namespace Robust.Benchmarks.Serialization.Write
{
[MemoryDiagnoser]
public class SerializationWriteBenchmark : SerializationBenchmark
{
public SerializationWriteBenchmark()
{
InitializeSerialization();
DataDefinitionWithString = new DataDefinitionWithString {StringField = "ABC"};
var yamlStream = new YamlStream();
yamlStream.Load(new StringReader(SeedDataDefinition.Prototype));
var seedMapping = yamlStream.Documents[0].RootNode.ToDataNodeCast<SequenceDataNode>().Cast<MappingDataNode>(0);
Seed = SerializationManager.ReadValueOrThrow<SeedDataDefinition>(seedMapping);
}
private const string String = "ABC";
private const int Integer = 1;
private DataDefinitionWithString DataDefinitionWithString { get; }
private SeedDataDefinition Seed { get; }
private BenchmarkFlagsEnum FlagZero = BenchmarkFlagsEnum.Zero;
private BenchmarkFlagsEnum FlagThirtyOne = BenchmarkFlagsEnum.ThirtyOne;
[Benchmark]
public DataNode WriteString()
{
return SerializationManager.WriteValue(String);
}
[Benchmark]
public DataNode WriteInteger()
{
return SerializationManager.WriteValue(Integer);
}
[Benchmark]
public DataNode WriteDataDefinitionWithString()
{
return SerializationManager.WriteValue(DataDefinitionWithString);
}
[Benchmark]
public DataNode WriteSeedDataDefinition()
{
return SerializationManager.WriteValue(Seed);
}
[Benchmark]
public DataNode BaselineWriteSeedDataDefinition()
{
var mapping = new MappingDataNode();
mapping.Add("id", Seed.ID);
mapping.Add("name", Seed.Name);
mapping.Add("seedName", Seed.SeedName);
mapping.Add("displayName", Seed.DisplayName);
mapping.Add("productPrototypes", Seed.ProductPrototypes);
mapping.Add("harvestRepeat", Seed.HarvestRepeat.ToString());
mapping.Add("lifespan", Seed.Lifespan.ToString(CultureInfo.InvariantCulture));
mapping.Add("maturation", Seed.Maturation.ToString(CultureInfo.InvariantCulture));
mapping.Add("production", Seed.Production.ToString(CultureInfo.InvariantCulture));
mapping.Add("yield", Seed.Yield.ToString(CultureInfo.InvariantCulture));
mapping.Add("potency", Seed.Potency.ToString(CultureInfo.InvariantCulture));
mapping.Add("growthStages", Seed.GrowthStages.ToString(CultureInfo.InvariantCulture));
mapping.Add("idealLight", Seed.IdealLight.ToString(CultureInfo.InvariantCulture));
mapping.Add("idealHeat", Seed.IdealHeat.ToString(CultureInfo.InvariantCulture));
var chemicals = new MappingDataNode();
foreach (var (name, quantity) in Seed.Chemicals)
{
chemicals.Add(name, new MappingDataNode
{
["Min"] = new ValueDataNode(quantity.Min.ToString(CultureInfo.InvariantCulture)),
["Max"] = new ValueDataNode(quantity.Max.ToString(CultureInfo.InvariantCulture)),
["PotencyDivisor"] = new ValueDataNode(quantity.PotencyDivisor.ToString(CultureInfo.InvariantCulture))
});
}
mapping.Add("chemicals", chemicals);
return mapping;
}
[Benchmark]
[BenchmarkCategory("flag")]
public DataNode WriteFlagZero()
{
return SerializationManager.WriteWithTypeSerializer(
typeof(int),
typeof(FlagSerializer<BenchmarkFlags>),
FlagZero);
}
[Benchmark]
[BenchmarkCategory("flag")]
public DataNode WriteThirtyOne()
{
return SerializationManager.WriteWithTypeSerializer(
typeof(int),
typeof(FlagSerializer<BenchmarkFlags>),
FlagThirtyOne);
}
[Benchmark]
[BenchmarkCategory("customTypeSerializer")]
public DataNode WriteIntegerCustomSerializer()
{
return SerializationManager.WriteWithTypeSerializer(
typeof(int),
typeof(BenchmarkIntSerializer),
Integer);
}
}
}

View File

@@ -0,0 +1,32 @@
using Xilium.CefGlue;
namespace Robust.Client.CEF
{
public sealed class BeforeBrowseContext
{
internal readonly CefRequest CefRequest;
public string Url => CefRequest.Url;
public string Method => CefRequest.Method;
public bool IsRedirect { get; }
public bool UserGesture { get; }
public bool IsCancelled { get; private set; }
internal BeforeBrowseContext(
bool isRedirect,
bool userGesture,
CefRequest cefRequest)
{
CefRequest = cefRequest;
IsRedirect = isRedirect;
UserGesture = userGesture;
}
public void DoCancel()
{
IsCancelled = true;
}
}
}

View File

@@ -0,0 +1,593 @@
using System;
using System.Collections.Generic;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.UserInterface;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using SixLabors.ImageSharp.PixelFormats;
using Xilium.CefGlue;
using static Robust.Client.CEF.CefKeyCodes;
using static Robust.Client.CEF.CefKeyCodes.ChromiumKeyboardCode;
using static Robust.Client.Input.Keyboard;
namespace Robust.Client.CEF
{
// Funny browser control to integrate in UI.
public class BrowserControl : Control, IBrowserControl, IRawInputControl
{
private const int ScrollSpeed = 50;
[Dependency] private readonly IClyde _clyde = default!;
[Dependency] private readonly IInputManager _inputMgr = default!;
[Dependency] private readonly CefManager _cef = default!;
private RobustRequestHandler _requestHandler = new RobustRequestHandler(Logger.GetSawmill("root"));
private LiveData? _data;
private string _startUrl = "about:blank";
[ViewVariables(VVAccess.ReadWrite)]
public string Url
{
get => _data == null ? _startUrl : _data.Browser.GetMainFrame().Url;
set
{
if (_data == null)
_startUrl = value;
else
_data.Browser.GetMainFrame().LoadUrl(value);
}
}
[ViewVariables] public bool IsLoading => _data?.Browser.IsLoading ?? false;
private readonly Dictionary<Key, ChromiumKeyboardCode> _keyMap = new()
{
[Key.A] = VKEY_A,
[Key.B] = VKEY_B,
[Key.C] = VKEY_C,
[Key.D] = VKEY_D,
[Key.E] = VKEY_E,
[Key.F] = VKEY_F,
[Key.G] = VKEY_G,
[Key.H] = VKEY_H,
[Key.I] = VKEY_I,
[Key.J] = VKEY_J,
[Key.K] = VKEY_K,
[Key.L] = VKEY_L,
[Key.M] = VKEY_M,
[Key.N] = VKEY_N,
[Key.O] = VKEY_O,
[Key.P] = VKEY_P,
[Key.Q] = VKEY_Q,
[Key.R] = VKEY_R,
[Key.S] = VKEY_S,
[Key.T] = VKEY_T,
[Key.U] = VKEY_U,
[Key.V] = VKEY_V,
[Key.W] = VKEY_W,
[Key.X] = VKEY_X,
[Key.Y] = VKEY_Y,
[Key.Z] = VKEY_Z,
[Key.Num0] = VKEY_0,
[Key.Num1] = VKEY_1,
[Key.Num2] = VKEY_2,
[Key.Num3] = VKEY_3,
[Key.Num4] = VKEY_4,
[Key.Num5] = VKEY_5,
[Key.Num6] = VKEY_6,
[Key.Num7] = VKEY_7,
[Key.Num8] = VKEY_8,
[Key.Num9] = VKEY_9,
[Key.NumpadNum0] = VKEY_NUMPAD0,
[Key.NumpadNum1] = VKEY_NUMPAD1,
[Key.NumpadNum2] = VKEY_NUMPAD2,
[Key.NumpadNum3] = VKEY_NUMPAD3,
[Key.NumpadNum4] = VKEY_NUMPAD4,
[Key.NumpadNum5] = VKEY_NUMPAD5,
[Key.NumpadNum6] = VKEY_NUMPAD6,
[Key.NumpadNum7] = VKEY_NUMPAD7,
[Key.NumpadNum8] = VKEY_NUMPAD8,
[Key.NumpadNum9] = VKEY_NUMPAD9,
[Key.Escape] = VKEY_ESCAPE,
[Key.Control] = VKEY_CONTROL,
[Key.Shift] = VKEY_SHIFT,
[Key.Alt] = VKEY_MENU,
[Key.LSystem] = VKEY_LWIN,
[Key.RSystem] = VKEY_RWIN,
[Key.LBracket] = VKEY_OEM_4,
[Key.RBracket] = VKEY_OEM_6,
[Key.SemiColon] = VKEY_OEM_1,
[Key.Comma] = VKEY_OEM_COMMA,
[Key.Period] = VKEY_OEM_PERIOD,
[Key.Apostrophe] = VKEY_OEM_7,
[Key.Slash] = VKEY_OEM_2,
[Key.BackSlash] = VKEY_OEM_5,
[Key.Tilde] = VKEY_OEM_3,
[Key.Equal] = VKEY_OEM_PLUS,
[Key.Space] = VKEY_SPACE,
[Key.Return] = VKEY_RETURN,
[Key.BackSpace] = VKEY_BACK,
[Key.Tab] = VKEY_TAB,
[Key.PageUp] = VKEY_PRIOR,
[Key.PageDown] = VKEY_NEXT,
[Key.End] = VKEY_END,
[Key.Home] = VKEY_HOME,
[Key.Insert] = VKEY_INSERT,
[Key.Delete] = VKEY_DELETE,
[Key.Minus] = VKEY_OEM_MINUS,
[Key.NumpadAdd] = VKEY_ADD,
[Key.NumpadSubtract] = VKEY_SUBTRACT,
[Key.NumpadDivide] = VKEY_DIVIDE,
[Key.NumpadMultiply] = VKEY_MULTIPLY,
[Key.NumpadDecimal] = VKEY_DECIMAL,
[Key.Left] = VKEY_LEFT,
[Key.Right] = VKEY_RIGHT,
[Key.Up] = VKEY_UP,
[Key.Down] = VKEY_DOWN,
[Key.F1] = VKEY_F1,
[Key.F2] = VKEY_F2,
[Key.F3] = VKEY_F3,
[Key.F4] = VKEY_F4,
[Key.F5] = VKEY_F5,
[Key.F6] = VKEY_F6,
[Key.F7] = VKEY_F7,
[Key.F8] = VKEY_F8,
[Key.F9] = VKEY_F9,
[Key.F10] = VKEY_F10,
[Key.F11] = VKEY_F11,
[Key.F12] = VKEY_F12,
[Key.F13] = VKEY_F13,
[Key.F14] = VKEY_F14,
[Key.F15] = VKEY_F15,
[Key.Pause] = VKEY_PAUSE,
};
public BrowserControl()
{
CanKeyboardFocus = true;
KeyboardFocusOnClick = true;
MouseFilter = MouseFilterMode.Stop;
IoCManager.InjectDependencies(this);
}
protected override void EnteredTree()
{
base.EnteredTree();
_cef.CheckInitialized();
DebugTools.AssertNull(_data);
// A funny render handler that will allow us to render to the control.
var renderer = new ControlRenderHandler(this);
// A funny web cef client. This can actually be shared by multiple browsers, but I'm not sure how the
// rendering would work in that case? TODO CEF: Investigate a way to share the web client?
var client = new RobustCefClient(renderer, _requestHandler, new RobustLoadHandler());
var info = CefWindowInfo.Create();
// FUNFACT: If you DO NOT set these below and set info.Width/info.Height instead, you get an external window
// Good to know, huh? Setup is the same, except you can pass a dummy render handler to the CEF client.
info.SetAsWindowless(IntPtr.Zero, false); // TODO CEF: Pass parent handle?
info.WindowlessRenderingEnabled = true;
var settings = new CefBrowserSettings()
{
WindowlessFrameRate = 60
};
// Create the web browser! And by default, we go to about:blank.
var browser = CefBrowserHost.CreateBrowserSync(info, client, settings, _startUrl);
var texture = _clyde.CreateBlankTexture<Bgra32>(Vector2i.One);
_data = new LiveData(texture, client, browser, renderer);
}
protected override void ExitedTree()
{
base.ExitedTree();
DebugTools.AssertNotNull(_data);
_data!.Texture.Dispose();
_data.Browser.GetHost().CloseBrowser(true);
_data = null;
}
protected internal override void MouseMove(GUIMouseMoveEventArgs args)
{
base.MouseMove(args);
if (_data == null)
return;
// Logger.Debug();
var modifiers = CalcMouseModifiers();
var mouseEvent = new CefMouseEvent(
(int) args.RelativePosition.X, (int) args.RelativePosition.Y,
modifiers);
_data.Browser.GetHost().SendMouseMoveEvent(mouseEvent, false);
}
protected internal override void MouseExited()
{
base.MouseExited();
if (_data == null)
return;
var modifiers = CalcMouseModifiers();
_data.Browser.GetHost().SendMouseMoveEvent(new CefMouseEvent(0, 0, modifiers), true);
}
protected internal override void MouseWheel(GUIMouseWheelEventArgs args)
{
base.MouseWheel(args);
if (_data == null)
return;
var modifiers = CalcMouseModifiers();
var mouseEvent = new CefMouseEvent(
(int) args.RelativePosition.X, (int) args.RelativePosition.Y,
modifiers);
_data.Browser.GetHost().SendMouseWheelEvent(
mouseEvent,
(int) args.Delta.X * ScrollSpeed,
(int) args.Delta.Y * ScrollSpeed);
}
bool IRawInputControl.RawKeyEvent(in GuiRawKeyEvent guiRawEvent)
{
if (_data == null)
return false;
var host = _data.Browser.GetHost();
if (guiRawEvent.Key is Key.MouseLeft or Key.MouseMiddle or Key.MouseRight)
{
var key = guiRawEvent.Key switch
{
Key.MouseLeft => CefMouseButtonType.Left,
Key.MouseMiddle => CefMouseButtonType.Middle,
Key.MouseRight => CefMouseButtonType.Right,
_ => default // not possible
};
var mouseEvent = new CefMouseEvent(
guiRawEvent.MouseRelative.X, guiRawEvent.MouseRelative.Y,
CefEventFlags.None);
// Logger.Debug($"MOUSE: {guiRawEvent.Action} {guiRawEvent.Key} {guiRawEvent.ScanCode} {key}");
// TODO: double click support?
host.SendMouseClickEvent(mouseEvent, key, guiRawEvent.Action == RawKeyAction.Up, 1);
}
else
{
// TODO: Handle left/right modifier keys??
if (!_keyMap.TryGetValue(guiRawEvent.Key, out var vkKey))
vkKey = default;
// Logger.Debug($"{guiRawEvent.Action} {guiRawEvent.Key} {guiRawEvent.ScanCode} {vkKey}");
var lParam = 0;
lParam |= (guiRawEvent.ScanCode & 0xFF) << 16;
if (guiRawEvent.Action != RawKeyAction.Down)
lParam |= 1 << 30;
if (guiRawEvent.Action == RawKeyAction.Up)
lParam |= 1 << 31;
var modifiers = CalcModifiers(guiRawEvent.Key);
host.SendKeyEvent(new CefKeyEvent
{
// Repeats are sent as key downs, I guess?
EventType = guiRawEvent.Action == RawKeyAction.Up
? CefKeyEventType.KeyUp
: CefKeyEventType.RawKeyDown,
NativeKeyCode = lParam,
// NativeKeyCode = guiRawEvent.ScanCode,
WindowsKeyCode = (int) vkKey,
IsSystemKey = false, // TODO
Modifiers = modifiers
});
if (guiRawEvent.Action != RawKeyAction.Up && guiRawEvent.Key == Key.Return)
{
host.SendKeyEvent(new CefKeyEvent
{
EventType = CefKeyEventType.Char,
WindowsKeyCode = '\r',
NativeKeyCode = lParam,
Modifiers = modifiers
});
}
}
return true;
}
private CefEventFlags CalcModifiers(Key key)
{
CefEventFlags modifiers = default;
if (_inputMgr.IsKeyDown(Key.Control))
modifiers |= CefEventFlags.ControlDown;
if (_inputMgr.IsKeyDown(Key.Alt))
modifiers |= CefEventFlags.AltDown;
if (_inputMgr.IsKeyDown(Key.Shift))
modifiers |= CefEventFlags.ShiftDown;
if (_inputMgr.IsKeyDown(Key.Shift))
modifiers |= CefEventFlags.ShiftDown;
return modifiers;
}
private CefEventFlags CalcMouseModifiers()
{
CefEventFlags modifiers = default;
if (_inputMgr.IsKeyDown(Key.Control))
modifiers |= CefEventFlags.ControlDown;
if (_inputMgr.IsKeyDown(Key.Alt))
modifiers |= CefEventFlags.AltDown;
if (_inputMgr.IsKeyDown(Key.Shift))
modifiers |= CefEventFlags.ShiftDown;
if (_inputMgr.IsKeyDown(Key.Shift))
modifiers |= CefEventFlags.ShiftDown;
if (_inputMgr.IsKeyDown(Key.MouseLeft))
modifiers |= CefEventFlags.LeftMouseButton;
if (_inputMgr.IsKeyDown(Key.MouseMiddle))
modifiers |= CefEventFlags.MiddleMouseButton;
if (_inputMgr.IsKeyDown(Key.MouseRight))
modifiers |= CefEventFlags.RightMouseButton;
return modifiers;
}
protected internal override void TextEntered(GUITextEventArgs args)
{
base.TextEntered(args);
if (_data == null)
return;
var host = _data.Browser.GetHost();
Span<char> buf = stackalloc char[2];
var written = args.AsRune.EncodeToUtf16(buf);
for (var i = 0; i < written; i++)
{
host.SendKeyEvent(new CefKeyEvent
{
EventType = CefKeyEventType.Char,
WindowsKeyCode = buf[i],
Character = buf[i],
UnmodifiedCharacter = buf[i]
});
}
}
protected override void Resized()
{
base.Resized();
if (_data == null)
return;
_data.Browser.GetHost().NotifyMoveOrResizeStarted();
_data.Browser.GetHost().WasResized();
_data.Texture.Dispose();
_data.Texture = _clyde.CreateBlankTexture<Bgra32>((PixelWidth, PixelHeight));
}
protected internal override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
if (_data == null)
return;
var bufImg = _data.Renderer.Buffer.Buffer;
_data.Texture.SetSubImage(
Vector2i.Zero,
bufImg,
new UIBox2i(
0, 0,
Math.Min(PixelWidth, bufImg.Width),
Math.Min(PixelHeight, bufImg.Height)));
handle.DrawTexture(_data.Texture, Vector2.Zero);
}
public void StopLoad()
{
if (_data == null)
throw new InvalidOperationException();
_data.Browser.StopLoad();
}
public void Reload()
{
if (_data == null)
throw new InvalidOperationException();
_data.Browser.Reload();
}
public bool GoBack()
{
if (_data == null)
throw new InvalidOperationException();
if (!_data.Browser.CanGoBack)
return false;
_data.Browser.GoBack();
return true;
}
public bool GoForward()
{
if (_data == null)
throw new InvalidOperationException();
if (!_data.Browser.CanGoForward)
return false;
_data.Browser.GoForward();
return true;
}
public void ExecuteJavaScript(string code)
{
if (_data == null)
throw new InvalidOperationException();
// TODO: this should not run until the browser is done loading seriously does this even work?
_data.Browser.GetMainFrame().ExecuteJavaScript(code, string.Empty, 1);
}
public void AddResourceRequestHandler(Action<RequestHandlerContext> handler)
{
_requestHandler.AddResourceRequestHandler(handler);
}
public void RemoveResourceRequestHandler(Action<RequestHandlerContext> handler)
{
_requestHandler.RemoveResourceRequestHandler(handler);
}
public void AddBeforeBrowseHandler(Action<BeforeBrowseContext> handler)
{
_requestHandler.AddBeforeBrowseHandler(handler);
}
public void RemoveBeforeBrowseHandler(Action<BeforeBrowseContext> handler)
{
_requestHandler.RemoveBeforeBrowseHandler(handler);
}
private sealed class LiveData
{
public OwnedTexture Texture;
public readonly RobustCefClient Client;
public readonly CefBrowser Browser;
public readonly ControlRenderHandler Renderer;
public LiveData(
OwnedTexture texture,
RobustCefClient client,
CefBrowser browser,
ControlRenderHandler renderer)
{
Texture = texture;
Client = client;
Browser = browser;
Renderer = renderer;
}
}
}
internal class ControlRenderHandler : CefRenderHandler
{
public ImageBuffer Buffer { get; }
private Control _control;
internal ControlRenderHandler(Control control)
{
Buffer = new ImageBuffer(control);
_control = control;
}
protected override CefAccessibilityHandler? GetAccessibilityHandler() => null;
protected override void GetViewRect(CefBrowser browser, out CefRectangle rect)
{
if (_control.Disposed)
{
rect = new CefRectangle();
return;
}
// TODO CEF: Do we need to pass real screen coords? Cause what we do already works...
//var screenCoords = _control.ScreenCoordinates;
//rect = new CefRectangle((int) screenCoords.X, (int) screenCoords.Y, (int)Math.Max(_control.Size.X, 1), (int)Math.Max(_control.Size.Y, 1));
// We do the max between size and 1 because it will LITERALLY CRASH WITHOUT AN ERROR otherwise.
rect = new CefRectangle(0, 0, (int) Math.Max(_control.Size.X, 1), (int) Math.Max(_control.Size.Y, 1));
}
protected override bool GetScreenInfo(CefBrowser browser, CefScreenInfo screenInfo)
{
if (_control.Disposed)
return false;
// TODO CEF: Get actual scale factor?
screenInfo.DeviceScaleFactor = 1.0f;
return true;
}
protected override void OnPopupSize(CefBrowser browser, CefRectangle rect)
{
if (_control.Disposed)
return;
}
protected override void OnPaint(CefBrowser browser, CefPaintElementType type, CefRectangle[] dirtyRects,
IntPtr buffer, int width, int height)
{
if (_control.Disposed)
return;
foreach (var dirtyRect in dirtyRects)
{
Buffer.UpdateBuffer(width, height, buffer, dirtyRect);
}
}
protected override void OnAcceleratedPaint(CefBrowser browser, CefPaintElementType type,
CefRectangle[] dirtyRects, IntPtr sharedHandle)
{
// Unused, but we're forced to implement it so.. NOOP.
}
protected override void OnScrollOffsetChanged(CefBrowser browser, double x, double y)
{
if (_control.Disposed)
return;
}
protected override void OnImeCompositionRangeChanged(CefBrowser browser, CefRange selectedRange,
CefRectangle[] characterBounds)
{
if (_control.Disposed)
return;
}
}
}

View File

@@ -0,0 +1,16 @@
namespace Robust.Client.CEF
{
public sealed class BrowserWindowCreateParameters
{
public int Width { get; set; }
public int Height { get; set; }
public string Url { get; set; } = "about:blank";
public BrowserWindowCreateParameters(int width, int height)
{
Width = width;
Height = height;
}
}
}

View File

@@ -0,0 +1,225 @@
using System.Diagnostics.CodeAnalysis;
namespace Robust.Client.CEF
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "IdentifierTypo")]
[SuppressMessage("ReSharper", "CA1069")]
[SuppressMessage("ReSharper", "CommentTypo")]
internal static class CefKeyCodes
{
// Taken from https://chromium.googlesource.com/chromium/src/+/refs/heads/main/ui/events/keycodes/keyboard_codes_posix.h
// See also https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
public enum ChromiumKeyboardCode
{
VKEY_CANCEL = 0x03,
VKEY_BACK = 0x08,
VKEY_TAB = 0x09,
VKEY_BACKTAB = 0x0A,
VKEY_CLEAR = 0x0C,
VKEY_RETURN = 0x0D,
VKEY_SHIFT = 0x10,
VKEY_CONTROL = 0x11,
VKEY_MENU = 0x12,
VKEY_PAUSE = 0x13,
VKEY_CAPITAL = 0x14,
VKEY_KANA = 0x15,
VKEY_HANGUL = 0x15,
VKEY_PASTE = 0x16,
VKEY_JUNJA = 0x17,
VKEY_FINAL = 0x18,
VKEY_HANJA = 0x19,
VKEY_KANJI = 0x19,
VKEY_ESCAPE = 0x1B,
VKEY_CONVERT = 0x1C,
VKEY_NONCONVERT = 0x1D,
VKEY_ACCEPT = 0x1E,
VKEY_MODECHANGE = 0x1F,
VKEY_SPACE = 0x20,
VKEY_PRIOR = 0x21,
VKEY_NEXT = 0x22,
VKEY_END = 0x23,
VKEY_HOME = 0x24,
VKEY_LEFT = 0x25,
VKEY_UP = 0x26,
VKEY_RIGHT = 0x27,
VKEY_DOWN = 0x28,
VKEY_SELECT = 0x29,
VKEY_PRINT = 0x2A,
VKEY_EXECUTE = 0x2B,
VKEY_SNAPSHOT = 0x2C, // Print Screen / SysRq
VKEY_INSERT = 0x2D,
VKEY_DELETE = 0x2E,
VKEY_HELP = 0x2F,
VKEY_0 = 0x30,
VKEY_1 = 0x31,
VKEY_2 = 0x32,
VKEY_3 = 0x33,
VKEY_4 = 0x34,
VKEY_5 = 0x35,
VKEY_6 = 0x36,
VKEY_7 = 0x37,
VKEY_8 = 0x38,
VKEY_9 = 0x39,
VKEY_A = 0x41,
VKEY_B = 0x42,
VKEY_C = 0x43,
VKEY_D = 0x44,
VKEY_E = 0x45,
VKEY_F = 0x46,
VKEY_G = 0x47,
VKEY_H = 0x48,
VKEY_I = 0x49,
VKEY_J = 0x4A,
VKEY_K = 0x4B,
VKEY_L = 0x4C,
VKEY_M = 0x4D,
VKEY_N = 0x4E,
VKEY_O = 0x4F,
VKEY_P = 0x50,
VKEY_Q = 0x51,
VKEY_R = 0x52,
VKEY_S = 0x53,
VKEY_T = 0x54,
VKEY_U = 0x55,
VKEY_V = 0x56,
VKEY_W = 0x57,
VKEY_X = 0x58,
VKEY_Y = 0x59,
VKEY_Z = 0x5A,
VKEY_LWIN = 0x5B,
VKEY_COMMAND = VKEY_LWIN, // Provide the Mac name for convenience.
VKEY_RWIN = 0x5C,
VKEY_APPS = 0x5D,
VKEY_SLEEP = 0x5F,
VKEY_NUMPAD0 = 0x60,
VKEY_NUMPAD1 = 0x61,
VKEY_NUMPAD2 = 0x62,
VKEY_NUMPAD3 = 0x63,
VKEY_NUMPAD4 = 0x64,
VKEY_NUMPAD5 = 0x65,
VKEY_NUMPAD6 = 0x66,
VKEY_NUMPAD7 = 0x67,
VKEY_NUMPAD8 = 0x68,
VKEY_NUMPAD9 = 0x69,
VKEY_MULTIPLY = 0x6A,
VKEY_ADD = 0x6B,
VKEY_SEPARATOR = 0x6C,
VKEY_SUBTRACT = 0x6D,
VKEY_DECIMAL = 0x6E,
VKEY_DIVIDE = 0x6F,
VKEY_F1 = 0x70,
VKEY_F2 = 0x71,
VKEY_F3 = 0x72,
VKEY_F4 = 0x73,
VKEY_F5 = 0x74,
VKEY_F6 = 0x75,
VKEY_F7 = 0x76,
VKEY_F8 = 0x77,
VKEY_F9 = 0x78,
VKEY_F10 = 0x79,
VKEY_F11 = 0x7A,
VKEY_F12 = 0x7B,
VKEY_F13 = 0x7C,
VKEY_F14 = 0x7D,
VKEY_F15 = 0x7E,
VKEY_F16 = 0x7F,
VKEY_F17 = 0x80,
VKEY_F18 = 0x81,
VKEY_F19 = 0x82,
VKEY_F20 = 0x83,
VKEY_F21 = 0x84,
VKEY_F22 = 0x85,
VKEY_F23 = 0x86,
VKEY_F24 = 0x87,
VKEY_NUMLOCK = 0x90,
VKEY_SCROLL = 0x91,
VKEY_LSHIFT = 0xA0,
VKEY_RSHIFT = 0xA1,
VKEY_LCONTROL = 0xA2,
VKEY_RCONTROL = 0xA3,
VKEY_LMENU = 0xA4,
VKEY_RMENU = 0xA5,
VKEY_BROWSER_BACK = 0xA6,
VKEY_BROWSER_FORWARD = 0xA7,
VKEY_BROWSER_REFRESH = 0xA8,
VKEY_BROWSER_STOP = 0xA9,
VKEY_BROWSER_SEARCH = 0xAA,
VKEY_BROWSER_FAVORITES = 0xAB,
VKEY_BROWSER_HOME = 0xAC,
VKEY_VOLUME_MUTE = 0xAD,
VKEY_VOLUME_DOWN = 0xAE,
VKEY_VOLUME_UP = 0xAF,
VKEY_MEDIA_NEXT_TRACK = 0xB0,
VKEY_MEDIA_PREV_TRACK = 0xB1,
VKEY_MEDIA_STOP = 0xB2,
VKEY_MEDIA_PLAY_PAUSE = 0xB3,
VKEY_MEDIA_LAUNCH_MAIL = 0xB4,
VKEY_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5,
VKEY_MEDIA_LAUNCH_APP1 = 0xB6,
VKEY_MEDIA_LAUNCH_APP2 = 0xB7,
VKEY_OEM_1 = 0xBA,
VKEY_OEM_PLUS = 0xBB,
VKEY_OEM_COMMA = 0xBC,
VKEY_OEM_MINUS = 0xBD,
VKEY_OEM_PERIOD = 0xBE,
VKEY_OEM_2 = 0xBF,
VKEY_OEM_3 = 0xC0,
VKEY_OEM_4 = 0xDB,
VKEY_OEM_5 = 0xDC,
VKEY_OEM_6 = 0xDD,
VKEY_OEM_7 = 0xDE,
VKEY_OEM_8 = 0xDF,
VKEY_OEM_102 = 0xE2,
VKEY_OEM_103 = 0xE3, // GTV KEYCODE_MEDIA_REWIND
VKEY_OEM_104 = 0xE4, // GTV KEYCODE_MEDIA_FAST_FORWARD
VKEY_PROCESSKEY = 0xE5,
VKEY_PACKET = 0xE7,
VKEY_OEM_ATTN = 0xF0, // JIS DomKey::ALPHANUMERIC
VKEY_OEM_FINISH = 0xF1, // JIS DomKey::KATAKANA
VKEY_OEM_COPY = 0xF2, // JIS DomKey::HIRAGANA
VKEY_DBE_SBCSCHAR = 0xF3, // JIS DomKey::HANKAKU
VKEY_DBE_DBCSCHAR = 0xF4, // JIS DomKey::ZENKAKU
VKEY_OEM_BACKTAB = 0xF5, // JIS DomKey::ROMAJI
VKEY_ATTN = 0xF6, // DomKey::ATTN or JIS DomKey::KANA_MODE
VKEY_CRSEL = 0xF7,
VKEY_EXSEL = 0xF8,
VKEY_EREOF = 0xF9,
VKEY_PLAY = 0xFA,
VKEY_ZOOM = 0xFB,
VKEY_NONAME = 0xFC,
VKEY_PA1 = 0xFD,
VKEY_OEM_CLEAR = 0xFE,
VKEY_UNKNOWN = 0,
// POSIX specific VKEYs. Note that as of Windows SDK 7.1, 0x97-9F, 0xD8-DA,
// and 0xE8 are unassigned.
VKEY_WLAN = 0x97,
VKEY_POWER = 0x98,
VKEY_ASSISTANT = 0x99,
VKEY_SETTINGS = 0x9A,
VKEY_PRIVACY_SCREEN_TOGGLE = 0x9B,
VKEY_BRIGHTNESS_DOWN = 0xD8,
VKEY_BRIGHTNESS_UP = 0xD9,
VKEY_KBD_BRIGHTNESS_DOWN = 0xDA,
VKEY_KBD_BRIGHTNESS_UP = 0xE8,
// Windows does not have a specific key code for AltGr. We use the unused 0xE1
// (VK_OEM_AX) code to represent AltGr, matching the behaviour of Firefox on
// Linux.
VKEY_ALTGR = 0xE1,
// Windows does not have a specific key code for Compose. We use the unused
// 0xE6 (VK_ICO_CLEAR) code to represent Compose.
VKEY_COMPOSE = 0xE6,
// Windows does not have specific key codes for Media Play and Media Pause. We
// use the unused 0xE9 (VK_OEM_RESET) and 0xEA (VK_OEM_JUMP) codes to
// represent them.
VKEY_MEDIA_PLAY = 0xE9,
VKEY_MEDIA_PAUSE = 0xEA,
};
}
}

View File

@@ -0,0 +1,186 @@
using System;
using System.Collections.Generic;
using Robust.Client.Graphics;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.ViewVariables;
using Xilium.CefGlue;
namespace Robust.Client.CEF
{
public partial class CefManager
{
[Dependency] private readonly IClydeInternal _clyde = default!;
private readonly List<BrowserWindowImpl> _browserWindows = new();
public IEnumerable<IBrowserWindow> AllBrowserWindows => _browserWindows;
public IBrowserWindow CreateBrowserWindow(BrowserWindowCreateParameters createParams)
{
var mainHWnd = (_clyde.MainWindow as IClydeWindowInternal)?.WindowsHWnd ?? 0;
var info = CefWindowInfo.Create();
info.Width = createParams.Width;
info.Height = createParams.Height;
info.SetAsPopup(mainHWnd, "ss14cef");
var impl = new BrowserWindowImpl(this);
var lifeSpanHandler = new WindowLifeSpanHandler(impl);
var reqHandler = new RobustRequestHandler(Logger.GetSawmill("root"));
var client = new WindowCefClient(lifeSpanHandler, reqHandler);
var settings = new CefBrowserSettings();
impl.Browser = CefBrowserHost.CreateBrowserSync(info, client, settings, createParams.Url);
impl.RequestHandler = reqHandler;
_browserWindows.Add(impl);
return impl;
}
private sealed class BrowserWindowImpl : IBrowserWindow
{
private readonly CefManager _manager;
internal CefBrowser Browser = default!;
internal RobustRequestHandler RequestHandler = default!;
public Action<RequestHandlerContext>? OnResourceRequest { get; set; }
[ViewVariables(VVAccess.ReadWrite)]
public string Url
{
get
{
CheckClosed();
return Browser.GetMainFrame().Url;
}
set
{
CheckClosed();
Browser.GetMainFrame().LoadUrl(value);
}
}
[ViewVariables]
public bool IsLoading
{
get
{
CheckClosed();
return Browser.IsLoading;
}
}
public BrowserWindowImpl(CefManager manager)
{
_manager = manager;
}
public void StopLoad()
{
CheckClosed();
Browser.StopLoad();
}
public void Reload()
{
CheckClosed();
Browser.Reload();
}
public bool GoBack()
{
CheckClosed();
if (!Browser.CanGoBack)
return false;
Browser.GoBack();
return true;
}
public bool GoForward()
{
CheckClosed();
if (!Browser.CanGoForward)
return false;
Browser.GoForward();
return true;
}
public void ExecuteJavaScript(string code)
{
CheckClosed();
Browser.GetMainFrame().ExecuteJavaScript(code, string.Empty, 1);
}
public void AddResourceRequestHandler(Action<RequestHandlerContext> handler)
{
RequestHandler.AddResourceRequestHandler(handler);
}
public void RemoveResourceRequestHandler(Action<RequestHandlerContext> handler)
{
RequestHandler.RemoveResourceRequestHandler(handler);
}
public void Dispose()
{
if (Closed)
return;
Browser.GetHost().CloseBrowser(true);
Closed = true;
}
public bool Closed { get; private set; }
public void OnClose()
{
Closed = true;
_manager._browserWindows.Remove(this);
Logger.Debug("Removing window");
}
private void CheckClosed()
{
if (Closed)
throw new ObjectDisposedException("BrowserWindow");
}
}
private sealed class WindowCefClient : CefClient
{
private readonly CefLifeSpanHandler _lifeSpanHandler;
private readonly CefRequestHandler _requestHandler;
public WindowCefClient(CefLifeSpanHandler lifeSpanHandler, CefRequestHandler requestHandler)
{
_lifeSpanHandler = lifeSpanHandler;
_requestHandler = requestHandler;
}
protected override CefLifeSpanHandler GetLifeSpanHandler() => _lifeSpanHandler;
protected override CefRequestHandler GetRequestHandler() => _requestHandler;
}
private sealed class WindowLifeSpanHandler : CefLifeSpanHandler
{
private readonly BrowserWindowImpl _windowImpl;
public WindowLifeSpanHandler(BrowserWindowImpl windowImpl)
{
_windowImpl = windowImpl;
}
protected override void OnBeforeClose(CefBrowser browser)
{
base.OnBeforeClose(browser);
_windowImpl.OnClose();
}
}
}
}

View File

@@ -0,0 +1,104 @@
using System;
using System.IO;
using JetBrains.Annotations;
using Robust.Shared.ContentPack;
using Robust.Shared.Log;
using Robust.Shared.Utility;
// The library we're using right now. TODO CEF: Do we want to use something else? We will need to ship it ourselves if so.
using Xilium.CefGlue;
namespace Robust.Client.CEF
{
// Register this with IoC.
// TODO CEF: think if making this inherit CefApp is a good idea...
// TODO CEF: A way to handle external window browsers...
[UsedImplicitly]
public partial class CefManager
{
private CefApp _app = default!;
private bool _initialized = false;
/// <summary>
/// Call this to initialize CEF.
/// </summary>
public void Initialize()
{
DebugTools.Assert(!_initialized);
string subProcessName;
if (OperatingSystem.IsWindows())
subProcessName = "Robust.Client.CEF.exe";
else if (OperatingSystem.IsLinux())
subProcessName = "Robust.Client.CEF";
else
throw new NotSupportedException("Unsupported platform for CEF!");
var subProcessPath = PathHelpers.ExecutableRelativeFile(subProcessName);
var settings = new CefSettings()
{
WindowlessRenderingEnabled = true, // So we can render to our UI controls.
ExternalMessagePump = false, // Unsure, honestly. TODO CEF: Research this?
NoSandbox = true, // Not disabling the sandbox crashes CEF.
BrowserSubprocessPath = subProcessPath,
LocalesDirPath = Path.Combine(PathHelpers.GetExecutableDirectory(), "locales"),
ResourcesDirPath = PathHelpers.GetExecutableDirectory(),
RemoteDebuggingPort = 9222
};
Logger.Info($"CEF Version: {CefRuntime.ChromeVersion}");
// --------------------------- README --------------------------------------------------
// By the way! You're gonna need the CEF binaries in your client's bin folder.
// More specifically, version cef_binary_91.1.21+g9dd45fe+chromium-91.0.4472.114
// https://cef-builds.spotifycdn.com/cef_binary_91.1.21%2Bg9dd45fe%2Bchromium-91.0.4472.114_windows64_minimal.tar.bz2
// https://cef-builds.spotifycdn.com/cef_binary_91.1.21%2Bg9dd45fe%2Bchromium-91.0.4472.114_linux64_minimal.tar.bz2
// Here's how to get it to work:
// 1. Copy all the contents of "Release" to the bin folder.
// 2. Copy all the contents of "Resources" to the bin folder.
// Supposedly, you should just need libcef.so in Release and icudtl.dat in Resources...
// The rest might be optional.
// Maybe. Good luck! If you get odd crashes with no info and a weird exit code, use GDB!
// -------------------------------------------------------------------------------------
_app = new RobustCefApp();
// We pass no main arguments...
CefRuntime.Initialize(new CefMainArgs(null), settings, _app, IntPtr.Zero);
// TODO CEF: After this point, debugging breaks. No, literally. My client crashes but ONLY with the debugger.
// I have tried using the DEBUG and RELEASE versions of libcef.so, stripped or non-stripped...
// And nothing seemed to work. Odd.
_initialized = true;
}
public void CheckInitialized()
{
if (!_initialized)
throw new InvalidOperationException("CefManager has not been initialized!");
}
/// <summary>
/// Needs to be called regularly for CEF to keep working.
/// </summary>
public void Update()
{
DebugTools.Assert(_initialized);
// Calling this makes CEF do its work, without using its own update loop.
CefRuntime.DoMessageLoopWork();
}
/// <summary>
/// Call before program shutdown.
/// </summary>
public void Shutdown()
{
DebugTools.Assert(_initialized);
CefRuntime.Shutdown();
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
namespace Robust.Client.CEF
{
public interface IBrowserControl
{
/// <summary>
/// Current URL of the browser. Set to load a new page.
/// </summary>
string Url { get; set; }
/// <summary>
/// Whether the browser is currently loading a page.
/// </summary>
bool IsLoading { get; }
/// <summary>
/// Stops loading the current page.
/// </summary>
void StopLoad();
/// <summary>
/// Reload the current page.
/// </summary>
void Reload();
/// <summary>
/// Navigate back.
/// </summary>
/// <returns>Whether the browser could navigate back.</returns>
bool GoBack();
/// <summary>
/// Navigate forward.
/// </summary>
/// <returns>Whether the browser could navigate forward.</returns>
bool GoForward();
/// <summary>
/// Execute arbitrary JavaScript on the current page.
/// </summary>
/// <param name="code">JavaScript code.</param>
void ExecuteJavaScript(string code);
void AddResourceRequestHandler(Action<RequestHandlerContext> handler);
void RemoveResourceRequestHandler(Action<RequestHandlerContext> handler);
}
}

View File

@@ -0,0 +1,9 @@
using System;
namespace Robust.Client.CEF
{
public interface IBrowserWindow : IBrowserControl, IDisposable
{
bool Closed { get; }
}
}

View File

@@ -0,0 +1,42 @@
using System;
using Robust.Client.UserInterface;
using Robust.Client.Utility;
using Robust.Shared.Maths;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using Xilium.CefGlue;
namespace Robust.Client.CEF
{
internal sealed class ImageBuffer
{
private readonly Control _control;
public ImageBuffer(Control control)
{
_control = control;
}
public Image<Bgra32> Buffer { get; private set; } = new(1, 1);
public unsafe void UpdateBuffer(int width, int height, IntPtr buffer, CefRectangle dirtyRect)
{
if (width != Buffer.Width || height != Buffer.Height)
UpdateSize(width, height);
var span = new ReadOnlySpan<Bgra32>((void*) buffer, width * height);
ImageSharpExt.Blit(
span,
width,
UIBox2i.FromDimensions(dirtyRect.X, dirtyRect.Y, dirtyRect.Width, dirtyRect.Height),
Buffer,
(dirtyRect.X, dirtyRect.Y));
}
private void UpdateSize(int width, int height)
{
Buffer = new Image<Bgra32>(width, height);
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using Xilium.CefGlue;
namespace Robust.Client.CEF
{
public 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)
{
// This is a workaround for this to work on UNIX.
var argv = args;
if (CefRuntime.Platform != CefRuntimePlatform.Windows)
{
argv = new string[args.Length + 1];
Array.Copy(args, 0, argv, 1, args.Length);
argv[0] = "-";
}
var mainArgs = new CefMainArgs(argv);
// This will block executing until the subprocess is shut down.
var code = CefRuntime.ExecuteProcess(mainArgs, null, IntPtr.Zero);
if (code != 0)
{
System.Console.WriteLine($"CEF Subprocess exited unsuccessfully with exit code {code}! Arguments: {string.Join(' ', argv)}");
}
return code;
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.IO;
using System.Net;
using Xilium.CefGlue;
namespace Robust.Client.CEF
{
public sealed class RequestHandlerContext
{
internal readonly CefRequest CefRequest;
public bool IsNavigation { get; }
public bool IsDownload { get; }
public string RequestInitiator { get; }
public string Url => CefRequest.Url;
public string Method => CefRequest.Method;
public bool IsHandled { get; private set; }
public bool IsCancelled { get; private set; }
internal IRequestResult? Result { get; private set; }
internal RequestHandlerContext(
bool isNavigation,
bool isDownload,
string requestInitiator,
CefRequest cefRequest)
{
CefRequest = cefRequest;
IsNavigation = isNavigation;
IsDownload = isDownload;
RequestInitiator = requestInitiator;
}
public void DoCancel()
{
CheckNotHandled();
IsHandled = true;
IsCancelled = true;
}
public void DoRespondStream(Stream stream, string contentType, HttpStatusCode code = HttpStatusCode.OK)
{
Result = new RequestResultStream(stream, contentType, code);
}
private void CheckNotHandled()
{
if (IsHandled)
throw new InvalidOperationException("Request has already been handled");
}
}
}

View File

@@ -0,0 +1,93 @@
using System;
using System.IO;
using System.Net;
using Xilium.CefGlue;
namespace Robust.Client.CEF
{
internal interface IRequestResult
{
CefResourceHandler MakeHandler();
}
internal sealed class RequestResultStream : IRequestResult
{
private readonly Stream _stream;
private readonly HttpStatusCode _code;
private readonly string _contentType;
public RequestResultStream(Stream stream, string contentType, HttpStatusCode code)
{
_stream = stream;
_code = code;
_contentType = contentType;
}
public CefResourceHandler MakeHandler()
{
return new Handler(_stream, _contentType, _code);
}
private sealed class Handler : CefResourceHandler
{
// TODO: async
// TODO: exception handling
private readonly Stream _stream;
private readonly HttpStatusCode _code;
private readonly string _contentType;
public Handler(Stream stream, string contentType, HttpStatusCode code)
{
_stream = stream;
_code = code;
_contentType = contentType;
}
protected override bool Open(CefRequest request, out bool handleRequest, CefCallback callback)
{
handleRequest = true;
return true;
}
protected override void GetResponseHeaders(CefResponse response, out long responseLength, out string? redirectUrl)
{
response.Status = (int) _code;
response.StatusText = _code.ToString();
response.MimeType = _contentType;
if (_stream.CanSeek)
responseLength = _stream.Length;
else
responseLength = -1;
redirectUrl = default;
}
protected override bool Skip(long bytesToSkip, out long bytesSkipped, CefResourceSkipCallback callback)
{
if (!_stream.CanSeek)
{
bytesSkipped = -2;
return false;
}
bytesSkipped = _stream.Seek(bytesToSkip, SeekOrigin.Begin);
return true;
}
protected override unsafe bool Read(IntPtr dataOut, int bytesToRead, out int bytesRead, CefResourceReadCallback callback)
{
var byteSpan = new Span<byte>((void*) dataOut, bytesToRead);
bytesRead = _stream.Read(byteSpan);
return bytesRead != 0;
}
protected override void Cancel()
{
}
}
}
}

View File

@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\MSBuild\Robust.Properties.targets" />
<Import Project="..\MSBuild\Robust.Engine.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputType>WinExe</OutputType>
</PropertyGroup>
<Import Project="..\MSBuild\Robust.DefineConstants.targets" />
<Target Name="RobustAfterBuild" AfterTargets="Build" />
<Import Project="..\MSBuild\Robust.Engine.targets" />
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2020.3.0" />
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\cefglue\CefGlue\CefGlue.csproj" />
<ProjectReference Include="..\Robust.Client\Robust.Client.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,48 @@
using System;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Xilium.CefGlue;
namespace Robust.Client.CEF
{
internal class RobustCefApp : CefApp
{
private readonly BrowserProcessHandler _browserProcessHandler = new();
private readonly RenderProcessHandler _renderProcessHandler = new();
protected override CefBrowserProcessHandler GetBrowserProcessHandler()
{
return _browserProcessHandler;
}
protected override CefRenderProcessHandler GetRenderProcessHandler()
{
return _renderProcessHandler;
}
protected override void OnBeforeCommandLineProcessing(string processType, CefCommandLine commandLine)
{
// Disable zygote on Linux.
commandLine.AppendSwitch("--no-zygote");
//commandLine.AppendSwitch("--disable-gpu");
//commandLine.AppendSwitch("--disable-gpu-compositing");
//commandLine.AppendSwitch("--in-process-gpu");
commandLine.AppendSwitch("disable-threaded-scrolling", "1");
commandLine.AppendSwitch("disable-features", "TouchpadAndWheelScrollLatching,AsyncWheelEvents");
if(IoCManager.Instance != null)
Logger.Debug($"{commandLine}");
}
private class BrowserProcessHandler : CefBrowserProcessHandler
{
}
// TODO CEF: Research - Is this even needed?
private class RenderProcessHandler : CefRenderProcessHandler
{
}
}
}

View File

@@ -0,0 +1,23 @@
using Xilium.CefGlue;
namespace Robust.Client.CEF
{
// Simple CEF client.
internal class RobustCefClient : CefClient
{
private readonly CefRenderHandler _renderHandler;
private readonly CefRequestHandler _requestHandler;
private readonly CefLoadHandler _loadHandler;
internal RobustCefClient(CefRenderHandler handler, CefRequestHandler requestHandler, CefLoadHandler loadHandler)
{
_renderHandler = handler;
_requestHandler = requestHandler;
_loadHandler = loadHandler;
}
protected override CefRenderHandler GetRenderHandler() => _renderHandler;
protected override CefRequestHandler GetRequestHandler() => _requestHandler;
protected override CefLoadHandler GetLoadHandler() => _loadHandler;
}
}

View File

@@ -0,0 +1,17 @@
using Xilium.CefGlue;
namespace Robust.Client.CEF
{
public sealed class RobustLoadHandler : CefLoadHandler
{
protected override void OnLoadStart(CefBrowser browser, CefFrame frame, CefTransitionType transitionType)
{
base.OnLoadStart(browser, frame, transitionType);
}
protected override void OnLoadEnd(CefBrowser browser, CefFrame frame, int httpStatusCode)
{
base.OnLoadEnd(browser, frame, httpStatusCode);
}
}
}

View File

@@ -0,0 +1,128 @@
using System;
using System.Collections.Generic;
using Robust.Shared.Log;
using Xilium.CefGlue;
namespace Robust.Client.CEF
{
internal sealed class RobustRequestHandler : CefRequestHandler
{
private readonly ISawmill _sawmill;
private readonly List<Action<RequestHandlerContext>> _resourceRequestHandlers = new();
private readonly List<Action<BeforeBrowseContext>> _beforeBrowseHandlers = new();
public RobustRequestHandler(ISawmill sawmill)
{
_sawmill = sawmill;
}
public void AddResourceRequestHandler(Action<RequestHandlerContext> handler)
{
lock (_resourceRequestHandlers)
{
_resourceRequestHandlers.Add(handler);
}
}
public void RemoveResourceRequestHandler(Action<RequestHandlerContext> handler)
{
lock (_resourceRequestHandlers)
{
_resourceRequestHandlers.Remove(handler);
}
}
public void AddBeforeBrowseHandler(Action<BeforeBrowseContext> handler)
{
lock (_beforeBrowseHandlers)
{
_beforeBrowseHandlers.Add(handler);
}
}
public void RemoveBeforeBrowseHandler(Action<BeforeBrowseContext> handler)
{
lock (_beforeBrowseHandlers)
{
_beforeBrowseHandlers.Remove(handler);
}
}
protected override CefResourceRequestHandler? GetResourceRequestHandler(
CefBrowser browser,
CefFrame frame,
CefRequest request,
bool isNavigation,
bool isDownload,
string requestInitiator,
ref bool disableDefaultHandling)
{
lock (_resourceRequestHandlers)
{
_sawmill.Debug($"HANDLING REQUEST: {request.Url}");
var context = new RequestHandlerContext(isNavigation, isDownload, requestInitiator, request);
foreach (var handler in _resourceRequestHandlers)
{
handler(context);
if (context.IsHandled)
disableDefaultHandling = true;
if (context.IsCancelled)
return null;
if (context.Result != null)
return new WrapReaderResourceHandler(context.Result.MakeHandler());
}
}
return null;
}
protected override bool OnBeforeBrowse(CefBrowser browser, CefFrame frame, CefRequest request, bool userGesture, bool isRedirect)
{
lock (_beforeBrowseHandlers)
{
var context = new BeforeBrowseContext(isRedirect, userGesture, request);
foreach (var handler in _beforeBrowseHandlers)
{
handler(context);
if (context.IsCancelled)
return true;
}
}
return false;
}
private sealed class WrapReaderResourceHandler : CefResourceRequestHandler
{
private readonly CefResourceHandler _handler;
public WrapReaderResourceHandler(CefResourceHandler handler)
{
_handler = handler;
}
protected override CefCookieAccessFilter? GetCookieAccessFilter(
CefBrowser browser,
CefFrame frame,
CefRequest request)
{
return null;
}
protected override CefResourceHandler GetResourceHandler(
CefBrowser browser,
CefFrame frame,
CefRequest request)
{
return _handler;
}
}
}
}

View File

@@ -0,0 +1,101 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.Build.Framework;
namespace Robust.Build.Tasks
{
/// <summary>
/// Based on https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs
/// </summary>
public class CompileRobustXamlTask : ITask
{
public bool Execute()
{
//Debugger.Launch();
OutputPath = OutputPath ?? AssemblyFile;
var outputPdb = GetPdbPath(OutputPath);
var input = AssemblyFile;
var inputPdb = GetPdbPath(input);
// Make a copy and delete the original file to prevent MSBuild from thinking that everything is OK
if (OriginalCopyPath != null)
{
File.Copy(AssemblyFile, OriginalCopyPath, true);
input = OriginalCopyPath;
File.Delete(AssemblyFile);
if (File.Exists(inputPdb))
{
var copyPdb = GetPdbPath(OriginalCopyPath);
File.Copy(inputPdb, copyPdb, true);
File.Delete(inputPdb);
inputPdb = copyPdb;
}
}
var msg = $"CompileRobustXamlTask -> AssemblyFile:{AssemblyFile}, ProjectDirectory:{ProjectDirectory}, OutputPath:{OutputPath}";
BuildEngine.LogMessage(msg, MessageImportance.High);
var res = XamlCompiler.Compile(BuildEngine, input,
File.ReadAllLines(ReferencesFilePath).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray(),
ProjectDirectory, OutputPath,
(SignAssembly && !DelaySign) ? AssemblyOriginatorKeyFile : null);
if (!res.success)
return false;
if (!res.writtentofile)
{
File.Copy(input, OutputPath, true);
if(File.Exists(inputPdb))
File.Copy(inputPdb, outputPdb, true);
}
if (!string.IsNullOrEmpty(UpdateBuildIndicator))
{
if (!File.Exists(UpdateBuildIndicator))
{
File.Create(UpdateBuildIndicator).Dispose();
}
else
{
File.SetLastWriteTime(UpdateBuildIndicator, DateTime.Now);
}
}
return true;
}
[Required]
public string ReferencesFilePath { get; set; }
[Required]
public string ProjectDirectory { get; set; }
[Required]
public string AssemblyFile { get; set; }
[Required]
public string OriginalCopyPath { get; set; }
public string OutputPath { get; set; }
public string UpdateBuildIndicator { get; set; }
public string AssemblyOriginatorKeyFile { get; set; }
public bool SignAssembly { get; set; }
public bool DelaySign { get; set; }
// shamelessly copied from avalonia
string GetPdbPath(string p)
{
var d = Path.GetDirectoryName(p);
var f = Path.GetFileNameWithoutExtension(p);
var rv = f + ".pdb";
if (d != null)
rv = Path.Combine(d, rv);
return rv;
}
public IBuildEngine BuildEngine { get; set; }
public ITaskHost HostObject { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using Microsoft.Build.Framework;
namespace Robust.Build.Tasks
{
/// <summary>
/// Taken from https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Avalonia.Build.Tasks/Extensions.cs
/// </summary>
public static class Extensions
{
//shamefully copied from avalonia
public static void LogMessage(this IBuildEngine engine, string message, MessageImportance imp)
{
engine.LogMessageEvent(new BuildMessageEventArgs(message, "", "Avalonia", imp));
}
}
}

View File

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

View File

@@ -0,0 +1,63 @@
using System;
using System.Collections;
using System.IO;
using Microsoft.Build.Framework;
namespace Robust.Build.Tasks
{
/// <summary>
/// Based on https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Avalonia.Build.Tasks/Program.cs
/// </summary>
class Program
{
static int Main(string[] args)
{
if (args.Length != 3)
{
Console.Error.WriteLine("expected: input references output");
return 1;
}
return new CompileRobustXamlTask
{
AssemblyFile = args[0],
ReferencesFilePath = args[1],
OutputPath = args[2],
BuildEngine = new ConsoleBuildEngine(),
ProjectDirectory = Directory.GetCurrentDirectory()
}.Execute() ? 0 : 2;
}
}
//formatted according to https://github.com/dotnet/msbuild/blob/main/src/Shared/CanonicalError.cs#L57
class ConsoleBuildEngine : IBuildEngine
{
public void LogErrorEvent(BuildErrorEventArgs e)
{
Console.WriteLine($"{e.File} ({e.LineNumber},{e.ColumnNumber},{e.EndLineNumber},{e.EndColumnNumber}): XAMLIL ERROR {e.Code}: {e.Message}");
}
public void LogWarningEvent(BuildWarningEventArgs e)
{
Console.WriteLine($"{e.File} ({e.LineNumber},{e.ColumnNumber},{e.EndLineNumber},{e.EndColumnNumber}): XAMLIL WARNING {e.Code}: {e.Message}");
}
public void LogMessageEvent(BuildMessageEventArgs e)
{
Console.WriteLine($"{e.File} ({e.LineNumber},{e.ColumnNumber},{e.EndLineNumber},{e.EndColumnNumber}): XAMLIL MESSAGE {e.Code}: {e.Message}");
}
public void LogCustomEvent(CustomBuildEventArgs e)
{
Console.WriteLine(e.Message);
}
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; }
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build.Framework" Version="16.8.0" />
<PackageReference Include="Mono.Cecil" Version="0.11.3" />
<PackageReference Include="Pidgin" Version="2.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\XamlX\src\XamlX.IL.Cecil\XamlX.IL.Cecil.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,225 @@
using System.Diagnostics;
using System.Linq;
using XamlX;
using XamlX.Ast;
using XamlX.Emit;
using XamlX.IL;
using XamlX.Transform;
using XamlX.TypeSystem;
namespace Robust.Build.Tasks
{
/// <summary>
/// Emitters & Transformers based on:
/// - https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlRootObjectScopeTransformer.cs
/// - https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AddNameScopeRegistration.cs
/// - https://github.com/AvaloniaUI/Avalonia/blob/afb8ae6f3c517dae912729511483995b16cb31af/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/IgnoredDirectivesTransformer.cs
/// </summary>
public class RobustXamlILCompiler : XamlILCompiler
{
public RobustXamlILCompiler(TransformerConfiguration configuration, XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult> emitMappings, bool fillWithDefaults) : base(configuration, emitMappings, fillWithDefaults)
{
Transformers.Insert(0, new IgnoredDirectivesTransformer());
Transformers.Add(new AddNameScopeRegistration());
Transformers.Add(new RobustMarkRootObjectScopeNode());
Emitters.Add(new AddNameScopeRegistration.Emitter());
Emitters.Add(new RobustMarkRootObjectScopeNode.Emitter());
}
class AddNameScopeRegistration : IXamlAstTransformer
{
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
{
if (node is XamlPropertyAssignmentNode pa)
{
if (pa.Property.Name == "Name"
&& pa.Property.DeclaringType.FullName == "Robust.Client.UserInterface.Control")
{
if (context.ParentNodes().FirstOrDefault() is XamlManipulationGroupNode mg
&& mg.Children.OfType<RobustNameScopeRegistrationXamlIlNode>().Any())
return node;
IXamlAstValueNode value = null;
for (var c = 0; c < pa.Values.Count; c++)
if (pa.Values[c].Type.GetClrType().Equals(context.Configuration.WellKnownTypes.String))
{
value = pa.Values[c];
if (!(value is XamlAstTextNode))
{
var local = new XamlAstCompilerLocalNode(value);
// Wrap original in local initialization
pa.Values[c] = new XamlAstLocalInitializationNodeEmitter(value, value, local);
// Use local
value = local;
}
break;
}
if (value != null)
{
var objectType = context.ParentNodes().OfType<XamlAstConstructableObjectNode>().FirstOrDefault()?.Type.GetClrType();
return new XamlManipulationGroupNode(pa)
{
Children =
{
pa,
new RobustNameScopeRegistrationXamlIlNode(value, objectType)
}
};
}
}
/*else if (pa.Property.CustomAttributes.Select(attr => attr.Type).Intersect(context.Configuration.TypeMappings.DeferredContentPropertyAttributes).Any())
{
pa.Values[pa.Values.Count - 1] =
new NestedScopeMetadataNode(pa.Values[pa.Values.Count - 1]);
}*/
}
return node;
}
class RobustNameScopeRegistrationXamlIlNode : XamlAstNode, IXamlAstManipulationNode
{
public IXamlAstValueNode Name { get; set; }
public IXamlType TargetType { get; }
public RobustNameScopeRegistrationXamlIlNode(IXamlAstValueNode name, IXamlType targetType) : base(name)
{
TargetType = targetType;
Name = name;
}
public override void VisitChildren(IXamlAstVisitor visitor)
=> Name = (IXamlAstValueNode)Name.Visit(visitor);
}
internal class Emitter : IXamlAstLocalsNodeEmitter<IXamlILEmitter, XamlILNodeEmitResult>
{
public XamlILNodeEmitResult Emit(IXamlAstNode node, XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{
if (node is RobustNameScopeRegistrationXamlIlNode registration)
{
var scopeField = context.RuntimeContext.ContextType.Fields.First(f =>
f.Name == XamlCompiler.ContextNameScopeFieldName);
var namescopeRegisterFunction = context.Configuration.TypeSystem
.FindType("Robust.Client.UserInterface.XAML.NameScope").Methods
.First(m => m.Name == "Register");
using (var targetLoc = context.GetLocalOfType(context.Configuration.TypeSystem.FindType("Robust.Client.UserInterface.Control")))
{
codeGen
// var target = {pop}
.Stloc(targetLoc.Local)
// _context.NameScope.Register(Name, target)
.Ldloc(context.ContextLocal)
.Ldfld(scopeField);
context.Emit(registration.Name, codeGen, registration.Name.Type.GetClrType());
codeGen
.Ldloc(targetLoc.Local)
.EmitCall(namescopeRegisterFunction, true);
}
return XamlILNodeEmitResult.Void(1);
}
return default;
}
}
}
class RobustMarkRootObjectScopeNode : IXamlAstTransformer
{
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
{
if (!context.ParentNodes().Any()
&& node is XamlValueWithManipulationNode mnode)
{
mnode.Manipulation = new XamlManipulationGroupNode(mnode,
new[]
{
mnode.Manipulation,
new HandleRootObjectScopeNode(mnode)
});
}
return node;
}
class HandleRootObjectScopeNode : XamlAstNode, IXamlAstManipulationNode
{
public HandleRootObjectScopeNode(IXamlLineInfo lineInfo) : base(lineInfo)
{
}
}
internal class Emitter : IXamlILAstNodeEmitter
{
public XamlILNodeEmitResult Emit(IXamlAstNode node, XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{
if (!(node is HandleRootObjectScopeNode))
{
return null;
}
var controlType = context.Configuration.TypeSystem.FindType("Robust.Client.UserInterface.Control");
var next = codeGen.DefineLabel();
var dontAbsorb = codeGen.DefineLabel();
var end = codeGen.DefineLabel();
var contextScopeField = context.RuntimeContext.ContextType.Fields.First(f =>
f.Name == XamlCompiler.ContextNameScopeFieldName);
var controlNameScopeField = controlType.Fields.First(f => f.Name == "NameScope");
var nameScopeType = context.Configuration.TypeSystem
.FindType("Robust.Client.UserInterface.XAML.NameScope");
var nameScopeCompleteMethod = nameScopeType.Methods.First(m => m.Name == "Complete");
var nameScopeAbsorbMethod = nameScopeType.Methods.First(m => m.Name == "Absorb");
using (var local = codeGen.LocalsPool.GetLocal(controlType))
{
codeGen
.Isinst(controlType)
.Dup()
.Stloc(local.Local) //store control in local field
.Brfalse(next) //if control is null, move to next (this should never happen but whatev, avalonia does it)
.Ldloc(context.ContextLocal)
.Ldfld(contextScopeField)
.Ldloc(local.Local) //load control from local field
.Ldfld(controlNameScopeField) //load namescope field from control
.EmitCall(nameScopeAbsorbMethod, true)
.Ldloc(local.Local) //load control
.Ldloc(context.ContextLocal) //load contextObject
.Ldfld(contextScopeField) //load namescope field from context obj
.Stfld(controlNameScopeField) //store namescope field in control
.MarkLabel(next)
.Ldloc(context.ContextLocal)
.Ldfld(contextScopeField)
.EmitCall(nameScopeCompleteMethod, true); //set the namescope as complete
}
return XamlILNodeEmitResult.Void(1);
}
}
}
class IgnoredDirectivesTransformer : IXamlAstTransformer
{
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
{
if (node is XamlAstObjectNode astNode)
{
astNode.Children.RemoveAll(n =>
n is XamlAstXmlDirective dir &&
dir.Namespace == XamlNamespaces.Xaml2006 &&
(dir.Name == "Class" ||
dir.Name == "Precompile" ||
dir.Name == "FieldModifier" ||
dir.Name == "ClassModifier"));
}
return node;
}
}
}
}

View File

@@ -0,0 +1,78 @@
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using XamlX.TypeSystem;
namespace Robust.Build.Tasks
{
/// <summary>
/// Helpers taken from:
/// - https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
/// - https://github.com/AvaloniaUI/Avalonia/blob/c85fa2b9977d251a31886c2534613b4730fbaeaf/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.Helpers.cs
/// </summary>
public partial class XamlCompiler
{
static bool CheckXamlName(IResource r) => r.Name.ToLowerInvariant().EndsWith(".xaml")
|| r.Name.ToLowerInvariant().EndsWith(".paml")
|| r.Name.ToLowerInvariant().EndsWith(".axaml");
private static bool MatchThisCall(Collection<Instruction> instructions, int idx)
{
var i = instructions[idx];
// A "normal" way of passing `this` to a static method:
// ldarg.0
// call void [Avalonia.Markup.Xaml]Avalonia.Markup.Xaml.AvaloniaXamlLoader::Load(object)
return i.OpCode == OpCodes.Ldarg_0 || (i.OpCode == OpCodes.Ldarg && i.Operand?.Equals(0) == true);
}
interface IResource : IFileSource
{
string Uri { get; }
string Name { get; }
void Remove();
}
interface IResourceGroup
{
string Name { get; }
IEnumerable<IResource> Resources { get; }
}
class EmbeddedResources : IResourceGroup
{
private readonly AssemblyDefinition _asm;
public string Name => "EmbeddedResource";
public IEnumerable<IResource> Resources => _asm.MainModule.Resources.OfType<EmbeddedResource>()
.Select(r => new WrappedResource(_asm, r)).ToList();
public EmbeddedResources(AssemblyDefinition asm)
{
_asm = asm;
}
class WrappedResource : IResource
{
private readonly AssemblyDefinition _asm;
private readonly EmbeddedResource _res;
public WrappedResource(AssemblyDefinition asm, EmbeddedResource res)
{
_asm = asm;
_res = res;
}
public string Uri => $"resm:{Name}?assembly={_asm.Name.Name}";
public string Name => _res.Name;
public string FilePath => Name;
public byte[] FileContents => _res.GetResourceData();
public void Remove() => _asm.MainModule.Resources.Remove(_res);
}
}
}
}

View File

@@ -0,0 +1,434 @@
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("Robust.Client.UserInterface.XAML.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);
var loaderDispatcherDef = new TypeDefinition("CompiledRobustXaml", "!XamlLoader",
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
var loaderDispatcherMethod = new MethodDefinition("TryLoad",
MethodAttributes.Static | MethodAttributes.Public,
asm.MainModule.TypeSystem.Object)
{
Parameters = {new ParameterDefinition(asm.MainModule.TypeSystem.String)}
};
loaderDispatcherDef.Methods.Add(loaderDispatcherMethod);
asm.MainModule.Types.Add(loaderDispatcherDef);
var stringEquals = asm.MainModule.ImportReference(asm.MainModule.TypeSystem.String.Resolve().Methods.First(
m =>
m.IsStatic && m.Name == "Equals" && m.Parameters.Count == 2 &&
m.ReturnType.FullName == "System.Boolean"
&& m.Parameters[0].ParameterType.FullName == "System.String"
&& m.Parameters[1].ParameterType.FullName == "System.String"));
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.");
}
}
//add compiled build method
var compiledBuildMethod = typeSystem.GetTypeReference(builder).Resolve().Methods
.First(m => m.Name == buildName);
var parameterlessCtor = classTypeDefinition.GetConstructors()
.FirstOrDefault(c => c.IsPublic && !c.IsStatic && !c.HasParameters);
if (compiledBuildMethod != null && parameterlessCtor != null)
{
var i = loaderDispatcherMethod.Body.Instructions;
var nop = Instruction.Create(OpCodes.Nop);
i.Add(Instruction.Create(OpCodes.Ldarg_0));
i.Add(Instruction.Create(OpCodes.Ldstr, res.Uri));
i.Add(Instruction.Create(OpCodes.Call, stringEquals));
i.Add(Instruction.Create(OpCodes.Brfalse, nop));
if (parameterlessCtor != null)
i.Add(Instruction.Create(OpCodes.Newobj, parameterlessCtor));
else
{
i.Add(Instruction.Create(OpCodes.Call, compiledBuildMethod));
}
i.Add(Instruction.Create(OpCodes.Ret));
i.Add(nop);
}
}
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;
}
loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull));
loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
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

@@ -0,0 +1,19 @@
using System;
using Microsoft.CodeAnalysis;
namespace Robust.Client.NameGenerator
{
public class InvalidXamlRootTypeException : Exception
{
public readonly INamedTypeSymbol ExpectedType;
public readonly INamedTypeSymbol ExpectedBaseType;
public readonly INamedTypeSymbol Actual;
public InvalidXamlRootTypeException(INamedTypeSymbol actual, INamedTypeSymbol expectedType, INamedTypeSymbol expectedBaseType)
{
Actual = actual;
ExpectedType = expectedType;
ExpectedBaseType = expectedBaseType;
}
}
}

View File

@@ -0,0 +1,21 @@
using System.Collections.Generic;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Robust.Client.NameGenerator
{
/// <summary>
/// Taken from https://github.com/AvaloniaUI/Avalonia.NameGenerator/blob/ecc9677a23de5cbc90af07ccac14e31c0da41d6a/src/Avalonia.NameGenerator/NameReferenceSyntaxReceiver.cs
/// </summary>
internal class NameReferenceSyntaxReceiver : ISyntaxReceiver
{
public List<ClassDeclarationSyntax> CandidateClasses { get; } = new List<ClassDeclarationSyntax>();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax &&
classDeclarationSyntax.AttributeLists.Count > 0)
CandidateClasses.Add(classDeclarationSyntax);
}
}
}

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<Compile Link="XamlX\filename" Include="../XamlX/src/XamlX/**/*.cs" />
<Compile Remove="../XamlX/src/XamlX/**/SreTypeSystem.cs" />
<Compile Remove="../XamlX/src/XamlX/obj/**" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,287 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using XamlX.TypeSystem;
namespace Robust.Client.NameGenerator
{
/// <summary>
/// Taken from https://github.com/AvaloniaUI/Avalonia.NameGenerator/blob/ecc9677a23de5cbc90af07ccac14e31c0da41d6a/src/Avalonia.NameGenerator/Infrastructure/RoslynTypeSystem.cs
/// </summary>
public class RoslynTypeSystem : IXamlTypeSystem
{
private readonly List<IXamlAssembly> _assemblies = new List<IXamlAssembly>();
public RoslynTypeSystem(CSharpCompilation compilation)
{
_assemblies.Add(new RoslynAssembly(compilation.Assembly));
var assemblySymbols = compilation
.References
.Select(compilation.GetAssemblyOrModuleSymbol)
.OfType<IAssemblySymbol>()
.Select(assembly => new RoslynAssembly(assembly))
.ToList();
_assemblies.AddRange(assemblySymbols);
}
public IReadOnlyList<IXamlAssembly> Assemblies => _assemblies;
public IXamlAssembly FindAssembly(string substring) => _assemblies[0];
public IXamlType FindType(string name)
{
foreach (var assembly in _assemblies)
{
var type = assembly.FindType(name);
if (type != null)
return type;
}
return null;
}
public IXamlType FindType(string name, string assembly)
{
foreach (var assemblyInstance in _assemblies)
{
var type = assemblyInstance.FindType(name);
if (type != null)
return type;
}
return null;
}
}
public class RoslynAssembly : IXamlAssembly
{
private readonly IAssemblySymbol _symbol;
public RoslynAssembly(IAssemblySymbol symbol) => _symbol = symbol;
public bool Equals(IXamlAssembly other) =>
other is RoslynAssembly roslynAssembly &&
SymbolEqualityComparer.Default.Equals(_symbol, roslynAssembly._symbol);
public string Name => _symbol.Name;
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes =>
_symbol.GetAttributes()
.Select(data => new RoslynAttribute(data, this))
.ToList();
public IXamlType FindType(string fullName)
{
var type = _symbol.GetTypeByMetadataName(fullName);
return type is null ? null : new RoslynType(type, this);
}
}
public class RoslynAttribute : IXamlCustomAttribute
{
private readonly AttributeData _data;
private readonly RoslynAssembly _assembly;
public RoslynAttribute(AttributeData data, RoslynAssembly assembly)
{
_data = data;
_assembly = assembly;
}
public bool Equals(IXamlCustomAttribute other) =>
other is RoslynAttribute attribute &&
_data == attribute._data;
public IXamlType Type => new RoslynType(_data.AttributeClass, _assembly);
public List<object> Parameters =>
_data.ConstructorArguments
.Select(argument => argument.Value)
.ToList();
public Dictionary<string, object> Properties =>
_data.NamedArguments.ToDictionary(
pair => pair.Key,
pair => pair.Value.Value);
}
public class RoslynType : IXamlType
{
private static readonly SymbolDisplayFormat SymbolDisplayFormat = new SymbolDisplayFormat(
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters |
SymbolDisplayGenericsOptions.IncludeTypeConstraints |
SymbolDisplayGenericsOptions.IncludeVariance);
private readonly RoslynAssembly _assembly;
private readonly INamedTypeSymbol _symbol;
public RoslynType(INamedTypeSymbol symbol, RoslynAssembly assembly)
{
_symbol = symbol;
_assembly = assembly;
}
public bool Equals(IXamlType other) =>
other is RoslynType roslynType &&
SymbolEqualityComparer.Default.Equals(_symbol, roslynType._symbol);
public object Id => _symbol;
public string Name => _symbol.Name;
public string Namespace => _symbol.ContainingNamespace.ToDisplayString(SymbolDisplayFormat);
public string FullName => $"{Namespace}.{Name}";
public IXamlAssembly Assembly => _assembly;
public IReadOnlyList<IXamlProperty> Properties =>
_symbol.GetMembers()
.Where(member => member.Kind == SymbolKind.Property)
.OfType<IPropertySymbol>()
.Select(property => new RoslynProperty(property, _assembly))
.ToList();
public IReadOnlyList<IXamlEventInfo> Events { get; } = new List<IXamlEventInfo>();
public IReadOnlyList<IXamlField> Fields { get; } = new List<IXamlField>();
public IReadOnlyList<IXamlMethod> Methods { get; } = new List<IXamlMethod>();
public IReadOnlyList<IXamlConstructor> Constructors =>
_symbol.Constructors
.Select(method => new RoslynConstructor(method, _assembly))
.ToList();
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes { get; } = new List<IXamlCustomAttribute>();
public IReadOnlyList<IXamlType> GenericArguments { get; } = new List<IXamlType>();
public bool IsAssignableFrom(IXamlType type) => type == this;
public IXamlType MakeGenericType(IReadOnlyList<IXamlType> typeArguments) => this;
public IXamlType GenericTypeDefinition => this;
public bool IsArray => false;
public IXamlType ArrayElementType { get; } = null;
public IXamlType MakeArrayType(int dimensions) => null;
public IXamlType BaseType => _symbol.BaseType == null ? null : new RoslynType(_symbol.BaseType, _assembly);
public bool IsValueType { get; } = false;
public bool IsEnum { get; } = false;
public IReadOnlyList<IXamlType> Interfaces =>
_symbol.AllInterfaces
.Select(abstraction => new RoslynType(abstraction, _assembly))
.ToList();
public bool IsInterface => _symbol.IsAbstract;
public IXamlType GetEnumUnderlyingType() => null;
public IReadOnlyList<IXamlType> GenericParameters { get; } = new List<IXamlType>();
}
public class RoslynConstructor : IXamlConstructor
{
private readonly IMethodSymbol _symbol;
private readonly RoslynAssembly _assembly;
public RoslynConstructor(IMethodSymbol symbol, RoslynAssembly assembly)
{
_symbol = symbol;
_assembly = assembly;
}
public bool Equals(IXamlConstructor other) =>
other is RoslynConstructor roslynConstructor &&
SymbolEqualityComparer.Default.Equals(_symbol, roslynConstructor._symbol);
public bool IsPublic => true;
public bool IsStatic => false;
public IReadOnlyList<IXamlType> Parameters =>
_symbol.Parameters
.Select(parameter => parameter.Type)
.OfType<INamedTypeSymbol>()
.Select(type => new RoslynType(type, _assembly))
.ToList();
}
public class RoslynProperty : IXamlProperty
{
private readonly IPropertySymbol _symbol;
private readonly RoslynAssembly _assembly;
public RoslynProperty(IPropertySymbol symbol, RoslynAssembly assembly)
{
_symbol = symbol;
_assembly = assembly;
}
public bool Equals(IXamlProperty other) =>
other is RoslynProperty roslynProperty &&
SymbolEqualityComparer.Default.Equals(_symbol, roslynProperty._symbol);
public string Name => _symbol.Name;
public IXamlType PropertyType =>
_symbol.Type is INamedTypeSymbol namedTypeSymbol
? new RoslynType(namedTypeSymbol, _assembly)
: null;
public IXamlMethod Getter => _symbol.GetMethod == null ? null : new RoslynMethod(_symbol.GetMethod, _assembly);
public IXamlMethod Setter => _symbol.SetMethod == null ? null : new RoslynMethod(_symbol.SetMethod, _assembly);
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes { get; } = new List<IXamlCustomAttribute>();
public IReadOnlyList<IXamlType> IndexerParameters { get; } = new List<IXamlType>();
}
public class RoslynMethod : IXamlMethod
{
private readonly IMethodSymbol _symbol;
private readonly RoslynAssembly _assembly;
public RoslynMethod(IMethodSymbol symbol, RoslynAssembly assembly)
{
_symbol = symbol;
_assembly = assembly;
}
public bool Equals(IXamlMethod other) =>
other is RoslynMethod roslynMethod &&
SymbolEqualityComparer.Default.Equals(roslynMethod._symbol, _symbol);
public string Name => _symbol.Name;
public bool IsPublic => true;
public bool IsStatic => false;
public IXamlType ReturnType => new RoslynType((INamedTypeSymbol) _symbol.ReturnType, _assembly);
public IReadOnlyList<IXamlType> Parameters =>
_symbol.Parameters.Select(parameter => parameter.Type)
.OfType<INamedTypeSymbol>()
.Select(type => new RoslynType(type, _assembly))
.ToList();
public IXamlType DeclaringType => new RoslynType((INamedTypeSymbol)_symbol.ReceiverType, _assembly);
public IXamlMethod MakeGenericMethod(IReadOnlyList<IXamlType> typeArguments) => null;
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes { get; } = new List<IXamlCustomAttribute>();
}
}

View File

@@ -0,0 +1,299 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using XamlX.Ast;
using XamlX.Emit;
using XamlX.IL;
using XamlX.Parsers;
using XamlX.Transform;
using XamlX.Transform.Transformers;
using XamlX.TypeSystem;
namespace Robust.Client.NameGenerator
{
/// <summary>
/// Based on https://github.com/AvaloniaUI/Avalonia.NameGenerator/blob/ecc9677a23de5cbc90af07ccac14e31c0da41d6a/src/Avalonia.NameGenerator/NameReferenceGenerator.cs
/// Adjusted for our UI-Framework & needs.
/// </summary>
[Generator]
public class XamlUiPartialClassGenerator : ISourceGenerator
{
private const string AttributeName = "Robust.Client.AutoGenerated.GenerateTypedNameReferencesAttribute";
private const string AttributeFile = "GenerateTypedNameReferencesAttribute";
private const string AttributeCode = @"// <auto-generated />
using System;
namespace Robust.Client.AutoGenerated
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class GenerateTypedNameReferencesAttribute : Attribute { }
}
";
class NameVisitor : IXamlAstVisitor
{
private List<(string name, string type)> _names = new List<(string name, string type)>();
public static List<(string name, string type)> GetNames(IXamlAstNode node)
{
var visitor = new NameVisitor();
node.Visit(visitor);
return visitor._names;
}
private bool IsControl(IXamlType type) => type.FullName != "System.Object" &&
(type.FullName == "Robust.Client.UserInterface.Control" ||
IsControl(type.BaseType));
public IXamlAstNode Visit(IXamlAstNode node)
{
if (node is XamlAstObjectNode objectNode)
{
var clrtype = objectNode.Type.GetClrType();
var isControl = IsControl(clrtype);
//clrtype.Interfaces.Any(i =>
//i.IsInterface && i.FullName == "Robust.Client.UserInterface.IControl");
if (!isControl)
return node;
foreach (var child in objectNode.Children)
{
if (child is XamlAstXamlPropertyValueNode propertyValueNode &&
propertyValueNode.Property is XamlAstNamePropertyReference namedProperty &&
namedProperty.Name == "Name" &&
propertyValueNode.Values.Count > 0 &&
propertyValueNode.Values[0] is XamlAstTextNode text)
{
var reg = (text.Text, $@"{clrtype.Namespace}.{clrtype.Name}");
if (!_names.Contains(reg))
{
_names.Add(reg);
}
}
}
}
return node;
}
public void Push(IXamlAstNode node)
{
}
public void Pop()
{
}
}
private static string GenerateSourceCode(
INamedTypeSymbol classSymbol,
string xamlFile,
CSharpCompilation comp)
{
var className = classSymbol.Name;
var nameSpace = classSymbol.ContainingNamespace.ToDisplayString();
var parsed = XDocumentXamlParser.Parse(xamlFile);
var typeSystem = new RoslynTypeSystem(comp);
var compiler =
new XamlILCompiler(
new TransformerConfiguration(typeSystem, typeSystem.Assemblies[0],
new XamlLanguageTypeMappings(typeSystem)
{
XmlnsAttributes = {typeSystem.GetType("Avalonia.Metadata.XmlnsDefinitionAttribute")}
}),
new XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult>(), false);
compiler.Transformers.Add(new TypeReferenceResolver());
compiler.Transform(parsed);
var initialRoot = (XamlAstObjectNode) parsed.Root;
var names = NameVisitor.GetNames(initialRoot);
var rootType = (INamedTypeSymbol)initialRoot.Type.GetClrType().Id;
var rootTypeString = rootType.ToString();
if (classSymbol.ToString() != rootTypeString && classSymbol.BaseType?.ToString() != rootTypeString)
throw new InvalidXamlRootTypeException(rootType, classSymbol, classSymbol.BaseType);
var fieldAccess = classSymbol.IsSealed ? "private" : "protected";
//var names = NameVisitor.GetNames((XamlAstObjectNode)XDocumentXamlParser.Parse(xamlFile).Root);
var namedControls = names.Select(info => " " +
$"{fieldAccess} global::{info.type} {info.name} => " +
$"this.FindControl<global::{info.type}>(\"{info.name}\");");
return $@"// <auto-generated />
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
namespace {nameSpace}
{{
partial class {className}
{{
{string.Join("\n", namedControls)}
}}
}}
";
}
public void Execute(GeneratorExecutionContext context)
{
var comp = (CSharpCompilation) context.Compilation;
if (comp.GetTypeByMetadataName(AttributeName) == null)
context.AddSource(AttributeFile, SourceText.From(AttributeCode, Encoding.UTF8));
if (!(context.SyntaxReceiver is NameReferenceSyntaxReceiver receiver))
{
return;
}
var symbols = UnpackAnnotatedTypes(context, comp, receiver);
if (symbols == null)
return;
foreach (var typeSymbol in symbols)
{
var xamlFileName = $"{typeSymbol.Name}.xaml";
var xamlFileNameSep = $"{Path.DirectorySeparatorChar}{xamlFileName}";
var relevantXamlFiles = context.AdditionalFiles.Where(t => t.Path.EndsWith(xamlFileNameSep)).ToArray();
if (relevantXamlFiles.Length == 0)
{
context.ReportDiagnostic(
Diagnostic.Create(
new DiagnosticDescriptor(
"RXN0001",
$"Unable to discover the relevant Robust XAML file for {typeSymbol}.",
"Unable to discover the relevant Robust XAML file " +
$"expected at {xamlFileName}",
"Usage",
DiagnosticSeverity.Error,
true),
typeSymbol.Locations[0]));
continue;
}
if (relevantXamlFiles.Length > 1)
{
context.ReportDiagnostic(
Diagnostic.Create(
new DiagnosticDescriptor(
"RXN0002",
$"Found multiple candidate XAML files for {typeSymbol}",
$"Multiple files exist with name {xamlFileName}",
"Usage",
DiagnosticSeverity.Error,
true),
typeSymbol.Locations[0]));
continue;
}
var txt = relevantXamlFiles[0].GetText()?.ToString();
if (txt == null)
{
context.ReportDiagnostic(
Diagnostic.Create(
new DiagnosticDescriptor(
"RXN0004",
$"Unexpected empty Xaml-File was found at {xamlFileName}",
"Expected Content due to a Class with the same name being annotated with [GenerateTypedNameReferences].",
"Usage",
DiagnosticSeverity.Error,
true),
Location.Create(xamlFileName, new TextSpan(0, 0),
new LinePositionSpan(new LinePosition(0, 0), new LinePosition(0, 0)))));
continue;
}
try
{
var sourceCode = GenerateSourceCode(typeSymbol, txt, comp);
context.AddSource($"{typeSymbol.Name}.g.cs", SourceText.From(sourceCode, Encoding.UTF8));
}
catch (InvalidXamlRootTypeException invRootType)
{
context.ReportDiagnostic(
Diagnostic.Create(
new DiagnosticDescriptor(
"RXN0005",
$"XAML-File {xamlFileName} has the wrong root type!",
$"{xamlFileName}: Expected root type '{invRootType.ExpectedType}' or '{invRootType.ExpectedBaseType}', but got '{invRootType.Actual}'.",
"Usage",
DiagnosticSeverity.Error,
true),
Location.Create(xamlFileName, new TextSpan(0, 0),
new LinePositionSpan(new LinePosition(0, 0), new LinePosition(0, 0)))));
continue;
}
catch (Exception e)
{
context.ReportDiagnostic(
Diagnostic.Create(
new DiagnosticDescriptor(
"RXN0003",
"Unhandled exception occured while generating typed Name references.",
$"Unhandled exception occured while generating typed Name references: {e}",
"Usage",
DiagnosticSeverity.Error,
true),
typeSymbol.Locations[0]));
continue;
}
}
}
private IReadOnlyList<INamedTypeSymbol> UnpackAnnotatedTypes(in GeneratorExecutionContext context,
CSharpCompilation comp, NameReferenceSyntaxReceiver receiver)
{
var options = (CSharpParseOptions) comp.SyntaxTrees[0].Options;
var compilation =
comp.AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(AttributeCode, Encoding.UTF8), options));
var symbols = new List<INamedTypeSymbol>();
var attributeSymbol = compilation.GetTypeByMetadataName(AttributeName);
foreach (var candidateClass in receiver.CandidateClasses)
{
var model = compilation.GetSemanticModel(candidateClass.SyntaxTree);
var typeSymbol = (INamedTypeSymbol) model.GetDeclaredSymbol(candidateClass);
var relevantAttribute = typeSymbol.GetAttributes().FirstOrDefault(attr =>
attr.AttributeClass != null &&
attr.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.Default));
if (relevantAttribute == null)
{
continue;
}
var isPartial = candidateClass.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword));
if (isPartial)
{
symbols.Add(typeSymbol);
}
else
{
var missingPartialKeywordMessage =
$"The type {typeSymbol.Name} should be declared with the 'partial' keyword " +
"as it is annotated with the [GenerateTypedNameReferences] attribute.";
context.ReportDiagnostic(
Diagnostic.Create(
new DiagnosticDescriptor(
"RXN0006",
missingPartialKeywordMessage,
missingPartialKeywordMessage,
"Usage",
DiagnosticSeverity.Error,
true),
Location.None));
}
}
return symbols;
}
public void Initialize(GeneratorInitializationContext context)
{
context.RegisterForSyntaxNotifications(() => new NameReferenceSyntaxReceiver());
}
}
}

View File

@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using Robust.Client.GameObjects.Components.Animations;
using Robust.Client.GameObjects;
namespace Robust.Client.Animations
{
@@ -13,7 +13,7 @@ namespace Robust.Client.Animations
/// <seealso cref="AnimationPlayerComponent"/>
public sealed class Animation
{
public readonly List<AnimationTrack> AnimationTracks = new();
public List<AnimationTrack> AnimationTracks { get; private set; } = new();
public TimeSpan Length { get; set; }
}

View File

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

View File

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

View File

@@ -1,11 +1,9 @@
using System;
using System.Collections.Generic;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Client.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Utility;
using Robust.Shared.GameObjects;
using Robust.Shared.Player;
namespace Robust.Client.Animations
{
@@ -17,7 +15,7 @@ namespace Robust.Client.Animations
/// <summary>
/// A list of key frames for when to fire flicks.
/// </summary>
public readonly List<KeyFrame> KeyFrames = new();
public List<KeyFrame> KeyFrames { get; private set; } = new();
public override (int KeyFrameIndex, float FramePlayingTime) InitPlayback()
{
@@ -39,8 +37,7 @@ namespace Robust.Client.Animations
var keyFrame = KeyFrames[keyFrameIndex];
EntitySystem.Get<AudioSystem>()
.Play(keyFrame.Resource, entity, keyFrame.AudioParamsFunc.Invoke());
SoundSystem.Play(Filter.Local(), keyFrame.Resource, entity, keyFrame.AudioParamsFunc.Invoke());
}
return (keyFrameIndex, playingTime);

View File

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

View File

@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Utility;
namespace Robust.Client.Animations
@@ -15,7 +15,7 @@ namespace Robust.Client.Animations
/// <summary>
/// A list of key frames for when to fire flicks.
/// </summary>
public readonly List<KeyFrame> KeyFrames = new();
public List<KeyFrame> KeyFrames { get; private set; } = new();
// TODO: Should this layer key be per keyframe maybe?
/// <summary>

View File

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

View File

@@ -4,17 +4,20 @@ using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using NFluidsynth;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Log;
using Robust.Shared.Interfaces.Physics;
using Robust.Shared.Interfaces.Resources;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.ContentPack;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Broadphase;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using Logger = Robust.Shared.Log.Logger;
namespace Robust.Client.Audio.Midi
@@ -33,24 +36,6 @@ namespace Robust.Client.Audio.Midi
/// </returns>
IMidiRenderer? GetNewRenderer();
/*
/// <summary>
/// Checks whether the file at the given path is a valid midi file or not.
/// </summary>
/// <remarks>
/// We add this here so content doesn't need to reference NFluidsynth.
/// </remarks>
bool IsMidiFile(string filename);
/// <summary>
/// Checks whether the file at the given path is a valid midi file or not.
/// </summary>
/// <remarks>
/// We add this here so content doesn't need to reference NFluidsynth.
/// </remarks>
bool IsSoundfontFile(string filename);
*/
/// <summary>
/// Method called every frame.
/// Should be used to update positional audio.
@@ -58,20 +43,31 @@ namespace Robust.Client.Audio.Midi
/// <param name="frameTime"></param>
void FrameUpdate(float frameTime);
/// <summary>
/// Volume, in db.
/// </summary>
float Volume { get; set; }
/// <summary>
/// If true, MIDI support is available.
/// </summary>
bool IsAvailable { get; }
public int OcclusionCollisionMask { get; set; }
void Shutdown();
}
internal class MidiManager : IDisposable, IMidiManager
internal class MidiManager : IMidiManager
{
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IResourceManagerInternal _resourceManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IConfigurationManager _cfgMan = default!;
private SharedBroadphaseSystem _broadPhaseSystem = default!;
[ViewVariables]
public bool IsAvailable
{
get
@@ -82,12 +78,29 @@ namespace Robust.Client.Audio.Midi
}
}
private readonly List<MidiRenderer> _renderers = new();
[ViewVariables]
private readonly List<IMidiRenderer> _renderers = new();
private bool _alive = true;
private Settings? _settings;
private Thread? _midiThread;
private ISawmill _midiSawmill = default!;
private float _volume = 0f;
private bool _volumeDirty = true;
[ViewVariables(VVAccess.ReadWrite)]
public float Volume
{
get => _volume;
set
{
if (MathHelper.CloseToPercent(_volume, value))
return;
_cfgMan.SetCVar(CVars.MidiVolume, value);
_volumeDirty = true;
}
}
private static readonly string[] LinuxSoundfonts =
{
@@ -104,7 +117,7 @@ namespace Robust.Client.Audio.Midi
private const string OsxSoundfont =
"/System/Library/Components/CoreAudio.component/Contents/Resources/gs_instruments.dls";
private const string FallbackSoundfont = "/Resources/Midi/fallback.sf2";
private const string FallbackSoundfont = "/Midi/fallback.sf2";
private readonly ResourceLoaderCallbacks _soundfontLoaderCallbacks = new();
@@ -114,12 +127,19 @@ namespace Robust.Client.Audio.Midi
private NFluidsynth.Logger.LoggerDelegate _loggerDelegate = default!;
private ISawmill _sawmill = default!;
[ViewVariables(VVAccess.ReadWrite)]
public int OcclusionCollisionMask { get; set; }
private void InitializeFluidsynth()
{
if (FluidsynthInitialized || _failedInitialize) return;
_cfgMan.OnValueChanged(CVars.MidiVolume, value =>
{
_volume = value;
_volumeDirty = true;
}, true);
_midiSawmill = Logger.GetSawmill("midi");
_sawmill = Logger.GetSawmill("midi.fluidsynth");
_loggerDelegate = LoggerDelegate;
@@ -155,6 +175,7 @@ namespace Robust.Client.Audio.Midi
_midiThread = new Thread(ThreadUpdate);
_midiThread.Start();
_broadPhaseSystem = EntitySystem.Get<SharedBroadphaseSystem>();
FluidsynthInitialized = true;
}
@@ -171,18 +192,6 @@ namespace Robust.Client.Audio.Midi
_sawmill.Log(rLevel, message);
}
/*
public bool IsMidiFile(string filename)
{
return SoundFont.IsMidiFile(filename);
}
public bool IsSoundfontFile(string filename)
{
return SoundFont.IsSoundFont(filename);
}
*/
public IMidiRenderer? GetNewRenderer()
{
if (!FluidsynthInitialized)
@@ -207,19 +216,16 @@ namespace Robust.Client.Audio.Midi
var renderer = new MidiRenderer(_settings!, soundfontLoader);
foreach (var file in _resourceManager.ContentFindFiles(new ResourcePath("/Audio/MidiCustom/")))
foreach (var file in _resourceManager.ContentFindFiles(("/Audio/MidiCustom/")))
{
if (file.Extension != "sf2" && file.Extension != "dls") continue;
if (_resourceManager.TryGetDiskFilePath(file, out var path))
{
renderer.LoadSoundfont(path);
}
renderer.LoadSoundfont(file.ToString());
}
// Since the last loaded soundfont takes priority, we load the fallback soundfont before the soundfont.
renderer.LoadSoundfont(FallbackSoundfont);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
if (OperatingSystem.IsLinux())
{
foreach (var filepath in LinuxSoundfonts)
{
@@ -237,19 +243,21 @@ namespace Robust.Client.Audio.Midi
break;
}
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
else if (OperatingSystem.IsMacOS())
{
if (File.Exists(OsxSoundfont) && SoundFont.IsSoundFont(OsxSoundfont))
renderer.LoadSoundfont(OsxSoundfont, true);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
else if (OperatingSystem.IsWindows())
{
if (File.Exists(WindowsSoundfont) && SoundFont.IsSoundFont(WindowsSoundfont))
renderer.LoadSoundfont(WindowsSoundfont, true);
}
lock (_renderers)
{
_renderers.Add(renderer);
}
return renderer;
}
@@ -267,69 +275,79 @@ namespace Robust.Client.Audio.Midi
}
// Update positions of streams every frame.
lock (_renderers)
foreach (var renderer in _renderers)
foreach (var renderer in _renderers)
{
if (renderer.Disposed)
continue;
if(_volumeDirty)
renderer.Source.SetVolume(Volume);
if (!renderer.Mono)
{
if (renderer.Disposed)
continue;
if (!renderer.Mono)
{
renderer.Source.SetGlobal();
continue;
}
MapCoordinates? mapPos = null;
if (renderer.TrackingCoordinates != null)
{
mapPos = renderer.TrackingCoordinates.Value.ToMap(_entityManager);
}
else if (renderer.TrackingEntity != null)
{
mapPos = renderer.TrackingEntity.Transform.MapPosition;
}
if (mapPos != null)
{
var pos = mapPos.Value;
if (pos.MapId != _eyeManager.CurrentMap)
{
renderer.Source.SetVolume(-10000000);
}
else
{
var sourceRelative = _eyeManager.CurrentEye.Position.Position - pos.Position;
var occlusion = 0f;
if (sourceRelative.Length > 0)
{
occlusion = IoCManager.Resolve<IPhysicsManager>().IntersectRayPenetration(
pos.MapId,
new CollisionRay(
pos.Position,
sourceRelative.Normalized,
OcclusionCollisionMask),
sourceRelative.Length,
renderer.TrackingEntity);
}
renderer.Source.SetOcclusion(occlusion);
}
if (renderer.Source.SetPosition(pos.Position))
{
continue;
}
if (float.IsNaN(pos.Position.X) || float.IsNaN(pos.Position.Y))
{
// just duck out instead of move to NaN
renderer.Source.SetOcclusion(float.MaxValue);
continue;
}
_midiSawmill?.Warning("Interrupting positional audio, can't set position.");
renderer.Source.StopPlaying();
}
renderer.Source.SetGlobal();
continue;
}
MapCoordinates? mapPos = null;
if (renderer.TrackingCoordinates != null)
{
mapPos = renderer.TrackingCoordinates.Value.ToMap(_entityManager);
}
else if (renderer.TrackingEntity != null)
{
mapPos = renderer.TrackingEntity.Transform.MapPosition;
}
if (mapPos != null)
{
var pos = mapPos.Value;
if (pos.MapId != _eyeManager.CurrentMap)
{
renderer.Source.SetVolume(-10000000);
}
else
{
var sourceRelative = _eyeManager.CurrentEye.Position.Position - pos.Position;
var occlusion = 0f;
if (sourceRelative.Length > 0)
{
occlusion = _broadPhaseSystem.IntersectRayPenetration(
pos.MapId,
new CollisionRay(
pos.Position,
sourceRelative.Normalized,
OcclusionCollisionMask),
sourceRelative.Length,
renderer.TrackingEntity);
}
renderer.Source.SetOcclusion(occlusion);
}
if (renderer.Source.SetPosition(pos.Position))
{
continue;
}
if (renderer.TrackingEntity != null)
{
renderer.Source.SetVelocity(renderer.TrackingEntity.GlobalLinearVelocity());
}
if (float.IsNaN(pos.Position.X) || float.IsNaN(pos.Position.Y))
{
// just duck out instead of move to NaN
renderer.Source.SetOcclusion(float.MaxValue);
continue;
}
_midiSawmill?.Warning("Interrupting positional audio, can't set position.");
renderer.Source.StopPlaying();
}
}
_volumeDirty = false;
}
/// <summary>
@@ -340,6 +358,7 @@ namespace Robust.Client.Audio.Midi
while (_alive)
{
lock (_renderers)
{
for (var i = 0; i < _renderers.Count; i++)
{
var renderer = _renderers[i];
@@ -347,23 +366,28 @@ namespace Robust.Client.Audio.Midi
renderer.Render();
else
{
((IMidiRenderer)renderer).InternalDispose();
renderer.InternalDispose();
_renderers.Remove(renderer);
}
}
}
Thread.Sleep(1);
}
}
public void Dispose()
public void Shutdown()
{
_alive = false;
_midiThread?.Join();
_settings?.Dispose();
foreach (var renderer in _renderers)
lock (_renderers)
{
renderer?.Dispose();
foreach (var renderer in _renderers)
{
renderer?.Dispose();
}
}
if (FluidsynthInitialized && !_failedInitialize)
@@ -382,10 +406,18 @@ namespace Robust.Client.Audio.Midi
public override IntPtr Open(string filename)
{
Stream? stream;
if (filename.StartsWith("/Resources/"))
if (string.IsNullOrEmpty(filename))
{
if (!IoCManager.Resolve<IResourceCache>().TryContentFileRead(filename.Substring(10), out stream))
return IntPtr.Zero;
}
Stream? stream;
var resourceCache = IoCManager.Resolve<IResourceCache>();
var resourcePath = new ResourcePath(filename);
if (resourcePath.IsRooted && resourceCache.ContentFileExists(filename))
{
if (!resourceCache.TryContentFileRead(filename, out stream))
return IntPtr.Zero;
}
else if (File.Exists(filename))
@@ -410,6 +442,7 @@ namespace Robust.Client.Audio.Midi
var span = new Span<byte>(buf.ToPointer(), length);
var stream = _openStreams[(int) sfHandle];
// Fluidsynth's docs state that this method should leave the buffer unmodified if it fails. (returns -1)
try
{
// Fluidsynth does a LOT of tiny allocations (frankly, way too much).
@@ -433,6 +466,7 @@ namespace Robust.Client.Audio.Midi
{
return -1;
}
return 0;
}
@@ -454,10 +488,12 @@ namespace Robust.Client.Audio.Midi
public override int Close(IntPtr sfHandle)
{
var stream = _openStreams[(int) sfHandle];
if (!_openStreams.Remove((int) sfHandle, out var stream))
return -1;
stream.Dispose();
_openStreams.Remove((int) sfHandle);
return 0;
}
}
}

View File

@@ -1,15 +1,13 @@
using System;
using System.IO;
using System.Runtime.Intrinsics.X86;
using NFluidsynth;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Graphics;
using Robust.Shared.Asynchronous;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Log;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Utility;
using Robust.Shared.Maths;
using Robust.Shared.ViewVariables;
using MidiEvent = NFluidsynth.MidiEvent;
namespace Robust.Client.Audio.Midi
@@ -23,6 +21,17 @@ namespace Robust.Client.Audio.Midi
public interface IMidiRenderer : IDisposable
{
/// <summary>
/// The buffered audio source of this renderer.
/// </summary>
internal IClydeBufferedAudioSource Source { get; }
/// <summary>
/// Whether this renderer has been disposed or not.
/// </summary>
bool Disposed { get; }
/// <summary>
/// This controls whether the midi file being played will loop or not.
/// </summary>
@@ -72,9 +81,9 @@ namespace Robust.Client.Audio.Midi
int PlayerTotalTick { get; }
/// <summary>
/// Gets the current tick of the MIDI player.
/// Gets or sets (seeks) the current tick of the MIDI player.
/// </summary>
int PlayerTick { get; }
int PlayerTick { get; set; }
/// <summary>
/// Gets the current tick of the sequencer.
@@ -112,6 +121,11 @@ namespace Robust.Client.Audio.Midi
/// </summary>
void StopAllNotes();
/// <summary>
/// Render and play MIDI to the audio source.
/// </summary>
internal void Render();
/// <summary>
/// Loads a new soundfont into the renderer.
/// </summary>
@@ -161,7 +175,7 @@ namespace Robust.Client.Audio.Midi
internal void InternalDispose();
}
public class MidiRenderer : IMidiRenderer
internal class MidiRenderer : IMidiRenderer
{
[Dependency] private readonly IClydeAudio _clydeAudio = default!;
[Dependency] private readonly ITaskManager _taskManager = default!;
@@ -188,60 +202,90 @@ namespace Robust.Client.Audio.Midi
private const int SampleRate = 44100;
private const int Buffers = SampleRate / 2205;
private readonly object _playerStateLock = new();
private bool _debugEvents = false;
private SequencerClientId _synthRegister;
private SequencerClientId _debugRegister;
public IClydeBufferedAudioSource Source { get; set; }
IClydeBufferedAudioSource IMidiRenderer.Source => Source;
[ViewVariables]
public bool Disposed { get; private set; } = false;
[ViewVariables(VVAccess.ReadWrite)]
public byte MidiProgram
{
get => _midiProgram;
set
{
lock (_playerStateLock)
for (var i = 0; i < 16; i++)
for (var i = 0; i < _synth.MidiChannelCount; i++)
_synth.ProgramChange(i, value);
_midiProgram = value;
}
}
[ViewVariables(VVAccess.ReadWrite)]
public byte MidiBank
{
get => _midiBank;
set
{
lock (_playerStateLock)
for (var i = 0; i < 16; i++)
for (var i = 0; i < _synth.MidiChannelCount; i++)
_synth.BankSelect(i, value);
_midiBank = value;
}
}
[ViewVariables(VVAccess.ReadWrite)]
public uint MidiSoundfont
{
get => _midiSoundfont;
set
{
lock (_playerStateLock)
for (var i = 0; i < 16; i++)
for (var i = 0; i < _synth.MidiChannelCount; i++)
_synth.SoundFontSelect(i, value);
_midiSoundfont = value;
}
}
[ViewVariables(VVAccess.ReadWrite)]
public bool DisablePercussionChannel { get; set; } = true;
[ViewVariables(VVAccess.ReadWrite)]
public bool DisableProgramChangeEvent { get; set; } = true;
[ViewVariables(VVAccess.ReadWrite)]
public int PlayerTotalTick => _player?.GetTotalTicks ?? 0;
public int PlayerTick => _player?.CurrentTick ?? 0;
[ViewVariables(VVAccess.ReadWrite)]
public int PlayerTick
{
get => _player?.CurrentTick ?? 0;
set
{
lock (_playerStateLock)
_player?.Seek(Math.Max(Math.Min(value, PlayerTotalTick), 0));
}
}
[ViewVariables(VVAccess.ReadWrite)]
public uint SequencerTick => _sequencer?.Tick ?? 0;
[ViewVariables(VVAccess.ReadWrite)]
public double SequencerTimeScale => _sequencer?.TimeScale ?? 0;
[ViewVariables(VVAccess.ReadWrite)]
public bool Mono { get; set; }
[ViewVariables]
public MidiRendererStatus Status { get; private set; } = MidiRendererStatus.None;
[ViewVariables(VVAccess.ReadWrite)]
public bool LoopMidi
{
get => _loopMidi;
@@ -253,10 +297,11 @@ namespace Robust.Client.Audio.Midi
}
}
[ViewVariables(VVAccess.ReadWrite)]
public IEntity? TrackingEntity { get; set; } = null;
public EntityCoordinates? TrackingCoordinates { get; set; } = null;
internal bool Free { get; set; } = false;
[ViewVariables(VVAccess.ReadWrite)]
public EntityCoordinates? TrackingCoordinates { get; set; } = null;
internal MidiRenderer(Settings settings, SoundFontLoader soundFontLoader, bool mono = true)
{
@@ -269,6 +314,7 @@ namespace Robust.Client.Audio.Midi
_soundFontLoader = soundFontLoader;
_synth = new Synth(_settings);
_sequencer = new Sequencer(false);
_debugRegister = _sequencer.RegisterClient("honk", DumpSequencerEvent);
_synthRegister = _sequencer.RegisterFluidsynth(_synth);
_synth.AddSoundFontLoader(soundFontLoader);
@@ -278,6 +324,27 @@ namespace Robust.Client.Audio.Midi
Source.StartPlaying();
}
private void DumpSequencerEvent(uint time, SequencerEvent @event)
{
// ReSharper disable once UseStringInterpolation
_midiSawmill.Debug(string.Format(
"{0:D8}: {1} chan:{2:D2} key:{3:D5} bank:{4:D2} ctrl:{5:D5} dur:{6:D5} pitch:{7:D5} prog:{8:D3} val:{9:D5} vel:{10:D5}",
time,
@event.Type.ToString().PadLeft(22),
@event.Channel,
@event.Key,
@event.Bank,
@event.Control,
@event.Duration,
@event.Pitch,
@event.Program,
@event.Value,
@event.Velocity));
@event.Dest = _synthRegister;
_sequencer.SendNow(@event);
}
public bool OpenInput()
{
if (Disposed)
@@ -287,7 +354,11 @@ namespace Robust.Client.Audio.Midi
Status = MidiRendererStatus.Input;
StopAllNotes();
_driver = new MidiDriver(_settings, MidiDriverEventHandler);
lock (_playerStateLock)
{
_driver = new MidiDriver(_settings, MidiDriverEventHandler);
}
return true;
}
@@ -310,9 +381,8 @@ namespace Robust.Client.Audio.Midi
lock (_playerStateLock)
{
if (_player == null)
_player = new NFluidsynth.Player(_synth);
_player.Stop();
_player?.Dispose();
_player = new NFluidsynth.Player(_synth);
_player.AddMem(buffer);
_player.SetPlaybackCallback(MidiPlayerEventHandler);
_player.Play();
@@ -326,8 +396,13 @@ namespace Robust.Client.Audio.Midi
{
if (Status != MidiRendererStatus.Input) return false;
Status = MidiRendererStatus.None;
_driver?.Dispose();
_driver = null;
lock (_playerStateLock)
{
_driver?.Dispose();
_driver = null;
}
StopAllNotes();
return true;
}
@@ -351,10 +426,8 @@ namespace Robust.Client.Audio.Midi
public void StopAllNotes()
{
for (var i = 0; i < 16; i++)
{
_synth.AllNotesOff(i);
}
lock(_playerStateLock)
_synth.AllNotesOff(-1);
}
public void LoadSoundfont(string filename, bool resetPresets = false)
@@ -369,13 +442,15 @@ namespace Robust.Client.Audio.Midi
public event Action<Shared.Audio.Midi.MidiEvent>? OnMidiEvent;
public event Action? OnMidiPlayerFinished;
internal void Render(int length = SampleRate / 250)
void IMidiRenderer.Render()
{
Render();
}
private void Render(int length = SampleRate / 250)
{
if (Disposed) return;
// SSE needs this.
DebugTools.Assert(length % 4 == 0, "Sample length must be multiple of 4");
var buffersProcessed = Source.GetNumberOfBuffersProcessed();
if(buffersProcessed == Buffers) _midiSawmill.Warning("MIDI buffer overflow!");
if (buffersProcessed == 0) return;
@@ -390,36 +465,16 @@ namespace Robust.Client.Audio.Midi
Source.GetBuffersProcessed(buffers);
lock (_playerStateLock)
{
// _sequencer.Process(10);
_synth?.WriteSampleFloat(length * buffers.Length, audio, 0, Mono ? 1 : 2,
audio, Mono ? length * buffers.Length : 1, Mono ? 1 : 2);
}
if (Mono) // Turn audio to mono
{
var l = length * buffers.Length;
if (Sse.IsSupported)
{
fixed (float* ptr = audio)
{
for (var j = 0; j < l; j += 4)
{
var k = j + l;
var jV = Sse.LoadVector128(ptr + j);
var kV = Sse.LoadVector128(ptr + k);
Sse.Store(j + ptr, Sse.Add(jV, kV));
}
}
}
else
{
for (var j = 0; j < l; j++)
{
var k = j + l;
audio[j] = ((audio[k] + audio[j]));
}
}
NumericsHelpers.Add(audio[..l], audio[l..]);
}
for (var i = 0; i < buffers.Length; i++)
@@ -449,6 +504,7 @@ namespace Robust.Client.Audio.Midi
var timestamp = SequencerTick;
var midiEv = (Shared.Audio.Midi.MidiEvent) midiEvent;
midiEv.Tick = timestamp;
midiEvent.Dispose();
SendMidiEvent(midiEv);
return 0;
}
@@ -459,6 +515,7 @@ namespace Robust.Client.Audio.Midi
var timestamp = SequencerTick;
var midiEv = (Shared.Audio.Midi.MidiEvent) midiEvent;
midiEv.Tick = timestamp;
midiEvent.Dispose();
SendMidiEvent(midiEv);
return 0;
}
@@ -475,22 +532,16 @@ namespace Robust.Client.Audio.Midi
lock(_playerStateLock)
switch (midiEvent.Type)
{
// Sometimes MIDI files spam these for no good reason and I can't find any info on what they are.
case 1:
case 5:
case 81:
break;
// Note On 0x80
case 144:
_synth.NoteOn(midiEvent.Channel, midiEvent.Key, midiEvent.Velocity);
break;
// Note Off - 0x90
// Note Off - 0x80
case 128:
_synth.NoteOff(midiEvent.Channel, midiEvent.Key);
break;
// Note On 0x90
case 144:
_synth.NoteOn(midiEvent.Channel, midiEvent.Key, midiEvent.Velocity);
break;
// After Touch - 0xA
case 160:
_synth.KeyPressure(midiEvent.Channel, midiEvent.Key, midiEvent.Value);
@@ -503,8 +554,10 @@ namespace Robust.Client.Audio.Midi
// Program Change - 0xC0
case 192:
if(!DisableProgramChangeEvent)
if (!DisableProgramChangeEvent)
_synth.ProgramChange(midiEvent.Channel, midiEvent.Program);
else
return;
break;
// Channel Pressure - 0xD0
@@ -517,13 +570,27 @@ namespace Robust.Client.Audio.Midi
_synth.PitchBend(midiEvent.Channel, midiEvent.Pitch);
break;
// Sometimes MIDI files spam these for no good reason and I can't find any info on what they are.
case 1:
case 5:
// MetaEvent -- SetTempo - 0x51
case 81:
// Already handled by the player.
return;
// System Messages - 0xF0
case 240:
switch ((byte)midiEvent.Control)
{
case 11:
_synth.AllNotesOff(midiEvent.Channel);
break;
}
break;
default:
_midiSawmill.Warning("Unhandled midi event of type {0}", midiEvent.Type, midiEvent);
break;
return;
}
}
catch (FluidSynthInteropException)
@@ -540,7 +607,7 @@ namespace Robust.Client.Audio.Midi
if (Disposed) return;
var seqEv = (SequencerEvent) midiEvent;
seqEv.Dest = _synthRegister;
seqEv.Dest = _debugEvents ? _debugRegister : _synthRegister;
_sequencer.SendAt(seqEv, time, absolute);
}
@@ -563,10 +630,15 @@ namespace Robust.Client.Audio.Midi
void IMidiRenderer.InternalDispose()
{
Source?.Dispose();
_driver?.Dispose();
// Do NOT dispose of the sequencer after the synth or it'll cause a segfault for some fucking reason.
_sequencer?.UnregisterClient(_debugRegister);
_sequencer?.UnregisterClient(_synthRegister);
_sequencer?.Dispose();
_synth?.Dispose();
_player?.Dispose();
_driver?.Dispose();
_sequencer?.Dispose();
}
}
}

View File

@@ -1,21 +1,20 @@
using System;
using System.Net;
using Robust.Client.Interfaces;
using Robust.Client.Interfaces.Debugging;
using Robust.Client.Interfaces.GameObjects;
using Robust.Client.Interfaces.GameStates;
using Robust.Client.Interfaces.Utility;
using Robust.Client.Debugging;
using Robust.Client.GameObjects;
using Robust.Client.GameStates;
using Robust.Client.Player;
using Robust.Client.Utility;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Network.Messages;
using Robust.Shared.Players;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Robust.Client
@@ -25,8 +24,9 @@ namespace Robust.Client
{
[Dependency] private readonly IClientNetManager _net = default!;
[Dependency] private readonly IPlayerManager _playMan = default!;
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly INetConfigurationManager _configManager = default!;
[Dependency] private readonly IClientEntityManager _entityManager = default!;
[Dependency] private readonly IEntityLookup _entityLookup = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IDiscordRichPresence _discord = default!;
[Dependency] private readonly IGameTiming _timing = default!;
@@ -50,18 +50,28 @@ namespace Robust.Client
/// <inheritdoc />
public void Initialize()
{
_net.RegisterNetMessage<MsgServerInfo>(MsgServerInfo.NAME, HandleServerInfo);
_net.RegisterNetMessage<MsgSetTickRate>(MsgSetTickRate.NAME, HandleSetTickRate);
_net.RegisterNetMessage<MsgServerInfoReq>(MsgServerInfoReq.NAME);
_net.Connected += OnConnected;
_net.ConnectFailed += OnConnectFailed;
_net.Disconnect += OnNetDisconnect;
_configManager.OnValueChanged(CVars.NetTickrate, TickRateChanged, invokeImmediately: true);
_playMan.Initialize();
_debugDrawMan.Initialize();
Reset();
}
private void TickRateChanged(int tickrate)
{
if (GameInfo != null)
{
GameInfo.TickRate = (byte) tickrate;
}
_timing.TickRate = (byte) tickrate;
Logger.InfoS("client", $"Tickrate changed to: {tickrate} on tick {_timing.CurTick}");
}
/// <inheritdoc />
public void ConnectToServer(DnsEndPoint endPoint)
{
@@ -89,6 +99,25 @@ namespace Robust.Client
_net.ClientDisconnect(reason);
}
/// <inheritdoc />
public void StartSinglePlayer()
{
DebugTools.Assert(RunLevel < ClientRunLevel.Connecting);
DebugTools.Assert(!_net.IsConnected);
_playMan.Startup();
_playMan.LocalPlayer!.Name = PlayerNameOverride ?? _configManager.GetCVar(CVars.PlayerName);
OnRunLevelChanged(ClientRunLevel.SinglePlayerGame);
GameStartedSetup();
}
/// <inheritdoc />
public void StopSinglePlayer()
{
DebugTools.Assert(RunLevel == ClientRunLevel.SinglePlayerGame);
DebugTools.Assert(!_net.IsConnected);
GameStoppedReset();
}
/// <inheritdoc />
public event EventHandler<RunLevelChangedEventArgs>? RunLevelChanged;
@@ -98,9 +127,39 @@ namespace Robust.Client
private void OnConnected(object? sender, NetChannelArgs args)
{
// request base info about the server
var msgInfo = _net.CreateNetMessage<MsgServerInfoReq>();
_net.ClientSendMessage(msgInfo);
_configManager.SyncWithServer();
_configManager.ReceivedInitialNwVars += OnReceivedClientData;
}
private void OnReceivedClientData(object? sender, EventArgs e)
{
_configManager.ReceivedInitialNwVars -= OnReceivedClientData;
var info = GameInfo;
var serverName = _configManager.GetCVar<string>("game.hostname");
if (info == null)
{
GameInfo = info = new ServerInfo(serverName);
}
else
{
info.ServerName = serverName;
}
var maxPlayers = _configManager.GetCVar<int>("game.maxplayers");
info.ServerMaxPlayers = maxPlayers;
var userName = _net.ServerChannel!.UserName;
var userId = _net.ServerChannel.UserId;
_discord.Update(info.ServerName, userName, info.ServerMaxPlayers.ToString());
// start up player management
_playMan.Startup();
_playMan.LocalPlayer!.UserId = userId;
_playMan.LocalPlayer.Name = userName;
_playMan.LocalPlayer.StatusChanged += OnLocalStatusChanged;
}
/// <summary>
@@ -108,16 +167,13 @@ namespace Robust.Client
/// receiving states when they join the lobby.
/// </summary>
/// <param name="session">Session of the player.</param>
private void OnPlayerJoinedServer(IPlayerSession session)
private void OnPlayerJoinedServer(ICommonSession session)
{
DebugTools.Assert(RunLevel < ClientRunLevel.Connected);
OnRunLevelChanged(ClientRunLevel.Connected);
_entityManager.Startup();
_mapManager.Startup();
GameStartedSetup();
_timing.ResetSimTime();
_timing.Paused = false;
PlayerJoinedServer?.Invoke(this, new PlayerEventArgs(session));
}
@@ -125,7 +181,7 @@ namespace Robust.Client
/// Player is joining the game
/// </summary>
/// <param name="session">Session of the player.</param>
private void OnPlayerJoinedGame(IPlayerSession session)
private void OnPlayerJoinedGame(ICommonSession session)
{
DebugTools.Assert(RunLevel >= ClientRunLevel.Connected);
OnRunLevelChanged(ClientRunLevel.InGame);
@@ -135,6 +191,7 @@ namespace Robust.Client
private void Reset()
{
_configManager.ClearReceivedInitialNwVars();
OnRunLevelChanged(ClientRunLevel.Initialize);
}
@@ -151,51 +208,31 @@ namespace Robust.Client
PlayerLeaveServer?.Invoke(this, new PlayerEventArgs(_playMan.LocalPlayer?.Session));
LastDisconnectReason = args.Reason;
GameStoppedReset();
}
private void GameStartedSetup()
{
_entityManager.Startup();
_mapManager.Startup();
_entityLookup.Startup();
_timing.ResetSimTime();
_timing.Paused = false;
}
private void GameStoppedReset()
{
IoCManager.Resolve<INetConfigurationManager>().FlushMessages();
_gameStates.Reset();
_playMan.Shutdown();
_entityLookup.Shutdown();
_entityManager.Shutdown();
_mapManager.Shutdown();
_discord.ClearPresence();
Reset();
}
private void HandleServerInfo(MsgServerInfo msg)
{
var info = GameInfo;
if (info == null)
{
GameInfo = info = new ServerInfo(msg.ServerName);
}
else
{
info.ServerName = msg.ServerName;
}
info.ServerMaxPlayers = msg.ServerMaxPlayers;
info.TickRate = msg.TickRate;
_timing.TickRate = msg.TickRate;
Logger.InfoS("client", $"Tickrate changed to: {msg.TickRate}");
var userName = msg.MsgChannel.UserName;
var userId = msg.MsgChannel.UserId;
_discord.Update(info.ServerName, userName, info.ServerMaxPlayers.ToString());
// start up player management
_playMan.Startup(_net.ServerChannel!);
_playMan.LocalPlayer!.UserId = userId;
_playMan.LocalPlayer.Name = userName;
_playMan.LocalPlayer.StatusChanged += OnLocalStatusChanged;
}
private void HandleSetTickRate(MsgSetTickRate message)
{
_timing.TickRate = message.NewTickRate;
Logger.InfoS("client", $"Tickrate changed to: {message.NewTickRate} on tick {_timing.CurTick}");
}
private void OnLocalStatusChanged(object? obj, StatusEventArgs eventArgs)
{
// player finished fully connecting to the server.
@@ -246,6 +283,11 @@ namespace Robust.Client
/// The client is now in the game, moving around.
/// </summary>
InGame,
/// <summary>
/// The client is now in singleplayer mode, in-game.
/// </summary>
SinglePlayerGame,
}
/// <summary>
@@ -256,12 +298,12 @@ namespace Robust.Client
/// <summary>
/// The session that triggered the event.
/// </summary>
private IPlayerSession? Session { get; }
private ICommonSession? Session { get; }
/// <summary>
/// Constructs a new instance of the class.
/// </summary>
public PlayerEventArgs(IPlayerSession? session)
public PlayerEventArgs(ICommonSession? session)
{
Session = session;
}

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