mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Compare commits
108 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
876de4065a | ||
|
|
60e159f0d0 | ||
|
|
80f3aae30c | ||
|
|
98b1862433 | ||
|
|
d2311c193f | ||
|
|
f05ed96461 | ||
|
|
dc23dfaf4d | ||
|
|
62315f7c2e | ||
|
|
b2d121e780 | ||
|
|
fb4b029122 | ||
|
|
66239d23ea | ||
|
|
dbb45f1c13 | ||
|
|
6284e16b64 | ||
|
|
f6c55085fe | ||
|
|
30eafd26e7 | ||
|
|
63423d96b4 | ||
|
|
474334aff2 | ||
|
|
be102f86bf | ||
|
|
d7962c7190 | ||
|
|
7fe9385c3b | ||
|
|
a9d9d1348a | ||
|
|
4eaf624555 | ||
|
|
e37c131fb4 | ||
|
|
9df4606492 | ||
|
|
3be8070274 | ||
|
|
8a440d705f | ||
|
|
5849474022 | ||
|
|
b7d67c0ece | ||
|
|
b04cf71bc0 | ||
|
|
ea87df649a | ||
|
|
dab7a9112f | ||
|
|
d3dc89832a | ||
|
|
3ade9ca447 | ||
|
|
149e9a2613 | ||
|
|
d164148ce2 | ||
|
|
d898b52449 | ||
|
|
dcf7a1e580 | ||
|
|
65c6bb74eb | ||
|
|
d6d88bea91 | ||
|
|
d6467f768a | ||
|
|
4f0f020f56 | ||
|
|
5ce8369fb9 | ||
|
|
2446e64033 | ||
|
|
bdd65cda4b | ||
|
|
77e949bfe8 | ||
|
|
d4171351f4 | ||
|
|
e67d0ad3d6 | ||
|
|
aff5711fde | ||
|
|
a886222946 | ||
|
|
5843f1087e | ||
|
|
93c0ce815f | ||
|
|
1c64fa1f28 | ||
|
|
c825c1e413 | ||
|
|
f30fb47834 | ||
|
|
5d255e06c8 | ||
|
|
80357c8ec4 | ||
|
|
ac3a434bdf | ||
|
|
21719b8884 | ||
|
|
dbb6b90654 | ||
|
|
4b92be5324 | ||
|
|
95169b7a71 | ||
|
|
b699e22c85 | ||
|
|
e48cc62d0b | ||
|
|
aade062a49 | ||
|
|
e02166d5c4 | ||
|
|
8037bfae14 | ||
|
|
49781791af | ||
|
|
92719aa29f | ||
|
|
1d47a9677d | ||
|
|
14fe8eba6d | ||
|
|
2ff99d4a62 | ||
|
|
ce8b2d82a3 | ||
|
|
f8f99450db | ||
|
|
a3cf4877e4 | ||
|
|
6ab08f7dc1 | ||
|
|
819f6921cf | ||
|
|
cf91369d27 | ||
|
|
0e1328675c | ||
|
|
a7315b1c95 | ||
|
|
c8f2a55cbe | ||
|
|
7812502b0b | ||
|
|
3149f99954 | ||
|
|
ef8c6379cd | ||
|
|
f932e023ee | ||
|
|
a137c839fc | ||
|
|
3e43b88518 | ||
|
|
3d974e0305 | ||
|
|
b3682017ac | ||
|
|
194743a9b0 | ||
|
|
34d65a7960 | ||
|
|
6cd4a37a8f | ||
|
|
40d879fddc | ||
|
|
df398c5b13 | ||
|
|
804b698172 | ||
|
|
346514c6e0 | ||
|
|
d65e2eb169 | ||
|
|
ff41329ad7 | ||
|
|
6151a26622 | ||
|
|
1c7ae13bfa | ||
|
|
cb6645aebe | ||
|
|
fffe3c56e9 | ||
|
|
204e881690 | ||
|
|
161b1874c2 | ||
|
|
7c3634f1f5 | ||
|
|
9969899f38 | ||
|
|
ed35839942 | ||
|
|
380ccfacd8 | ||
|
|
cc0cc6afb1 |
@@ -1,4 +1,4 @@
|
||||
<Project>
|
||||
|
||||
<!-- This file automatically reset by Tools/version.py -->
|
||||
<!-- This file automatically reset by Tools/version.py -->
|
||||
|
||||
|
||||
@@ -25,4 +25,7 @@
|
||||
|
||||
<!-- analyzer -->
|
||||
<Import Project="Robust.Analyzers.targets" Condition="'$(SkipRobustAnalyzer)' != 'true'" />
|
||||
|
||||
<!-- serialization generator -->
|
||||
<Import Project="Robust.Serialization.Generator.targets" />
|
||||
</Project>
|
||||
|
||||
5
MSBuild/Robust.Serialization.Generator.targets
Normal file
5
MSBuild/Robust.Serialization.Generator.targets
Normal file
@@ -0,0 +1,5 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\Robust.Serialization.Generator\Robust.Serialization.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
312
RELEASE-NOTES.md
312
RELEASE-NOTES.md
@@ -54,6 +54,318 @@ END TEMPLATE-->
|
||||
*None yet*
|
||||
|
||||
|
||||
## 150.0.1
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix some partial datadefs.
|
||||
|
||||
|
||||
## 150.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Remove the Id field from Fixtures as the Id is already stored on FixturesComponent.
|
||||
|
||||
### New features
|
||||
|
||||
* Add AbstractDictionarySerializer for abstract classes.
|
||||
* Add many new spawn functions for entities for common operations.
|
||||
|
||||
|
||||
## 149.0.1
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix serialization sharing instances when copying data definitions and not assigning null when the source is null.
|
||||
* Fixed resizing a window to be bigger than its set maxsize crashing the client.
|
||||
|
||||
|
||||
## 149.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Data definitions must now be partial, their data fields must not be readonly and their data field properties must have a setter.
|
||||
|
||||
### Internal
|
||||
|
||||
* Copying data definitions through the serialization manager is now faster and consumes less memory.
|
||||
|
||||
|
||||
## 148.4.0
|
||||
|
||||
### New features
|
||||
|
||||
* Add recursive PVS overrides and remove IsOverride()
|
||||
|
||||
|
||||
## 148.3.0
|
||||
|
||||
### New features
|
||||
|
||||
* Happy eyeballs delay can be configured.
|
||||
* Added more colors.
|
||||
* Allow pre-startup components to be shut down.
|
||||
* Added tile texture reload command.
|
||||
* Add implementation of Random.Pick(ValueList<T> ..).
|
||||
* Add IntegrationInstance fields for common dependencies.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Prevent invalid prototypes from being spawned.
|
||||
* Change default value of EntityLastModifiedTick from zero to one.
|
||||
* Make DiscordRichPresence icon CVars server-side with replication.
|
||||
|
||||
|
||||
## 148.2.0
|
||||
|
||||
### New features
|
||||
|
||||
* `SpinBox.LineEditControl` exposes the underlying `LineEdit`.
|
||||
* Add VV attributes to various fields across overlay and sessions.
|
||||
* Add IsPaused to EntityManager to check if an entity is paused.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix SetActiveTheme not updating the theme.
|
||||
|
||||
|
||||
## 148.1.0
|
||||
|
||||
### New features
|
||||
|
||||
* Added IgnoreUIChecksComponent that lets entities ignore bound user interface range checks which would normally close the UI.
|
||||
* Add support for F16-F24 keybinds.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix gamestate bug where PVS is disabled.
|
||||
|
||||
### Other
|
||||
|
||||
* EntityQuery.HasComponent override for nullable entity uids.
|
||||
|
||||
|
||||
## 148.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Several NuGet dependencies are now private assets.
|
||||
* Added `IViewportControl.PixelToMap()` and `PixelToMapEvent`. These are variants of the existing screen-to-map functions that should account for distortion effects.
|
||||
|
||||
### New features
|
||||
|
||||
* Added several new rich-text tags, including italic and bold-italic.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fixed log messages for unknown components not working due to threaded IoC issues.
|
||||
* Replay recordings no longer record invalid prototype uploads.
|
||||
|
||||
|
||||
## 147.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Renamed one of the EntitySystem.Dirty() methods to `DirtyEntity()` to avoid confusion with the component-dirtying methods.
|
||||
|
||||
### New features
|
||||
|
||||
* Added debug commands that return the entity system update order.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fixed a bug in MetaDataSystem that was causing the metadata component to not be marked as dirty.
|
||||
|
||||
|
||||
## 146.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Remove readOnly for DataFields and rename some ShaderPrototype C# fields internally to align with the normal schema.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Add InvariantCulture to angle validation.
|
||||
|
||||
### Internal
|
||||
|
||||
* Add some additional EntityQuery<T> usages and remove a redundant CanCollide call on fixture shutdown.
|
||||
|
||||
|
||||
## 145.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Removed some old SpriteComponent data-fields ("rsi", and "layerDatums").
|
||||
|
||||
### New features
|
||||
|
||||
* Added `ActorSystem.TryGetActorFromUserId()`.
|
||||
* Added IPrototypeManager.EnumerateKinds().
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fixed SpriteSpecifierSerializer yaml validation not working properly.
|
||||
* Fixed IoC/Threading exceptions in `Resource.Load()`.
|
||||
* Fixed `TransformSystem.SetCoordinates()` throwing uninformative client-side errors.
|
||||
* Fixed `IResourceManager.ContentFileExists()` and `TryContentFileRead()` throwing exceptions on windows when trying to open a directory.
|
||||
|
||||
|
||||
## 144.0.1
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix some EntityLookup queries incorrectly being double transformed internally.
|
||||
* Shrink TileEnlargement even further for EntityLookup default queries.
|
||||
|
||||
|
||||
## 144.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Add new args to entitylookup methods to allow for shrinkage of tile-bounds checks. Default changed to shrink the grid-local AABB by the polygon skin to avoid clipping neighboring tile entities.
|
||||
* Non-hard fixtures will no longer count by default for EntityLookup.
|
||||
|
||||
### New features
|
||||
|
||||
* Added new EntityLookup flag to return non-hard fixtures or not.
|
||||
|
||||
|
||||
## 143.3.0
|
||||
|
||||
### New features
|
||||
|
||||
* Entity placement and spawn commands now raise informative events that content can handle.
|
||||
* Replay clients can now optionally ignore some errors instead of refusing to load the replay.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* `AudioParams.PlayOffsetSecond` will no longer apply an offset that is larger then the length of the audio stream.
|
||||
* Fixed yaml serialization of arrays of virtual/abstract objects.
|
||||
|
||||
|
||||
### Other
|
||||
|
||||
* Removed an incorrect gamestate debug assert.
|
||||
|
||||
|
||||
## 143.2.0
|
||||
|
||||
### New features
|
||||
|
||||
* Add support for tests to load extra prototypes from multiple sources.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix named toolshed command.
|
||||
* Unsubscribe from grid rendering events on shutdown.
|
||||
|
||||
### Other
|
||||
|
||||
* Remove unnecessary test prototypes.
|
||||
|
||||
|
||||
## 143.1.0
|
||||
|
||||
### New features
|
||||
|
||||
* Add locale support for grammatical measure words.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Don't raise contact events for entities that were QueueDeleted during the tick.
|
||||
* Exception on duplicate broadcast subscriptions as this was unsupported behaviour.
|
||||
|
||||
### Other
|
||||
|
||||
* Add VV ReadWrite to PhysicsComponent BodyStatus.
|
||||
|
||||
|
||||
## 143.0.0
|
||||
|
||||
### New features
|
||||
|
||||
|
||||
- Toolshed, a tacit shell language, has been introduced.
|
||||
- Use Robust.Shared.ToolshedManager to invoke commands, with optional input and output.
|
||||
- Implement IInvocationContext for custom invocation contexts i.e. scripting systems.
|
||||
|
||||
|
||||
## 142.1.2
|
||||
|
||||
### Other
|
||||
|
||||
* Don't log an error on failing to resolve for joint relay refreshing.
|
||||
|
||||
|
||||
## 142.1.1
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fixed a bad debug assert in `DetachParentToNull()`
|
||||
|
||||
|
||||
## 142.1.0
|
||||
|
||||
### New features
|
||||
|
||||
* `IHttpClientHolder` holds a shared `HttpClient` for use by content. It has Happy Eyeballs fixed and an appropriate `User-Agent`.
|
||||
* Added `DataNode.ToString()`. Makes it easier to save yaml files and debug code.
|
||||
* Added some cvars to modify discord rich presence icons.
|
||||
* .ogg files now read the `Artist` and `Title` tags and make them available via new fields in `AudioStream`.
|
||||
* The default fragment shaders now have access to the local light level (`lowp vec3 lightSample`).
|
||||
* Added `IPrototypeManager.ValidateAllPrototypesSerializable()`, which can be used to check that all currently loaded prototypes can be serialised & deserialised.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix certain debug commands and tools crashing on non-SS14 RobustToolbox games due to a missing font.
|
||||
* Discord rich presence strings are now truncated if they are too long.
|
||||
* Fixed a couple of broadphase/entity-lookup update bugs that were affecting containers and entities attached to other (non-grid/map) entities.
|
||||
* Fixed `INetChannel.Disconnect()` not properly disconnecting clients in integration tests.
|
||||
|
||||
### Other
|
||||
|
||||
* Outgoing HTTP requests now all use Happy Eyeballs to try to prioritize IPv6. This is necessary because .NET still does not support this critical feature itself.
|
||||
* Made various physics related component properties VV-editable.
|
||||
* The default EntitySystem sawmill log level now defaults to `Info` instead of `Verbose`. The level remains verbose when in debug mode.
|
||||
|
||||
### Internal
|
||||
|
||||
* The debug asserts in `DetachParentToNull()` are now more informative.
|
||||
|
||||
|
||||
## 142.0.1
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix Enum serialization.
|
||||
|
||||
|
||||
## 142.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* `EntityManager.GetAllComponents()` now returns a (EntityUid, Component) tuple
|
||||
|
||||
### New features
|
||||
|
||||
* Added `IPrototypeManager.ValidateFields()`, which uses reflection to validate that the default values of c# string fields correspond to valid entity prototypes. Validates any fields with a `ValidatePrototypeIdAttribute` and any data-field that uses the PrototypeIdSerializer custom type serializer.
|
||||
|
||||
### Other
|
||||
|
||||
* Replay playback will now log errors when encountering unhandled messages.
|
||||
* Made `GetAssemblyByName()` throw descriptive error messages.
|
||||
* Improved performance of various EntityLookupSystem functions
|
||||
|
||||
|
||||
## 141.2.1
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix component trait dictionaries not clearing on reconnect leading to bad GetComponent in areas (e.g. entire game looks black due to no entities).
|
||||
|
||||
|
||||
## 141.2.0
|
||||
|
||||
### Other
|
||||
|
||||
BIN
Resources/EngineFonts/NotoSans/NotoSansMono-Regular.ttf
Normal file
BIN
Resources/EngineFonts/NotoSans/NotoSansMono-Regular.ttf
Normal file
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
- type: uiTheme
|
||||
id: Default
|
||||
path: /Textures/Interface/Default
|
||||
path: /Textures/Interface/Default/
|
||||
colors:
|
||||
# Root
|
||||
rootBackground: "#000000"
|
||||
|
||||
@@ -17,15 +17,15 @@ cmd-error-dir-not-found = Could not find directory: {$dir}.
|
||||
cmd-failure-no-attached-entity = There is no entity attached to this shell.
|
||||
|
||||
## 'help' command
|
||||
cmd-help-desc = Display general help or help text for a specific command
|
||||
cmd-help-help = Usage: help [command name]
|
||||
cmd-oldhelp-desc = Display general help or help text for a specific command
|
||||
cmd-oldhelp-help = Usage: help [command name]
|
||||
When no command name is provided, displays general-purpose help text. If a command name is provided, displays help text for that command.
|
||||
|
||||
cmd-help-no-args = To display help for a specific command, write 'help <command>'. To list all available commands, write 'list'. To search for commands, use 'list <filter>'.
|
||||
cmd-help-unknown = Unknown command: { $command }
|
||||
cmd-help-top = { $command } - { $description }
|
||||
cmd-help-invalid-args = Invalid amount of arguments.
|
||||
cmd-help-arg-cmdname = [command name]
|
||||
cmd-oldhelp-no-args = To display help for a specific command, write 'help <command>'. To list all available commands, write 'list'. To search for commands, use 'list <filter>'.
|
||||
cmd-oldhelp-unknown = Unknown command: { $command }
|
||||
cmd-oldhelp-top = { $command } - { $description }
|
||||
cmd-oldhelp-invalid-args = Invalid amount of arguments.
|
||||
cmd-oldhelp-arg-cmdname = [command name]
|
||||
|
||||
## 'cvar' command
|
||||
cmd-cvar-desc = Gets or sets a CVar.
|
||||
@@ -558,3 +558,6 @@ cmd-vfs_ls-help = Usage: vfs_list <path>
|
||||
|
||||
cmd-vfs_ls-err-args = Need exactly 1 argument.
|
||||
cmd-vfs_ls-hint-path = <path>
|
||||
|
||||
cmd-reloadtiletextures-desc = Reloads the tile texture atlas to allow hot reloading tile sprites
|
||||
cmd-reloadtiletextures-help = Usage: reloadtiletextures
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
discord-rpc-in-main-menu = In Main Menu
|
||||
discord-rpc-in-main-menu-logo-text = I think coolsville SUCKS
|
||||
discord-rpc-character = Username: {$username}
|
||||
discord-rpc-on-server = On Server: {$servername}
|
||||
discord-rpc-players = Players: {$players}/{$maxplayers}
|
||||
discord-rpc-players = Players: {$players}/{$maxplayers}
|
||||
|
||||
@@ -18,6 +18,15 @@ input-key-F12 = F12
|
||||
input-key-F13 = F13
|
||||
input-key-F14 = F14
|
||||
input-key-F15 = F15
|
||||
input-key-F16 = F16
|
||||
input-key-F17 = F17
|
||||
input-key-F18 = F18
|
||||
input-key-F19 = F19
|
||||
input-key-F20 = F20
|
||||
input-key-F21 = F21
|
||||
input-key-F22 = F22
|
||||
input-key-F23 = F23
|
||||
input-key-F24 = F24
|
||||
input-key-Pause = Pause
|
||||
input-key-Left = Left
|
||||
input-key-Up = Up
|
||||
|
||||
169
Resources/Locale/en-US/toolshed-commands.ftl
Normal file
169
Resources/Locale/en-US/toolshed-commands.ftl
Normal file
@@ -0,0 +1,169 @@
|
||||
command-description-tpto =
|
||||
Teleport the given entities to some target entity.
|
||||
command-description-player-list =
|
||||
Returns a list of all player sessions.
|
||||
command-description-player-self =
|
||||
Returns the current player session.
|
||||
command-description-player-imm =
|
||||
Returns the session associated with the player given as argument.
|
||||
command-description-player-entity =
|
||||
Returns the entities of the input sessions.
|
||||
command-description-self =
|
||||
Returns the current attached entity.
|
||||
command-description-physics-velocity =
|
||||
Returns the velocity of the input entities.
|
||||
command-description-physics-angular-velocity =
|
||||
Returns the angular velocity of the input entities.
|
||||
command-description-buildinfo =
|
||||
Provides information about the build of the game.
|
||||
command-description-cmd-list =
|
||||
Returns a list of all commands, for this side.
|
||||
command-description-explain =
|
||||
Explains the given expression, providing command descriptions and signatures.
|
||||
command-description-search =
|
||||
Searches through the input for the provided value.
|
||||
command-description-stopwatch =
|
||||
Measures the execution time of the given expression.
|
||||
command-description-types-consumers =
|
||||
Provides all commands that can consume the given type.
|
||||
command-description-types-tree =
|
||||
Debug tool to return all types the command interpreter can downcast the input to.
|
||||
command-description-types-gettype =
|
||||
Returns the type of the input.
|
||||
command-description-types-fullname =
|
||||
Returns the full name of the input type according to CoreCLR.
|
||||
command-description-as =
|
||||
Casts the input to the given type.
|
||||
Effectively a type hint if you know the type but the interpreter does not.
|
||||
command-description-count =
|
||||
Counts the amount of entries in it's input, returning an integer.
|
||||
command-description-map =
|
||||
Maps the input over the given block, with the provided expected return type.
|
||||
This command may be modified to not need an explicit return type in the future.
|
||||
command-description-select =
|
||||
Selects N objects or N% of objects from the input.
|
||||
One can additionally invert this command with not to make it select everything except N objects instead.
|
||||
command-description-comp =
|
||||
Returns the given component from the input entities, discarding entities without that component.
|
||||
command-description-delete =
|
||||
Deletes the input entities.
|
||||
command-description-ent =
|
||||
Returns the provided entity ID.
|
||||
command-description-entities =
|
||||
Returns all entities on the server.
|
||||
command-description-paused =
|
||||
Filters the input entities by whether or not they are paused.
|
||||
This command can be inverted with not.
|
||||
command-description-with =
|
||||
Filters the input entities by whether or not they have the given component.
|
||||
This command can be inverted with not.
|
||||
command-description-fuck =
|
||||
Throws an exception.
|
||||
command-description-ecscomp-listty =
|
||||
Lists every type of component registered.
|
||||
command-description-cd =
|
||||
Changes the session's current directory to the given relative or absolute path.
|
||||
command-description-ls-here =
|
||||
Lists the contents of the current directory.
|
||||
command-description-ls-in =
|
||||
Lists the contents of the given relative or absolute path.
|
||||
command-description-methods-get =
|
||||
Returns all methods associated with the input type.
|
||||
command-description-methods-overrides =
|
||||
Returns all methods overriden on the input type.
|
||||
command-description-methods-overridesfrom =
|
||||
Returns all methods overriden from the given type on the input type.
|
||||
command-description-cmd-moo =
|
||||
Asks the important questions.
|
||||
command-description-cmd-descloc =
|
||||
Returns the localization string for a command's description.
|
||||
command-description-cmd-getshim =
|
||||
Returns a command's execution shim.
|
||||
command-description-help =
|
||||
Provides a quick rundown of how to use toolshed.
|
||||
command-description-ioc-registered =
|
||||
Returns all the types registered with IoCManager on the current thread (usually the game thread)
|
||||
command-description-ioc-get =
|
||||
Gets an instance of an IoC registration.
|
||||
command-description-loc-tryloc =
|
||||
Tries to get a localization string, returning null if unable.
|
||||
command-description-loc-loc =
|
||||
Gets a localization string, returning the unlocalized string if unable.
|
||||
command-description-physics-angular_velocity =
|
||||
Returns the angular velocity of the given entities.
|
||||
command-description-vars =
|
||||
Provides a list of all variables set in this session.
|
||||
command-description-any =
|
||||
Returns true if there's any values in the input, otherwise false.
|
||||
command-description-ArrowCommand =
|
||||
Assigns the input to a variable.
|
||||
command-description-isempty =
|
||||
Returns true if the input is empty, otherwise false.
|
||||
command-description-isnull =
|
||||
Returns true if the input is null, otherwise false.
|
||||
command-description-unique =
|
||||
Filters the input sequence for uniqueness, removing duplicate values.
|
||||
command-description-where =
|
||||
Given some input sequence IEnumerable<T>, takes a block of signature T -> bool that decides if each input value should be included in the output sequence.
|
||||
command-description-do =
|
||||
Backwards compatibility with BQL, applies the given old commands over the input sequence.
|
||||
command-description-named =
|
||||
Filters the input entities by their name, with the regex ^selector$.
|
||||
command-description-prototyped =
|
||||
Filters the input entities by their prototype.
|
||||
command-description-nearby =
|
||||
Creates a new list of all entities nearby the inputs within the given range.
|
||||
command-description-first =
|
||||
Returns the first entry of the given enumerable.
|
||||
command-description-splat =
|
||||
"Splats" a block, value, or variable, creating N copies of it in a list.
|
||||
command-description-val =
|
||||
Casts the given value, block, or variable to the given type. This is mostly a workaround for current limitations of variables.
|
||||
command-description-actor-controlled =
|
||||
Filters entities by whether or not they're actively controlled.
|
||||
command-description-actor-session =
|
||||
Returns the sessions associated with the input entities.
|
||||
command-description-physics-parent =
|
||||
Returns the parent(s) of the input entities.
|
||||
command-description-emplace =
|
||||
Runs the given block over it's inputs, with the input value placed into the variable $value within the block.
|
||||
Additionally breaks out $wx, $wy, $proto, $desc, $name, and $paused for entities.
|
||||
Can also have breakout values for other types, consult the documentation for that type for further info.
|
||||
command-description-AddCommand =
|
||||
Performs numeric addition.
|
||||
command-description-SubtractCommand =
|
||||
Performs numeric subtraction.
|
||||
command-description-MultiplyCommand =
|
||||
Performs numeric multiplication.
|
||||
command-description-DivideCommand =
|
||||
Performs numeric division.
|
||||
command-description-min =
|
||||
Returns the minimum of two values.
|
||||
command-description-max =
|
||||
Returns the maximum of two values.
|
||||
command-description-BitAndCommand =
|
||||
Performs bitwise AND.
|
||||
command-description-BitOrCommand =
|
||||
Performs bitwise OR.
|
||||
command-description-BitXorCommand =
|
||||
Performs bitwise XOR.
|
||||
command-description-neg =
|
||||
Negates the input.
|
||||
command-description-GreaterThanCommand =
|
||||
Performs a greater-than comparison, x > y.
|
||||
command-description-LessThanCommand =
|
||||
Performs a less-than comparison, x < y.
|
||||
command-description-GreaterThanOrEqualCommand =
|
||||
Performs a greater-than-or-equal comparison, x >= y.
|
||||
command-description-LessThanOrEqualCommand =
|
||||
Performs a less-than-or-equal comparison, x <= y.
|
||||
command-description-EqualCommand =
|
||||
Performs an equality comparison, returning true if the inputs are equal.
|
||||
command-description-NotEqualCommand =
|
||||
Performs an equality comparison, returning true if the inputs are not equal.
|
||||
|
||||
command-description-entitysystemupdateorder-tick =
|
||||
Lists the tick update order of entity systems.
|
||||
|
||||
command-description-entitysystemupdateorder-frame =
|
||||
Lists the frame update order of entity systems.
|
||||
293
Robust.Analyzers/DataDefinitionAnalyzer.cs
Normal file
293
Robust.Analyzers/DataDefinitionAnalyzer.cs
Normal file
@@ -0,0 +1,293 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
|
||||
namespace Robust.Analyzers;
|
||||
|
||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||
public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
|
||||
{
|
||||
private const string DataDefinitionNamespace = "Robust.Shared.Serialization.Manager.Attributes.DataDefinitionAttribute";
|
||||
private const string ImplicitDataDefinitionNamespace = "Robust.Shared.Serialization.Manager.Attributes.ImplicitDataDefinitionForInheritorsAttribute";
|
||||
private const string DataFieldBaseNamespace = "Robust.Shared.Serialization.Manager.Attributes.DataFieldBaseAttribute";
|
||||
|
||||
private static readonly DiagnosticDescriptor DataDefinitionPartialRule = new(
|
||||
Diagnostics.IdDataDefinitionPartial,
|
||||
"Type must be partial",
|
||||
"Type {0} is a DataDefinition but is not partial.",
|
||||
"Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
true,
|
||||
"Make sure to mark any type that is a data definition as partial."
|
||||
);
|
||||
|
||||
private static readonly DiagnosticDescriptor NestedDataDefinitionPartialRule = new(
|
||||
Diagnostics.IdNestedDataDefinitionPartial,
|
||||
"Type must be partial",
|
||||
"Type {0} contains nested data definition {1} but is not partial.",
|
||||
"Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
true,
|
||||
"Make sure to mark any type containing a nested data definition as partial."
|
||||
);
|
||||
|
||||
private static readonly DiagnosticDescriptor DataFieldWritableRule = new(
|
||||
Diagnostics.IdDataFieldWritable,
|
||||
"Data field must not be readonly",
|
||||
"Data field {0} in data definition {1} is readonly.",
|
||||
"Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
true,
|
||||
"Make sure to remove the readonly modifier."
|
||||
);
|
||||
|
||||
private static readonly DiagnosticDescriptor DataFieldPropertyWritableRule = new(
|
||||
Diagnostics.IdDataFieldPropertyWritable,
|
||||
"Data field property must have a setter",
|
||||
"Data field property {0} in data definition {1} does not have a setter.",
|
||||
"Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
true,
|
||||
"Make sure to add a setter."
|
||||
);
|
||||
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(
|
||||
DataDefinitionPartialRule, NestedDataDefinitionPartialRule, DataFieldWritableRule, DataFieldPropertyWritableRule
|
||||
);
|
||||
|
||||
public override void Initialize(AnalysisContext context)
|
||||
{
|
||||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.None);
|
||||
context.EnableConcurrentExecution();
|
||||
|
||||
context.RegisterSyntaxNodeAction(AnalyzeDataDefinition, SyntaxKind.ClassDeclaration);
|
||||
context.RegisterSyntaxNodeAction(AnalyzeDataDefinition, SyntaxKind.StructDeclaration);
|
||||
context.RegisterSyntaxNodeAction(AnalyzeDataDefinition, SyntaxKind.RecordDeclaration);
|
||||
context.RegisterSyntaxNodeAction(AnalyzeDataDefinition, SyntaxKind.RecordStructDeclaration);
|
||||
context.RegisterSyntaxNodeAction(AnalyzeDataDefinition, SyntaxKind.InterfaceDeclaration);
|
||||
|
||||
context.RegisterSyntaxNodeAction(AnalyzeDataField, SyntaxKind.FieldDeclaration);
|
||||
context.RegisterSyntaxNodeAction(AnalyzeDataFieldProperty, SyntaxKind.PropertyDeclaration);
|
||||
}
|
||||
|
||||
private void AnalyzeDataDefinition(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
if (context.Node is not TypeDeclarationSyntax declaration)
|
||||
return;
|
||||
|
||||
var type = context.SemanticModel.GetDeclaredSymbol(declaration)!;
|
||||
if (!IsDataDefinition(type))
|
||||
return;
|
||||
|
||||
if (!IsPartial(declaration))
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(DataDefinitionPartialRule, declaration.Keyword.GetLocation(), type.Name));
|
||||
}
|
||||
|
||||
var containingType = type.ContainingType;
|
||||
while (containingType != null)
|
||||
{
|
||||
var containingTypeDeclaration = (TypeDeclarationSyntax) containingType.DeclaringSyntaxReferences[0].GetSyntax();
|
||||
if (!IsPartial(containingTypeDeclaration))
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(NestedDataDefinitionPartialRule, containingTypeDeclaration.Keyword.GetLocation(), containingType.Name, type.Name));
|
||||
}
|
||||
|
||||
containingType = containingType.ContainingType;
|
||||
}
|
||||
}
|
||||
|
||||
private void AnalyzeDataField(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
if (context.Node is not FieldDeclarationSyntax field)
|
||||
return;
|
||||
|
||||
var typeDeclaration = field.FirstAncestorOrSelf<TypeDeclarationSyntax>();
|
||||
if (typeDeclaration == null)
|
||||
return;
|
||||
|
||||
var type = context.SemanticModel.GetDeclaredSymbol(typeDeclaration)!;
|
||||
if (!IsDataDefinition(type))
|
||||
return;
|
||||
|
||||
foreach (var variable in field.Declaration.Variables)
|
||||
{
|
||||
var fieldSymbol = context.SemanticModel.GetDeclaredSymbol(variable);
|
||||
if (fieldSymbol == null)
|
||||
continue;
|
||||
|
||||
if (IsReadOnlyDataField(type, fieldSymbol))
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(DataFieldWritableRule, context.Node.GetLocation(), fieldSymbol.Name, type.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AnalyzeDataFieldProperty(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
if (context.Node is not PropertyDeclarationSyntax property)
|
||||
return;
|
||||
|
||||
var typeDeclaration = property.FirstAncestorOrSelf<TypeDeclarationSyntax>();
|
||||
if (typeDeclaration == null)
|
||||
return;
|
||||
|
||||
var type = context.SemanticModel.GetDeclaredSymbol(typeDeclaration)!;
|
||||
if (!IsDataDefinition(type) || type.IsRecord || type.IsValueType)
|
||||
return;
|
||||
|
||||
var propertySymbol = context.SemanticModel.GetDeclaredSymbol(property);
|
||||
if (propertySymbol == null)
|
||||
return;
|
||||
|
||||
if (IsReadOnlyDataField(type, propertySymbol))
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(DataFieldPropertyWritableRule, context.Node.GetLocation(), propertySymbol.Name, type.Name));
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsReadOnlyDataField(ITypeSymbol type, ISymbol field)
|
||||
{
|
||||
if (!IsDataField(field, out _, out _))
|
||||
return false;
|
||||
|
||||
return IsReadOnlyMember(type, field);
|
||||
}
|
||||
|
||||
private static bool IsPartial(TypeDeclarationSyntax type)
|
||||
{
|
||||
return type.Modifiers.IndexOf(SyntaxKind.PartialKeyword) != -1;
|
||||
}
|
||||
|
||||
private static bool IsDataDefinition(ITypeSymbol? type)
|
||||
{
|
||||
if (type == null)
|
||||
return false;
|
||||
|
||||
return HasAttribute(type, DataDefinitionNamespace) ||
|
||||
IsImplicitDataDefinition(type);
|
||||
}
|
||||
|
||||
private static bool IsDataField(ISymbol member, out ITypeSymbol type, out AttributeData attribute)
|
||||
{
|
||||
// TODO data records and other attributes
|
||||
if (member is IFieldSymbol field)
|
||||
{
|
||||
foreach (var attr in field.GetAttributes())
|
||||
{
|
||||
if (attr.AttributeClass != null && Inherits(attr.AttributeClass, DataFieldBaseNamespace))
|
||||
{
|
||||
type = field.Type;
|
||||
attribute = attr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (member is IPropertySymbol property)
|
||||
{
|
||||
foreach (var attr in property.GetAttributes())
|
||||
{
|
||||
if (attr.AttributeClass != null && Inherits(attr.AttributeClass, DataFieldBaseNamespace))
|
||||
{
|
||||
type = property.Type;
|
||||
attribute = attr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type = null!;
|
||||
attribute = null!;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool Inherits(ITypeSymbol type, string parent)
|
||||
{
|
||||
foreach (var baseType in GetBaseTypes(type))
|
||||
{
|
||||
if (baseType.ToDisplayString() == parent)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsReadOnlyMember(ITypeSymbol type, ISymbol member)
|
||||
{
|
||||
if (member is IFieldSymbol field)
|
||||
{
|
||||
return field.IsReadOnly;
|
||||
}
|
||||
else if (member is IPropertySymbol property)
|
||||
{
|
||||
if (property.SetMethod == null)
|
||||
return true;
|
||||
|
||||
if (property.SetMethod.IsInitOnly)
|
||||
return type.IsReferenceType;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool HasAttribute(ITypeSymbol type, string attributeName)
|
||||
{
|
||||
foreach (var attribute in type.GetAttributes())
|
||||
{
|
||||
if (attribute.AttributeClass?.ToDisplayString() == attributeName)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsImplicitDataDefinition(ITypeSymbol type)
|
||||
{
|
||||
if (HasAttribute(type, ImplicitDataDefinitionNamespace))
|
||||
return true;
|
||||
|
||||
foreach (var baseType in GetBaseTypes(type))
|
||||
{
|
||||
if (HasAttribute(baseType, ImplicitDataDefinitionNamespace))
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var @interface in type.AllInterfaces)
|
||||
{
|
||||
if (IsImplicitDataDefinitionInterface(@interface))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsImplicitDataDefinitionInterface(ITypeSymbol @interface)
|
||||
{
|
||||
if (HasAttribute(@interface, ImplicitDataDefinitionNamespace))
|
||||
return true;
|
||||
|
||||
foreach (var subInterface in @interface.AllInterfaces)
|
||||
{
|
||||
if (HasAttribute(subInterface, ImplicitDataDefinitionNamespace))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static IEnumerable<ITypeSymbol> GetBaseTypes(ITypeSymbol type)
|
||||
{
|
||||
var baseType = type.BaseType;
|
||||
while (baseType != null)
|
||||
{
|
||||
yield return baseType;
|
||||
baseType = baseType.BaseType;
|
||||
}
|
||||
}
|
||||
}
|
||||
168
Robust.Analyzers/DataDefinitionFixer.cs
Normal file
168
Robust.Analyzers/DataDefinitionFixer.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
#nullable enable
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CodeActions;
|
||||
using Microsoft.CodeAnalysis.CodeFixes;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxKind;
|
||||
using static Robust.Analyzers.Diagnostics;
|
||||
|
||||
namespace Robust.Analyzers;
|
||||
|
||||
[ExportCodeFixProvider(LanguageNames.CSharp)]
|
||||
public sealed class DefinitionFixer : CodeFixProvider
|
||||
{
|
||||
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(
|
||||
IdDataDefinitionPartial, IdNestedDataDefinitionPartial, IdDataFieldWritable, IdDataFieldPropertyWritable
|
||||
);
|
||||
|
||||
public override Task RegisterCodeFixesAsync(CodeFixContext context)
|
||||
{
|
||||
foreach (var diagnostic in context.Diagnostics)
|
||||
{
|
||||
switch (diagnostic.Id)
|
||||
{
|
||||
case IdDataDefinitionPartial:
|
||||
return RegisterPartialTypeFix(context, diagnostic);
|
||||
case IdNestedDataDefinitionPartial:
|
||||
return RegisterPartialTypeFix(context, diagnostic);
|
||||
case IdDataFieldWritable:
|
||||
return RegisterDataFieldFix(context, diagnostic);
|
||||
case IdDataFieldPropertyWritable:
|
||||
return RegisterDataFieldPropertyFix(context, diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override FixAllProvider GetFixAllProvider()
|
||||
{
|
||||
return WellKnownFixAllProviders.BatchFixer;
|
||||
}
|
||||
|
||||
private static async Task RegisterPartialTypeFix(CodeFixContext context, Diagnostic diagnostic)
|
||||
{
|
||||
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
|
||||
var span = diagnostic.Location.SourceSpan;
|
||||
var token = root?.FindToken(span.Start).Parent?.AncestorsAndSelf().OfType<TypeDeclarationSyntax>().First();
|
||||
|
||||
if (token == null)
|
||||
return;
|
||||
|
||||
context.RegisterCodeFix(CodeAction.Create(
|
||||
"Make type partial",
|
||||
c => MakeDataDefinitionPartial(context.Document, token, c),
|
||||
"Make type partial"
|
||||
), diagnostic);
|
||||
}
|
||||
|
||||
private static async Task<Document> MakeDataDefinitionPartial(Document document, TypeDeclarationSyntax declaration, CancellationToken cancellation)
|
||||
{
|
||||
var root = (CompilationUnitSyntax?) await document.GetSyntaxRootAsync(cancellation);
|
||||
var token = SyntaxFactory.Token(PartialKeyword);
|
||||
var newDeclaration = declaration.AddModifiers(token);
|
||||
|
||||
root = root!.ReplaceNode(declaration, newDeclaration);
|
||||
|
||||
return document.WithSyntaxRoot(root);
|
||||
}
|
||||
|
||||
private static async Task RegisterDataFieldFix(CodeFixContext context, Diagnostic diagnostic)
|
||||
{
|
||||
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
|
||||
var span = diagnostic.Location.SourceSpan;
|
||||
var field = root?.FindToken(span.Start).Parent?.AncestorsAndSelf().OfType<FieldDeclarationSyntax>().FirstOrDefault();
|
||||
|
||||
if (field == null)
|
||||
return;
|
||||
|
||||
context.RegisterCodeFix(CodeAction.Create(
|
||||
"Make data field writable",
|
||||
c => MakeFieldWritable(context.Document, field, c),
|
||||
"Make data field writable"
|
||||
), diagnostic);
|
||||
}
|
||||
|
||||
private static async Task RegisterDataFieldPropertyFix(CodeFixContext context, Diagnostic diagnostic)
|
||||
{
|
||||
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
|
||||
var span = diagnostic.Location.SourceSpan;
|
||||
var property = root?.FindToken(span.Start).Parent?.AncestorsAndSelf().OfType<PropertyDeclarationSyntax>().FirstOrDefault();
|
||||
|
||||
if (property == null)
|
||||
return;
|
||||
|
||||
context.RegisterCodeFix(CodeAction.Create(
|
||||
"Make data field writable",
|
||||
c => MakePropertyWritable(context.Document, property, c),
|
||||
"Make data field writable"
|
||||
), diagnostic);
|
||||
}
|
||||
|
||||
private static async Task<Document> MakeFieldWritable(Document document, FieldDeclarationSyntax declaration, CancellationToken cancellation)
|
||||
{
|
||||
var root = (CompilationUnitSyntax?) await document.GetSyntaxRootAsync(cancellation);
|
||||
var token = declaration.Modifiers.First(t => t.IsKind(ReadOnlyKeyword));
|
||||
var newDeclaration = declaration.WithModifiers(declaration.Modifiers.Remove(token));
|
||||
|
||||
root = root!.ReplaceNode(declaration, newDeclaration);
|
||||
|
||||
return document.WithSyntaxRoot(root);
|
||||
}
|
||||
|
||||
private static async Task<Document> MakePropertyWritable(Document document, PropertyDeclarationSyntax declaration, CancellationToken cancellation)
|
||||
{
|
||||
var root = (CompilationUnitSyntax?) await document.GetSyntaxRootAsync(cancellation);
|
||||
var newDeclaration = declaration;
|
||||
var privateSet = newDeclaration
|
||||
.AccessorList?
|
||||
.Accessors
|
||||
.FirstOrDefault(s => s.IsKind(SetAccessorDeclaration) || s.IsKind(InitAccessorDeclaration));
|
||||
|
||||
if (newDeclaration.AccessorList != null && privateSet != null)
|
||||
{
|
||||
newDeclaration = newDeclaration.WithAccessorList(
|
||||
newDeclaration.AccessorList.WithAccessors(
|
||||
newDeclaration.AccessorList.Accessors.Remove(privateSet)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
AccessorDeclarationSyntax setter;
|
||||
if (declaration.Modifiers.Any(m => m.IsKind(PrivateKeyword)))
|
||||
{
|
||||
setter = SyntaxFactory.AccessorDeclaration(
|
||||
SetAccessorDeclaration,
|
||||
default,
|
||||
default,
|
||||
SyntaxFactory.Token(SetKeyword),
|
||||
default,
|
||||
default,
|
||||
SyntaxFactory.Token(SemicolonToken)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
setter = SyntaxFactory.AccessorDeclaration(
|
||||
SetAccessorDeclaration,
|
||||
default,
|
||||
SyntaxFactory.TokenList(SyntaxFactory.Token(PrivateKeyword)),
|
||||
SyntaxFactory.Token(SetKeyword),
|
||||
default,
|
||||
default,
|
||||
SyntaxFactory.Token(SemicolonToken)
|
||||
);
|
||||
}
|
||||
|
||||
newDeclaration = newDeclaration.AddAccessorListAccessors(setter);
|
||||
|
||||
root = root!.ReplaceNode(declaration, newDeclaration);
|
||||
|
||||
return document.WithSyntaxRoot(root);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,10 @@ public static class Diagnostics
|
||||
public const string IdValueEventSubscribedByRef = "RA0014";
|
||||
public const string IdByRefEventRaisedByValue = "RA0015";
|
||||
public const string IdValueEventRaisedByRef = "RA0016";
|
||||
public const string IdDataDefinitionPartial = "RA0017";
|
||||
public const string IdNestedDataDefinitionPartial = "RA0018";
|
||||
public const string IdDataFieldWritable = "RA0019";
|
||||
public const string IdDataFieldPropertyWritable = "RA0020";
|
||||
|
||||
public static SuppressionDescriptor MeansImplicitAssignment =>
|
||||
new SuppressionDescriptor("RADC1000", "CS0649", "Marked as implicitly assigned.");
|
||||
|
||||
@@ -8,7 +8,7 @@ using Robust.UnitTesting.Server;
|
||||
namespace Robust.Benchmarks.EntityManager;
|
||||
|
||||
[Virtual]
|
||||
public class AddRemoveComponentBenchmark
|
||||
public partial class AddRemoveComponentBenchmark
|
||||
{
|
||||
private ISimulation _simulation = default!;
|
||||
private IEntityManager _entityManager = default!;
|
||||
@@ -48,7 +48,7 @@ public class AddRemoveComponentBenchmark
|
||||
}
|
||||
|
||||
[ComponentProtoName("A")]
|
||||
public sealed class A : Component
|
||||
public sealed partial class A : Component
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using Robust.UnitTesting.Server;
|
||||
|
||||
namespace Robust.Benchmarks.EntityManager;
|
||||
|
||||
public class ComponentIteratorBenchmark
|
||||
public partial class ComponentIteratorBenchmark
|
||||
{
|
||||
private ISimulation _simulation = default!;
|
||||
private IEntityManager _entityManager = default!;
|
||||
@@ -69,7 +69,7 @@ public class ComponentIteratorBenchmark
|
||||
}
|
||||
|
||||
[ComponentProtoName("A")]
|
||||
public sealed class A : Component
|
||||
public sealed partial class A : Component
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Analyzers;
|
||||
@@ -9,7 +8,7 @@ using Robust.UnitTesting.Server;
|
||||
namespace Robust.Benchmarks.EntityManager;
|
||||
|
||||
[Virtual]
|
||||
public class GetComponentBenchmark
|
||||
public partial class GetComponentBenchmark
|
||||
{
|
||||
private ISimulation _simulation = default!;
|
||||
private IEntityManager _entityManager = default!;
|
||||
@@ -55,7 +54,7 @@ public class GetComponentBenchmark
|
||||
}
|
||||
|
||||
[ComponentProtoName("A")]
|
||||
public sealed class A : Component
|
||||
public sealed partial class A : Component
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ using Robust.UnitTesting.Server;
|
||||
namespace Robust.Benchmarks.EntityManager;
|
||||
|
||||
[Virtual]
|
||||
public class SpawnDeleteEntityBenchmark
|
||||
public partial class SpawnDeleteEntityBenchmark
|
||||
{
|
||||
private ISimulation _simulation = default!;
|
||||
private IEntityManager _entityManager = default!;
|
||||
@@ -56,7 +56,7 @@ public class SpawnDeleteEntityBenchmark
|
||||
}
|
||||
|
||||
[ComponentProtoName("A")]
|
||||
public sealed class A : Component
|
||||
public sealed partial class A : Component
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ namespace Robust.Benchmarks.Serialization.Definitions
|
||||
{
|
||||
[DataDefinition]
|
||||
[Virtual]
|
||||
public class DataDefinitionWithString
|
||||
public partial class DataDefinitionWithString
|
||||
{
|
||||
[DataField("string")]
|
||||
public string StringField { get; init; } = default!;
|
||||
public string StringField { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
namespace Robust.Benchmarks.Serialization.Definitions
|
||||
{
|
||||
[DataDefinition]
|
||||
public sealed class SealedDataDefinitionWithString
|
||||
public sealed partial class SealedDataDefinitionWithString
|
||||
{
|
||||
[DataField("string")]
|
||||
public string StringField { get; init; } = default!;
|
||||
public string StringField { get; private set; } = default!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
@@ -10,8 +11,7 @@ namespace Robust.Benchmarks.Serialization.Definitions
|
||||
/// Arbitrarily large data definition for benchmarks.
|
||||
/// Taken from content.
|
||||
/// </summary>
|
||||
[Prototype("seed")]
|
||||
public sealed class SeedDataDefinition : IPrototype
|
||||
public sealed partial class SeedDataDefinition : Component
|
||||
{
|
||||
public const string Prototype = @"
|
||||
- type: seed
|
||||
@@ -106,7 +106,7 @@ namespace Robust.Benchmarks.Serialization.Definitions
|
||||
}
|
||||
|
||||
[DataDefinition]
|
||||
public struct SeedChemQuantity
|
||||
public partial struct SeedChemQuantity
|
||||
{
|
||||
[DataField("Min")]
|
||||
public int Min;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using Robust.Client.Graphics;
|
||||
|
||||
namespace Robust.Client.Audio;
|
||||
@@ -8,13 +8,17 @@ public sealed class AudioStream
|
||||
public TimeSpan Length { get; }
|
||||
internal ClydeHandle? ClydeHandle { get; }
|
||||
public string? Name { get; }
|
||||
public string? Title { get; }
|
||||
public string? Artist { get; }
|
||||
public int ChannelCount { get; }
|
||||
|
||||
internal AudioStream(ClydeHandle handle, TimeSpan length, int channelCount, string? name = null)
|
||||
internal AudioStream(ClydeHandle handle, TimeSpan length, int channelCount, string? name = null, string? title = null, string? artist = null)
|
||||
{
|
||||
ClydeHandle = handle;
|
||||
Length = length;
|
||||
ChannelCount = channelCount;
|
||||
Name = name;
|
||||
Title = title;
|
||||
Artist = artist;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ namespace Robust.Client
|
||||
deps.Register<IComponentFactory, ComponentFactory>();
|
||||
deps.Register<ITileDefinitionManager, ClydeTileDefinitionManager>();
|
||||
deps.Register<IClydeTileDefinitionManager, ClydeTileDefinitionManager>();
|
||||
deps.Register<ClydeTileDefinitionManager, ClydeTileDefinitionManager>();
|
||||
deps.Register<GameController, GameController>();
|
||||
deps.Register<IGameController, GameController>();
|
||||
deps.Register<IGameControllerInternal, GameController>();
|
||||
|
||||
@@ -6,7 +6,7 @@ using Robust.Shared.Physics;
|
||||
namespace Robust.Client.ComponentTrees;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class LightTreeComponent: Component, IComponentTreeComponent<PointLightComponent>
|
||||
public sealed partial class LightTreeComponent: Component, IComponentTreeComponent<PointLightComponent>
|
||||
{
|
||||
public DynamicTree<ComponentTreeEntry<PointLightComponent>> Tree { get; set; } = default!;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using Robust.Shared.Physics;
|
||||
namespace Robust.Client.ComponentTrees;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class SpriteTreeComponent: Component, IComponentTreeComponent<SpriteComponent>
|
||||
public sealed partial class SpriteTreeComponent: Component, IComponentTreeComponent<SpriteComponent>
|
||||
{
|
||||
public DynamicTree<ComponentTreeEntry<SpriteComponent>> Tree { get; set; } = default!;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ internal sealed partial class ClientConsoleHost
|
||||
private int _completionSeq;
|
||||
|
||||
|
||||
public async Task<CompletionResult> GetCompletions(List<string> args, CancellationToken cancel)
|
||||
public async Task<CompletionResult> GetCompletions(List<string> args, string argStr, CancellationToken cancel)
|
||||
{
|
||||
// Last element is the command currently being typed. May be empty.
|
||||
|
||||
@@ -24,10 +24,10 @@ internal sealed partial class ClientConsoleHost
|
||||
if (delay > 0)
|
||||
await Task.Delay((int)(delay * 1000), cancel);
|
||||
|
||||
return await CalcCompletions(args, cancel);
|
||||
return await CalcCompletions(args, argStr, cancel);
|
||||
}
|
||||
|
||||
private Task<CompletionResult> CalcCompletions(List<string> args, CancellationToken cancel)
|
||||
private Task<CompletionResult> CalcCompletions(List<string> args, string argStr, CancellationToken cancel)
|
||||
{
|
||||
if (args.Count == 1)
|
||||
{
|
||||
@@ -44,10 +44,10 @@ internal sealed partial class ClientConsoleHost
|
||||
if (!AvailableCommands.TryGetValue(args[0], out var cmd))
|
||||
return Task.FromResult(CompletionResult.Empty);
|
||||
|
||||
return cmd.GetCompletionAsync(LocalShell, args.ToArray()[1..], cancel).AsTask();
|
||||
return cmd.GetCompletionAsync(LocalShell, args.ToArray()[1..], argStr, cancel).AsTask();
|
||||
}
|
||||
|
||||
private Task<CompletionResult> DoServerCompletions(List<string> args, CancellationToken cancel)
|
||||
private Task<CompletionResult> DoServerCompletions(List<string> args, string argStr, CancellationToken cancel)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<CompletionResult>();
|
||||
var cts = CancellationTokenSource.CreateLinkedTokenSource(cancel);
|
||||
@@ -62,6 +62,7 @@ internal sealed partial class ClientConsoleHost
|
||||
var msg = new MsgConCompletion
|
||||
{
|
||||
Args = args.ToArray(),
|
||||
ArgString = argStr,
|
||||
Seq = seq
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ using Robust.Shared.Console;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Players;
|
||||
@@ -21,13 +22,13 @@ namespace Robust.Client.Console
|
||||
{
|
||||
public sealed class AddStringArgs : EventArgs
|
||||
{
|
||||
public string Text { get; }
|
||||
public FormattedMessage Text { get; }
|
||||
|
||||
public bool Local { get; }
|
||||
|
||||
public bool Error { get; }
|
||||
|
||||
public AddStringArgs(string text, bool local, bool error)
|
||||
public AddStringArgs(FormattedMessage text, bool local, bool error)
|
||||
{
|
||||
Text = text;
|
||||
Local = local;
|
||||
@@ -132,10 +133,17 @@ namespace Robust.Client.Console
|
||||
AddFormatted?.Invoke(this, new AddFormattedMessageArgs(message));
|
||||
}
|
||||
|
||||
public override void WriteLine(ICommonSession? session, FormattedMessage msg)
|
||||
{
|
||||
AddFormattedLine(msg);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void WriteError(ICommonSession? session, string text)
|
||||
{
|
||||
OutputText(text, true, true);
|
||||
var msg = new FormattedMessage();
|
||||
msg.AddText(text);
|
||||
OutputText(msg, true, true);
|
||||
}
|
||||
|
||||
public bool IsCmdServer(IConsoleCommand cmd)
|
||||
@@ -151,8 +159,13 @@ namespace Robust.Client.Console
|
||||
if (string.IsNullOrWhiteSpace(command))
|
||||
return;
|
||||
|
||||
WriteLine(null, "");
|
||||
var msg = new FormattedMessage();
|
||||
msg.PushColor(Color.Gold);
|
||||
msg.AddText("> " + command);
|
||||
msg.Pop();
|
||||
// echo the command locally
|
||||
WriteLine(null, "> " + command);
|
||||
OutputText(msg, true, false);
|
||||
|
||||
//Commands are processed locally and then sent to the server to be processed there again.
|
||||
var args = new List<string>();
|
||||
@@ -205,7 +218,9 @@ namespace Robust.Client.Console
|
||||
/// <inheritdoc />
|
||||
public override void WriteLine(ICommonSession? session, string text)
|
||||
{
|
||||
OutputText(text, true, false);
|
||||
var msg = new FormattedMessage();
|
||||
msg.AddText(text);
|
||||
OutputText(msg, true, false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -214,12 +229,12 @@ namespace Robust.Client.Console
|
||||
// We don't have anything to dispose.
|
||||
}
|
||||
|
||||
private void OutputText(string text, bool local, bool error)
|
||||
private void OutputText(FormattedMessage text, bool local, bool error)
|
||||
{
|
||||
AddString?.Invoke(this, new AddStringArgs(text, local, error));
|
||||
|
||||
var level = error ? LogLevel.Warning : LogLevel.Info;
|
||||
_conLogger.Log(level, text);
|
||||
_conLogger.Log(level, text.ToString());
|
||||
}
|
||||
|
||||
private void OnNetworkConnected(object? sender, NetChannelArgs netChannelArgs)
|
||||
@@ -229,7 +244,7 @@ namespace Robust.Client.Console
|
||||
|
||||
private void HandleConCmdAck(MsgConCmdAck msg)
|
||||
{
|
||||
OutputText("< " + msg.Text, false, msg.Error);
|
||||
OutputText(msg.Text, false, msg.Error);
|
||||
}
|
||||
|
||||
private void HandleConCmdReg(MsgConCmdReg msg)
|
||||
@@ -303,13 +318,14 @@ namespace Robust.Client.Console
|
||||
public async ValueTask<CompletionResult> GetCompletionAsync(
|
||||
IConsoleShell shell,
|
||||
string[] args,
|
||||
string argStr,
|
||||
CancellationToken cancel)
|
||||
{
|
||||
var host = (ClientConsoleHost)shell.ConsoleHost;
|
||||
var argsList = args.ToList();
|
||||
argsList.Insert(0, Command);
|
||||
|
||||
return await host.DoServerCompletions(argsList, cancel);
|
||||
return await host.DoServerCompletions(argsList, argStr, cancel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,10 +343,11 @@ namespace Robust.Client.Console
|
||||
public override async ValueTask<CompletionResult> GetCompletionAsync(
|
||||
IConsoleShell shell,
|
||||
string[] args,
|
||||
string argStr,
|
||||
CancellationToken cancel)
|
||||
{
|
||||
var host = (ClientConsoleHost)shell.ConsoleHost;
|
||||
return await host.DoServerCompletions(args.ToList(), cancel);
|
||||
return await host.DoServerCompletions(args.ToList(), argStr[">".Length..], cancel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -630,7 +630,7 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var mousePos = _eye.ScreenToMap(_input.MouseScreenPosition);
|
||||
var mousePos = _eye.PixelToMap(_input.MouseScreenPosition);
|
||||
|
||||
if (!_map.TryFindGridAt(mousePos, out var gridUid, out var grid))
|
||||
{
|
||||
|
||||
@@ -19,6 +19,6 @@ namespace Robust.Client.Console
|
||||
|
||||
void AddFormattedLine(FormattedMessage message);
|
||||
|
||||
Task<CompletionResult> GetCompletions(List<string> args, CancellationToken cancel);
|
||||
Task<CompletionResult> GetCompletions(List<string> args, string argStr, CancellationToken cancel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace Robust.Client.Debugging
|
||||
}
|
||||
|
||||
var mouseSpot = _inputManager.MouseScreenPosition;
|
||||
var spot = _eyeManager.ScreenToMap(mouseSpot);
|
||||
var spot = _eyeManager.PixelToMap(mouseSpot);
|
||||
|
||||
if (!_mapManager.TryFindGridAt(spot, out var gridUid, out var grid))
|
||||
{
|
||||
|
||||
@@ -218,7 +218,7 @@ namespace Robust.Client.Debugging
|
||||
_debugPhysicsSystem = system;
|
||||
_lookup = lookup;
|
||||
_physicsSystem = physicsSystem;
|
||||
_font = new VectorFont(cache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf"), 10);
|
||||
_font = new VectorFont(cache.GetResource<FontResource>("/EngineFonts/NotoSans/NotoSans-Regular.ttf"), 10);
|
||||
}
|
||||
|
||||
private void DrawWorld(DrawingHandleWorld worldHandle, OverlayDrawArgs args)
|
||||
@@ -371,7 +371,7 @@ namespace Robust.Client.Debugging
|
||||
if ((_debugPhysicsSystem.Flags & PhysicsDebugFlags.ShapeInfo) != 0x0)
|
||||
{
|
||||
var hoverBodies = new List<PhysicsComponent>();
|
||||
var bounds = Box2.UnitCentered.Translated(_eyeManager.ScreenToMap(mousePos.Position).Position);
|
||||
var bounds = Box2.UnitCentered.Translated(_eyeManager.PixelToMap(mousePos.Position).Position);
|
||||
|
||||
foreach (var physBody in _physicsSystem.GetCollidingEntities(mapId, bounds))
|
||||
{
|
||||
@@ -404,7 +404,7 @@ namespace Robust.Client.Debugging
|
||||
|
||||
if ((_debugPhysicsSystem.Flags & PhysicsDebugFlags.Distance) != 0x0)
|
||||
{
|
||||
var mapPos = _eyeManager.ScreenToMap(mousePos);
|
||||
var mapPos = _eyeManager.PixelToMap(mousePos);
|
||||
|
||||
if (mapPos.MapId != args.MapId)
|
||||
return;
|
||||
|
||||
@@ -33,6 +33,7 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Profiling;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Replays;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
@@ -85,6 +86,7 @@ namespace Robust.Client
|
||||
[Dependency] private readonly IReplayLoadManager _replayLoader = default!;
|
||||
[Dependency] private readonly IReplayPlaybackManager _replayPlayback = default!;
|
||||
[Dependency] private readonly IReplayRecordingManagerInternal _replayRecording = default!;
|
||||
[Dependency] private readonly IReflectionManager _reflectionManager = default!;
|
||||
|
||||
private IWebViewManagerHook? _webViewHook;
|
||||
|
||||
@@ -162,6 +164,7 @@ namespace Robust.Client
|
||||
// before prototype load.
|
||||
ProgramShared.FinishCheckBadFileExtensions(checkBadExtensions);
|
||||
|
||||
_reflectionManager.Initialize();
|
||||
_prototypeManager.Initialize();
|
||||
_prototypeManager.LoadDefaultPrototypes();
|
||||
_prototypeManager.ResolveResults();
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Robust.Client.GameObjects
|
||||
/// Plays back <see cref="Animation"/>s on entities.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class AnimationPlayerComponent : Component
|
||||
public sealed partial class AnimationPlayerComponent : Component
|
||||
{
|
||||
// TODO: Give this component a friend someday. Way too much content shit to change atm ._.
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Robust.Client.GameObjects;
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[Access(typeof(GenericVisualizerSystem))]
|
||||
public sealed class GenericVisualizerComponent : Component
|
||||
public sealed partial class GenericVisualizerComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a nested dictionary that maps appearance data keys -> sprite layer keys -> appearance data values -> layer data.
|
||||
|
||||
@@ -10,7 +10,7 @@ using Robust.Shared.ViewVariables;
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[RegisterComponent, ComponentReference(typeof(SharedEyeComponent))]
|
||||
public sealed class EyeComponent : SharedEyeComponent
|
||||
public sealed partial class EyeComponent : SharedEyeComponent
|
||||
{
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace Robust.Client.GameObjects;
|
||||
/// updated.
|
||||
/// </remarks>
|
||||
[RegisterComponent]
|
||||
public sealed class IconComponent : Component
|
||||
public sealed partial class IconComponent : Component
|
||||
{
|
||||
[IncludeDataField]
|
||||
public readonly SpriteSpecifier.Rsi Icon = default!;
|
||||
public SpriteSpecifier.Rsi Icon = default!;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Robust.Client.GameObjects
|
||||
/// Defines data fields used in the <see cref="InputSystem"/>.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class InputComponent : Component
|
||||
public sealed partial class InputComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The context that will be made active for a client that attaches to this entity.
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedPointLightComponent))]
|
||||
public sealed class PointLightComponent : SharedPointLightComponent, IComponentTreeEntry<PointLightComponent>
|
||||
public sealed partial class PointLightComponent : SharedPointLightComponent, IComponentTreeEntry<PointLightComponent>
|
||||
{
|
||||
public EntityUid? TreeUid { get; set; }
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public interface IRenderableComponent : IComponent
|
||||
public partial interface IRenderableComponent : IComponent
|
||||
{
|
||||
int DrawDepth { get; set; }
|
||||
float Bottom { get; }
|
||||
|
||||
@@ -32,7 +32,7 @@ using static Robust.Shared.Serialization.TypeSerializers.Implementations.SpriteS
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class SpriteComponent : Component, IComponentDebug, ISerializationHooks, IComponentTreeEntry<SpriteComponent>, IAnimationProperties
|
||||
public sealed partial class SpriteComponent : Component, IComponentDebug, ISerializationHooks, IComponentTreeEntry<SpriteComponent>, IAnimationProperties
|
||||
{
|
||||
[Dependency] private readonly IResourceCache resourceCache = default!;
|
||||
[Dependency] private readonly IPrototypeManager prototypes = default!;
|
||||
@@ -167,40 +167,9 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
public bool TreeUpdateQueued { get; set; }
|
||||
|
||||
[DataField("layerDatums")]
|
||||
private List<PrototypeLayerData> LayerDatums
|
||||
{
|
||||
get
|
||||
{
|
||||
var layerDatums = new List<PrototypeLayerData>();
|
||||
foreach (var layer in Layers)
|
||||
{
|
||||
layerDatums.Add(layer.ToPrototypeData());
|
||||
}
|
||||
|
||||
return layerDatums;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null) return;
|
||||
|
||||
Layers.Clear();
|
||||
foreach (var layerDatum in value)
|
||||
{
|
||||
AddLayer(layerDatum);
|
||||
}
|
||||
|
||||
_layerMapShared = true;
|
||||
|
||||
QueueUpdateRenderTree();
|
||||
QueueUpdateIsInert();
|
||||
}
|
||||
}
|
||||
|
||||
private RSI? _baseRsi;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("rsi", priority: 2)]
|
||||
public RSI? BaseRSI
|
||||
{
|
||||
get => _baseRsi;
|
||||
@@ -357,7 +326,16 @@ namespace Robust.Client.GameObjects
|
||||
if (layerDatums.Count != 0)
|
||||
{
|
||||
LayerMap.Clear();
|
||||
LayerDatums = layerDatums;
|
||||
Layers.Clear();
|
||||
foreach (var datum in layerDatums)
|
||||
{
|
||||
AddLayer(datum);
|
||||
}
|
||||
|
||||
_layerMapShared = true;
|
||||
|
||||
QueueUpdateRenderTree();
|
||||
QueueUpdateIsInert();
|
||||
}
|
||||
|
||||
UpdateLocalMatrix();
|
||||
|
||||
@@ -7,7 +7,7 @@ using Robust.Shared.ViewVariables;
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[RegisterComponent, ComponentReference(typeof(SharedUserInterfaceComponent))]
|
||||
public sealed class ClientUserInterfaceComponent : SharedUserInterfaceComponent
|
||||
public sealed partial class ClientUserInterfaceComponent : SharedUserInterfaceComponent
|
||||
{
|
||||
[ViewVariables]
|
||||
internal readonly Dictionary<Enum, PrototypeData> _interfaces = new();
|
||||
|
||||
@@ -314,9 +314,9 @@ public sealed class AudioSystem : SharedAudioSystem
|
||||
return source != null;
|
||||
}
|
||||
|
||||
private PlayingStream CreateAndStartPlayingStream(IClydeAudioSource source, AudioParams? audioParams)
|
||||
private PlayingStream CreateAndStartPlayingStream(IClydeAudioSource source, AudioParams? audioParams, AudioStream stream)
|
||||
{
|
||||
ApplyAudioParams(audioParams, source);
|
||||
ApplyAudioParams(audioParams, source, stream);
|
||||
source.StartPlaying();
|
||||
var playing = new PlayingStream
|
||||
{
|
||||
@@ -365,7 +365,7 @@ public sealed class AudioSystem : SharedAudioSystem
|
||||
|
||||
source.SetGlobal();
|
||||
|
||||
return CreateAndStartPlayingStream(source, audioParams);
|
||||
return CreateAndStartPlayingStream(source, audioParams, stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -416,7 +416,7 @@ public sealed class AudioSystem : SharedAudioSystem
|
||||
if (!source.SetPosition(worldPos))
|
||||
return Play(stream, fallbackCoordinates.Value, fallbackCoordinates.Value, audioParams);
|
||||
|
||||
var playing = CreateAndStartPlayingStream(source, audioParams);
|
||||
var playing = CreateAndStartPlayingStream(source, audioParams, stream);
|
||||
playing.TrackingEntity = entity;
|
||||
playing.TrackingFallbackCoordinates = fallbackCoordinates != EntityCoordinates.Invalid ? fallbackCoordinates : null;
|
||||
return playing;
|
||||
@@ -469,7 +469,7 @@ public sealed class AudioSystem : SharedAudioSystem
|
||||
return null;
|
||||
}
|
||||
|
||||
var playing = CreateAndStartPlayingStream(source, audioParams);
|
||||
var playing = CreateAndStartPlayingStream(source, audioParams, stream);
|
||||
playing.TrackingCoordinates = coordinates;
|
||||
playing.TrackingFallbackCoordinates = fallbackCoordinates != EntityCoordinates.Invalid ? fallbackCoordinates : null;
|
||||
return playing;
|
||||
@@ -493,7 +493,7 @@ public sealed class AudioSystem : SharedAudioSystem
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ApplyAudioParams(AudioParams? audioParams, IClydeAudioSource source)
|
||||
private void ApplyAudioParams(AudioParams? audioParams, IClydeAudioSource source, AudioStream audio)
|
||||
{
|
||||
if (!audioParams.HasValue)
|
||||
return;
|
||||
@@ -508,8 +508,12 @@ public sealed class AudioSystem : SharedAudioSystem
|
||||
source.SetRolloffFactor(audioParams.Value.RolloffFactor);
|
||||
source.SetMaxDistance(audioParams.Value.MaxDistance);
|
||||
source.SetReferenceDistance(audioParams.Value.ReferenceDistance);
|
||||
source.SetPlaybackPosition(audioParams.Value.PlayOffsetSeconds);
|
||||
source.IsLooping = audioParams.Value.Loop;
|
||||
|
||||
// TODO clamp the offset inside of SetPlaybackPosition() itself.
|
||||
var offset = audioParams.Value.PlayOffsetSeconds;
|
||||
offset = Math.Clamp(offset, 0f, (float) audio.Length.TotalSeconds);
|
||||
source.SetPlaybackPosition(offset);
|
||||
}
|
||||
|
||||
public sealed class PlayingStream : IPlayingAudioStream
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
while (chunkEnumerator.MoveNext(out var chunk))
|
||||
{
|
||||
foreach (var fixture in chunk.Fixtures)
|
||||
foreach (var fixture in chunk.Fixtures.Values)
|
||||
{
|
||||
var poly = (PolygonShape) fixture.Shape;
|
||||
|
||||
|
||||
@@ -16,4 +16,9 @@ internal sealed class GridRenderingSystem : EntitySystem
|
||||
{
|
||||
_clyde.RegisterGridEcsEvents();
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
_clyde.ShutdownGridEcsEvents();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -745,10 +745,6 @@ namespace Robust.Client.GameStates
|
||||
}
|
||||
}
|
||||
|
||||
var contQuery = _entities.GetEntityQuery<ContainerManagerComponent>();
|
||||
var physicsQuery = _entities.GetEntityQuery<PhysicsComponent>();
|
||||
var fixturesQuery = _entities.GetEntityQuery<FixturesComponent>();
|
||||
var broadQuery = _entities.GetEntityQuery<BroadphaseComponent>();
|
||||
var queuedBroadphaseUpdates = new List<(EntityUid, TransformComponent)>(enteringPvs);
|
||||
|
||||
// Apply entity states.
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Robust.Client.GameStates
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
var cache = IoCManager.Resolve<IResourceCache>();
|
||||
_font = new VectorFont(cache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf"), 10);
|
||||
_font = new VectorFont(cache.GetResource<FontResource>("/EngineFonts/NotoSans/NotoSans-Regular.ttf"), 10);
|
||||
_lineHeight = _font.GetLineHeight(1);
|
||||
|
||||
_gameStateManager.GameStateApplied += HandleGameStateApplied;
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Robust.Client.GameStates
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
var cache = IoCManager.Resolve<IResourceCache>();
|
||||
_font = new VectorFont(cache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf"), 10);
|
||||
_font = new VectorFont(cache.GetResource<FontResource>("/EngineFonts/NotoSans/NotoSans-Regular.ttf"), 10);
|
||||
|
||||
_gameStateManager.GameStateApplied += HandleGameStateApplied;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Robust.Client.Graphics.Audio
|
||||
readSamples += read;
|
||||
}
|
||||
|
||||
return new OggVorbisData(totalSamples, sampleRate, channels, buffer);
|
||||
return new OggVorbisData(totalSamples, sampleRate, channels, buffer, vorbis.Tags.Title, vorbis.Tags.Artist);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,13 +37,17 @@ namespace Robust.Client.Graphics.Audio
|
||||
public readonly long SampleRate;
|
||||
public readonly long Channels;
|
||||
public readonly ReadOnlyMemory<float> Data;
|
||||
public readonly string Title;
|
||||
public readonly string Artist;
|
||||
|
||||
public OggVorbisData(long totalSamples, long sampleRate, long channels, ReadOnlyMemory<float> data)
|
||||
public OggVorbisData(long totalSamples, long sampleRate, long channels, ReadOnlyMemory<float> data, string title, string artist)
|
||||
{
|
||||
TotalSamples = totalSamples;
|
||||
SampleRate = sampleRate;
|
||||
Channels = channels;
|
||||
Data = data;
|
||||
Title = title;
|
||||
Artist = artist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ namespace Robust.Client.Graphics.Audio
|
||||
var handle = new ClydeHandle(_audioSampleBuffers.Count);
|
||||
_audioSampleBuffers.Add(new LoadedAudioSample(buffer));
|
||||
var length = TimeSpan.FromSeconds(vorbis.TotalSamples / (double) vorbis.SampleRate);
|
||||
return new AudioStream(handle, length, (int) vorbis.Channels, name);
|
||||
return new AudioStream(handle, length, (int) vorbis.Channels, name, vorbis.Title, vorbis.Artist);
|
||||
}
|
||||
|
||||
public AudioStream LoadAudioWav(Stream stream, string? name = null)
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace Robust.Client.Graphics
|
||||
[Dependency] private readonly IClyde _displayManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
|
||||
private ISawmill _logMill = default!;
|
||||
|
||||
// We default to this when we get set to a null eye.
|
||||
private readonly FixedEye _defaultEye = new();
|
||||
@@ -53,6 +54,7 @@ namespace Robust.Client.Graphics
|
||||
void IEyeManager.Initialize()
|
||||
{
|
||||
MainViewport = _uiManager.MainViewport;
|
||||
_logMill = IoCManager.Resolve<ILogManager>().RootSawmill;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -129,14 +131,14 @@ namespace Robust.Client.Graphics
|
||||
/// <inheritdoc />
|
||||
public ScreenCoordinates CoordinatesToScreen(EntityCoordinates point)
|
||||
{
|
||||
return MapToScreen(point.ToMap(_entityManager));
|
||||
return MapToScreen(point.ToMap(_entityManager, _entityManager.System<SharedTransformSystem>()));
|
||||
}
|
||||
|
||||
public ScreenCoordinates MapToScreen(MapCoordinates point)
|
||||
{
|
||||
if (CurrentEye.Position.MapId != point.MapId)
|
||||
{
|
||||
Logger.Error($"Attempted to convert map coordinates ({point}) to screen coordinates with an eye on another map ({CurrentEye.Position.MapId})");
|
||||
_logMill.Error($"Attempted to convert map coordinates ({point}) to screen coordinates with an eye on another map ({CurrentEye.Position.MapId})");
|
||||
return new(default, WindowId.Invalid);
|
||||
}
|
||||
|
||||
@@ -146,12 +148,10 @@ namespace Robust.Client.Graphics
|
||||
/// <inheritdoc />
|
||||
public MapCoordinates ScreenToMap(ScreenCoordinates point)
|
||||
{
|
||||
var (pos, window) = point;
|
||||
|
||||
if (_uiManager.MouseGetControl(point) is not IViewportControl viewport)
|
||||
return default;
|
||||
|
||||
return viewport.ScreenToMap(pos);
|
||||
return viewport.ScreenToMap(point.Position);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -159,6 +159,21 @@ namespace Robust.Client.Graphics
|
||||
{
|
||||
return MainViewport.ScreenToMap(point);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public MapCoordinates PixelToMap(ScreenCoordinates point)
|
||||
{
|
||||
if (_uiManager.MouseGetControl(point) is not IViewportControl viewport)
|
||||
return default;
|
||||
|
||||
return viewport.PixelToMap(point.Position);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public MapCoordinates PixelToMap(Vector2 point)
|
||||
{
|
||||
return MainViewport.PixelToMap(point);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CurrentEyeChangedEvent : EntityEventArgs
|
||||
|
||||
@@ -79,6 +79,16 @@ namespace Robust.Client.Graphics
|
||||
/// <returns>Corresponding point in the world.</returns>
|
||||
MapCoordinates ScreenToMap(Vector2 point);
|
||||
|
||||
/// <summary>
|
||||
/// Similar to <see cref="ScreenToMap(ScreenCoordinates)"/>, except it should compensate for the effects of shaders on viewports.
|
||||
/// </summary>
|
||||
MapCoordinates PixelToMap(ScreenCoordinates point);
|
||||
|
||||
/// <summary>
|
||||
/// Similar to <see cref="ScreenToMap(Vector2)"/>, except it should compensate for the effects of shaders on viewports.
|
||||
/// </summary>
|
||||
MapCoordinates PixelToMap(Vector2 point);
|
||||
|
||||
void ClearCurrentEye();
|
||||
void Initialize();
|
||||
}
|
||||
|
||||
@@ -176,6 +176,14 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_entityManager.EventBus.SubscribeEvent<GridModifiedEvent>(EventSource.Local, this, _updateOnGridModified);
|
||||
}
|
||||
|
||||
public void ShutdownGridEcsEvents()
|
||||
{
|
||||
_entityManager.EventBus.UnsubscribeEvent<TileChangedEvent>(EventSource.Local, this);
|
||||
_entityManager.EventBus.UnsubscribeEvent<GridStartupEvent>(EventSource.Local, this);
|
||||
_entityManager.EventBus.UnsubscribeEvent<GridRemovalEvent>(EventSource.Local, this);
|
||||
_entityManager.EventBus.UnsubscribeEvent<GridModifiedEvent>(EventSource.Local, this);
|
||||
}
|
||||
|
||||
private void GLInitBindings(bool gles)
|
||||
{
|
||||
_glBindingsContext = _glContext!.BindingsContext;
|
||||
|
||||
@@ -88,6 +88,11 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// Nada.
|
||||
}
|
||||
|
||||
public void ShutdownGridEcsEvents()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void SetWindowTitle(string title)
|
||||
{
|
||||
// Nada.
|
||||
|
||||
@@ -12,9 +12,9 @@ void main()
|
||||
|
||||
lowp vec4 COLOR;
|
||||
|
||||
// [SHADER_CODE]
|
||||
|
||||
lowp vec3 lightSample = texture2D(lightMap, Pos).rgb;
|
||||
|
||||
// [SHADER_CODE]
|
||||
|
||||
gl_FragColor = zAdjustResult(COLOR * VtxModulate * vec4(lightSample, 1.0));
|
||||
}
|
||||
|
||||
@@ -207,6 +207,15 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{GlfwKey.F13, Key.F13},
|
||||
{GlfwKey.F14, Key.F14},
|
||||
{GlfwKey.F15, Key.F15},
|
||||
{GlfwKey.F16, Key.F16},
|
||||
{GlfwKey.F17, Key.F17},
|
||||
{GlfwKey.F18, Key.F18},
|
||||
{GlfwKey.F19, Key.F19},
|
||||
{GlfwKey.F20, Key.F20},
|
||||
{GlfwKey.F21, Key.F21},
|
||||
{GlfwKey.F22, Key.F22},
|
||||
{GlfwKey.F23, Key.F23},
|
||||
{GlfwKey.F24, Key.F24},
|
||||
{GlfwKey.Pause, Key.Pause},
|
||||
{GlfwKey.World1, Key.World1},
|
||||
};
|
||||
|
||||
@@ -191,6 +191,15 @@ internal partial class Clyde
|
||||
MapKey(SDL_SCANCODE_F13, Key.F13);
|
||||
MapKey(SDL_SCANCODE_F14, Key.F14);
|
||||
MapKey(SDL_SCANCODE_F15, Key.F15);
|
||||
MapKey(SDL_SCANCODE_F16, Key.F16);
|
||||
MapKey(SDL_SCANCODE_F17, Key.F17);
|
||||
MapKey(SDL_SCANCODE_F18, Key.F18);
|
||||
MapKey(SDL_SCANCODE_F19, Key.F19);
|
||||
MapKey(SDL_SCANCODE_F20, Key.F20);
|
||||
MapKey(SDL_SCANCODE_F21, Key.F21);
|
||||
MapKey(SDL_SCANCODE_F22, Key.F22);
|
||||
MapKey(SDL_SCANCODE_F23, Key.F23);
|
||||
MapKey(SDL_SCANCODE_F24, Key.F24);
|
||||
MapKey(SDL_SCANCODE_PAUSE, Key.Pause);
|
||||
|
||||
KeyMapReverse = new Dictionary<Key, SDL_Scancode>();
|
||||
|
||||
@@ -65,6 +65,8 @@ namespace Robust.Client.Graphics
|
||||
|
||||
void RegisterGridEcsEvents();
|
||||
|
||||
void ShutdownGridEcsEvents();
|
||||
|
||||
void RunOnWindowThread(Action action);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Client.Graphics
|
||||
{
|
||||
@@ -11,6 +12,7 @@ namespace Robust.Client.Graphics
|
||||
{
|
||||
[Dependency] private readonly ILogManager _logMan = default!;
|
||||
|
||||
[ViewVariables]
|
||||
private readonly Dictionary<Type, Overlay> _overlays = new Dictionary<Type, Overlay>();
|
||||
private ISawmill _logger = default!;
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ namespace Robust.Client.Graphics
|
||||
}
|
||||
|
||||
[DataDefinition]
|
||||
public struct StencilParameters
|
||||
public partial struct StencilParameters
|
||||
{
|
||||
public StencilParameters()
|
||||
{
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace Robust.Client.Graphics
|
||||
public sealed class ShaderPrototype : IPrototype, ISerializationHooks
|
||||
{
|
||||
[ViewVariables]
|
||||
[IdDataFieldAttribute]
|
||||
public string ID { get; } = default!;
|
||||
[IdDataField]
|
||||
public string ID { get; private set; } = default!;
|
||||
|
||||
[ViewVariables] private ShaderKind Kind;
|
||||
[ViewVariables] private Dictionary<string, object>? _params;
|
||||
@@ -65,12 +65,12 @@ namespace Robust.Client.Graphics
|
||||
|
||||
case ShaderKind.Canvas:
|
||||
|
||||
var hasLight = rawMode != "unshaded";
|
||||
var hasLight = _rawMode != "unshaded";
|
||||
ShaderBlendMode? blend = null;
|
||||
if (rawBlendMode != null)
|
||||
if (_rawBlendMode != null)
|
||||
{
|
||||
if (!Enum.TryParse<ShaderBlendMode>(rawBlendMode.ToUpper(), out var parsed))
|
||||
Logger.Error($"invalid mode: {rawBlendMode}");
|
||||
if (!Enum.TryParse<ShaderBlendMode>(_rawBlendMode.ToUpper(), out var parsed))
|
||||
Logger.Error($"invalid mode: {_rawBlendMode}");
|
||||
else
|
||||
blend = parsed;
|
||||
}
|
||||
@@ -94,11 +94,20 @@ namespace Robust.Client.Graphics
|
||||
return Instance().Duplicate();
|
||||
}
|
||||
|
||||
[DataField("kind", readOnly: true, required: true)] private string _rawKind = default!;
|
||||
[DataField("path", readOnly: true)] private ResPath path;
|
||||
[DataField("params", readOnly: true)] private Dictionary<string, string>? paramMapping;
|
||||
[DataField("light_mode", readOnly: true)] private string? rawMode;
|
||||
[DataField("blend_mode", readOnly: true)] private string? rawBlendMode;
|
||||
[DataField("kind", required: true)]
|
||||
private string _rawKind = default!;
|
||||
|
||||
[DataField("path")]
|
||||
private ResPath? _path;
|
||||
|
||||
[DataField("params")]
|
||||
private Dictionary<string, string>? _paramMapping;
|
||||
|
||||
[DataField("light_mode")]
|
||||
private string? _rawMode;
|
||||
|
||||
[DataField("blend_mode")]
|
||||
private string? _rawBlendMode;
|
||||
|
||||
void ISerializationHooks.AfterDeserialization()
|
||||
{
|
||||
@@ -106,18 +115,22 @@ namespace Robust.Client.Graphics
|
||||
{
|
||||
case "source":
|
||||
Kind = ShaderKind.Source;
|
||||
if (path == null) throw new InvalidOperationException();
|
||||
_source = IoCManager.Resolve<IResourceCache>().GetResource<ShaderSourceResource>(path);
|
||||
|
||||
if (paramMapping != null)
|
||||
// TODO use a custom type serializer.
|
||||
if (_path == null)
|
||||
throw new InvalidOperationException("Source shaders must specify a source file.");
|
||||
|
||||
_source = IoCManager.Resolve<IResourceCache>().GetResource<ShaderSourceResource>(_path.Value);
|
||||
|
||||
if (_paramMapping != null)
|
||||
{
|
||||
_params = new Dictionary<string, object>();
|
||||
foreach (var item in paramMapping!)
|
||||
foreach (var item in _paramMapping!)
|
||||
{
|
||||
var name = item.Key;
|
||||
if (!_source.ParsedShader.Uniforms.TryGetValue(name, out var uniformDefinition))
|
||||
{
|
||||
Logger.ErrorS("shader", "Shader param '{0}' does not exist on shader '{1}'", name, path);
|
||||
Logger.ErrorS("shader", "Shader param '{0}' does not exist on shader '{1}'", name, _path);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -161,6 +161,15 @@ namespace Robust.Client.Input
|
||||
F13,
|
||||
F14,
|
||||
F15,
|
||||
F16,
|
||||
F17,
|
||||
F18,
|
||||
F19,
|
||||
F20,
|
||||
F21,
|
||||
F22,
|
||||
F23,
|
||||
F24,
|
||||
Pause,
|
||||
World1,
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using Robust.Shared.Serialization.Manager.Attributes;
|
||||
namespace Robust.Client.Input
|
||||
{
|
||||
[DataDefinition]
|
||||
public sealed class KeyBindingRegistration
|
||||
public sealed partial class KeyBindingRegistration
|
||||
{
|
||||
[DataField("function")]
|
||||
public BoundKeyFunction Function;
|
||||
|
||||
@@ -3,13 +3,16 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Map;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Toolshed;
|
||||
using Robust.Shared.Utility;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
@@ -52,8 +55,11 @@ namespace Robust.Client.Map
|
||||
_genTextureAtlas();
|
||||
}
|
||||
|
||||
private void _genTextureAtlas()
|
||||
internal void _genTextureAtlas()
|
||||
{
|
||||
_tileRegions.Clear();
|
||||
_tileTextureAtlas = null;
|
||||
|
||||
var defList = TileDefs.Where(t => t.Sprite != null).ToList();
|
||||
|
||||
// If there are no tile definitions, we do nothing.
|
||||
@@ -144,4 +150,17 @@ namespace Robust.Client.Map
|
||||
_tileTextureAtlas = Texture.LoadFromImage(sheet, "Tile Atlas");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ReloadTileTexturesCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly ClydeTileDefinitionManager _tile = default!;
|
||||
|
||||
public override string Command => "reloadtiletextures";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
_tile._genTextureAtlas();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,6 @@ namespace Robust.Client.Physics;
|
||||
/// Simple component used to tag entities that have physics prediction enabled.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class PredictedPhysicsComponent : Component
|
||||
public sealed partial class PredictedPhysicsComponent : Component
|
||||
{
|
||||
}
|
||||
|
||||
@@ -532,7 +532,7 @@ namespace Robust.Client.Placement
|
||||
return false;
|
||||
}
|
||||
coordinates = EntityCoordinates.FromMap(MapManager,
|
||||
EyeManager.ScreenToMap(InputManager.MouseScreenPosition));
|
||||
EyeManager.PixelToMap(InputManager.MouseScreenPosition));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ namespace Robust.Client.Placement
|
||||
public IEnumerable<EntityCoordinates> LineCoordinates()
|
||||
{
|
||||
var mouseScreen = pManager.InputManager.MouseScreenPosition;
|
||||
var mousePos = pManager.EyeManager.ScreenToMap(mouseScreen);
|
||||
var mousePos = pManager.EyeManager.PixelToMap(mouseScreen);
|
||||
|
||||
if (mousePos.MapId == MapId.Nullspace)
|
||||
yield break;
|
||||
@@ -165,7 +165,7 @@ namespace Robust.Client.Placement
|
||||
public IEnumerable<EntityCoordinates> GridCoordinates()
|
||||
{
|
||||
var mouseScreen = pManager.InputManager.MouseScreenPosition;
|
||||
var mousePos = pManager.EyeManager.ScreenToMap(mouseScreen);
|
||||
var mousePos = pManager.EyeManager.PixelToMap(mouseScreen);
|
||||
|
||||
if (mousePos.MapId == MapId.Nullspace)
|
||||
yield break;
|
||||
@@ -254,7 +254,7 @@ namespace Robust.Client.Placement
|
||||
|
||||
protected EntityCoordinates ScreenToCursorGrid(ScreenCoordinates coords)
|
||||
{
|
||||
var mapCoords = pManager.EyeManager.ScreenToMap(coords.Position);
|
||||
var mapCoords = pManager.EyeManager.PixelToMap(coords.Position);
|
||||
if (!pManager.MapManager.TryFindGridAt(mapCoords, out var gridUid, out var grid))
|
||||
{
|
||||
return EntityCoordinates.FromMap(pManager.MapManager, mapCoords);
|
||||
|
||||
@@ -3,14 +3,18 @@ using System.Collections.Generic;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Client.Player
|
||||
{
|
||||
public interface IPlayerManager : Shared.Players.ISharedPlayerManager
|
||||
{
|
||||
new IEnumerable<ICommonSession> Sessions { get; }
|
||||
|
||||
[ViewVariables]
|
||||
IReadOnlyDictionary<NetUserId, ICommonSession> SessionsDict { get; }
|
||||
|
||||
[ViewVariables]
|
||||
LocalPlayer? LocalPlayer { get; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -2,6 +2,7 @@ using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Client.Player
|
||||
{
|
||||
@@ -17,11 +18,14 @@ namespace Robust.Client.Player
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[ViewVariables]
|
||||
public EntityUid? AttachedEntity { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[ViewVariables]
|
||||
public NetUserId UserId { get; }
|
||||
|
||||
[ViewVariables]
|
||||
internal string Name { get; set; } = "<Unknown>";
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -31,9 +35,11 @@ namespace Robust.Client.Player
|
||||
set => this.Name = value;
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
internal short Ping { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[ViewVariables]
|
||||
public INetChannel ConnectedClient { get; internal set; } = null!;
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -24,7 +24,7 @@ public sealed class LiveProfileViewControl : Control
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
if (!_resourceCache.TryGetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf", out var font))
|
||||
if (!_resourceCache.TryGetResource<FontResource>("/EngineFonts/NotoSans/NotoSans-Regular.ttf", out var font))
|
||||
return;
|
||||
|
||||
_font = font.MakeDefault();
|
||||
|
||||
@@ -7,6 +7,7 @@ using Robust.Shared.Network;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using System.Threading.Tasks;
|
||||
using Robust.Client.Upload.Commands;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Replays;
|
||||
@@ -131,12 +132,16 @@ public sealed partial class ReplayLoadManager
|
||||
var ticksSinceLastCheckpoint = 0;
|
||||
var spawnedTracker = 0;
|
||||
var stateTracker = 0;
|
||||
var curState = state0;
|
||||
for (var i = 1; i < states.Count; i++)
|
||||
{
|
||||
if (i % 10 == 0)
|
||||
await callback(i, states.Count, LoadingState.ProcessingFiles, false);
|
||||
|
||||
var curState = states[i];
|
||||
var lastState = curState;
|
||||
curState = states[i];
|
||||
DebugTools.Assert(curState.FromSequence <= lastState.ToSequence);
|
||||
|
||||
UpdatePlayerStates(curState.PlayerStates.Span, playerStates);
|
||||
UpdateEntityStates(curState.EntityStates.Span, entStates, ref spawnedTracker, ref stateTracker, detached);
|
||||
UpdateMessages(messages[i], uploadedFiles, prototypes, cvars, detachQueue, ref timeBase);
|
||||
@@ -222,7 +227,13 @@ public sealed partial class ReplayLoadManager
|
||||
// forwards. Also, note that files HAVE to be uploaded while generating checkpoints, in case
|
||||
// someone spawns an entity that relies on uploaded data.
|
||||
if (!ignoreDuplicates)
|
||||
throw new NotSupportedException("Overwriting an existing file is not yet supported by replays.");
|
||||
{
|
||||
var msg = $"Overwriting an existing file upload! Path: {path}";
|
||||
if (_confMan.GetCVar(CVars.ReplayIgnoreErrors))
|
||||
_sawmill.Error(msg);
|
||||
else
|
||||
throw new NotSupportedException(msg);
|
||||
}
|
||||
|
||||
message.Messages.RemoveSwap(i);
|
||||
break;
|
||||
@@ -240,31 +251,56 @@ public sealed partial class ReplayLoadManager
|
||||
continue;
|
||||
|
||||
message.Messages.RemoveSwap(i);
|
||||
var changed = new Dictionary<Type, HashSet<string>>();
|
||||
_protoMan.LoadString(protoUpload.PrototypeData, true, changed);
|
||||
|
||||
foreach (var (kind, ids) in changed)
|
||||
try
|
||||
{
|
||||
var protos = prototypes[kind];
|
||||
var count = protos.Count;
|
||||
protos.UnionWith(ids);
|
||||
if (!ignoreDuplicates && ids.Count + count != protos.Count)
|
||||
{
|
||||
// An existing prototype was overwritten. Much like for resource uploading, supporting this
|
||||
// requires tracking the last-modified time of prototypes and either resetting or applying
|
||||
// prototype changes when jumping around in time. This also requires reworking how the initial
|
||||
// implicit state data is generated, because we can't simply cache it anymore.
|
||||
// Also, does reloading prototypes in release mode modify existing entities?
|
||||
throw new NotSupportedException($"Overwriting an existing prototype is not yet supported by replays.");
|
||||
}
|
||||
LoadPrototype(protoUpload.PrototypeData, prototypes, ignoreDuplicates);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e is NotSupportedException || !_confMan.GetCVar(CVars.ReplayIgnoreErrors))
|
||||
throw;
|
||||
|
||||
_protoMan.ResolveResults();
|
||||
_protoMan.ReloadPrototypes(changed);
|
||||
_locMan.ReloadLocalizations();
|
||||
var msg = $"Caught exception while parsing uploaded prototypes in a replay. Exception: {e}";
|
||||
_sawmill.Error(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadPrototype(
|
||||
string data,
|
||||
Dictionary<Type, HashSet<string>> prototypes,
|
||||
bool ignoreDuplicates)
|
||||
{
|
||||
var changed = new Dictionary<Type, HashSet<string>>();
|
||||
_protoMan.LoadString(data, true, changed);
|
||||
|
||||
foreach (var (kind, ids) in changed)
|
||||
{
|
||||
var protos = prototypes[kind];
|
||||
var count = protos.Count;
|
||||
protos.UnionWith(ids);
|
||||
if (!ignoreDuplicates && ids.Count + count != protos.Count)
|
||||
{
|
||||
// An existing prototype was overwritten. Much like for resource uploading, supporting this
|
||||
// requires tracking the last-modified time of prototypes and either resetting or applying
|
||||
// prototype changes when jumping around in time. This also requires reworking how the initial
|
||||
// implicit state data is generated, because we can't simply cache it anymore.
|
||||
// Also, does reloading prototypes in release mode modify existing entities?
|
||||
|
||||
var msg = $"Overwriting an existing prototype! Kind: {kind.Name}. Ids: {string.Join(", ", ids)}";
|
||||
if (_confMan.GetCVar(CVars.ReplayIgnoreErrors))
|
||||
_sawmill.Error(msg);
|
||||
else
|
||||
throw new NotSupportedException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
_protoMan.ResolveResults();
|
||||
_protoMan.ReloadPrototypes(changed);
|
||||
_locMan.ReloadLocalizations();
|
||||
}
|
||||
|
||||
private void UpdateDeletions(NetListAsArray<EntityUid> entityDeletions,
|
||||
Dictionary<EntityUid, EntityState> entStates, HashSet<EntityUid> detached)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.GameStates;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -64,6 +66,18 @@ public sealed partial class ReplayLoadManager
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("Missing metadata component");
|
||||
if (!entState.ComponentChanges.HasContents)
|
||||
{
|
||||
// This shouldn't be possible, yet it has happened?
|
||||
// TODO this should probably also throw an exception.
|
||||
_sawmill.Error($"Encountered blank entity state? Entity: {entState.Uid}. Last modified: {entState.EntityLastModified}. Attempting to continue.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!_confMan.GetCVar(CVars.ReplayIgnoreErrors))
|
||||
throw new MissingMetadataException(entState.Uid);
|
||||
|
||||
_sawmill.Error($"Missing metadata component. Entity: {entState.Uid}. Last modified: {entState.EntityLastModified}.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using Robust.Shared.Utility;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Replays;
|
||||
using static Robust.Shared.Replays.ReplayConstants;
|
||||
|
||||
@@ -136,9 +137,21 @@ public sealed partial class ReplayLoadManager
|
||||
if (data == null)
|
||||
throw new Exception("Failed to load yaml metadata");
|
||||
|
||||
TimeSpan duration;
|
||||
var finalData = LoadYamlFinalMetadata(fileReader);
|
||||
if (finalData == null)
|
||||
throw new Exception("Failed to load final yaml metadata");
|
||||
{
|
||||
var msg = "Failed to load final yaml metadata";
|
||||
if (!_confMan.GetCVar(CVars.ReplayIgnoreErrors))
|
||||
throw new Exception(msg);
|
||||
|
||||
_sawmill.Error(msg);
|
||||
duration = TimeSpan.FromDays(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
duration = TimeSpan.Parse(((ValueDataNode) finalData[MetaFinalKeyDuration]).Value);
|
||||
}
|
||||
|
||||
var typeHash = Convert.FromHexString(((ValueDataNode) data[MetaKeyTypeHash]).Value);
|
||||
var stringHash = Convert.FromHexString(((ValueDataNode) data[MetaKeyStringHash]).Value);
|
||||
@@ -146,7 +159,6 @@ public sealed partial class ReplayLoadManager
|
||||
var timeBaseTick = ((ValueDataNode) data[MetaKeyBaseTick]).Value;
|
||||
var timeBaseTimespan = ((ValueDataNode) data[MetaKeyBaseTime]).Value;
|
||||
var clientSide = bool.Parse(((ValueDataNode) data[MetaKeyIsClientRecording]).Value);
|
||||
var duration = TimeSpan.Parse(((ValueDataNode) finalData[MetaFinalKeyDuration]).Value);
|
||||
|
||||
if (!typeHash.SequenceEqual(_serializer.GetSerializableTypesHash()))
|
||||
throw new Exception($"{nameof(IRobustSerializer)} hashes do not match. Loading replays using a bad replay-client version?");
|
||||
|
||||
@@ -97,6 +97,8 @@ internal sealed partial class ReplayPlaybackManager
|
||||
|
||||
if (message is EntityEventArgs args)
|
||||
_entMan.DispatchReceivedNetworkMsg(args);
|
||||
else if (_warned.Add(message.GetType()))
|
||||
_sawmill.Error($"Unhandled replay message: {message.GetType()}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ internal sealed partial class ReplayPlaybackManager : IReplayPlaybackManager
|
||||
|
||||
private bool _initialized;
|
||||
private ISawmill _sawmill = default!;
|
||||
private HashSet<Type> _warned = new();
|
||||
|
||||
public bool Playing
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -40,5 +41,9 @@ namespace Robust.Client.ResourceManagement
|
||||
// Resource load callbacks so content can hook stuff like click maps.
|
||||
event Action<TextureLoadedEventArgs> OnRawTextureLoaded;
|
||||
event Action<RsiLoadedEventArgs> OnRsiLoaded;
|
||||
|
||||
IClyde Clyde { get; }
|
||||
IClydeAudio ClydeAudio { get; }
|
||||
IFontManager FontManager { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ namespace Robust.Client.ResourceManagement
|
||||
{
|
||||
internal partial class ResourceCache
|
||||
{
|
||||
[Dependency] private readonly IClyde _clyde = default!;
|
||||
[field: Dependency] public IClyde Clyde { get; } = default!;
|
||||
[field: Dependency] public IClydeAudio ClydeAudio { get; } = default!;
|
||||
[field: Dependency] public IFontManager FontManager { get; } = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||
|
||||
@@ -70,7 +72,7 @@ namespace Robust.Client.ResourceManagement
|
||||
|
||||
try
|
||||
{
|
||||
TextureResource.LoadTexture(_clyde, data);
|
||||
TextureResource.LoadTexture(Clyde, data);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -198,7 +200,7 @@ namespace Robust.Client.ResourceManagement
|
||||
|
||||
void FinalizeMetaAtlas(int toIndex, Image<Rgba32> sheet)
|
||||
{
|
||||
var atlas = _clyde.LoadTextureFromImage(sheet);
|
||||
var atlas = Clyde.LoadTextureFromImage(sheet);
|
||||
for (int i = finalized + 1; i <= toIndex; i++)
|
||||
{
|
||||
var rsi = rsiList[i];
|
||||
|
||||
@@ -20,14 +20,13 @@ namespace Robust.Client.ResourceManagement
|
||||
|
||||
using (var fileStream = cache.ContentFileRead(path))
|
||||
{
|
||||
var clyde = IoCManager.Resolve<IClydeAudio>();
|
||||
if (path.Extension == "ogg")
|
||||
{
|
||||
AudioStream = clyde.LoadAudioOggVorbis(fileStream, path.ToString());
|
||||
AudioStream = cache.ClydeAudio.LoadAudioOggVorbis(fileStream, path.ToString());
|
||||
}
|
||||
else if (path.Extension == "wav")
|
||||
{
|
||||
AudioStream = clyde.LoadAudioWav(fileStream, path.ToString());
|
||||
AudioStream = cache.ClydeAudio.LoadAudioWav(fileStream, path.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Robust.Client.ResourceManagement
|
||||
|
||||
using (stream)
|
||||
{
|
||||
FontFaceHandle = IoCManager.Resolve<IFontManagerInternal>().Load(stream);
|
||||
FontFaceHandle = ((IFontManagerInternal)cache.FontManager).Load(stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,12 +34,10 @@ namespace Robust.Client.ResourceManagement
|
||||
|
||||
public override void Load(IResourceCache cache, ResPath path)
|
||||
{
|
||||
var clyde = IoCManager.Resolve<IClyde>();
|
||||
|
||||
var loadStepData = new LoadStepData {Path = path};
|
||||
LoadPreTexture(cache, loadStepData);
|
||||
|
||||
loadStepData.AtlasTexture = clyde.LoadTextureFromImage(
|
||||
loadStepData.AtlasTexture = cache.Clyde.LoadTextureFromImage(
|
||||
loadStepData.AtlasSheet,
|
||||
loadStepData.Path.ToString());
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Clyde;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -27,8 +28,7 @@ namespace Robust.Client.ResourceManagement
|
||||
ParsedShader = ShaderParser.Parse(reader, cache);
|
||||
}
|
||||
|
||||
var clyde = IoCManager.Resolve<IClydeInternal>();
|
||||
ClydeHandle = clyde.LoadShader(ParsedShader, path.ToString());
|
||||
ClydeHandle = ((IClydeInternal)cache.Clyde).LoadShader(ParsedShader, path.ToString());
|
||||
}
|
||||
|
||||
public override void Reload(IResourceCache cache, ResPath path, CancellationToken ct = default)
|
||||
@@ -57,8 +57,7 @@ namespace Robust.Client.ResourceManagement
|
||||
}
|
||||
}
|
||||
|
||||
var clyde = IoCManager.Resolve<IClydeInternal>();
|
||||
clyde.ReloadShader(ClydeHandle, ParsedShader);
|
||||
((IClydeInternal)cache.Clyde).ReloadShader(ClydeHandle, ParsedShader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ namespace Robust.Client.ResourceManagement
|
||||
|
||||
public override void Load(IResourceCache cache, ResPath path)
|
||||
{
|
||||
var clyde = IoCManager.Resolve<IClyde>();
|
||||
|
||||
if (path.Directory.Filename.EndsWith(".rsi"))
|
||||
{
|
||||
Logger.WarningS(
|
||||
@@ -33,7 +31,7 @@ namespace Robust.Client.ResourceManagement
|
||||
var data = new LoadStepData {Path = path};
|
||||
|
||||
LoadPreTexture(cache, data);
|
||||
LoadTexture(clyde, data);
|
||||
LoadTexture(cache.Clyde, data);
|
||||
LoadFinish(cache, data);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,25 +10,26 @@
|
||||
<RobustILLink>true</RobustILLink>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DiscordRichPresence" Version="1.0.175" />
|
||||
<PackageReference Include="DiscordRichPresence" Version="1.0.175" PrivateAssets="compile" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="6.0.9" />
|
||||
<PackageReference Include="SQLitePCLRaw.provider.sqlite3" Version="2.1.2" Condition="'$(UseSystemSqlite)' == 'True'" />
|
||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.2" Condition="'$(UseSystemSqlite)' != 'True'" />
|
||||
<PackageReference Include="SpaceWizards.NFluidsynth" Version="0.1.1" />
|
||||
<PackageReference Include="NVorbis" Version="0.10.1" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="6.0.9" PrivateAssets="compile" />
|
||||
<PackageReference Include="SQLitePCLRaw.provider.sqlite3" Version="2.1.2" Condition="'$(UseSystemSqlite)' == 'True'" PrivateAssets="compile" />
|
||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.2" Condition="'$(UseSystemSqlite)' != 'True'" PrivateAssets="compile" />
|
||||
<PackageReference Include="SpaceWizards.NFluidsynth" Version="0.1.1" PrivateAssets="compile" />
|
||||
<PackageReference Include="NVorbis" Version="0.10.1" PrivateAssets="compile" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
|
||||
<PackageReference Include="OpenToolkit.Graphics" Version="4.0.0-pre9.1" />
|
||||
<PackageReference Include="OpenTK.OpenAL" Version="4.7.5" />
|
||||
<PackageReference Include="SpaceWizards.SharpFont" Version="1.0.1" />
|
||||
<PackageReference Include="OpenToolkit.Graphics" Version="4.0.0-pre9.1" PrivateAssets="compile" />
|
||||
<PackageReference Include="OpenTK.OpenAL" Version="4.7.5" PrivateAssets="compile" />
|
||||
<PackageReference Include="SpaceWizards.SharpFont" Version="1.0.1" PrivateAssets="compile" />
|
||||
<PackageReference Include="Robust.Natives" Version="0.1.1" />
|
||||
<PackageReference Include="TerraFX.Interop.Windows" Version="10.0.20348-rc2" />
|
||||
<PackageReference Condition="'$(FullRelease)' != 'True'" Include="JetBrains.Profiler.Api" Version="1.2.0" />
|
||||
<PackageReference Include="TerraFX.Interop.Windows" Version="10.0.20348-rc2" PrivateAssets="compile" />
|
||||
<PackageReference Condition="'$(FullRelease)' != 'True'" Include="JetBrains.Profiler.Api" Version="1.2.0" PrivateAssets="compile" />
|
||||
<PackageReference Include="SpaceWizards.Sodium" Version="0.2.1" PrivateAssets="compile" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(EnableClientScripting)' == 'True'">
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" Version="4.0.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.0.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" Version="4.0.1" PrivateAssets="compile" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.0.1" PrivateAssets="compile" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.1" PrivateAssets="compile" />
|
||||
|
||||
<ProjectReference Include="..\Robust.Shared.Scripting\Robust.Shared.Scripting.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
@@ -29,7 +28,7 @@ public sealed class ClientSpriteSpecifierSerializer : SpriteSpecifierSerializer
|
||||
}
|
||||
|
||||
var res = dependencies.Resolve<IResourceCache>();
|
||||
var rsiPath = SpriteSpecifierSerializer.TextureRoot / valuePathNode.Value;
|
||||
var rsiPath = TextureRoot / valuePathNode.Value;
|
||||
if (!res.TryGetResource(rsiPath, out RSIResource? resource))
|
||||
{
|
||||
return new ErrorNode(node, "Failed to load RSI");
|
||||
@@ -40,6 +39,10 @@ public sealed class ClientSpriteSpecifierSerializer : SpriteSpecifierSerializer
|
||||
return new ErrorNode(node, "Invalid RSI state");
|
||||
}
|
||||
|
||||
return new ValidatedMappingNode(new());
|
||||
return new ValidatedMappingNode(new()
|
||||
{
|
||||
{ new ValidatedValueNode(new ValueDataNode("sprite")), new ValidatedValueNode(pathNode)},
|
||||
{ new ValidatedValueNode(new ValueDataNode("state")), new ValidatedValueNode(valueStateNode)},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -715,7 +715,7 @@ namespace Robust.Client.UserInterface
|
||||
maxH = MathHelper.Clamp(maxConstraint, minH, maxH);
|
||||
|
||||
minConstraint = float.IsNaN(setH) ? 0 : setH;
|
||||
minH = MathHelper.Clamp(maxH, minConstraint, minH);
|
||||
minH = MathHelper.Clamp(minConstraint, minH, maxH);
|
||||
|
||||
return new Vector2(
|
||||
Math.Clamp(avail.X, minW, maxW),
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
public void AddMessage(FormattedMessage message)
|
||||
{
|
||||
var entry = new RichTextEntry(message, this, _tagManager);
|
||||
var entry = new RichTextEntry(message, this, _tagManager, null);
|
||||
|
||||
entry.Update(_getFont(), _getContentBox().Width, UIScale);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Numerics;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.RichText;
|
||||
@@ -21,18 +22,18 @@ namespace Robust.Client.UserInterface.Controls
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
public void SetMessage(FormattedMessage message)
|
||||
public void SetMessage(FormattedMessage message, Type[]? tagsAllowed = null, Color? defaultColor = null)
|
||||
{
|
||||
_message = message;
|
||||
_entry = new RichTextEntry(_message, this, _tagManager);
|
||||
_entry = new RichTextEntry(_message, this, _tagManager, tagsAllowed, defaultColor);
|
||||
InvalidateMeasure();
|
||||
}
|
||||
|
||||
public void SetMessage(string message)
|
||||
public void SetMessage(string message, Type[]? tagsAllowed = null, Color? defaultColor = null)
|
||||
{
|
||||
var msg = new FormattedMessage();
|
||||
msg.AddText(message);
|
||||
SetMessage(msg);
|
||||
SetMessage(msg, tagsAllowed, defaultColor);
|
||||
}
|
||||
|
||||
public string? GetMessage() => _message?.ToMarkup();
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
public const string LeftButtonStyle = "spinbox-left";
|
||||
public const string RightButtonStyle = "spinbox-right";
|
||||
public const string MiddleButtonStyle = "spinbox-middle";
|
||||
private LineEdit _lineEdit;
|
||||
public LineEdit LineEditControl { get; }
|
||||
private List<Button> _leftButtons = new();
|
||||
private List<Button> _rightButtons = new();
|
||||
private int _stepSize = 1;
|
||||
@@ -35,7 +35,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
return;
|
||||
}
|
||||
_value = value;
|
||||
_lineEdit.Text = value.ToString();
|
||||
LineEditControl.Text = value.ToString();
|
||||
ValueChanged?.Invoke(new ValueChangedEventArgs(value));
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
return;
|
||||
}
|
||||
_value = value;
|
||||
_lineEdit.Text = value.ToString();
|
||||
LineEditControl.Text = value.ToString();
|
||||
}
|
||||
|
||||
public event Action<ValueChangedEventArgs>? ValueChanged;
|
||||
@@ -62,17 +62,17 @@ namespace Robust.Client.UserInterface.Controls
|
||||
Orientation = LayoutOrientation.Horizontal;
|
||||
MouseFilter = MouseFilterMode.Pass;
|
||||
|
||||
_lineEdit = new LineEdit
|
||||
LineEditControl = new LineEdit
|
||||
{
|
||||
MinSize = new Vector2(40, 0),
|
||||
HorizontalExpand = true
|
||||
};
|
||||
AddChild(_lineEdit);
|
||||
AddChild(LineEditControl);
|
||||
|
||||
Value = 0;
|
||||
|
||||
_lineEdit.IsValid = (str) => int.TryParse(str, out var i) && (IsValid == null || IsValid(i));
|
||||
_lineEdit.OnTextChanged += (args) =>
|
||||
LineEditControl.IsValid = (str) => int.TryParse(str, out var i) && (IsValid == null || IsValid(i));
|
||||
LineEditControl.OnTextChanged += (args) =>
|
||||
{
|
||||
if (int.TryParse(args.Text, out int i))
|
||||
Value = i;
|
||||
@@ -143,8 +143,8 @@ namespace Robust.Client.UserInterface.Controls
|
||||
/// </summary>
|
||||
public bool LineEditDisabled
|
||||
{
|
||||
get => !_lineEdit.Editable;
|
||||
set => _lineEdit.Editable = !value;
|
||||
get => !LineEditControl.Editable;
|
||||
set => LineEditControl.Editable = !value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -185,7 +185,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
base.MouseWheel(args);
|
||||
|
||||
if (!_lineEdit.HasKeyboardFocus())
|
||||
if (!LineEditControl.HasKeyboardFocus())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Control xmlns="https://spacestation14.io"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<OutputPanel Name="Output" VerticalExpand="True">
|
||||
<OutputPanel Name="Output" VerticalExpand="True" StyleClasses="monospace">
|
||||
<OutputPanel.StyleBoxOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#25252add"
|
||||
ContentMarginLeftOverride="3" ContentMarginRightOverride="3"
|
||||
|
||||
@@ -90,7 +90,7 @@ public sealed partial class DebugConsole
|
||||
|
||||
private async void TypeUpdateCompletions(bool fullUpdate)
|
||||
{
|
||||
var (args, _, _) = CalcTypingArgs();
|
||||
var (args, _, _, str) = CalcTypingArgs();
|
||||
|
||||
if (args.Count != _compParamCount)
|
||||
{
|
||||
@@ -101,7 +101,7 @@ public sealed partial class DebugConsole
|
||||
if (fullUpdate)
|
||||
{
|
||||
var seq = ++_compSeqSend;
|
||||
var task = _consoleHost.GetCompletions(args, _compCancel.Token);
|
||||
var task = _consoleHost.GetCompletions(args, str, _compCancel.Token);
|
||||
|
||||
if (!task.IsCompleted)
|
||||
{
|
||||
@@ -140,7 +140,7 @@ public sealed partial class DebugConsole
|
||||
if (_compCurResult == null)
|
||||
return;
|
||||
|
||||
var (_, curTyping, _) = CalcTypingArgs();
|
||||
var (_, curTyping, _, _) = CalcTypingArgs();
|
||||
|
||||
var curSelected = _compFiltered?.Length > 0 ? _compFiltered[_compSelected] : default;
|
||||
_compFiltered = FilterCompletions(_compCurResult.Options, curTyping);
|
||||
@@ -168,7 +168,7 @@ public sealed partial class DebugConsole
|
||||
|
||||
DebugTools.AssertNotNull(_compCurResult);
|
||||
|
||||
var (_, _, endRange) = CalcTypingArgs();
|
||||
var (_, _, endRange, _) = CalcTypingArgs();
|
||||
|
||||
var offset = CommandBar.GetOffsetAtIndex(endRange.start);
|
||||
// Logger.Debug($"Offset: {offset}");
|
||||
@@ -231,7 +231,7 @@ public sealed partial class DebugConsole
|
||||
}
|
||||
}
|
||||
|
||||
private (List<string> args, string curTyping, (int start, int end) lastRange) CalcTypingArgs()
|
||||
private (List<string> args, string curTyping, (int start, int end) lastRange, string argStr) CalcTypingArgs()
|
||||
{
|
||||
var cursor = CommandBar.CursorPosition;
|
||||
// Don't consider text after the cursor.
|
||||
@@ -252,7 +252,7 @@ public sealed partial class DebugConsole
|
||||
else
|
||||
lastRange = (cursor, cursor);
|
||||
|
||||
return (args, args[^1], lastRange);
|
||||
return (args, args[^1], lastRange, text.ToString());
|
||||
}
|
||||
|
||||
private CompletionOption[] FilterCompletions(IEnumerable<CompletionOption> completions, string curTyping)
|
||||
@@ -270,7 +270,7 @@ public sealed partial class DebugConsole
|
||||
{
|
||||
// Figure out typing word so we know how much to replace.
|
||||
var (completion, _, completionFlags) = _compFiltered[_compSelected];
|
||||
var (_, _, lastRange) = CalcTypingArgs();
|
||||
var (_, _, lastRange, _) = CalcTypingArgs();
|
||||
|
||||
// Replace the full word from the start.
|
||||
// This means that letter casing will match the completion suggestion.
|
||||
|
||||
@@ -23,9 +23,9 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
/// <summary>
|
||||
/// Write a line with a specific color to the console window.
|
||||
/// </summary>
|
||||
void AddLine(string text, Color color);
|
||||
void AddLine(FormattedMessage text, Color color);
|
||||
|
||||
void AddLine(string text);
|
||||
void AddLine(FormattedMessage text);
|
||||
|
||||
void AddFormattedLine(FormattedMessage message);
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
|
||||
private Color DetermineColor(bool local, bool error)
|
||||
{
|
||||
return Color.White;
|
||||
return error ? Color.Red : Color.White;
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
@@ -136,16 +136,16 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
_flushHistoryToDisk();
|
||||
}
|
||||
|
||||
public void AddLine(string text, Color color)
|
||||
public void AddLine(FormattedMessage text, Color color)
|
||||
{
|
||||
var formatted = new FormattedMessage(3);
|
||||
formatted.PushColor(color);
|
||||
formatted.AddText(text);
|
||||
formatted.AddMessage(text);
|
||||
formatted.Pop();
|
||||
AddFormattedLine(formatted);
|
||||
}
|
||||
|
||||
public void AddLine(string text)
|
||||
public void AddLine(FormattedMessage text)
|
||||
{
|
||||
AddLine(text, Color.White);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Robust.Client.UserInterface.CustomControls.DebugMonitorControls
|
||||
EntityCoordinates mouseGridPos;
|
||||
TileRef tile;
|
||||
|
||||
var mouseWorldMap = _eyeManager.ScreenToMap(mouseScreenPos);
|
||||
var mouseWorldMap = _eyeManager.PixelToMap(mouseScreenPos);
|
||||
if (mouseWorldMap == MapCoordinates.Nullspace)
|
||||
return;
|
||||
|
||||
|
||||
@@ -24,6 +24,11 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
/// </param>
|
||||
MapCoordinates ScreenToMap(Vector2 coords);
|
||||
|
||||
/// <summary>
|
||||
/// Similar to <see cref="ScreenToMap(Vector2)"/>, except it should compensate for the effects of shaders on viewports.
|
||||
/// </summary>
|
||||
MapCoordinates PixelToMap(Vector2 point);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a point on the map to screen coordinates.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.GameObjects;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Robust.Client.UserInterface.CustomControls;
|
||||
|
||||
/// <summary>
|
||||
/// An event used to reverse distortion effects applied by shaders.
|
||||
/// Used to find the map position that visible pixels originate from so that severe distortion shaders do not make interaction nigh-impossible.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct PixelToMapEvent(Vector2 LocalPosition, IViewportControl Control, IClydeViewport Viewport)
|
||||
{
|
||||
/// <summary>
|
||||
/// The local position of the pixel within the <see cref="Control"/> that we are trying to convert to a map position.
|
||||
/// </summary>
|
||||
public readonly Vector2 LocalPosition = LocalPosition;
|
||||
|
||||
/// <summary>
|
||||
/// The original (or WIP) location of the pixel within the <see cref="Control"/> that we are trying to convert to a map position.
|
||||
/// Used as the output of the event.
|
||||
/// </summary>
|
||||
public Vector2 VisiblePosition = LocalPosition;
|
||||
|
||||
/// <summary>
|
||||
/// The control the pixel we are considering is located within.
|
||||
/// </summary>
|
||||
public readonly IViewportControl Control = Control;
|
||||
|
||||
/// <summary>
|
||||
/// The viewport being displayed by the control we are considering.
|
||||
/// </summary>
|
||||
public readonly IClydeViewport Viewport = Viewport;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Numerics;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
@@ -13,8 +14,9 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
[Virtual]
|
||||
public class ViewportContainer : Control, IViewportControl
|
||||
{
|
||||
private readonly IClyde _displayManager;
|
||||
private readonly IInputManager _inputManager;
|
||||
[Dependency] private readonly IClyde _displayManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
|
||||
public IClydeViewport? Viewport { get; set; }
|
||||
|
||||
@@ -36,8 +38,7 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
|
||||
public ViewportContainer()
|
||||
{
|
||||
_displayManager = IoCManager.Resolve<IClyde>();
|
||||
_inputManager = IoCManager.Resolve<IInputManager>();
|
||||
IoCManager.InjectDependencies(this);
|
||||
MouseFilter = MouseFilterMode.Stop;
|
||||
Resized();
|
||||
}
|
||||
@@ -99,8 +100,7 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
// -- Handlers: In --
|
||||
|
||||
// -- Utils / S2M-M2S Base --
|
||||
|
||||
public MapCoordinates LocalPixelToMap(Vector2 point)
|
||||
public MapCoordinates LocalCoordsToMap(Vector2 point)
|
||||
{
|
||||
if (Viewport == null)
|
||||
return default;
|
||||
@@ -111,6 +111,19 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
return Viewport.LocalToWorld(point);
|
||||
}
|
||||
|
||||
public MapCoordinates LocalPixelToMap(Vector2 point)
|
||||
{
|
||||
if (Viewport == null)
|
||||
return default;
|
||||
|
||||
// pre-scaler
|
||||
point *= _viewportResolution;
|
||||
var ev = new PixelToMapEvent(point, this, Viewport);
|
||||
_entityManager.EventBus.RaiseEvent(EventSource.Local, ref ev);
|
||||
|
||||
return Viewport.LocalToWorld(ev.VisiblePosition);
|
||||
}
|
||||
|
||||
public Vector2 WorldToLocalPixel(Vector2 point)
|
||||
{
|
||||
if (Viewport?.Eye == null)
|
||||
@@ -127,6 +140,12 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
// -- Utils / S2M-M2S Extended --
|
||||
|
||||
public MapCoordinates ScreenToMap(Vector2 point)
|
||||
{
|
||||
return LocalCoordsToMap(point - GlobalPixelPosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public MapCoordinates PixelToMap(Vector2 point)
|
||||
{
|
||||
return LocalPixelToMap(point - GlobalPixelPosition);
|
||||
}
|
||||
|
||||
29
Robust.Client/UserInterface/RichText/BoldItalicTag.cs
Normal file
29
Robust.Client/UserInterface/RichText/BoldItalicTag.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.UserInterface.RichText;
|
||||
|
||||
public sealed class BoldItalicTag : IMarkupTag
|
||||
{
|
||||
public const string BoldItalicFont = "DefaultBoldItalic";
|
||||
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
public string Name => "bolditalic";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PushDrawContext(MarkupNode node, MarkupDrawingContext context)
|
||||
{
|
||||
var font = FontTag.CreateFont(context.Font, node, _resourceCache, _prototypeManager, BoldItalicFont);
|
||||
context.Font.Push(font);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PopDrawContext(MarkupNode node, MarkupDrawingContext context)
|
||||
{
|
||||
context.Font.Pop();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Linq;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -14,12 +15,18 @@ public sealed class BoldTag : IMarkupTag
|
||||
|
||||
public string Name => "bold";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PushDrawContext(MarkupNode node, MarkupDrawingContext context)
|
||||
{
|
||||
var font = FontTag.CreateFont(context.Font, node, _resourceCache, _prototypeManager, BoldFont);
|
||||
var font = FontTag.CreateFont(context.Font, node, _resourceCache, _prototypeManager,
|
||||
context.Tags.Any(static x => x is ItalicTag)
|
||||
? BoldItalicTag.BoldItalicFont
|
||||
: BoldFont
|
||||
);
|
||||
context.Font.Push(font);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PopDrawContext(MarkupNode node, MarkupDrawingContext context)
|
||||
{
|
||||
context.Font.Pop();
|
||||
|
||||
11
Robust.Client/UserInterface/RichText/BulletTag.cs
Normal file
11
Robust.Client/UserInterface/RichText/BulletTag.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.UserInterface.RichText;
|
||||
|
||||
public sealed class BulletTag : IMarkupTag
|
||||
{
|
||||
public string Name => "bullet";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string TextBefore(MarkupNode _) => " · ";
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace Robust.Client.UserInterface.RichText;
|
||||
/// </summary>
|
||||
public sealed class ColorTag : IMarkupTag
|
||||
{
|
||||
private static readonly Color DefaultColor = new(200, 200, 200);
|
||||
public static readonly Color DefaultColor = new(200, 200, 200);
|
||||
|
||||
public string Name => "color";
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace Robust.Client.UserInterface.RichText;
|
||||
public sealed class FontPrototype : IPrototype
|
||||
{
|
||||
[IdDataField]
|
||||
public string ID { get; } = default!;
|
||||
public string ID { get; private set; } = default!;
|
||||
|
||||
[DataField("path", required: true)]
|
||||
public ResPath Path { get; } = default!;
|
||||
public ResPath Path { get; private set; } = default!;
|
||||
}
|
||||
|
||||
@@ -14,12 +14,14 @@ namespace Robust.Client.UserInterface.RichText;
|
||||
public sealed class FontTag : IMarkupTag
|
||||
{
|
||||
public const string DefaultFont = "Default";
|
||||
public const int DefaultSize = 12;
|
||||
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
public string Name => "font";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PushDrawContext(MarkupNode node, MarkupDrawingContext context)
|
||||
{
|
||||
string fontId = node.Value.StringValue ?? DefaultFont;
|
||||
@@ -28,6 +30,7 @@ public sealed class FontTag : IMarkupTag
|
||||
context.Font.Push(font);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PopDrawContext(MarkupNode node, MarkupDrawingContext context)
|
||||
{
|
||||
context.Font.Pop();
|
||||
@@ -44,7 +47,7 @@ public sealed class FontTag : IMarkupTag
|
||||
IPrototypeManager prototypeManager,
|
||||
string fontId)
|
||||
{
|
||||
var size = 12;
|
||||
var size = DefaultSize;
|
||||
|
||||
if (contextFontStack.TryPeek(out var previousFont))
|
||||
{
|
||||
|
||||
36
Robust.Client/UserInterface/RichText/HeadingTag.cs
Normal file
36
Robust.Client/UserInterface/RichText/HeadingTag.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.UserInterface.RichText;
|
||||
|
||||
public sealed class HeadingTag : IMarkupTag
|
||||
{
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
public string Name => "head";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PushDrawContext(MarkupNode node, MarkupDrawingContext context)
|
||||
{
|
||||
if (!node.Value.TryGetLong(out var levelParam))
|
||||
return;
|
||||
|
||||
var level = Math.Min(Math.Max((int)levelParam, 1), 3);
|
||||
node.Attributes["size"] = new MarkupParameter(
|
||||
(int)Math.Ceiling(FontTag.DefaultSize * 2 / Math.Sqrt(level))
|
||||
);
|
||||
|
||||
var font = FontTag.CreateFont(context.Font, node, _resourceCache, _prototypeManager, BoldTag.BoldFont);
|
||||
context.Font.Push(font);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void PopDrawContext(MarkupNode node, MarkupDrawingContext context)
|
||||
{
|
||||
context.Font.Pop();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user