mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ef7ef139b | ||
|
|
facc16e931 | ||
|
|
11e4084652 | ||
|
|
f12eb3a36a | ||
|
|
2fa83181e2 | ||
|
|
36f02b4a18 | ||
|
|
e842142dd7 | ||
|
|
2eb740cea8 | ||
|
|
a044f04e3b | ||
|
|
a4723d1f62 | ||
|
|
627c1eb054 | ||
|
|
836aec0b87 | ||
|
|
9116e64291 | ||
|
|
a6bfb5f557 | ||
|
|
5c83678c78 | ||
|
|
eac94b1032 | ||
|
|
efd870d070 | ||
|
|
94f98073b0 | ||
|
|
5aa9378de0 | ||
|
|
850e9ab695 | ||
|
|
7319f3a241 | ||
|
|
b6252c9e4f | ||
|
|
fcd507d1f9 | ||
|
|
1eb874f4c3 | ||
|
|
a628d31c4b | ||
|
|
2b0ecd7166 | ||
|
|
bde650689b | ||
|
|
87d8d74d8c | ||
|
|
dddf13a19a | ||
|
|
75626a86a3 | ||
|
|
3e3cd0e257 | ||
|
|
a3a90154a4 | ||
|
|
9240c94e59 | ||
|
|
a95ba9f181 | ||
|
|
074a4faa92 | ||
|
|
6b4d74f46e | ||
|
|
f648218756 | ||
|
|
b497efb0c0 | ||
|
|
d8f2b917b4 | ||
|
|
6dd6b79db6 | ||
|
|
ff4548f108 | ||
|
|
8f41405b31 | ||
|
|
f285c62674 | ||
|
|
56c30edf04 | ||
|
|
783d529ec4 | ||
|
|
895bfb8ec0 | ||
|
|
6ef67cf513 | ||
|
|
15a2f6702c | ||
|
|
c5c2c2022a | ||
|
|
3c378640dd | ||
|
|
0a149fa91c | ||
|
|
fe8d1d9422 | ||
|
|
c89c529ba4 | ||
|
|
dd56de70b7 | ||
|
|
710408c613 | ||
|
|
2461cd94dd |
@@ -15,10 +15,10 @@
|
||||
<PackageVersion Include="ILReader.Core" Version="1.0.0.4" />
|
||||
<PackageVersion Include="JetBrains.Annotations" Version="2023.3.0" />
|
||||
<PackageVersion Include="JetBrains.Profiler.Api" Version="1.4.0" />
|
||||
<PackageVersion Include="Linguini.Bundle" Version="0.1.3" />
|
||||
<PackageVersion Include="Linguini.Bundle" Version="0.8.1" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzer.Testing" Version="1.1.1"/>
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.NUnit" Version="1.1.1"/>
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzer.Testing" Version="1.1.1" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.NUnit" Version="1.1.1" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Features" Version="4.8.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.8.0" />
|
||||
@@ -55,7 +55,7 @@
|
||||
<PackageVersion Include="Serilog" Version="3.1.1" />
|
||||
<PackageVersion Include="Serilog.Sinks.Loki" Version="4.0.0-beta3" />
|
||||
<PackageVersion Include="SharpZstd.Interop" Version="1.5.2-beta2" />
|
||||
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.3" />
|
||||
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.5" />
|
||||
<PackageVersion Include="SpaceWizards.HttpListener" Version="0.1.0" />
|
||||
<PackageVersion Include="SpaceWizards.NFluidsynth" Version="0.1.1" />
|
||||
<PackageVersion Include="SpaceWizards.SharpFont" Version="1.0.2" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project>
|
||||
|
||||
<!-- This file automatically reset by Tools/version.py -->
|
||||
<!-- This file automatically reset by Tools/version.py -->
|
||||
|
||||
|
||||
117
RELEASE-NOTES.md
117
RELEASE-NOTES.md
@@ -54,6 +54,123 @@ END TEMPLATE-->
|
||||
*None yet*
|
||||
|
||||
|
||||
## 225.0.2
|
||||
|
||||
|
||||
## 225.0.1
|
||||
|
||||
|
||||
## 225.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* `NetEntity.Parse` and `TryParse` will now fail to parse empty strings.
|
||||
* Try to prevent EventBus looping. This also caps the amount of directed component subscriptions for a particular component to 256.
|
||||
|
||||
### New features
|
||||
|
||||
* `IPrototypeManager.TryIndex` will now default to logging errors if passed an invalid prototype id struct (i,e., `EntProtoId` or `ProtoId<T>`). There is a new optional bool argument to disable logging errors.
|
||||
* `Eye` now allows its `Position` to be set directly. Please only do this with the `FixedEye` child type constructed manually.
|
||||
* Engine now respects the hub's `can_skip_build` parameter on info query, fixing an issue where the first hub advertisement fails due to ACZ taking too long.
|
||||
* Add GetSession & TryGetSession to ActorSystem.
|
||||
* Raise an event when an entity's name is changed.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* The `ent` toolshed command now takes `NetEntity` values, fixing parsing in practical uses.
|
||||
* Fix ComponentFactory test mocks.
|
||||
* Fix LookupFlags missing from a couple of EntityLookupSystem methods.
|
||||
|
||||
### Other
|
||||
|
||||
* Improved engine's Happy Eyeballs implementation, should result in more usage of IPv6 for HTTP APIs when available.
|
||||
* Remove CompIdx locks to improve performance inside Pvs at higher player counts.
|
||||
* Avoid a read lock in GetEntityQuery to also improve performance.
|
||||
* Mark `EntityManager.System<T>` as Pure.
|
||||
|
||||
|
||||
## 224.1.1
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fixed UserInterfaceSystem sometimes throwing a key-not-found exception when trying to close UIs.
|
||||
|
||||
|
||||
## 224.1.0
|
||||
|
||||
### New features
|
||||
|
||||
* `ServerIntegrationInstance` has new methods for adding dummy player sessions for tests that require multiple players.
|
||||
* Linguini has been updated to v0.8.1. Errors will now be logged when a duplicate localization key is found.
|
||||
* Added `UserInterfaceSystem.SetUi()` for modifying the `InterfaceData` associated with some BUI.
|
||||
* Added the `EntityPrototypeView` control for spawning & rendering an entity prototype.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix `UserInterfaceSystem` spamming client side errors when entities with UIs open are deleted while outside of PVS range.
|
||||
* Fix Toolshed's EnumTypeParse not working enum values with upercase characters.
|
||||
* Fixed `incmd` command not working due to an invalid cast.
|
||||
|
||||
### Other
|
||||
|
||||
* There have been various performance improvements to replay loading & playback.
|
||||
|
||||
### Internal
|
||||
|
||||
* Added `DummySession` and `DummyChannel` classes for use in integration tests and benchmarks to fool the server into thinking that there are multiple players connected.
|
||||
* Added `ICommonSessionInternal` and updated `CommonSession` so that the internal setters now go through that interface.
|
||||
|
||||
## 224.0.1
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fixes PVS throwing exceptions when invalid entities are passed to `ExpandPvsEvent`. Now it just logs an error.
|
||||
* Fixes BUIs not properly closing, resulting in invalid entities in `UserInterfaceUserComponent.OpenInterfaces`
|
||||
* Fixes an unknown/invalid prototype exception sometimes being thrown when running ``IPrototypeManager.ResolveResults()`
|
||||
|
||||
|
||||
## 224.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* `Matrix3` has been replaced with `System.Numerics.Matrix3x2`. Various Matrix related methods have been turned into extension methods in the `Matrix3Helpers` class.
|
||||
* Engine `EntityCategory` prototype IDs have been changed to use CamelCase. I.e., `hideSpawnMenu` -> `HideSpawnMenu`
|
||||
* Prototypes can now be implicitly cast `ProtoId<T>` or `EntProtoId` ID structs. The new implicit cast might cause previous function calls to be ambiguous.
|
||||
|
||||
### New features
|
||||
|
||||
* `Array.Clear(Array)` is now available in the sandbox.
|
||||
* BUIs now use `ExpandPvsEvent`. I.e., if a player has a UI open, then the entity associated with that UI will always get sent to the player by the PVS system.
|
||||
* Added `cvar_subs` command for listing all subscribers to cvar changes
|
||||
* Entity categories have been reworked
|
||||
* Each category now has a `HideSpawnMenu` field. The old `HideSpawnMenu` category is now just a normal category with that field set to true.
|
||||
* Reworked category inheritance. Inheritance can now be disabled per category using a `Inheritable` field.
|
||||
* Entity prototypes can now be automatically added to categories based on the components that they have, either by specifying components when defining the category in yml, or by adding the EntityCategoryAttribute to the component class.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fixed client-side BUI error log spam if an unknown entity has a UI open.
|
||||
* Fixed placement manager spawning entities with incorrect rotations.
|
||||
|
||||
### Other
|
||||
|
||||
* Added a try-catch block to BUI constructors, to avoid clients getting stuck in error loops while applying states.
|
||||
* Attempting to play sounds on terminating entities no longer logs an error.
|
||||
|
||||
|
||||
## 223.3.0
|
||||
|
||||
### New features
|
||||
|
||||
* Better exception logging for IRobustJob.
|
||||
* Add SetGridAudio helper for SharedAudioSystem.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix placement manager not setting entity rotation correctly.
|
||||
* Fix grid-based audio not playing correctly.
|
||||
|
||||
|
||||
## 223.2.0
|
||||
|
||||
### New features
|
||||
|
||||
@@ -2,4 +2,7 @@
|
||||
id: Audio
|
||||
name: Audio
|
||||
description: Audio entity used by engine
|
||||
save: false
|
||||
save: false
|
||||
components:
|
||||
- type: Transform
|
||||
gridTraversal: false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
- type: entity
|
||||
id: debugRotation
|
||||
abstract: true
|
||||
categories: [ debug ]
|
||||
categories: [ Debug ]
|
||||
components:
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
# debug related entities
|
||||
- type: entityCategory
|
||||
id: debug
|
||||
id: Debug
|
||||
name: entity-category-name-debug
|
||||
description: entity-category-desc-debug
|
||||
suffix: entity-category-suffix-debug
|
||||
|
||||
# entities that spawn other entities
|
||||
- type: entityCategory
|
||||
id: spawner
|
||||
id: Spawner
|
||||
name: entity-category-name-spawner
|
||||
description: entity-category-desc-spawner
|
||||
|
||||
# entities that should be hidden from the spawn menu
|
||||
# simple category that just exists to hide prototypes in spawn menus
|
||||
- type: entityCategory
|
||||
id: hideSpawnMenu
|
||||
id: HideSpawnMenu
|
||||
name: entity-category-name-hide
|
||||
description: entity-category-desc-hide
|
||||
hideSpawnMenu: true
|
||||
inheritable: false
|
||||
|
||||
@@ -9,6 +9,7 @@ cmd-parse-failure-float = {$arg} is not a valid float.
|
||||
cmd-parse-failure-bool = {$arg} is not a valid bool.
|
||||
cmd-parse-failure-uid = {$arg} is not a valid entity UID.
|
||||
cmd-parse-failure-mapid = {$arg} is not a valid MapId.
|
||||
cmd-parse-failure-enum = {$arg} is not a {$enum} Enum.
|
||||
cmd-parse-failure-grid = {$arg} is not a valid grid.
|
||||
cmd-parse-failure-entity-exist = UID {$arg} does not correspond to an existing entity.
|
||||
cmd-parse-failure-session = There is no session with username: {$username}
|
||||
@@ -43,6 +44,13 @@ cmd-cvar-compl-list = List available CVars
|
||||
cmd-cvar-arg-name = <name | ?>
|
||||
cmd-cvar-value-hidden = <value hidden>
|
||||
|
||||
## 'cvar_subs' command
|
||||
cmd-cvar_subs-desc = Lists the OnValueChanged subscriptions for a CVar.
|
||||
cmd-cvar_subs-help = Usage: cvar_subs <name>
|
||||
|
||||
cmd-cvar_subs-invalid-args = Must provide exactly one argument.
|
||||
cmd-cvar_subs-arg-name = <name>
|
||||
|
||||
## 'list' command
|
||||
cmd-list-desc = Lists available commands, with optional search filter
|
||||
cmd-list-help = Usage: list [filter]
|
||||
@@ -245,9 +253,6 @@ cmd-bind-arg-command = <InputCommand>
|
||||
cmd-net-draw-interp-desc = Toggles the debug drawing of the network interpolation.
|
||||
cmd-net-draw-interp-help = Usage: net_draw_interp
|
||||
|
||||
cmd-net-draw-interp-desc = Toggles the debug drawing of the network interpolation.
|
||||
cmd-net-draw-interp-help = Usage: net_draw_interp
|
||||
|
||||
cmd-net-watch-ent-desc = Dumps all network updates for an EntityId to the console.
|
||||
cmd-net-watch-ent-help = Usage: net_watchent <0|EntityUid>
|
||||
|
||||
@@ -299,16 +304,9 @@ cmd-savegrid-help = savegrid <gridID> <Path>
|
||||
cmd-testbed-desc = Loads a physics testbed on the specified map.
|
||||
cmd-testbed-help = testbed <mapid> <test>
|
||||
|
||||
cmd-saveconfig-desc = Saves the client configuration to the config file.
|
||||
cmd-saveconfig-help = saveconfig
|
||||
|
||||
## 'flushcookies' command
|
||||
# Note: the flushcookies command is from Robust.Client.WebView, it's not in the main engine code.
|
||||
|
||||
cmd-flushcookies-desc = Flush CEF cookie storage to disk
|
||||
cmd-flushcookies-help = This ensure cookies are properly saved to disk in the event of unclean shutdowns.
|
||||
Note that the actual operation is asynchronous.
|
||||
|
||||
## 'addcomp' command
|
||||
cmd-addcomp-desc = Adds a component to an entity.
|
||||
cmd-addcomp-help = addcomp <uid> <componentName>
|
||||
@@ -384,9 +382,9 @@ cmd-tp-desc = Teleports a player to any location in the round.
|
||||
cmd-tp-help = tp <x> <y> [<mapID>]
|
||||
|
||||
cmd-tpto-desc = Teleports the current player or the specified players/entities to the location of the first player/entity.
|
||||
cmd-tpto-help = tpto <username|uid> [username|uid]...
|
||||
cmd-tpto-destination-hint = destination (uid or username)
|
||||
cmd-tpto-victim-hint = entity to teleport (uid or username)
|
||||
cmd-tpto-help = tpto <username|uid> [username|NetEntity]...
|
||||
cmd-tpto-destination-hint = destination (NetEntity or username)
|
||||
cmd-tpto-victim-hint = entity to teleport (NetEntity or username)
|
||||
cmd-tpto-parse-error = Cant resolve entity or player: {$str}
|
||||
|
||||
cmd-listplayers-desc = Lists all players currently connected.
|
||||
@@ -446,9 +444,6 @@ cmd-showanchored-help = Usage: showanchored
|
||||
cmd-dmetamem-desc = Dumps a type's members in a format suitable for the sandbox configuration file.
|
||||
cmd-dmetamem-help = Usage: dmetamem <type>
|
||||
|
||||
cmd-dmetamem-desc = Displays chunk bounds for the purposes of rendering.
|
||||
cmd-dmetamem-help = Usage: showchunkbb <type>
|
||||
|
||||
cmd-launchauth-desc = Load authentication tokens from launcher data to aid in testing of live servers.
|
||||
cmd-launchauth-help = Usage: launchauth <account name>
|
||||
|
||||
@@ -515,9 +510,6 @@ cmd-profsnap-help = Usage: profsnap
|
||||
cmd-devwindow-desc = Dev Window
|
||||
cmd-devwindow-help = Usage: devwindow
|
||||
|
||||
cmd-devwindow-desc = Open file
|
||||
cmd-devwindow-help = Usage: testopenfile
|
||||
|
||||
cmd-scene-desc = Immediately changes the UI scene/state.
|
||||
cmd-scene-help = Usage: scene <className>
|
||||
|
||||
@@ -528,14 +520,11 @@ cmd-hwid-desc = Returns the current HWID (HardWare ID).
|
||||
cmd-hwid-help = Usage: hwid
|
||||
|
||||
cmd-vvread-desc = Retrieve a path's value using VV (View Variables).
|
||||
cmd-vvread-desc = Usage: vvread <path>
|
||||
cmd-vvread-help = Usage: vvread <path>
|
||||
|
||||
cmd-vvwrite-desc = Modify a path's value using VV (View Variables).
|
||||
cmd-vvwrite-help = Usage: vvwrite <path>
|
||||
|
||||
cmd-vv-desc = Opens View Variables (VV).
|
||||
cmd-vv-help = Usage: vv <path|entity ID|guihover>
|
||||
|
||||
cmd-vvinvoke-desc = Invoke/Call a path with arguments using VV.
|
||||
cmd-vvinvoke-help = Usage: vvinvoke <path> [arguments...]
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
entity-category-name-debug = Debug
|
||||
entity-category-desc-debug = Entity prototypes intended for debugging & testing.
|
||||
entity-category-suffix-debug = Debug
|
||||
|
||||
entity-category-name-spawner = Spawner
|
||||
entity-category-desc-spawner = Entity prototypes that spawn other entities.
|
||||
|
||||
entity-category-name-hide = Hidden
|
||||
entity-category-desc-hide = Entity prototypes that should be hidden from the spawn menu
|
||||
entity-category-desc-hide = Entity prototypes that should be hidden from entity spawn menus
|
||||
|
||||
@@ -41,7 +41,7 @@ public sealed partial class AudioSystem : SharedAudioSystem
|
||||
[Dependency] private readonly IParallelManager _parMan = default!;
|
||||
[Dependency] private readonly IRuntimeLog _runtimeLog = default!;
|
||||
[Dependency] private readonly IAudioInternal _audio = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||
[Dependency] private readonly SharedMapSystem _maps = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _xformSys = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
|
||||
@@ -216,11 +216,6 @@ public sealed partial class AudioSystem : SharedAudioSystem
|
||||
}
|
||||
}
|
||||
|
||||
if ((component.Flags & AudioFlags.GridAudio) != 0x0)
|
||||
{
|
||||
_metadata.SetFlag(entity.Owner, MetaDataFlags.Undetachable, true);
|
||||
}
|
||||
|
||||
// Need to set all initial data for first frame.
|
||||
ApplyAudioParams(component.Params, component);
|
||||
component.Source.Global = component.Global;
|
||||
@@ -336,55 +331,22 @@ public sealed partial class AudioSystem : SharedAudioSystem
|
||||
}
|
||||
|
||||
Vector2 worldPos;
|
||||
var gridUid = xform.ParentUid;
|
||||
component.Volume = component.Params.Volume;
|
||||
Vector2 delta;
|
||||
|
||||
// Handle grid audio differently by using nearest-edge instead of entity centre.
|
||||
// Handle grid audio differently by using grid position.
|
||||
if ((component.Flags & AudioFlags.GridAudio) != 0x0)
|
||||
{
|
||||
// It's our grid so max volume.
|
||||
if (_listenerGrid == gridUid)
|
||||
{
|
||||
component.Volume = component.Params.Volume;
|
||||
component.Occlusion = 0f;
|
||||
component.Position = listener.Position;
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Need a grid-optimised version because this is gonna be expensive.
|
||||
// Just to avoid clipping on and off grid or nearestPoint changing we'll
|
||||
// always set the sound to listener's pos, we'll just manually do gain ourselves.
|
||||
if (_physics.TryGetNearest(gridUid, listener, out _, out var gridDistance))
|
||||
{
|
||||
// Out of range
|
||||
if (gridDistance > component.MaxDistance)
|
||||
{
|
||||
component.Gain = 0f;
|
||||
return;
|
||||
}
|
||||
|
||||
var paramsGain = VolumeToGain(component.Params.Volume);
|
||||
|
||||
// Thought I'd never have to manually calculate gain again but this is the least
|
||||
// unpleasant audio I could get at the moment.
|
||||
component.Gain = paramsGain * _audio.GetAttenuationGain(
|
||||
gridDistance,
|
||||
component.Params.RolloffFactor,
|
||||
component.Params.ReferenceDistance,
|
||||
component.Params.MaxDistance);
|
||||
component.Position = listener.Position;
|
||||
return;
|
||||
}
|
||||
|
||||
// Can't get nearest point so don't play anymore.
|
||||
component.Gain = 0f;
|
||||
return;
|
||||
var parentUid = xform.ParentUid;
|
||||
worldPos = _maps.GetGridPosition(parentUid);
|
||||
}
|
||||
else
|
||||
{
|
||||
worldPos = _xformSys.GetWorldPosition(entity);
|
||||
}
|
||||
|
||||
worldPos = _xformSys.GetWorldPosition(entity);
|
||||
component.Volume = component.Params.Volume;
|
||||
|
||||
// Max distance check
|
||||
var delta = worldPos - listener.Position;
|
||||
delta = worldPos - listener.Position;
|
||||
var distance = delta.Length();
|
||||
|
||||
// Out of range so just clip it for us.
|
||||
@@ -403,8 +365,15 @@ public sealed partial class AudioSystem : SharedAudioSystem
|
||||
}
|
||||
|
||||
// Update audio occlusion
|
||||
var occlusion = GetOcclusion(listener, delta, distance, entity);
|
||||
component.Occlusion = occlusion;
|
||||
if ((component.Flags & AudioFlags.NoOcclusion) == AudioFlags.NoOcclusion)
|
||||
{
|
||||
component.Occlusion = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
var occlusion = GetOcclusion(listener, delta, distance, entity);
|
||||
component.Occlusion = occlusion;
|
||||
}
|
||||
|
||||
// Update audio positions.
|
||||
component.Position = worldPos;
|
||||
@@ -671,10 +640,10 @@ public sealed partial class AudioSystem : SharedAudioSystem
|
||||
private (EntityUid Entity, AudioComponent Component) CreateAndStartPlayingStream(AudioParams? audioParams, AudioStream stream)
|
||||
{
|
||||
var audioP = audioParams ?? AudioParams.Default;
|
||||
var entity = EntityManager.CreateEntityUninitialized("Audio", MapCoordinates.Nullspace);
|
||||
var comp = SetupAudio(entity, null, audioP, stream.Length);
|
||||
LoadStream((entity, comp), stream);
|
||||
var entity = SetupAudio(null, audioP, initialize: false, length: stream.Length);
|
||||
LoadStream(entity, stream);
|
||||
EntityManager.InitializeAndStartEntity(entity);
|
||||
var comp = entity.Comp;
|
||||
var source = comp.Source;
|
||||
|
||||
// TODO clamp the offset inside of SetPlaybackPosition() itself.
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var type = Type.GetType(args[0]);
|
||||
var type = GetType(args[0]);
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
@@ -25,6 +25,17 @@ namespace Robust.Client.Console.Commands
|
||||
shell.WriteLine(sig);
|
||||
}
|
||||
}
|
||||
|
||||
private Type? GetType(string name)
|
||||
{
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
if (assembly.GetType(name) is { } type)
|
||||
return type;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -368,7 +368,7 @@ namespace Robust.Client.Debugging
|
||||
}
|
||||
|
||||
worldHandle.UseShader(null);
|
||||
worldHandle.SetTransform(Matrix3.Identity);
|
||||
worldHandle.SetTransform(Matrix3x2.Identity);
|
||||
}
|
||||
|
||||
private void DrawScreen(DrawingHandleScreen screenHandle, OverlayDrawArgs args)
|
||||
@@ -443,7 +443,7 @@ namespace Robust.Client.Debugging
|
||||
}
|
||||
|
||||
screenHandle.UseShader(null);
|
||||
screenHandle.SetTransform(Matrix3.Identity);
|
||||
screenHandle.SetTransform(Matrix3x2.Identity);
|
||||
}
|
||||
|
||||
protected internal override void Draw(in OverlayDrawArgs args)
|
||||
@@ -520,11 +520,11 @@ namespace Robust.Client.Debugging
|
||||
var matrix1 = xform1.WorldMatrix;
|
||||
var matrix2 = xform2.WorldMatrix;
|
||||
|
||||
var xf1 = new Vector2(matrix1.R0C2, matrix1.R1C2);
|
||||
var xf2 = new Vector2(matrix2.R0C2, matrix2.R1C2);
|
||||
var xf1 = new Vector2(matrix1.M31, matrix1.M32);
|
||||
var xf2 = new Vector2(matrix2.M31, matrix2.M32);
|
||||
|
||||
var p1 = matrix1.Transform(joint.LocalAnchorA);
|
||||
var p2 = matrix2.Transform(joint.LocalAnchorB);
|
||||
var p1 = Vector2.Transform(joint.LocalAnchorA, matrix1);
|
||||
var p2 = Vector2.Transform(joint.LocalAnchorB, matrix2);
|
||||
|
||||
var xfa = new Transform(xf1, xform1.WorldRotation);
|
||||
var xfb = new Transform(xf2, xform2.WorldRotation);
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace Robust.Client.GameObjects
|
||||
[DataField("color")]
|
||||
private Color color = Color.White;
|
||||
|
||||
public Matrix3 LocalMatrix = Matrix3.Identity;
|
||||
public Matrix3x2 LocalMatrix = Matrix3x2.Identity;
|
||||
|
||||
[Animatable]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
@@ -389,10 +389,10 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
internal void UpdateLocalMatrix()
|
||||
{
|
||||
LocalMatrix = Matrix3.CreateTransform(in offset, in rotation, in scale);
|
||||
LocalMatrix = Matrix3Helpers.CreateTransform(in offset, in rotation, in scale);
|
||||
}
|
||||
|
||||
public Matrix3 GetLocalMatrix()
|
||||
public Matrix3x2 GetLocalMatrix()
|
||||
{
|
||||
return LocalMatrix;
|
||||
}
|
||||
@@ -1304,22 +1304,21 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
// worldRotation + eyeRotation should be the angle of the entity on-screen. If no-rot is enabled this is just set to zero.
|
||||
// However, at some point later the eye-matrix is applied separately, so we subtract -eye rotation for now:
|
||||
var entityMatrix = Matrix3.CreateTransform(worldPosition, NoRotation ? -eyeRotation : worldRotation - cardinal);
|
||||
var entityMatrix = Matrix3Helpers.CreateTransform(worldPosition, NoRotation ? -eyeRotation : worldRotation - cardinal);
|
||||
|
||||
Matrix3.Multiply(in LocalMatrix, in entityMatrix, out var transformSprite);
|
||||
var transformSprite = Matrix3x2.Multiply(LocalMatrix, entityMatrix);
|
||||
|
||||
if (GranularLayersRendering)
|
||||
{
|
||||
//Default rendering
|
||||
entityMatrix = Matrix3.CreateTransform(worldPosition, worldRotation);
|
||||
Matrix3.Multiply(in LocalMatrix, in entityMatrix, out var transformDefault);
|
||||
entityMatrix = Matrix3Helpers.CreateTransform(worldPosition, worldRotation);
|
||||
var transformDefault = Matrix3x2.Multiply(LocalMatrix, entityMatrix);
|
||||
//Snap to cardinals
|
||||
entityMatrix = Matrix3.CreateTransform(worldPosition, worldRotation - angle.GetCardinalDir().ToAngle());
|
||||
Matrix3.Multiply(in LocalMatrix, in entityMatrix, out var transformSnap);
|
||||
entityMatrix = Matrix3Helpers.CreateTransform(worldPosition, worldRotation - angle.GetCardinalDir().ToAngle());
|
||||
var transformSnap = Matrix3x2.Multiply(LocalMatrix, entityMatrix);
|
||||
//No rotation
|
||||
entityMatrix = Matrix3.CreateTransform(worldPosition, -eyeRotation);
|
||||
Matrix3.Multiply(in LocalMatrix, in entityMatrix, out var transformNoRot);
|
||||
|
||||
entityMatrix = Matrix3Helpers.CreateTransform(worldPosition, -eyeRotation);
|
||||
var transformNoRot = Matrix3x2.Multiply(LocalMatrix, entityMatrix);
|
||||
|
||||
foreach (var layer in Layers) {
|
||||
switch (layer.RenderingStrategy)
|
||||
@@ -1546,7 +1545,7 @@ namespace Robust.Client.GameObjects
|
||||
private RSI.State? _actualState;
|
||||
[ViewVariables] public RSI.State? ActualState => _actualState;
|
||||
|
||||
public Matrix3 LocalMatrix = Matrix3.Identity;
|
||||
public Matrix3x2 LocalMatrix = Matrix3x2.Identity;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public Vector2 Scale
|
||||
@@ -1692,7 +1691,7 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
internal void UpdateLocalMatrix()
|
||||
{
|
||||
LocalMatrix = Matrix3.CreateTransform(in _offset, in _rotation, in _scale);
|
||||
LocalMatrix = Matrix3Helpers.CreateTransform(in _offset, in _rotation, in _scale);
|
||||
}
|
||||
|
||||
RSI? ISpriteLayer.Rsi { get => RSI; set => SetRsi(value); }
|
||||
@@ -1964,27 +1963,27 @@ namespace Robust.Client.GameObjects
|
||||
/// Given the apparent rotation of an entity on screen (world + eye rotation), get layer's matrix for drawing &
|
||||
/// relevant RSI direction.
|
||||
/// </summary>
|
||||
public void GetLayerDrawMatrix(RsiDirection dir, out Matrix3 layerDrawMatrix)
|
||||
public void GetLayerDrawMatrix(RsiDirection dir, out Matrix3x2 layerDrawMatrix)
|
||||
{
|
||||
if (_parent.NoRotation || dir == RsiDirection.South)
|
||||
layerDrawMatrix = LocalMatrix;
|
||||
else
|
||||
{
|
||||
Matrix3.Multiply(in _rsiDirectionMatrices[(int)dir], in LocalMatrix, out layerDrawMatrix);
|
||||
layerDrawMatrix = Matrix3x2.Multiply(_rsiDirectionMatrices[(int)dir], LocalMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
private static Matrix3[] _rsiDirectionMatrices = new Matrix3[]
|
||||
private static Matrix3x2[] _rsiDirectionMatrices = new Matrix3x2[]
|
||||
{
|
||||
// array order chosen such that this array can be indexed by casing an RSI direction to an int
|
||||
Matrix3.Identity, // should probably just avoid matrix multiplication altogether if the direction is south.
|
||||
Matrix3.CreateRotation(-Direction.North.ToAngle()),
|
||||
Matrix3.CreateRotation(-Direction.East.ToAngle()),
|
||||
Matrix3.CreateRotation(-Direction.West.ToAngle()),
|
||||
Matrix3.CreateRotation(-Direction.SouthEast.ToAngle()),
|
||||
Matrix3.CreateRotation(-Direction.SouthWest.ToAngle()),
|
||||
Matrix3.CreateRotation(-Direction.NorthEast.ToAngle()),
|
||||
Matrix3.CreateRotation(-Direction.NorthWest.ToAngle())
|
||||
Matrix3x2.Identity, // should probably just avoid matrix multiplication altogether if the direction is south.
|
||||
Matrix3Helpers.CreateRotation(-Direction.North.ToAngle()),
|
||||
Matrix3Helpers.CreateRotation(-Direction.East.ToAngle()),
|
||||
Matrix3Helpers.CreateRotation(-Direction.West.ToAngle()),
|
||||
Matrix3Helpers.CreateRotation(-Direction.SouthEast.ToAngle()),
|
||||
Matrix3Helpers.CreateRotation(-Direction.SouthWest.ToAngle()),
|
||||
Matrix3Helpers.CreateRotation(-Direction.NorthEast.ToAngle()),
|
||||
Matrix3Helpers.CreateRotation(-Direction.NorthWest.ToAngle())
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -2018,7 +2017,7 @@ namespace Robust.Client.GameObjects
|
||||
/// <summary>
|
||||
/// Render a layer. This assumes that the input angle is between 0 and 2pi.
|
||||
/// </summary>
|
||||
internal void Render(DrawingHandleWorld drawingHandle, ref Matrix3 spriteMatrix, Angle angle, Direction? overrideDirection)
|
||||
internal void Render(DrawingHandleWorld drawingHandle, ref Matrix3x2 spriteMatrix, Angle angle, Direction? overrideDirection)
|
||||
{
|
||||
if (!Visible || Blank)
|
||||
return;
|
||||
@@ -2040,7 +2039,7 @@ namespace Robust.Client.GameObjects
|
||||
if (CopyToShaderParameters == null)
|
||||
{
|
||||
// Set the drawing transform for this layer
|
||||
Matrix3.Multiply(in layerMatrix, in spriteMatrix, out var transformMatrix);
|
||||
var transformMatrix = Matrix3x2.Multiply(layerMatrix, spriteMatrix);
|
||||
drawingHandle.SetTransform(in transformMatrix);
|
||||
|
||||
RenderTexture(drawingHandle, texture);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Containers;
|
||||
@@ -118,7 +119,7 @@ public sealed class EntityLookupOverlay : Overlay
|
||||
//DebugTools.Assert(!ent.IsInContainer(_entityManager));
|
||||
var (entPos, entRot) = _transform.GetWorldPositionRotation(ent);
|
||||
|
||||
var lookupPos = invMatrix.Transform(entPos);
|
||||
var lookupPos = Vector2.Transform(entPos, invMatrix);
|
||||
var lookupRot = entRot - rotation;
|
||||
|
||||
var aabb = _lookup.GetAABB(ent, lookupPos, lookupRot, xform, _xformQuery);
|
||||
@@ -127,6 +128,6 @@ public sealed class EntityLookupOverlay : Overlay
|
||||
}
|
||||
});
|
||||
|
||||
worldHandle.SetTransform(Matrix3.Identity);
|
||||
worldHandle.SetTransform(Matrix3x2.Identity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
worldHandle.SetTransform(Matrix3.Identity);
|
||||
worldHandle.SetTransform(Matrix3x2.Identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Robust.Client.GameObjects
|
||||
/// </summary>
|
||||
public sealed class InputSystem : SharedInputSystem, IPostInjectInit
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IClientGameStateManager _stateManager = default!;
|
||||
@@ -82,18 +83,35 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
// send it off to the server
|
||||
var clientMsg = (ClientFullInputCmdMessage)message;
|
||||
var fullMsg = new FullInputCmdMessage(
|
||||
clientMsg.Tick,
|
||||
clientMsg.SubTick,
|
||||
(int)clientMsg.InputSequence,
|
||||
clientMsg.InputFunctionId,
|
||||
clientMsg.State,
|
||||
GetNetCoordinates(clientMsg.Coordinates),
|
||||
clientMsg.ScreenCoordinates)
|
||||
var clientMsg = message switch
|
||||
{
|
||||
Uid = GetNetEntity(clientMsg.Uid)
|
||||
ClientFullInputCmdMessage clientInput => clientInput,
|
||||
FullInputCmdMessage fullInput => new ClientFullInputCmdMessage(
|
||||
fullInput.Tick,
|
||||
fullInput.SubTick,
|
||||
fullInput.InputFunctionId,
|
||||
GetCoordinates(fullInput.Coordinates),
|
||||
fullInput.ScreenCoordinates,
|
||||
fullInput.State,
|
||||
GetEntity(fullInput.Uid)),
|
||||
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
var fullMsg = message switch
|
||||
{
|
||||
FullInputCmdMessage fullInput => fullInput,
|
||||
ClientFullInputCmdMessage client => new FullInputCmdMessage(
|
||||
client.Tick,
|
||||
client.SubTick,
|
||||
client.InputFunctionId,
|
||||
clientMsg.State,
|
||||
GetNetCoordinates(client.Coordinates),
|
||||
clientMsg.ScreenCoordinates,
|
||||
GetNetEntity(clientMsg.Uid)
|
||||
),
|
||||
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
DispatchInputCommand(clientMsg, fullMsg);
|
||||
@@ -131,7 +149,7 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
_conHost.RegisterCommand("incmd",
|
||||
"Inserts an input command into the simulation",
|
||||
"incmd <KeyFunction> <d|u KeyState> <wxPos> <wyPos>",
|
||||
"incmd <KeyFunction> <KeyState> [wxPos] [wyPos]",
|
||||
GenerateInputCommand);
|
||||
}
|
||||
|
||||
@@ -147,17 +165,47 @@ namespace Robust.Client.GameObjects
|
||||
if (_playerManager.LocalEntity is not { } pent)
|
||||
return;
|
||||
|
||||
BoundKeyFunction keyFunction = new BoundKeyFunction(args[0]);
|
||||
BoundKeyState state = args[1] == "u" ? BoundKeyState.Up: BoundKeyState.Down;
|
||||
if (args.Length is not (2 or 4))
|
||||
{
|
||||
shell.WriteLine(Loc.GetString($"cmd-invalid-arg-number-error"));
|
||||
return;
|
||||
}
|
||||
|
||||
var pxform = Transform(pent);
|
||||
var wPos = pxform.WorldPosition + new Vector2(float.Parse(args[2]), float.Parse(args[3]));
|
||||
var coords = EntityCoordinates.FromMap(pent, new MapCoordinates(wPos, pxform.MapID), _transform, EntityManager);
|
||||
var keyFunction = new BoundKeyFunction(args[0]);
|
||||
if (!Enum.TryParse<BoundKeyState>(args[1], out var state))
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("cmd-parse-failure-enum", ("arg", args[1]), ("enum", nameof(BoundKeyState))));
|
||||
return;
|
||||
}
|
||||
|
||||
var wOffset = Vector2.Zero;
|
||||
if (args.Length == 4)
|
||||
{
|
||||
if (!float.TryParse(args[2], out var wX))
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-parse-failure-float", ("arg", args[2])));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!float.TryParse(args[3], out var wY))
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-parse-failure-float", ("arg", args[3])));
|
||||
return;
|
||||
}
|
||||
|
||||
wOffset = new Vector2(wX, wY);
|
||||
}
|
||||
|
||||
var coords = EntityCoordinates.FromMap(pent, _transform.GetMapCoordinates(pent).Offset(wOffset), _transform, EntityManager);
|
||||
var funcId = _inputManager.NetworkBindMap.KeyFunctionID(keyFunction);
|
||||
|
||||
var message = new FullInputCmdMessage(_timing.CurTick, _timing.TickFraction, funcId, state,
|
||||
GetNetCoordinates(coords), new ScreenCoordinates(0, 0, default), NetEntity.Invalid);
|
||||
var message = new ClientFullInputCmdMessage(_timing.CurTick,
|
||||
_timing.TickFraction,
|
||||
funcId,
|
||||
coords,
|
||||
new ScreenCoordinates(0, 0, default),
|
||||
state,
|
||||
EntityUid.Invalid);
|
||||
|
||||
HandleInputCommand(_playerManager.LocalSession, keyFunction, message);
|
||||
}
|
||||
|
||||
@@ -101,18 +101,16 @@ namespace Robust.Client.Graphics
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void GetScreenProjectionMatrix(out Matrix3 projMatrix)
|
||||
public void GetScreenProjectionMatrix(out Matrix3x2 projMatrix)
|
||||
{
|
||||
Matrix3 result = default;
|
||||
Matrix3x2 result = default;
|
||||
|
||||
result.R0C0 = PixelsPerMeter;
|
||||
result.R1C1 = -PixelsPerMeter;
|
||||
result.M11 = PixelsPerMeter;
|
||||
result.M22 = -PixelsPerMeter;
|
||||
|
||||
var screenSize = _displayManager.ScreenSize;
|
||||
result.R0C2 = screenSize.X / 2f;
|
||||
result.R1C2 = screenSize.Y / 2f;
|
||||
|
||||
result.R2C2 = 1;
|
||||
result.M31 = screenSize.X / 2f;
|
||||
result.M32 = screenSize.Y / 2f;
|
||||
|
||||
/* column major
|
||||
Sx 0 Tx
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Graphics;
|
||||
@@ -44,7 +44,7 @@ namespace Robust.Client.Graphics
|
||||
/// to UI screen space.
|
||||
/// </summary>
|
||||
/// <param name="projMatrix"></param>
|
||||
void GetScreenProjectionMatrix(out Matrix3 projMatrix);
|
||||
void GetScreenProjectionMatrix(out Matrix3x2 projMatrix);
|
||||
|
||||
/// <summary>
|
||||
/// Projects a point from world space to UI screen space using the main viewport.
|
||||
|
||||
@@ -367,7 +367,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_renderHandle.UseShader(entry.Sprite.PostShader);
|
||||
CalcScreenMatrices(viewport.Size, out var proj, out var view);
|
||||
_renderHandle.SetProjView(proj, view);
|
||||
_renderHandle.SetModelTransform(Matrix3.Identity);
|
||||
_renderHandle.SetModelTransform(Matrix3x2.Identity);
|
||||
|
||||
var rounded = roundedPos - entityPostRenderTarget.Size / 2;
|
||||
|
||||
@@ -530,7 +530,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// Because the math is wrong.
|
||||
// So there are distortions from incorrect projection.
|
||||
_renderHandle.UseShader(_fovDebugShaderInstance);
|
||||
_renderHandle.DrawingHandleScreen.SetTransform(Matrix3.Identity);
|
||||
_renderHandle.DrawingHandleScreen.SetTransform(Matrix3x2.Identity);
|
||||
var pos = UIBox2.FromDimensions(viewport.Size / 2 - new Vector2(200, 200), new Vector2(400, 400));
|
||||
_renderHandle.DrawingHandleScreen.DrawTextureRect(FovTexture, pos);
|
||||
}
|
||||
@@ -538,7 +538,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
if (DebugLayers == ClydeDebugLayers.Light)
|
||||
{
|
||||
_renderHandle.UseShader(null);
|
||||
_renderHandle.DrawingHandleScreen.SetTransform(Matrix3.Identity);
|
||||
_renderHandle.DrawingHandleScreen.SetTransform(Matrix3x2.Identity);
|
||||
_renderHandle.DrawingHandleScreen.DrawTextureRect(
|
||||
viewport.WallBleedIntermediateRenderTarget2.Texture,
|
||||
UIBox2.FromDimensions(Vector2.Zero, viewport.Size), new Color(1, 1, 1, 0.5f));
|
||||
|
||||
@@ -98,28 +98,34 @@ namespace Robust.Client.Graphics.Clyde
|
||||
[FieldOffset(20 * sizeof(float))] public Vector3 ViewMatrixC2;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ProjViewMatrices(in Matrix3 projMatrix, in Matrix3 viewMatrix)
|
||||
public ProjViewMatrices(in Matrix3x2 projMatrix, in Matrix3x2 viewMatrix)
|
||||
{
|
||||
ProjMatrixC0 = new Vector3(projMatrix.R0C0, projMatrix.R1C0, projMatrix.R2C0);
|
||||
ProjMatrixC1 = new Vector3(projMatrix.R0C1, projMatrix.R1C1, projMatrix.R2C1);
|
||||
ProjMatrixC2 = new Vector3(projMatrix.R0C2, projMatrix.R1C2, projMatrix.R2C2);
|
||||
// We put the rows of the input matrix into the columns of our GPU matrices
|
||||
// this transpose is required, as in C#, we premultiply vectors with matrices
|
||||
// (vM) while GL postmultiplies vectors with matrices (Mv); however, since
|
||||
// the Matrix3x2 data is stored row-major, and GL uses column-major, the
|
||||
// memory layout is the same (or would be, if Matrix3x2 didn't have an
|
||||
// implicit column)
|
||||
ProjMatrixC0 = new Vector3(projMatrix.M11, projMatrix.M12, 0);
|
||||
ProjMatrixC1 = new Vector3(projMatrix.M21, projMatrix.M22, 0);
|
||||
ProjMatrixC2 = new Vector3(projMatrix.M31, projMatrix.M32, 1);
|
||||
|
||||
ViewMatrixC0 = new Vector3(viewMatrix.R0C0, viewMatrix.R1C0, viewMatrix.R2C0);
|
||||
ViewMatrixC1 = new Vector3(viewMatrix.R0C1, viewMatrix.R1C1, viewMatrix.R2C1);
|
||||
ViewMatrixC2 = new Vector3(viewMatrix.R0C2, viewMatrix.R1C2, viewMatrix.R2C2);
|
||||
ViewMatrixC0 = new Vector3(viewMatrix.M11, viewMatrix.M12, 0);
|
||||
ViewMatrixC1 = new Vector3(viewMatrix.M21, viewMatrix.M22, 0);
|
||||
ViewMatrixC2 = new Vector3(viewMatrix.M31, viewMatrix.M32, 1);
|
||||
}
|
||||
|
||||
public void Apply(Clyde clyde, GLShaderProgram program)
|
||||
{
|
||||
program.SetUniformMaybe("projectionMatrix", new Matrix3(
|
||||
ProjMatrixC0.X, ProjMatrixC1.X, ProjMatrixC2.X,
|
||||
ProjMatrixC0.Y, ProjMatrixC1.Y, ProjMatrixC2.Y,
|
||||
ProjMatrixC0.Z, ProjMatrixC1.Z, ProjMatrixC2.Z
|
||||
program.SetUniformMaybe("projectionMatrix", new Matrix3x2(
|
||||
ProjMatrixC0.X, ProjMatrixC0.Y, // Implicit 0
|
||||
ProjMatrixC1.X, ProjMatrixC1.Y, // Implicit 0
|
||||
ProjMatrixC2.X, ProjMatrixC2.Y // Implicit 1
|
||||
));
|
||||
program.SetUniformMaybe("viewMatrix", new Matrix3(
|
||||
ViewMatrixC0.X, ViewMatrixC1.X, ViewMatrixC2.X,
|
||||
ViewMatrixC0.Y, ViewMatrixC1.Y, ViewMatrixC2.Y,
|
||||
ViewMatrixC0.Z, ViewMatrixC1.Z, ViewMatrixC2.Z
|
||||
program.SetUniformMaybe("viewMatrix", new Matrix3x2(
|
||||
ViewMatrixC0.X, ViewMatrixC0.Y, // Implicit 0
|
||||
ViewMatrixC1.X, ViewMatrixC1.Y, // Implicit 0
|
||||
ViewMatrixC2.X, ViewMatrixC2.Y // Implicit 1
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,18 +492,18 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
var offset = new Vector2(component.Radius, component.Radius);
|
||||
|
||||
Matrix3 matrix;
|
||||
Matrix3x2 matrix;
|
||||
if (mask == null)
|
||||
{
|
||||
matrix = Matrix3.Identity;
|
||||
matrix = Matrix3x2.Identity;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only apply rotation if a mask is said, because else it doesn't matter.
|
||||
matrix = Matrix3.CreateRotation(rotation);
|
||||
matrix = Matrix3Helpers.CreateRotation(rotation);
|
||||
}
|
||||
|
||||
(matrix.R0C2, matrix.R1C2) = lightPos;
|
||||
(matrix.M31, matrix.M32) = lightPos;
|
||||
|
||||
_drawQuad(-offset, offset, matrix, lightShader);
|
||||
}
|
||||
@@ -692,7 +692,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
// Blur horizontally to _wallBleedIntermediateRenderTarget1.
|
||||
shader.SetUniformMaybe("direction", Vector2.UnitX);
|
||||
_drawQuad(Vector2.Zero, viewport.Size, Matrix3.Identity, shader);
|
||||
_drawQuad(Vector2.Zero, viewport.Size, Matrix3x2.Identity, shader);
|
||||
|
||||
SetTexture(TextureUnit.Texture0, viewport.LightBlurTarget.Texture);
|
||||
|
||||
@@ -700,7 +700,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
// Blur vertically to _wallBleedIntermediateRenderTarget2.
|
||||
shader.SetUniformMaybe("direction", Vector2.UnitY);
|
||||
_drawQuad(Vector2.Zero, viewport.Size, Matrix3.Identity, shader);
|
||||
_drawQuad(Vector2.Zero, viewport.Size, Matrix3x2.Identity, shader);
|
||||
|
||||
SetTexture(TextureUnit.Texture0, viewport.LightRenderTarget.Texture);
|
||||
}
|
||||
@@ -754,14 +754,14 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
// Blur horizontally to _wallBleedIntermediateRenderTarget1.
|
||||
shader.SetUniformMaybe("direction", Vector2.UnitX);
|
||||
_drawQuad(Vector2.Zero, viewport.Size, Matrix3.Identity, shader);
|
||||
_drawQuad(Vector2.Zero, viewport.Size, Matrix3x2.Identity, shader);
|
||||
|
||||
SetTexture(TextureUnit.Texture0, viewport.WallBleedIntermediateRenderTarget1.Texture);
|
||||
BindRenderTargetFull(viewport.WallBleedIntermediateRenderTarget2);
|
||||
|
||||
// Blur vertically to _wallBleedIntermediateRenderTarget2.
|
||||
shader.SetUniformMaybe("direction", Vector2.UnitY);
|
||||
_drawQuad(Vector2.Zero, viewport.Size, Matrix3.Identity, shader);
|
||||
_drawQuad(Vector2.Zero, viewport.Size, Matrix3x2.Identity, shader);
|
||||
|
||||
SetTexture(TextureUnit.Texture0, viewport.WallBleedIntermediateRenderTarget2.Texture);
|
||||
}
|
||||
@@ -909,13 +909,13 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// Second modification is that output must be fov-centred (difference-space)
|
||||
uZero -= fovCentre;
|
||||
|
||||
var clipToDiff = new Matrix3(in uX, in uY, in uZero);
|
||||
var clipToDiff = new Matrix3x2(uX.X, uX.Y, uY.X, uY.Y, uZero.X, uZero.Y);
|
||||
|
||||
fovShader.SetUniformMaybe("clipToDiff", clipToDiff);
|
||||
_drawQuad(Vector2.Zero, Vector2.One, Matrix3.Identity, fovShader);
|
||||
_drawQuad(Vector2.Zero, Vector2.One, Matrix3x2.Identity, fovShader);
|
||||
}
|
||||
|
||||
private void UpdateOcclusionGeometry(MapId map, Box2 expandedBounds, Matrix3 eyeTransform)
|
||||
private void UpdateOcclusionGeometry(MapId map, Box2 expandedBounds, Matrix3x2 eyeTransform)
|
||||
{
|
||||
using var _ = _prof.Group("UpdateOcclusionGeometry");
|
||||
using var _p = DebugGroup(nameof(UpdateOcclusionGeometry));
|
||||
@@ -968,9 +968,9 @@ namespace Robust.Client.Graphics.Clyde
|
||||
var worldTransform = xformSystem.GetWorldMatrix(transform, xforms);
|
||||
var box = occluder.BoundingBox;
|
||||
|
||||
var tl = worldTransform.Transform(box.TopLeft);
|
||||
var tr = worldTransform.Transform(box.TopRight);
|
||||
var br = worldTransform.Transform(box.BottomRight);
|
||||
var tl = Vector2.Transform(box.TopLeft, worldTransform);
|
||||
var tr = Vector2.Transform(box.TopRight, worldTransform);
|
||||
var br = Vector2.Transform(box.BottomRight, worldTransform);
|
||||
var bl = tl + br - tr;
|
||||
|
||||
// Faces.
|
||||
@@ -1010,9 +1010,9 @@ namespace Robust.Client.Graphics.Clyde
|
||||
//
|
||||
|
||||
// Calculate delta positions from camera.
|
||||
var dTl = eyeTransform.Transform(tl);
|
||||
var dTr = eyeTransform.Transform(tr);
|
||||
var dBl = eyeTransform.Transform(bl);
|
||||
var dTl = Vector2.Transform(tl, eyeTransform);
|
||||
var dTr = Vector2.Transform(tr, eyeTransform);
|
||||
var dBl = Vector2.Transform(bl, eyeTransform);
|
||||
var dBr = dBl + dTr - dTl;
|
||||
|
||||
// Get which neighbors are occluding.
|
||||
|
||||
@@ -33,17 +33,17 @@ namespace Robust.Client.Graphics.Clyde
|
||||
DrawingHandleWorld = new DrawingHandleWorldImpl(white, this);
|
||||
}
|
||||
|
||||
public void SetModelTransform(in Matrix3 matrix)
|
||||
public void SetModelTransform(in Matrix3x2 matrix)
|
||||
{
|
||||
_clyde.DrawSetModelTransform(matrix);
|
||||
}
|
||||
|
||||
public Matrix3 GetModelTransform()
|
||||
public Matrix3x2 GetModelTransform()
|
||||
{
|
||||
return _clyde.DrawGetModelTransform();
|
||||
}
|
||||
|
||||
public void SetProjView(in Matrix3 proj, in Matrix3 view)
|
||||
public void SetProjView(in Matrix3x2 proj, in Matrix3x2 view)
|
||||
{
|
||||
_clyde.DrawSetProjViewTransform(proj, view);
|
||||
}
|
||||
@@ -177,9 +177,9 @@ namespace Robust.Client.Graphics.Clyde
|
||||
var oldModel = _clyde._currentMatrixModel;
|
||||
|
||||
var newModel = oldModel;
|
||||
position += new Vector2(oldModel.R0C2, oldModel.R1C2);
|
||||
newModel.R0C2 = 0;
|
||||
newModel.R1C2 = 0;
|
||||
position += new Vector2(oldModel.M31, oldModel.M32);
|
||||
newModel.M31 = 0;
|
||||
newModel.M32 = 0;
|
||||
SetModelTransform(newModel);
|
||||
|
||||
// Switch rendering to pseudo-world space.
|
||||
@@ -194,7 +194,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// Maaaaybe this is meant to have a minus sign.
|
||||
var rot = -(float) eyeRot.Theta;
|
||||
|
||||
var view = Matrix3.CreateTransform(ofsX, ofsY, rot, scale.X, scale.Y);
|
||||
var view = Matrix3Helpers.CreateTransform(ofsX, ofsY, rot, scale.X, scale.Y);
|
||||
SetProjView(proj, view);
|
||||
}
|
||||
|
||||
@@ -297,12 +297,12 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_renderHandle = renderHandle;
|
||||
}
|
||||
|
||||
public override void SetTransform(in Matrix3 matrix)
|
||||
public override void SetTransform(in Matrix3x2 matrix)
|
||||
{
|
||||
_renderHandle.SetModelTransform(matrix);
|
||||
}
|
||||
|
||||
public override Matrix3 GetTransform()
|
||||
public override Matrix3x2 GetTransform()
|
||||
{
|
||||
return _renderHandle.GetModelTransform();
|
||||
}
|
||||
@@ -402,12 +402,12 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_renderHandle = renderHandle;
|
||||
}
|
||||
|
||||
public override void SetTransform(in Matrix3 matrix)
|
||||
public override void SetTransform(in Matrix3x2 matrix)
|
||||
{
|
||||
_renderHandle.SetModelTransform(matrix);
|
||||
}
|
||||
|
||||
public override Matrix3 GetTransform()
|
||||
public override Matrix3x2 GetTransform()
|
||||
{
|
||||
return _renderHandle.GetModelTransform();
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// This matrix is applied to most normal geometry coming in.
|
||||
// Some is applied while the batch is being created (e.g. simple texture draw calls).
|
||||
// For DrawPrimitives OTOH the model matrix is passed along with the render command so is applied in the shader.
|
||||
private Matrix3 _currentMatrixModel = Matrix3.Identity;
|
||||
private Matrix3x2 _currentMatrixModel = Matrix3x2.Identity;
|
||||
|
||||
// Buffers and data for the batching system. Written into during (queue) and processed during (submit).
|
||||
private readonly Vertex2D[] BatchVertexData = new Vertex2D[MaxBatchQuads * 4];
|
||||
@@ -84,8 +84,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
// Current projection & view matrices that are being used ot render.
|
||||
// This gets updated to keep track during (queue) and (misc), but not during (submit).
|
||||
private Matrix3 _currentMatrixProj;
|
||||
private Matrix3 _currentMatrixView;
|
||||
private Matrix3x2 _currentMatrixProj;
|
||||
private Matrix3x2 _currentMatrixView;
|
||||
|
||||
// (queue) and (misc), current state of the scissor test. Null if disabled.
|
||||
private UIBox2i? _currentScissorState;
|
||||
@@ -110,25 +110,25 @@ namespace Robust.Client.Graphics.Clyde
|
||||
UniformConstantsUBO.Reallocate(constants);
|
||||
}
|
||||
|
||||
private void CalcScreenMatrices(in Vector2i screenSize, out Matrix3 proj, out Matrix3 view)
|
||||
private void CalcScreenMatrices(in Vector2i screenSize, out Matrix3x2 proj, out Matrix3x2 view)
|
||||
{
|
||||
proj = Matrix3.Identity;
|
||||
proj.R0C0 = 2f / screenSize.X;
|
||||
proj.R1C1 = -2f / screenSize.Y;
|
||||
proj.R0C2 = -1;
|
||||
proj.R1C2 = 1;
|
||||
proj = Matrix3x2.Identity;
|
||||
proj.M11 = 2f / screenSize.X;
|
||||
proj.M22 = -2f / screenSize.Y;
|
||||
proj.M31 = -1;
|
||||
proj.M32 = 1;
|
||||
|
||||
if (_currentRenderTarget.FlipY)
|
||||
{
|
||||
proj.R1C1 *= -1;
|
||||
proj.R1C2 *= -1;
|
||||
proj.M22 *= -1;
|
||||
proj.M32 *= -1;
|
||||
}
|
||||
|
||||
view = Matrix3.Identity;
|
||||
view = Matrix3x2.Identity;
|
||||
}
|
||||
|
||||
private void CalcWorldMatrices(in Vector2i screenSize, in Vector2 renderScale, IEye eye,
|
||||
out Matrix3 proj, out Matrix3 view)
|
||||
out Matrix3x2 proj, out Matrix3x2 view)
|
||||
{
|
||||
eye.GetViewMatrix(out view, renderScale);
|
||||
|
||||
@@ -136,20 +136,20 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void CalcWorldProjMatrix(in Vector2i screenSize, out Matrix3 proj)
|
||||
private void CalcWorldProjMatrix(in Vector2i screenSize, out Matrix3x2 proj)
|
||||
{
|
||||
proj = Matrix3.Identity;
|
||||
proj.R0C0 = EyeManager.PixelsPerMeter * 2f / screenSize.X;
|
||||
proj.R1C1 = EyeManager.PixelsPerMeter * 2f / screenSize.Y;
|
||||
proj = Matrix3x2.Identity;
|
||||
proj.M11 = EyeManager.PixelsPerMeter * 2f / screenSize.X;
|
||||
proj.M22 = EyeManager.PixelsPerMeter * 2f / screenSize.Y;
|
||||
|
||||
if (_currentRenderTarget.FlipY)
|
||||
{
|
||||
proj.R1C1 *= -1;
|
||||
proj.R1C2 *= -1;
|
||||
proj.M22 *= -1;
|
||||
proj.M32 *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetProjViewBuffer(in Matrix3 proj, in Matrix3 view)
|
||||
private void SetProjViewBuffer(in Matrix3x2 proj, in Matrix3x2 view)
|
||||
{
|
||||
// TODO: Fix perf here.
|
||||
// This immediately causes a glBufferData() call every time this is changed.
|
||||
@@ -160,7 +160,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
ProjViewUBO.Reallocate(combined);
|
||||
}
|
||||
|
||||
private void SetProjViewFull(in Matrix3 proj, in Matrix3 view)
|
||||
private void SetProjViewFull(in Matrix3x2 proj, in Matrix3x2 view)
|
||||
{
|
||||
_currentMatrixProj = proj;
|
||||
_currentMatrixView = view;
|
||||
@@ -285,21 +285,21 @@ namespace Robust.Client.Graphics.Clyde
|
||||
};
|
||||
}
|
||||
|
||||
private void _drawQuad(Vector2 a, Vector2 b, in Matrix3 modelMatrix, GLShaderProgram program)
|
||||
private void _drawQuad(Vector2 a, Vector2 b, in Matrix3x2 modelMatrix, GLShaderProgram program)
|
||||
{
|
||||
DrawQuadWithVao(QuadVAO, a, b, modelMatrix, program);
|
||||
}
|
||||
|
||||
private void DrawQuadWithVao(GLHandle vao, Vector2 a, Vector2 b, in Matrix3 modelMatrix,
|
||||
private void DrawQuadWithVao(GLHandle vao, Vector2 a, Vector2 b, in Matrix3x2 modelMatrix,
|
||||
GLShaderProgram program)
|
||||
{
|
||||
BindVertexArray(vao.Handle);
|
||||
CheckGlError();
|
||||
|
||||
var rectTransform = Matrix3.Identity;
|
||||
(rectTransform.R0C0, rectTransform.R1C1) = b - a;
|
||||
(rectTransform.R0C2, rectTransform.R1C2) = a;
|
||||
rectTransform.Multiply(modelMatrix);
|
||||
var rectTransform = Matrix3x2.Identity;
|
||||
(rectTransform.M11, rectTransform.M22) = b - a;
|
||||
(rectTransform.M31, rectTransform.M32) = a;
|
||||
rectTransform = rectTransform * modelMatrix;
|
||||
program.SetUniformMaybe(UniIModelMatrix, rectTransform);
|
||||
|
||||
_debugStats.LastGLDrawCalls += 1;
|
||||
@@ -315,7 +315,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
FlushBatchQueue();
|
||||
|
||||
// Reset renderer state.
|
||||
_currentMatrixModel = Matrix3.Identity;
|
||||
_currentMatrixModel = Matrix3x2.Identity;
|
||||
_queuedShaderInstance = _defaultShader;
|
||||
SetScissorFull(null);
|
||||
}
|
||||
@@ -496,7 +496,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
case bool b:
|
||||
program.SetUniform(name, b ? 1 : 0);
|
||||
break;
|
||||
case Matrix3 matrix3:
|
||||
case Matrix3x2 matrix3:
|
||||
program.SetUniform(name, matrix3);
|
||||
break;
|
||||
case Matrix4 matrix4:
|
||||
@@ -532,17 +532,17 @@ namespace Robust.Client.Graphics.Clyde
|
||||
return ref command;
|
||||
}
|
||||
|
||||
private void DrawSetModelTransform(in Matrix3 matrix)
|
||||
private void DrawSetModelTransform(in Matrix3x2 matrix)
|
||||
{
|
||||
_currentMatrixModel = matrix;
|
||||
}
|
||||
|
||||
private Matrix3 DrawGetModelTransform()
|
||||
private Matrix3x2 DrawGetModelTransform()
|
||||
{
|
||||
return _currentMatrixModel;
|
||||
}
|
||||
|
||||
private void DrawSetProjViewTransform(in Matrix3 proj, in Matrix3 view)
|
||||
private void DrawSetProjViewTransform(in Matrix3x2 proj, in Matrix3x2 view)
|
||||
{
|
||||
BreakBatch();
|
||||
|
||||
@@ -571,9 +571,9 @@ namespace Robust.Client.Graphics.Clyde
|
||||
EnsureBatchSpaceAvailable(4, GetQuadBatchIndexCount());
|
||||
EnsureBatchState(texture, true, GetQuadBatchPrimitiveType(), _queuedShader);
|
||||
|
||||
bl = _currentMatrixModel.Transform(bl);
|
||||
br = _currentMatrixModel.Transform(br);
|
||||
tr = _currentMatrixModel.Transform(tr);
|
||||
bl = Vector2.Transform(bl, _currentMatrixModel);
|
||||
br = Vector2.Transform(br, _currentMatrixModel);
|
||||
tr = Vector2.Transform(tr, _currentMatrixModel);
|
||||
tl = tr + bl - br;
|
||||
|
||||
// TODO: split batch if necessary.
|
||||
@@ -676,8 +676,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
EnsureBatchSpaceAvailable(2, 0);
|
||||
EnsureBatchState(_stockTextureWhite.TextureId, false, BatchPrimitiveType.LineList, _queuedShader);
|
||||
|
||||
a = _currentMatrixModel.Transform(a);
|
||||
b = _currentMatrixModel.Transform(b);
|
||||
a = Vector2.Transform(a, _currentMatrixModel);
|
||||
b = Vector2.Transform(b, _currentMatrixModel);
|
||||
|
||||
// TODO: split batch if necessary.
|
||||
var vIdx = BatchVertexIndex;
|
||||
@@ -807,7 +807,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
command.DrawBatch.ShaderInstance = metaData.ShaderInstance;
|
||||
|
||||
command.DrawBatch.Count = currentIndex - metaData.StartIndex;
|
||||
command.DrawBatch.ModelMatrix = Matrix3.Identity;
|
||||
command.DrawBatch.ModelMatrix = Matrix3x2.Identity;
|
||||
|
||||
_debugStats.LastBatches += 1;
|
||||
}
|
||||
@@ -882,7 +882,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_queuedRenderCommands.Clear();
|
||||
_currentViewport = null;
|
||||
_lightingReady = false;
|
||||
_currentMatrixModel = Matrix3.Identity;
|
||||
_currentMatrixModel = Matrix3x2.Identity;
|
||||
SetScissorFull(null);
|
||||
BindRenderTargetFull(_mainWindow!.RenderTarget);
|
||||
_batchMetaData = null;
|
||||
@@ -961,13 +961,13 @@ namespace Robust.Client.Graphics.Clyde
|
||||
public BatchPrimitiveType PrimitiveType;
|
||||
|
||||
// TODO: this makes the render commands so much more large please remove.
|
||||
public Matrix3 ModelMatrix;
|
||||
public Matrix3x2 ModelMatrix;
|
||||
}
|
||||
|
||||
private struct RenderCommandProjViewMatrix
|
||||
{
|
||||
public Matrix3 ProjMatrix;
|
||||
public Matrix3 ViewMatrix;
|
||||
public Matrix3x2 ProjMatrix;
|
||||
public Matrix3x2 ViewMatrix;
|
||||
}
|
||||
|
||||
private struct RenderCommandScissor
|
||||
@@ -1056,11 +1056,11 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
private readonly struct FullStoredRendererState
|
||||
{
|
||||
public readonly Matrix3 ProjMatrix;
|
||||
public readonly Matrix3 ViewMatrix;
|
||||
public readonly Matrix3x2 ProjMatrix;
|
||||
public readonly Matrix3x2 ViewMatrix;
|
||||
public readonly LoadedRenderTarget RenderTarget;
|
||||
|
||||
public FullStoredRendererState(in Matrix3 projMatrix, in Matrix3 viewMatrix,
|
||||
public FullStoredRendererState(in Matrix3x2 projMatrix, in Matrix3x2 viewMatrix,
|
||||
LoadedRenderTarget renderTarget)
|
||||
{
|
||||
ProjMatrix = projMatrix;
|
||||
|
||||
@@ -506,7 +506,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
data.Parameters[name] = value;
|
||||
}
|
||||
|
||||
private protected override void SetParameterImpl(string name, in Matrix3 value)
|
||||
private protected override void SetParameterImpl(string name, in Matrix3x2 value)
|
||||
{
|
||||
var data = Parent._shaderInstances[Handle];
|
||||
data.ParametersDirty = true;
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
// view matrix
|
||||
vp.Eye.GetViewMatrixInv(out var viewMatrixInv, vp.RenderScale);
|
||||
point = viewMatrixInv * point;
|
||||
point = Vector2.Transform(point, viewMatrixInv);
|
||||
|
||||
return point;
|
||||
}
|
||||
@@ -136,7 +136,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
// view matrix
|
||||
Eye.GetViewMatrixInv(out var viewMatrixInv, RenderScale);
|
||||
newPoint = viewMatrixInv * newPoint;
|
||||
newPoint = Vector2.Transform(newPoint, viewMatrixInv);
|
||||
|
||||
return new MapCoordinates(newPoint, Eye.Position.MapId);
|
||||
}
|
||||
@@ -150,7 +150,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
var newPoint = point;
|
||||
|
||||
eye.GetViewMatrix(out var viewMatrix, RenderScale);
|
||||
newPoint = viewMatrix * newPoint;
|
||||
newPoint = Vector2.Transform(newPoint, viewMatrix);
|
||||
|
||||
// (inlined version of UiProjMatrix)
|
||||
newPoint *= new Vector2(1, -1) * EyeManager.PixelsPerMeter;
|
||||
@@ -159,14 +159,14 @@ namespace Robust.Client.Graphics.Clyde
|
||||
return newPoint;
|
||||
}
|
||||
|
||||
public Matrix3 GetWorldToLocalMatrix()
|
||||
public Matrix3x2 GetWorldToLocalMatrix()
|
||||
{
|
||||
if (Eye == null)
|
||||
return Matrix3.Identity;
|
||||
return Matrix3x2.Identity;
|
||||
|
||||
Eye.GetViewMatrix(out var viewMatrix, RenderScale * new Vector2(EyeManager.PixelsPerMeter, -EyeManager.PixelsPerMeter));
|
||||
viewMatrix.R0C2 += Size.X / 2f;
|
||||
viewMatrix.R1C2 += Size.Y / 2f;
|
||||
viewMatrix.M31 += Size.X / 2f;
|
||||
viewMatrix.M32 += Size.Y / 2f;
|
||||
return viewMatrix;
|
||||
}
|
||||
|
||||
|
||||
@@ -361,7 +361,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
}
|
||||
|
||||
private protected override void SetParameterImpl(string name, in Matrix3 value)
|
||||
private protected override void SetParameterImpl(string name, in Matrix3x2 value)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -482,7 +482,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
return default;
|
||||
}
|
||||
|
||||
public Matrix3 GetWorldToLocalMatrix() => default;
|
||||
public Matrix3x2 GetWorldToLocalMatrix() => default;
|
||||
|
||||
public Vector2 WorldToLocal(Vector2 point)
|
||||
{
|
||||
|
||||
@@ -247,28 +247,33 @@ namespace Robust.Client.Graphics.Clyde
|
||||
GL.Uniform1(uniformId, singles.Length, singles);
|
||||
}
|
||||
|
||||
public void SetUniform(string uniformName, in Matrix3 matrix)
|
||||
public void SetUniform(string uniformName, in Matrix3x2 matrix)
|
||||
{
|
||||
var uniformId = GetUniform(uniformName);
|
||||
SetUniformDirect(uniformId, matrix);
|
||||
}
|
||||
|
||||
public void SetUniform(int uniformName, in Matrix3 matrix)
|
||||
public void SetUniform(int uniformName, in Matrix3x2 matrix)
|
||||
{
|
||||
var uniformId = GetUniform(uniformName);
|
||||
SetUniformDirect(uniformId, matrix);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private unsafe void SetUniformDirect(int slot, in Matrix3 value, bool transpose=true)
|
||||
private unsafe void SetUniformDirect(int slot, in Matrix3x2 value)
|
||||
{
|
||||
Matrix3 tmpTranspose = value;
|
||||
if (transpose)
|
||||
{
|
||||
// transposition not supported on GLES2, & no access to _hasGLES
|
||||
tmpTranspose.Transpose();
|
||||
}
|
||||
GL.UniformMatrix3(slot, 1, false, (float*) &tmpTranspose);
|
||||
// We put the rows of the input matrix into the columns of our GPU matrices
|
||||
// this transpose is required, as in C#, we premultiply vectors with matrices
|
||||
// (vM) while GL postmultiplies vectors with matrices (Mv); however, since
|
||||
// the Matrix3x2 data is stored row-major, and GL uses column-major, the
|
||||
// memory layout is the same (or would be, if Matrix3x2 didn't have an
|
||||
// implicit column)
|
||||
var buf = stackalloc float[9]{
|
||||
value.M11, value.M12, 0,
|
||||
value.M21, value.M22, 0,
|
||||
value.M31, value.M32, 1
|
||||
};
|
||||
GL.UniformMatrix3(slot, 1, false, (float*)buf);
|
||||
_clyde.CheckGlError();
|
||||
}
|
||||
|
||||
@@ -474,7 +479,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUniformMaybe(string uniformName, in Matrix3 value)
|
||||
public void SetUniformMaybe(string uniformName, in Matrix3x2 value)
|
||||
{
|
||||
if (TryGetUniform(uniformName, out var slot))
|
||||
{
|
||||
@@ -490,7 +495,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUniformMaybe(int uniformName, in Matrix3 value)
|
||||
public void SetUniformMaybe(int uniformName, in Matrix3x2 value)
|
||||
{
|
||||
if (TryGetUniform(uniformName, out var slot))
|
||||
{
|
||||
|
||||
@@ -44,19 +44,19 @@ namespace Robust.Client.Graphics
|
||||
{
|
||||
CheckDisposed();
|
||||
|
||||
var matrix = Matrix3.CreateTransform(in position, in rotation, in scale);
|
||||
var matrix = Matrix3Helpers.CreateTransform(in position, in rotation, in scale);
|
||||
SetTransform(in matrix);
|
||||
}
|
||||
|
||||
public void SetTransform(in Vector2 position, in Angle rotation)
|
||||
{
|
||||
var matrix = Matrix3.CreateTransform(in position, in rotation);
|
||||
var matrix = Matrix3Helpers.CreateTransform(in position, in rotation);
|
||||
SetTransform(in matrix);
|
||||
}
|
||||
|
||||
public abstract void SetTransform(in Matrix3 matrix);
|
||||
public abstract void SetTransform(in Matrix3x2 matrix);
|
||||
|
||||
public abstract Matrix3 GetTransform();
|
||||
public abstract Matrix3x2 GetTransform();
|
||||
|
||||
public abstract void UseShader(ShaderInstance? shader);
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Robust.Client.Graphics
|
||||
/// <summary>
|
||||
/// Matrix equivalent of <see cref="LocalToWorld(Vector2)"/>.
|
||||
/// </summary>
|
||||
Matrix3 GetWorldToLocalMatrix();
|
||||
Matrix3x2 GetWorldToLocalMatrix();
|
||||
|
||||
/// <summary>
|
||||
/// Converts a point in world-space to the viewport's screen coordinates.
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace Robust.Client.Graphics
|
||||
SetParameterImpl(name, value);
|
||||
}
|
||||
|
||||
public void SetParameter(string name, in Matrix3 value)
|
||||
public void SetParameter(string name, in Matrix3x2 value)
|
||||
{
|
||||
EnsureAlive();
|
||||
EnsureMutable();
|
||||
@@ -219,7 +219,7 @@ namespace Robust.Client.Graphics
|
||||
private protected abstract void SetParameterImpl(string name, int value);
|
||||
private protected abstract void SetParameterImpl(string name, Vector2i value);
|
||||
private protected abstract void SetParameterImpl(string name, bool value);
|
||||
private protected abstract void SetParameterImpl(string name, in Matrix3 value);
|
||||
private protected abstract void SetParameterImpl(string name, in Matrix3x2 value);
|
||||
private protected abstract void SetParameterImpl(string name, in Matrix4 value);
|
||||
private protected abstract void SetParameterImpl(string name, Texture value);
|
||||
private protected abstract void SetStencilImpl(StencilParameters value);
|
||||
|
||||
@@ -176,7 +176,7 @@ namespace Robust.Client.Graphics
|
||||
return node.AsVector4();
|
||||
}
|
||||
case ShaderDataType.Mat3:
|
||||
return node.AsMatrix3();
|
||||
return node.AsMatrix3x2();
|
||||
case ShaderDataType.Mat4:
|
||||
return node.AsMatrix4();
|
||||
default:
|
||||
@@ -219,7 +219,7 @@ namespace Robust.Client.Graphics
|
||||
case bool i:
|
||||
instance.SetParameter(key, i);
|
||||
break;
|
||||
case Matrix3 i:
|
||||
case Matrix3x2 i:
|
||||
instance.SetParameter(key, i);
|
||||
break;
|
||||
case Matrix4 i:
|
||||
|
||||
@@ -120,6 +120,6 @@ public sealed class TileEdgeOverlay : GridOverlay
|
||||
}
|
||||
}
|
||||
|
||||
args.WorldHandle.SetTransform(Matrix3.Identity);
|
||||
args.WorldHandle.SetTransform(Matrix3x2.Identity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace Robust.Client.Physics
|
||||
return true;
|
||||
}, true);
|
||||
|
||||
worldHandle.SetTransform(Matrix3.Identity);
|
||||
worldHandle.SetTransform(Matrix3x2.Identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Dynamics;
|
||||
|
||||
@@ -261,8 +261,8 @@ namespace Robust.Client.Player
|
||||
{
|
||||
// This is a new userid, so we create a new session.
|
||||
DebugTools.Assert(state.UserId != LocalPlayer?.UserId);
|
||||
var newSession = (CommonSession) CreateAndAddSession(state.UserId, state.Name);
|
||||
newSession.Ping = state.Ping;
|
||||
var newSession = (ICommonSessionInternal)CreateAndAddSession(state.UserId, state.Name);
|
||||
newSession.SetPing(state.Ping);
|
||||
SetStatus(newSession, state.Status);
|
||||
SetAttachedEntity(newSession, controlled, out _, true);
|
||||
dirty = true;
|
||||
@@ -279,9 +279,9 @@ namespace Robust.Client.Player
|
||||
}
|
||||
|
||||
dirty = true;
|
||||
var local = (CommonSession) session;
|
||||
local.Name = state.Name;
|
||||
local.Ping = state.Ping;
|
||||
var local = (ICommonSessionInternal)session;
|
||||
local.SetName(state.Name);
|
||||
local.SetPing(state.Ping);
|
||||
SetStatus(local, state.Status);
|
||||
SetAttachedEntity(local, controlled, out _, true);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,31 @@ namespace Robust.Client.Replays.Loading;
|
||||
// so that when jumping to tick 1001 the client only has to apply states for tick 1000 and 1001, instead of 0, 1, 2, ...
|
||||
public sealed partial class ReplayLoadManager
|
||||
{
|
||||
// Scratch data used by UpdateEntityStates.
|
||||
// Avoids copying changes for every change to an entity between checkpoints, instead copies once per checkpoint on
|
||||
// first change. We can also use this to avoid building a dictionary of ComponentChange inside the inner loop.
|
||||
private class UpdateScratchData
|
||||
{
|
||||
public Dictionary<ushort, ComponentChange> Changes;
|
||||
public EntityState lastChange;
|
||||
public HashSet<ushort>? netComps;
|
||||
|
||||
public UpdateScratchData(EntityState oldEntState)
|
||||
{
|
||||
Changes = oldEntState.ComponentChanges.Value.ToDictionary(x => x.NetID);
|
||||
lastChange = oldEntState;
|
||||
netComps = oldEntState.NetComponents;
|
||||
}
|
||||
|
||||
public EntityState BakeChanges()
|
||||
{
|
||||
return new EntityState(lastChange.NetEntity,
|
||||
Changes.Values.ToList(),
|
||||
lastChange.EntityLastModified,
|
||||
netComps);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(CheckpointState[], TimeSpan[])> GenerateCheckpointsAsync(
|
||||
ReplayMessage? initMessages,
|
||||
HashSet<string> initialCvars,
|
||||
@@ -138,6 +163,7 @@ public sealed partial class ReplayLoadManager
|
||||
var stats_due_spawned = 0;
|
||||
var stats_due_state = 0;
|
||||
|
||||
var modifiedEntities = new Dictionary<NetEntity, UpdateScratchData>();
|
||||
for (var i = 1; i < states.Count; i++)
|
||||
{
|
||||
if (i % 10 == 0)
|
||||
@@ -148,10 +174,10 @@ public sealed partial class ReplayLoadManager
|
||||
DebugTools.Assert(curState.FromSequence <= lastState.ToSequence);
|
||||
|
||||
UpdatePlayerStates(curState.PlayerStates.Span, playerStates);
|
||||
UpdateEntityStates(curState.EntityStates.Span, entStates, ref spawnedTracker, ref stateTracker, detached);
|
||||
UpdateEntityStates(curState.EntityStates.Span, entStates, modifiedEntities, ref spawnedTracker, ref stateTracker, detached);
|
||||
UpdateMessages(messages[i], uploadedFiles, prototypes, cvars, detachQueue, ref timeBase);
|
||||
ProcessQueue(curState.ToSequence, detachQueue, detached, entStates);
|
||||
UpdateDeletions(curState.EntityDeletions, entStates, detached);
|
||||
UpdateDeletions(curState.EntityDeletions, entStates, detached, modifiedEntities);
|
||||
serverTime[i] = GetTime(curState.ToSequence) - initialTime;
|
||||
ticksSinceLastCheckpoint++;
|
||||
|
||||
@@ -182,6 +208,8 @@ public sealed partial class ReplayLoadManager
|
||||
ticksSinceLastCheckpoint = 0;
|
||||
spawnedTracker = 0;
|
||||
stateTracker = 0;
|
||||
ApplyModifiedEntities(entStates, modifiedEntities);
|
||||
|
||||
var newState = new GameState(GameTick.Zero,
|
||||
curState.ToSequence,
|
||||
default,
|
||||
@@ -339,16 +367,18 @@ public sealed partial class ReplayLoadManager
|
||||
}
|
||||
|
||||
private void UpdateDeletions(NetListAsArray<NetEntity> entityDeletions,
|
||||
Dictionary<NetEntity, EntityState> entStates, HashSet<NetEntity> detached)
|
||||
Dictionary<NetEntity, EntityState> entStates, HashSet<NetEntity> detached, Dictionary<NetEntity, UpdateScratchData> modifiedEntities)
|
||||
{
|
||||
foreach (var ent in entityDeletions.Span)
|
||||
{
|
||||
entStates.Remove(ent);
|
||||
detached.Remove(ent);
|
||||
modifiedEntities.Remove(ent);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateEntityStates(ReadOnlySpan<EntityState> span, Dictionary<NetEntity, EntityState> entStates,
|
||||
Dictionary<NetEntity, UpdateScratchData> modified,
|
||||
ref int spawnedTracker, ref int stateTracker, HashSet<NetEntity> detached)
|
||||
{
|
||||
foreach (var entState in span)
|
||||
@@ -369,9 +399,22 @@ public sealed partial class ReplayLoadManager
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get scratch versions (with write access) for entities modified since last checkpoint
|
||||
UpdateScratchData? scratch;
|
||||
if (!modified.TryGetValue(entState.NetEntity, out scratch))
|
||||
{
|
||||
scratch = new UpdateScratchData(oldEntState);
|
||||
modified[entState.NetEntity] = scratch;
|
||||
}
|
||||
|
||||
stateTracker++;
|
||||
DebugTools.Assert(oldEntState.NetEntity == entState.NetEntity);
|
||||
entStates[entState.NetEntity] = MergeStates(entState, oldEntState.ComponentChanges.Value, oldEntState.NetComponents);
|
||||
// Note this does not change entStates, that change occurs later in ApplyModifiedEntities (to avoid early copies)
|
||||
UpdateScratch(entState, scratch.Changes);
|
||||
if (entState.NetComponents != null)
|
||||
scratch.netComps = entState.NetComponents;
|
||||
scratch.lastChange = entState;
|
||||
|
||||
|
||||
#if DEBUG
|
||||
foreach (var state in entStates[entState.NetEntity].ComponentChanges.Span)
|
||||
@@ -382,6 +425,53 @@ public sealed partial class ReplayLoadManager
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyModifiedEntities(Dictionary<NetEntity, EntityState> entStates, Dictionary<NetEntity, UpdateScratchData> modifiedEntities)
|
||||
{
|
||||
foreach (var modified in modifiedEntities)
|
||||
{
|
||||
entStates[modified.Key] = modified.Value.BakeChanges();
|
||||
}
|
||||
|
||||
modifiedEntities.Clear();
|
||||
}
|
||||
|
||||
private void UpdateScratch(
|
||||
EntityState newState,
|
||||
Dictionary<ushort, ComponentChange> oldState)
|
||||
{
|
||||
// remove any deleted components
|
||||
if (newState.NetComponents != null)
|
||||
{
|
||||
foreach (var change in oldState.Values)
|
||||
{
|
||||
if (!newState.NetComponents.Contains(change.NetID))
|
||||
oldState.Remove(change.NetID);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var newCompState in newState.ComponentChanges.Value)
|
||||
{
|
||||
if (!oldState.TryGetValue(newCompState.NetID, out var existing))
|
||||
{
|
||||
// This is a new component
|
||||
// I'm not 100% sure about this, but I think delta states should always be full states here?
|
||||
DebugTools.Assert(newCompState.State is not IComponentDeltaState newDelta);
|
||||
oldState[newCompState.NetID] = newCompState;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Modify or replace existing component
|
||||
if (newCompState.State is not IComponentDeltaState delta)
|
||||
{
|
||||
oldState[newCompState.NetID] = newCompState;
|
||||
continue;
|
||||
}
|
||||
|
||||
DebugTools.Assert(existing.State != null && existing.State is not IComponentDeltaState);
|
||||
oldState[newCompState.NetID] = new ComponentChange(existing.NetID, delta.CreateNewFullState(existing.State!), newCompState.LastModifiedTick);
|
||||
}
|
||||
}
|
||||
|
||||
private EntityState MergeStates(
|
||||
EntityState newState,
|
||||
IReadOnlyCollection<ComponentChange> oldState,
|
||||
@@ -420,7 +510,7 @@ public sealed partial class ReplayLoadManager
|
||||
foreach (var compChange in newCompStates.Values)
|
||||
{
|
||||
// I'm not 100% sure about this, but I think delta states should always be full states here?
|
||||
DebugTools.Assert(compChange.State is not IComponentDeltaState delta);
|
||||
DebugTools.Assert(compChange.State is not IComponentDeltaState);
|
||||
combined.Add(compChange);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ internal sealed partial class ReplayPlaybackManager
|
||||
/// </summary>
|
||||
/// <param name="index">The target tick/index. The actual checkpoint will have an index less than or equal to this.</param>
|
||||
/// <param name="flushEntities">Whether to delete all entities</param>
|
||||
public void ResetToNearestCheckpoint(int index, bool flushEntities)
|
||||
public void ResetToNearestCheckpoint(int index, bool flushEntities, CheckpointState? checkpoint = null)
|
||||
{
|
||||
if (Replay == null)
|
||||
throw new Exception("Not currently playing a replay");
|
||||
@@ -25,7 +25,8 @@ internal sealed partial class ReplayPlaybackManager
|
||||
if (flushEntities)
|
||||
_entMan.FlushEntities();
|
||||
|
||||
var checkpoint = GetLastCheckpoint(Replay, index);
|
||||
// Look up the desired checkpoint, unless our caller kindly provided one to us.
|
||||
checkpoint ??= GetLastCheckpoint(Replay, index);
|
||||
|
||||
_sawmill.Info($"Resetting to checkpoint. From {Replay.CurrentIndex} to {checkpoint.Index}");
|
||||
var st = new Stopwatch();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.GameStates;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.Replays.Playback;
|
||||
@@ -27,14 +28,19 @@ internal sealed partial class ReplayPlaybackManager
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Playing &= !pausePlayback;
|
||||
value = Math.Clamp(value, 0, Replay.States.Count - 1);
|
||||
if (value == Replay.CurrentIndex)
|
||||
{
|
||||
ScrubbingTarget = null;
|
||||
return;
|
||||
}
|
||||
|
||||
BeforeSetTick?.Invoke();
|
||||
|
||||
// Begin timing replay processing so we can abort when we run out of time (_replayMaxScrubTime)
|
||||
var st = RStopwatch.StartNew();
|
||||
|
||||
bool skipEffectEvents = value > Replay.CurrentIndex + _visualEventThreshold;
|
||||
if (value < Replay.CurrentIndex)
|
||||
{
|
||||
@@ -45,9 +51,12 @@ internal sealed partial class ReplayPlaybackManager
|
||||
{
|
||||
// If we are skipping many ticks into the future, we try to skip directly to a checkpoint instead of
|
||||
// applying every tick.
|
||||
var nextCheckpoint = GetNextCheckpoint(Replay, Replay.CurrentIndex);
|
||||
if (nextCheckpoint.Index < value && nextCheckpoint.Index > Replay.CurrentIndex)
|
||||
ResetToNearestCheckpoint(value, false);
|
||||
|
||||
var nextCheckpoint = GetLastCheckpoint(Replay, value);
|
||||
// Sanity-Check that the checkpoint is actually BEFORE the desired position.
|
||||
// Also check that it gets us closer to goal position than we already are.
|
||||
if (nextCheckpoint.Index <= value && nextCheckpoint.Index > Replay.CurrentIndex)
|
||||
ResetToNearestCheckpoint(value, false, nextCheckpoint);
|
||||
}
|
||||
|
||||
_entMan.EntitySysManager.GetEntitySystem<ClientDirtySystem>().Reset();
|
||||
@@ -75,6 +84,23 @@ internal sealed partial class ReplayPlaybackManager
|
||||
DebugTools.Assert(Replay.LastApplied >= state.FromSequence);
|
||||
DebugTools.Assert(Replay.LastApplied + 1 <= state.ToSequence);
|
||||
Replay.LastApplied = state.ToSequence;
|
||||
|
||||
if (st.Elapsed.TotalMilliseconds > _replayMaxScrubTime)
|
||||
{
|
||||
// Out of time to advance replay this tick
|
||||
// Note: We check at end of loop so we always advance at least 1 tick.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Use ScrubbingTarget to force a later invocation to continue moving towards the target tick
|
||||
if (Replay.CurrentIndex < value)
|
||||
{
|
||||
ScrubbingTarget = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScrubbingTarget = null;
|
||||
}
|
||||
|
||||
AfterSetTick?.Invoke();
|
||||
|
||||
@@ -52,6 +52,7 @@ internal sealed partial class ReplayPlaybackManager : IReplayPlaybackManager
|
||||
public ReplayData? Replay { get; private set; }
|
||||
public NetUserId? Recorder => Replay?.Recorder;
|
||||
private int _checkpointMinInterval;
|
||||
private int _replayMaxScrubTime;
|
||||
private int _visualEventThreshold;
|
||||
public uint? AutoPauseCountdown { get; set; }
|
||||
public int? ScrubbingTarget { get; set; }
|
||||
@@ -94,6 +95,7 @@ internal sealed partial class ReplayPlaybackManager : IReplayPlaybackManager
|
||||
_sawmill = _logMan.GetSawmill("replay");
|
||||
_metaId = _factory.GetRegistration(typeof(MetaDataComponent)).NetID!.Value;
|
||||
_confMan.OnValueChanged(CVars.CheckpointMinInterval, (value) => _checkpointMinInterval = value, true);
|
||||
_confMan.OnValueChanged(CVars.ReplayMaxScrubTime, (value) => _replayMaxScrubTime = value, true);
|
||||
_confMan.OnValueChanged(CVars.ReplaySkipThreshold, (value) => _visualEventThreshold = value, true);
|
||||
_client.RunLevelChanged += OnRunLevelChanged;
|
||||
}
|
||||
|
||||
@@ -567,7 +567,7 @@ namespace Robust.Client.UserInterface
|
||||
public Vector2i Position;
|
||||
public Color Modulate;
|
||||
public UIBox2i? ScissorBox;
|
||||
public ref Matrix3 CoordinateTransform;
|
||||
public ref Matrix3x2 CoordinateTransform;
|
||||
}
|
||||
|
||||
protected void RenderControl(ref ControlRenderArguments args, int childIndex, Vector2i position)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Numerics;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -20,19 +21,19 @@ public sealed class ColorSelectorStyleBox : StyleBoxTexture
|
||||
/// <summary>
|
||||
/// Base background colour.
|
||||
/// </summary>
|
||||
public Vector4 BaseColor;
|
||||
public Robust.Shared.Maths.Vector4 BaseColor;
|
||||
|
||||
/// <summary>
|
||||
/// Colour to add to the background colour along the X-axis.
|
||||
/// I.e., from left to right the background colour will vary from (BaseColour) to (BaseColour + XAxis)
|
||||
/// </summary>
|
||||
public Vector4 XAxis;
|
||||
public Robust.Shared.Maths.Vector4 XAxis;
|
||||
|
||||
/// <summary>
|
||||
/// Colour to add to the background colour along the y-axis.
|
||||
/// I.e., from left to right the background colour will vary from (BaseColour) to (BaseColour + XAxis)
|
||||
/// </summary>
|
||||
public Vector4 YAxis;
|
||||
public Robust.Shared.Maths.Vector4 YAxis;
|
||||
|
||||
/// <summary>
|
||||
/// If true, then <see cref="BaseColor"/>, <see cref="XAxis"/>, and <see cref="YAxis"/> will be interpreted as HSVa
|
||||
@@ -53,7 +54,7 @@ public sealed class ColorSelectorStyleBox : StyleBoxTexture
|
||||
var old = handle.GetShader();
|
||||
handle.UseShader(_shader);
|
||||
|
||||
var globalPixelPos = handle.GetTransform().Transform(default);
|
||||
var globalPixelPos = Vector2.Transform(default, handle.GetTransform());
|
||||
_shader.SetParameter("size", box.Size);
|
||||
_shader.SetParameter("offset", globalPixelPos);
|
||||
_shader.SetParameter("xAxis", XAxis);
|
||||
@@ -92,14 +93,14 @@ public sealed class ColorSelectorStyleBox : StyleBoxTexture
|
||||
{
|
||||
var colorData = Hsv
|
||||
? Color.ToHsv(color)
|
||||
: new Vector4(color.R, color.G, color.B, color.A);
|
||||
: new Robust.Shared.Maths.Vector4(color.R, color.G, color.B, color.A);
|
||||
SetBaseColor(colorData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that sets the base color by taking in some color and removing the components that are controlled by the x and y axes.
|
||||
/// </summary>
|
||||
public void SetBaseColor(Vector4 colorData)
|
||||
public void SetBaseColor(Robust.Shared.Maths.Vector4 colorData)
|
||||
{
|
||||
BaseColor = colorData - colorData * XAxis - colorData * YAxis;
|
||||
}
|
||||
|
||||
64
Robust.Client/UserInterface/Controls/EntityPrototypeView.cs
Normal file
64
Robust.Client/UserInterface/Controls/EntityPrototypeView.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Robust.Client.UserInterface.Controls;
|
||||
|
||||
[Virtual]
|
||||
public class EntityPrototypeView : SpriteView
|
||||
{
|
||||
private string? _currentPrototype;
|
||||
private EntityUid? _ourEntity;
|
||||
|
||||
public EntityPrototypeView()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public EntityPrototypeView(EntProtoId? entProto, IEntityManager entMan) : base(entMan)
|
||||
{
|
||||
SetPrototype(entProto);
|
||||
}
|
||||
|
||||
public void SetPrototype(EntProtoId? entProto)
|
||||
{
|
||||
SpriteSystem ??= EntMan.System<SpriteSystem>();
|
||||
|
||||
if (entProto == _currentPrototype
|
||||
&& EntMan.TryGetComponent(Entity?.Owner, out MetaDataComponent? meta)
|
||||
&& meta.EntityPrototype?.ID == _currentPrototype)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_currentPrototype = entProto;
|
||||
SetEntity(null);
|
||||
if (_ourEntity != null)
|
||||
{
|
||||
EntMan.DeleteEntity(_ourEntity);
|
||||
}
|
||||
|
||||
if (_currentPrototype != null)
|
||||
{
|
||||
_ourEntity = EntMan.Spawn(_currentPrototype);
|
||||
SpriteSystem.ForceUpdate(_ourEntity.Value);
|
||||
SetEntity(_ourEntity);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void EnteredTree()
|
||||
{
|
||||
base.EnteredTree();
|
||||
|
||||
if (_currentPrototype != null)
|
||||
SetPrototype(_currentPrototype);
|
||||
}
|
||||
|
||||
protected override void ExitedTree()
|
||||
{
|
||||
base.ExitedTree();
|
||||
|
||||
if (!EntMan.Deleted(_ourEntity))
|
||||
EntMan.QueueDeleteEntity(_ourEntity);
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,9 @@ namespace Robust.Client.UserInterface.Controls
|
||||
[Virtual]
|
||||
public class SpriteView : Control
|
||||
{
|
||||
private SpriteSystem? _sprite;
|
||||
protected SpriteSystem? SpriteSystem;
|
||||
private SharedTransformSystem? _transform;
|
||||
private readonly IEntityManager _entMan;
|
||||
protected readonly IEntityManager EntMan;
|
||||
|
||||
[ViewVariables]
|
||||
public SpriteComponent? Sprite => Entity?.Comp1;
|
||||
@@ -120,20 +120,26 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
public SpriteView()
|
||||
{
|
||||
IoCManager.Resolve(ref _entMan);
|
||||
IoCManager.Resolve(ref EntMan);
|
||||
RectClipContent = true;
|
||||
}
|
||||
|
||||
public SpriteView(IEntityManager entMan)
|
||||
{
|
||||
EntMan = entMan;
|
||||
RectClipContent = true;
|
||||
}
|
||||
|
||||
public SpriteView(EntityUid? uid, IEntityManager entMan)
|
||||
{
|
||||
_entMan = entMan;
|
||||
EntMan = entMan;
|
||||
RectClipContent = true;
|
||||
SetEntity(uid);
|
||||
}
|
||||
|
||||
public SpriteView(NetEntity uid, IEntityManager entMan)
|
||||
{
|
||||
_entMan = entMan;
|
||||
EntMan = entMan;
|
||||
RectClipContent = true;
|
||||
SetEntity(uid);
|
||||
}
|
||||
@@ -154,8 +160,8 @@ namespace Robust.Client.UserInterface.Controls
|
||||
if (Entity?.Owner == uid)
|
||||
return;
|
||||
|
||||
if (!_entMan.TryGetComponent(uid, out SpriteComponent? sprite)
|
||||
|| !_entMan.TryGetComponent(uid, out TransformComponent? xform))
|
||||
if (!EntMan.TryGetComponent(uid, out SpriteComponent? sprite)
|
||||
|| !EntMan.TryGetComponent(uid, out TransformComponent? xform))
|
||||
{
|
||||
Entity = null;
|
||||
NetEnt = null;
|
||||
@@ -163,7 +169,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
|
||||
Entity = new(uid.Value, sprite, xform);
|
||||
NetEnt = _entMan.GetNetEntity(uid);
|
||||
NetEnt = EntMan.GetNetEntity(uid);
|
||||
}
|
||||
|
||||
protected override Vector2 MeasureOverride(Vector2 availableSize)
|
||||
@@ -223,11 +229,11 @@ namespace Robust.Client.UserInterface.Controls
|
||||
if (!ResolveEntity(out var uid, out var sprite, out var xform))
|
||||
return;
|
||||
|
||||
_sprite ??= _entMan.System<SpriteSystem>();
|
||||
_transform ??= _entMan.System<TransformSystem>();
|
||||
SpriteSystem ??= EntMan.System<SpriteSystem>();
|
||||
_transform ??= EntMan.System<TransformSystem>();
|
||||
|
||||
// Ensure the sprite is animated despite possible not being visible in any viewport.
|
||||
_sprite.ForceUpdate(uid);
|
||||
SpriteSystem.ForceUpdate(uid);
|
||||
|
||||
var stretchVec = Stretch switch
|
||||
{
|
||||
@@ -258,13 +264,13 @@ namespace Robust.Client.UserInterface.Controls
|
||||
[NotNullWhen(true)] out SpriteComponent? sprite,
|
||||
[NotNullWhen(true)] out TransformComponent? xform)
|
||||
{
|
||||
if (NetEnt != null && Entity == null && _entMan.TryGetEntity(NetEnt, out var ent))
|
||||
if (NetEnt != null && Entity == null && EntMan.TryGetEntity(NetEnt, out var ent))
|
||||
SetEntity(ent);
|
||||
|
||||
if (Entity != null)
|
||||
{
|
||||
(uid, sprite, xform) = Entity.Value;
|
||||
return !_entMan.Deleted(uid);
|
||||
return !EntMan.Deleted(uid);
|
||||
}
|
||||
|
||||
sprite = null;
|
||||
|
||||
@@ -43,11 +43,11 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
/// <remarks>
|
||||
/// This is generally just be a combination of <see cref="IClydeViewport.GetWorldToLocalMatrix"/> and <see cref="GetLocalToScreenMatrix"/>
|
||||
/// </remarks>
|
||||
Matrix3 GetWorldToScreenMatrix();
|
||||
Matrix3x2 GetWorldToScreenMatrix();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a matrix that can be used to transform from view-port local to screen coordinates.
|
||||
/// </summary>
|
||||
Matrix3 GetLocalToScreenMatrix();
|
||||
Matrix3x2 GetLocalToScreenMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,17 +155,17 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
return WorldToLocalPixel(point) + GlobalPixelPosition;
|
||||
}
|
||||
|
||||
public Matrix3 GetWorldToScreenMatrix()
|
||||
public Matrix3x2 GetWorldToScreenMatrix()
|
||||
{
|
||||
if (Viewport == null)
|
||||
return Matrix3.Identity;
|
||||
return Matrix3x2.Identity;
|
||||
|
||||
return Viewport.GetWorldToLocalMatrix() * GetLocalToScreenMatrix();
|
||||
}
|
||||
|
||||
public Matrix3 GetLocalToScreenMatrix()
|
||||
public Matrix3x2 GetLocalToScreenMatrix()
|
||||
{
|
||||
return Matrix3.CreateTransform(GlobalPixelPosition, 0, Vector2.One / _viewportResolution);
|
||||
return Matrix3Helpers.CreateTransform(GlobalPixelPosition, 0, Vector2.One / _viewportResolution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Numerics;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Input;
|
||||
@@ -63,7 +63,7 @@ namespace Robust.Client.UserInterface
|
||||
Color GetMainClearColor();
|
||||
|
||||
void RenderControl(IRenderHandle renderHandle, ref int total, Control control, Vector2i position, Color modulate,
|
||||
UIBox2i? scissorBox, Matrix3 coordinateTransform);
|
||||
UIBox2i? scissorBox, Matrix3x2 coordinateTransform);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -130,9 +130,9 @@ internal sealed partial class UserInterfaceManager
|
||||
{
|
||||
var total = 0;
|
||||
var drawingHandle = renderHandle.DrawingHandleScreen;
|
||||
drawingHandle.SetTransform(Matrix3.Identity);
|
||||
RenderControl(renderHandle, ref total, root, Vector2i.Zero, Color.White, null, Matrix3.Identity);
|
||||
drawingHandle.SetTransform(Matrix3.Identity);
|
||||
drawingHandle.SetTransform(Matrix3x2.Identity);
|
||||
RenderControl(renderHandle, ref total, root, Vector2i.Zero, Color.White, null, Matrix3x2.Identity);
|
||||
drawingHandle.SetTransform(Matrix3x2.Identity);
|
||||
OnPostDrawUIRoot?.Invoke(new PostDrawUIRootEventArgs(root, drawingHandle));
|
||||
|
||||
_prof.WriteValue("Controls rendered", ProfData.Int32(total));
|
||||
|
||||
@@ -330,7 +330,7 @@ namespace Robust.Client.UserInterface
|
||||
}
|
||||
|
||||
public void RenderControl(IRenderHandle renderHandle, ref int total, Control control, Vector2i position, Color modulate,
|
||||
UIBox2i? scissorBox, Matrix3 coordinateTransform)
|
||||
UIBox2i? scissorBox, Matrix3x2 coordinateTransform)
|
||||
{
|
||||
if (!control.Visible)
|
||||
{
|
||||
@@ -378,8 +378,7 @@ namespace Robust.Client.UserInterface
|
||||
|
||||
var handle = renderHandle.DrawingHandleScreen;
|
||||
var oldXform = handle.GetTransform();
|
||||
var xform = oldXform;
|
||||
xform.Multiply(Matrix3.CreateTransform(position, Angle.Zero, Vector2.One));
|
||||
var xform = oldXform * Matrix3Helpers.CreateTransform(position, Angle.Zero, Vector2.One);
|
||||
handle.SetTransform(xform);
|
||||
modulate *= control.Modulate;
|
||||
|
||||
@@ -406,7 +405,7 @@ namespace Robust.Client.UserInterface
|
||||
|
||||
foreach (var child in control.Children)
|
||||
{
|
||||
var pos = position + (Vector2i) coordinateTransform.Transform(child.PixelPosition);
|
||||
var pos = position + (Vector2i)Vector2.Transform(child.PixelPosition, coordinateTransform);
|
||||
control.RenderChildOverride(ref args, child.GetPositionInParent(), pos);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,22 +4,6 @@ namespace Robust.Client.Utility
|
||||
{
|
||||
internal static class OpenTKConversions
|
||||
{
|
||||
public static OpenToolkit.Mathematics.Matrix3 ConvertOpenTK(this Matrix3 matrix)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
M11 = matrix.R0C0,
|
||||
M12 = matrix.R0C1,
|
||||
M13 = matrix.R0C2,
|
||||
M21 = matrix.R1C0,
|
||||
M22 = matrix.R1C1,
|
||||
M23 = matrix.R1C2,
|
||||
M31 = matrix.R2C0,
|
||||
M32 = matrix.R2C1,
|
||||
M33 = matrix.R2C2
|
||||
};
|
||||
}
|
||||
|
||||
public static OpenToolkit.Mathematics.Color4 ConvertOpenTK(this Color color)
|
||||
{
|
||||
return new(color.R, color.G, color.B, color.A);
|
||||
|
||||
@@ -42,6 +42,17 @@ public sealed partial class AudioSystem : SharedAudioSystem
|
||||
component.Source = new DummyAudioSource();
|
||||
}
|
||||
|
||||
public override void SetGridAudio(Entity<AudioComponent>? entity)
|
||||
{
|
||||
if (entity == null)
|
||||
return;
|
||||
|
||||
base.SetGridAudio(entity);
|
||||
|
||||
// Need to global override so everyone can hear it.
|
||||
_pvs.AddGlobalOverride(entity.Value.Owner);
|
||||
}
|
||||
|
||||
public override void SetMapAudio(Entity<AudioComponent>? audio)
|
||||
{
|
||||
if (audio == null)
|
||||
@@ -81,11 +92,10 @@ public sealed partial class AudioSystem : SharedAudioSystem
|
||||
/// <inheritdoc />
|
||||
public override (EntityUid Entity, AudioComponent Component)? PlayGlobal(string? filename, Filter playerFilter, bool recordReplay, AudioParams? audioParams = null)
|
||||
{
|
||||
var entity = Spawn("Audio", MapCoordinates.Nullspace);
|
||||
var audio = SetupAudio(entity, filename, audioParams);
|
||||
AddAudioFilter(entity, audio, playerFilter);
|
||||
audio.Global = true;
|
||||
return (entity, audio);
|
||||
var entity = SetupAudio(filename, audioParams);
|
||||
AddAudioFilter(entity, entity.Comp, playerFilter);
|
||||
entity.Comp.Global = true;
|
||||
return (entity, entity.Comp);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -95,16 +105,14 @@ public sealed partial class AudioSystem : SharedAudioSystem
|
||||
return null;
|
||||
|
||||
if (TerminatingOrDeleted(uid))
|
||||
{
|
||||
Log.Error($"Tried to play audio on a terminating / deleted entity {ToPrettyString(uid)}. Trace: {Environment.StackTrace}");
|
||||
return null;
|
||||
}
|
||||
|
||||
var entity = Spawn("Audio", new EntityCoordinates(uid, Vector2.Zero));
|
||||
var audio = SetupAudio(entity, filename, audioParams);
|
||||
AddAudioFilter(entity, audio, playerFilter);
|
||||
var entity = SetupAudio(filename, audioParams);
|
||||
// Move it after setting it up
|
||||
XformSystem.SetCoordinates(entity, new EntityCoordinates(uid, Vector2.Zero));
|
||||
AddAudioFilter(entity, entity.Comp, playerFilter);
|
||||
|
||||
return (entity, audio);
|
||||
return (entity, entity.Comp);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -114,15 +122,12 @@ public sealed partial class AudioSystem : SharedAudioSystem
|
||||
return null;
|
||||
|
||||
if (TerminatingOrDeleted(uid))
|
||||
{
|
||||
Log.Error($"Tried to play audio on a terminating / deleted entity {ToPrettyString(uid)}. Trace: {Environment.StackTrace}");
|
||||
return null;
|
||||
}
|
||||
|
||||
var entity = Spawn("Audio", new EntityCoordinates(uid, Vector2.Zero));
|
||||
var audio = SetupAudio(entity, filename, audioParams);
|
||||
var entity = SetupAudio(filename, audioParams);
|
||||
XformSystem.SetCoordinates(entity, new EntityCoordinates(uid, Vector2.Zero));
|
||||
|
||||
return (entity, audio);
|
||||
return (entity, entity.Comp);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -140,11 +145,11 @@ public sealed partial class AudioSystem : SharedAudioSystem
|
||||
if (!coordinates.IsValid(EntityManager))
|
||||
return null;
|
||||
|
||||
var entity = Spawn("Audio", coordinates);
|
||||
var audio = SetupAudio(entity, filename, audioParams);
|
||||
AddAudioFilter(entity, audio, playerFilter);
|
||||
var entity = SetupAudio(filename, audioParams);
|
||||
XformSystem.SetCoordinates(entity, coordinates);
|
||||
AddAudioFilter(entity, entity.Comp, playerFilter);
|
||||
|
||||
return (entity, audio);
|
||||
return (entity, entity.Comp);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -163,10 +168,11 @@ public sealed partial class AudioSystem : SharedAudioSystem
|
||||
if (!coordinates.IsValid(EntityManager))
|
||||
return null;
|
||||
|
||||
var entity = Spawn("Audio", coordinates);
|
||||
var audio = SetupAudio(entity, filename, audioParams);
|
||||
// TODO: Transform TryFindGridAt mess + optimisation required.
|
||||
var entity = SetupAudio(filename, audioParams);
|
||||
XformSystem.SetCoordinates(entity, coordinates);
|
||||
|
||||
return (entity, audio);
|
||||
return (entity, entity.Comp);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -844,7 +844,7 @@ public sealed class MapLoaderSystem : EntitySystem
|
||||
|
||||
if (xformQuery.TryGetComponent(rootEntity, out var xform) && IsRoot(xform, mapQuery) && !HasComp<MapComponent>(rootEntity))
|
||||
{
|
||||
_transform.SetLocalPosition(xform, data.Options.TransformMatrix.Transform(xform.LocalPosition));
|
||||
_transform.SetLocalPosition(xform, Vector2.Transform(xform.LocalPosition, data.Options.TransformMatrix));
|
||||
xform.LocalRotation += data.Options.Rotation;
|
||||
}
|
||||
}
|
||||
@@ -856,7 +856,7 @@ public sealed class MapLoaderSystem : EntitySystem
|
||||
if (xformQuery.TryGetComponent(entity, out var xform) && IsRoot(xform, mapQuery))
|
||||
{
|
||||
// Don't want to trigger events
|
||||
xform._localPosition = data.Options.TransformMatrix.Transform(xform.LocalPosition);
|
||||
xform._localPosition = Vector2.Transform(xform.LocalPosition, data.Options.TransformMatrix);
|
||||
if (!xform.NoLocalRotation)
|
||||
xform._localRotation += data.Options.Rotation;
|
||||
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
using Robust.Server.GameStates;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Robust.Server.GameObjects;
|
||||
|
||||
public sealed class ServerMetaDataSystem : MetaDataSystem
|
||||
{
|
||||
[Dependency] private readonly PvsSystem _pvsSystem = default!;
|
||||
private EntityQuery<MetaDataComponent> _mQuery;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -18,7 +13,6 @@ public sealed class ServerMetaDataSystem : MetaDataSystem
|
||||
|
||||
EntityManager.ComponentAdded += OnComponentAdded;
|
||||
EntityManager.ComponentRemoved += OnComponentRemoved;
|
||||
_mQuery = GetEntityQuery<MetaDataComponent>();
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
|
||||
@@ -1,9 +1,32 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Server.GameStates;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Server.GameObjects;
|
||||
|
||||
public sealed class UserInterfaceSystem : SharedUserInterfaceSystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<UserInterfaceUserComponent, ExpandPvsEvent>(OnBuiUserExpand);
|
||||
}
|
||||
|
||||
private void OnBuiUserExpand(Entity<UserInterfaceUserComponent> ent, ref ExpandPvsEvent args)
|
||||
{
|
||||
var buis = ent.Comp.OpenInterfaces.Keys;
|
||||
|
||||
if (buis.Count == 0)
|
||||
return;
|
||||
|
||||
args.Entities ??= new List<EntityUid>(buis.Count);
|
||||
|
||||
foreach (var ui in buis)
|
||||
{
|
||||
DebugTools.Assert(ent.Comp.OpenInterfaces[ui].Count > 0);
|
||||
DebugTools.Assert(HasComp<UserInterfaceComponent>(ui));
|
||||
args.Entities.Add(ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ internal sealed class PvsChunk
|
||||
/// <summary>
|
||||
/// The <see cref="Root"/>'s inverse world matrix.
|
||||
/// </summary>
|
||||
public Matrix3 InvWorldMatrix { get; set; }
|
||||
public Matrix3x2 InvWorldMatrix { get; set; }
|
||||
|
||||
// These are only used while populating the chunk. They aren't local variables because the chunks are pooled, so
|
||||
// the same chunk can be repopulated more than once.
|
||||
|
||||
@@ -72,7 +72,7 @@ internal sealed partial class PvsSystem
|
||||
var xform = Transform(chunk.Root);
|
||||
DebugTools.AssertEqual(chunk.Map.Owner, xform.MapUid);
|
||||
chunk.InvWorldMatrix = xform.InvLocalMatrix;
|
||||
var worldPos = xform.LocalMatrix.Transform(chunk.Centre);
|
||||
var worldPos = Vector2.Transform(chunk.Centre, xform.LocalMatrix);
|
||||
chunk.Position = new(worldPos, xform.MapID);
|
||||
chunk.UpdateQueued = false;
|
||||
}
|
||||
@@ -137,7 +137,7 @@ internal sealed partial class PvsSystem
|
||||
|
||||
foreach (var (grid, _) in _grids)
|
||||
{
|
||||
var localPos = _transform.GetInvWorldMatrix(grid).Transform(viewPos);
|
||||
var localPos = Vector2.Transform(viewPos, _transform.GetInvWorldMatrix(grid));
|
||||
var gridChunkEnumerator = new ChunkIndicesEnumerator(localPos, range, ChunkSize);
|
||||
while (gridChunkEnumerator.MoveNext(out var gridChunkIndices))
|
||||
{
|
||||
|
||||
@@ -100,7 +100,13 @@ internal sealed partial class PvsSystem
|
||||
/// </summary>
|
||||
private bool RecursivelyAddOverride(PvsSession session, EntityUid uid, GameTick fromTick, bool addChildren)
|
||||
{
|
||||
var xform = _xformQuery.GetComponent(uid);
|
||||
if (!_xformQuery.TryGetComponent(uid, out var xform))
|
||||
{
|
||||
// Can happen if systems add deleted entities to PVS move event.
|
||||
Log.Error($"Attempted to add non-existent entity {uid} to PVS override for session {session.Session}");
|
||||
return false;
|
||||
}
|
||||
|
||||
var parent = xform.ParentUid;
|
||||
|
||||
// First we process all parents. This is because while this entity may already have been added
|
||||
|
||||
@@ -7,6 +7,7 @@ using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -42,7 +43,7 @@ internal sealed partial class PvsSystem
|
||||
|
||||
// PVS benchmarks use dummy sessions.
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
if (session.Channel != null)
|
||||
if (session.Channel is not DummyChannel)
|
||||
{
|
||||
_netMan.ServerSendMessage(msg, session.Channel);
|
||||
if (msg.ShouldSendReliably())
|
||||
@@ -163,7 +164,7 @@ internal sealed partial class PvsSystem
|
||||
|
||||
dist = Math.Min(dist, (pos.Position - chunk.Position.Position).LengthSquared());
|
||||
|
||||
var relative = chunk.InvWorldMatrix.Transform(pos.Position) - chunk.Centre;
|
||||
var relative = Vector2.Transform(pos.Position, chunk.InvWorldMatrix) - chunk.Centre;
|
||||
relative = Vector2.Abs(relative);
|
||||
chebDist = Math.Min(chebDist, Math.Max(relative.X, relative.Y));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Numerics;
|
||||
using System.Numerics;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Robust.Server.Maps
|
||||
get => _offset;
|
||||
set
|
||||
{
|
||||
TransformMatrix = Matrix3.CreateTransform(value, Rotation);
|
||||
TransformMatrix = Matrix3Helpers.CreateTransform(value, Rotation);
|
||||
_offset = value;
|
||||
}
|
||||
}
|
||||
@@ -37,14 +37,14 @@ namespace Robust.Server.Maps
|
||||
get => _rotation;
|
||||
set
|
||||
{
|
||||
TransformMatrix = Matrix3.CreateTransform(Offset, value);
|
||||
TransformMatrix = Matrix3Helpers.CreateTransform(Offset, value);
|
||||
_rotation = value;
|
||||
}
|
||||
}
|
||||
|
||||
private Angle _rotation = Angle.Zero;
|
||||
|
||||
public Matrix3 TransformMatrix { get; set; } = Matrix3.Identity;
|
||||
public Matrix3x2 TransformMatrix { get; set; } = Matrix3x2.Identity;
|
||||
|
||||
/// <summary>
|
||||
/// If there is a map entity serialized should we also load it.
|
||||
|
||||
@@ -32,7 +32,7 @@ public sealed partial class GridFixtureSystem
|
||||
TransformComponent? xformA = null,
|
||||
TransformComponent? xformB = null)
|
||||
{
|
||||
var matrix = Matrix3.CreateTransform(offset, rotation);
|
||||
var matrix = Matrix3Helpers.CreateTransform(offset, rotation);
|
||||
Merge(gridAUid, gridBUid, matrix, gridA, gridB, xformA, xformB);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public sealed partial class GridFixtureSystem
|
||||
public void Merge(
|
||||
EntityUid gridAUid,
|
||||
EntityUid gridBUid,
|
||||
Matrix3 matrix,
|
||||
Matrix3x2 matrix,
|
||||
MapGridComponent? gridA = null,
|
||||
MapGridComponent? gridB = null,
|
||||
TransformComponent? xformA = null,
|
||||
@@ -63,7 +63,7 @@ public sealed partial class GridFixtureSystem
|
||||
|
||||
while (enumerator.MoveNext(out var tileRef))
|
||||
{
|
||||
var offsetTile = matrix.Transform(new Vector2(tileRef.Value.GridIndices.X, tileRef.Value.GridIndices.Y) + gridA.TileSizeHalfVector);
|
||||
var offsetTile = Vector2.Transform(new Vector2(tileRef.Value.GridIndices.X, tileRef.Value.GridIndices.Y) + gridA.TileSizeHalfVector, matrix);
|
||||
tiles.Add((offsetTile.Floored(), tileRef.Value.Tile));
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ public sealed partial class GridFixtureSystem
|
||||
if (snapgrid == null || snapgrid.Count == 0)
|
||||
continue;
|
||||
|
||||
var offsetTile = matrix.Transform(new Vector2(tileRef.Value.GridIndices.X, tileRef.Value.GridIndices.Y) + gridA.TileSizeHalfVector);
|
||||
var offsetTile = Vector2.Transform(new Vector2(tileRef.Value.GridIndices.X, tileRef.Value.GridIndices.Y) + gridA.TileSizeHalfVector, matrix);
|
||||
var tileIndex = offsetTile.Floored();
|
||||
|
||||
for (var j = snapgrid.Count - 1; j >= 0; j--)
|
||||
@@ -124,7 +124,7 @@ public sealed partial class GridFixtureSystem
|
||||
if (entXform.ParentUid != gridBUid ||
|
||||
!bounds.Contains(entXform.LocalPosition)) continue;
|
||||
|
||||
var newPos = matrix.Transform(entXform.LocalPosition);
|
||||
var newPos = Vector2.Transform(entXform.LocalPosition, matrix);
|
||||
|
||||
_xformSystem.SetCoordinates(ent, entXform, new EntityCoordinates(gridAUid, newPos), entXform.LocalRotation + rotationDiff, oldParent: xformB, newParent: xformA);
|
||||
}
|
||||
|
||||
@@ -172,16 +172,10 @@ namespace Robust.Server.Placement
|
||||
}
|
||||
}
|
||||
|
||||
var created = _entityManager.SpawnEntity(entityTemplateName, coordinates);
|
||||
var created = _entityManager.SpawnAttachedTo(entityTemplateName, coordinates, rotation: dirRcv.ToAngle());
|
||||
|
||||
var placementCreateEvent = new PlacementEntityEvent(created, coordinates, PlacementEventAction.Create, msg.MsgChannel.UserId);
|
||||
_entityManager.EventBus.RaiseEvent(EventSource.Local, placementCreateEvent);
|
||||
|
||||
// Some entities immediately delete themselves
|
||||
if (_entityManager.EntityExists(created))
|
||||
{
|
||||
_entityManager.GetComponent<TransformComponent>(created).LocalRotation = dirRcv.ToAngle();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -90,18 +90,18 @@ namespace Robust.Server.Player
|
||||
_cfg.SyncConnectingClient(args.Channel);
|
||||
}
|
||||
|
||||
private void EndSession(object? sender, NetChannelArgs args)
|
||||
{
|
||||
EndSession(args.Channel.UserId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ends a clients session, and disconnects them.
|
||||
/// </summary>
|
||||
private void EndSession(object? sender, NetChannelArgs args)
|
||||
internal void EndSession(NetUserId user)
|
||||
{
|
||||
if (!TryGetSessionByChannel(args.Channel, out var session))
|
||||
{
|
||||
if (!TryGetSessionById(user, out var session))
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure nothing got messed up during the life of the session
|
||||
DebugTools.Assert(session.Channel == args.Channel);
|
||||
|
||||
SetStatus(session, SessionStatus.Disconnected);
|
||||
SetAttachedEntity(session, null, out _, true);
|
||||
@@ -159,5 +159,32 @@ namespace Robust.Server.Player
|
||||
session = actor.PlayerSession;
|
||||
return true;
|
||||
}
|
||||
|
||||
internal ICommonSession AddDummySession(NetUserId user, string name)
|
||||
{
|
||||
#if FULL_RELEASE
|
||||
// Lets not make it completely trivial to fake player counts.
|
||||
throw new NotSupportedException();
|
||||
#endif
|
||||
Lock.EnterWriteLock();
|
||||
DummySession session;
|
||||
try
|
||||
{
|
||||
UserIdMap[name] = user;
|
||||
if (!PlayerData.TryGetValue(user, out var data))
|
||||
PlayerData[user] = data = new(user, name);
|
||||
|
||||
session = new DummySession(user, name, data);
|
||||
InternalSessions.Add(user, session);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
UpdateState(session);
|
||||
|
||||
return session;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,14 +312,14 @@ namespace Robust.Server.ServerStatus
|
||||
}
|
||||
|
||||
// Only call this if the download URL is not available!
|
||||
private async Task<AczManifestInfo?> PrepareAcz()
|
||||
private async Task<AczManifestInfo?> PrepareAcz(bool optional = false)
|
||||
{
|
||||
// Take the ACZ lock asynchronously
|
||||
await _aczLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
// Setting this now ensures that it won't fail repeatedly on exceptions/etc.
|
||||
if (_aczPrepareAttempted)
|
||||
if (_aczPrepareAttempted || optional)
|
||||
return _aczPrepared;
|
||||
|
||||
_aczPrepareAttempted = true;
|
||||
|
||||
@@ -80,8 +80,7 @@ namespace Robust.Server.ServerStatus
|
||||
if (string.IsNullOrEmpty(downloadUrl))
|
||||
{
|
||||
var query = HttpUtility.ParseQueryString(context.Url.Query);
|
||||
var optional = query.Keys;
|
||||
buildInfo = await PrepareACZBuildInfo();
|
||||
buildInfo = await PrepareACZBuildInfo(optional: query.Get("can_skip_build") == "1");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -129,9 +128,9 @@ namespace Robust.Server.ServerStatus
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<JsonObject?> PrepareACZBuildInfo()
|
||||
private async Task<JsonObject?> PrepareACZBuildInfo(bool optional)
|
||||
{
|
||||
var acm = await PrepareAcz();
|
||||
var acm = await PrepareAcz(optional);
|
||||
if (acm == null) return null;
|
||||
|
||||
// Fork ID is an interesting case, we don't want to cause too many redownloads but we also don't want to pollute disk.
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Robust.Shared.Maths
|
||||
public readonly Vector2 BottomLeft => Origin + Rotation.RotateVec(Box.BottomLeft - Origin);
|
||||
public readonly Vector2 Center => Origin + Rotation.RotateVec((Box.BottomLeft + Box.TopRight)/2 - Origin);
|
||||
|
||||
public Matrix3 Transform => Matrix3.CreateTransform(Origin - Rotation.RotateVec(Origin), Rotation);
|
||||
public Matrix3x2 Transform => Matrix3Helpers.CreateTransform(Origin - Rotation.RotateVec(Origin), Rotation);
|
||||
|
||||
public Box2Rotated(Vector2 bottomLeft, Vector2 topRight)
|
||||
: this(new Box2(bottomLeft, topRight))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
193
Robust.Shared.Maths/Matrix3Helpers.cs
Normal file
193
Robust.Shared.Maths/Matrix3Helpers.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
|
||||
|
||||
namespace Robust.Shared.Maths;
|
||||
|
||||
public static class Matrix3Helpers
|
||||
{
|
||||
public static bool EqualsApprox(this Matrix3x2 a, Matrix3x2 b, float tolerance = 1e-6f)
|
||||
{
|
||||
return
|
||||
Math.Abs(a.M11 - b.M11) <= tolerance &&
|
||||
Math.Abs(a.M12 - b.M12) <= tolerance &&
|
||||
Math.Abs(a.M21 - b.M21) <= tolerance &&
|
||||
Math.Abs(a.M22 - b.M22) <= tolerance &&
|
||||
Math.Abs(a.M31 - b.M31) <= tolerance &&
|
||||
Math.Abs(a.M32 - b.M32) <= tolerance;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool EqualsApprox(this Matrix3x2 a, Matrix3x2 b, double tolerance)
|
||||
{
|
||||
return a.EqualsApprox(b, (float) tolerance);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Box2 TransformBox(this Matrix3x2 refFromBox, Box2Rotated box)
|
||||
{
|
||||
return (box.Transform * refFromBox).TransformBox(box.Box);
|
||||
}
|
||||
|
||||
public static Box2 TransformBox(this Matrix3x2 refFromBox, in Box2 box)
|
||||
{
|
||||
// Do transformation on all 4 corners of the box at once.
|
||||
// Then min/max the results to get the new AABB.
|
||||
|
||||
var boxVec = Unsafe.As<Box2, Vector128<float>>(ref Unsafe.AsRef(in box));
|
||||
|
||||
// Convert box into list of X and Y values for each of the 4 corners
|
||||
var allX = Vector128.Shuffle(boxVec, Vector128.Create(0, 0, 2, 2));
|
||||
var allY = Vector128.Shuffle(boxVec, Vector128.Create(1, 3, 3, 1));
|
||||
|
||||
// Transform coordinates
|
||||
var modX = allX * Vector128.Create(refFromBox.M11);
|
||||
var modY = allX * Vector128.Create(refFromBox.M12);
|
||||
modX += allY * Vector128.Create(refFromBox.M21);
|
||||
modY += allY * Vector128.Create(refFromBox.M22);
|
||||
modX += Vector128.Create(refFromBox.M31);
|
||||
modY += Vector128.Create(refFromBox.M32);
|
||||
|
||||
// Get bounding box by finding the min and max X and Y values.
|
||||
var l = SimdHelpers.MinHorizontal128(modX);
|
||||
var b = SimdHelpers.MinHorizontal128(modY);
|
||||
var r = SimdHelpers.MaxHorizontal128(modX);
|
||||
var t = SimdHelpers.MaxHorizontal128(modY);
|
||||
|
||||
var lbrt = SimdHelpers.MergeRows128(l, b, r, t);
|
||||
return Unsafe.As<Vector128<float>, Box2>(ref lbrt);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rotation of the Matrix. Will have some precision loss.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Angle Rotation(this Matrix3x2 t)
|
||||
{
|
||||
return new Vector2(t.M11, t.M12).ToAngle();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateTransform(float posX, float posY, double angle, float scaleX = 1, float scaleY = 1)
|
||||
{
|
||||
// returns a matrix that is equivalent to returning CreateScale(scale) * CreateRotation(angle) * CreateTranslation(posX, posY)
|
||||
|
||||
var sin = (float) Math.Sin(angle);
|
||||
var cos = (float) Math.Cos(angle);
|
||||
|
||||
return new Matrix3x2
|
||||
{
|
||||
M11 = cos * scaleX,
|
||||
M21 = -sin * scaleY,
|
||||
M31 = posX,
|
||||
M12 = sin * scaleX,
|
||||
M22 = cos * scaleY,
|
||||
M32 = posY,
|
||||
};
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateTransform(in Vector2 position, in Angle angle)
|
||||
{
|
||||
// Rounding moment
|
||||
return angle.Theta switch
|
||||
{
|
||||
-Math.PI / 2 => new Matrix3x2(0f, -1f, 1, 0, position.X, position.Y),
|
||||
Math.PI / 2 => new Matrix3x2(0f, 1f, -1f, 0f, position.X, position.Y),
|
||||
Math.PI => new Matrix3x2(-1f, 0f, 0f, -1f, position.X, position.Y),
|
||||
_ => CreateTransform(position.X, position.Y, (float) angle.Theta)
|
||||
};
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateTransform(in Vector2 position, in Angle angle, in Vector2 scale)
|
||||
{
|
||||
return CreateTransform(position.X, position.Y, (float)angle.Theta, scale.X, scale.Y);
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateInverseTransform(float posX, float posY, double angle, float scaleX = 1, float scaleY = 1)
|
||||
{
|
||||
// returns a matrix that is equivalent to returning CreateTranslation(-posX, -posY) * CreateRotation(-angle) * CreateScale(1/scaleX, 1/scaleY)
|
||||
|
||||
var sin = (float) Math.Sin(angle);
|
||||
var cos = (float) Math.Cos(angle);
|
||||
|
||||
return new Matrix3x2
|
||||
{
|
||||
M11 = cos / scaleX,
|
||||
M21 = sin / scaleX,
|
||||
M31 = - (posX * cos + posY * sin) / scaleX,
|
||||
M12 = -sin / scaleY,
|
||||
M22 = cos / scaleY,
|
||||
M32 = (posX * sin - posY * cos) / scaleY,
|
||||
};
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateInverseTransform(in Vector2 position, in Angle angle)
|
||||
{
|
||||
return CreateInverseTransform(position.X, position.Y, (float)angle.Theta);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateInverseTransform(in Vector2 position, in Angle angle, in Vector2 scale)
|
||||
{
|
||||
return CreateInverseTransform(position.X, position.Y, (float)angle.Theta, scale.X, scale.Y);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateTranslation(float x, float y)
|
||||
{
|
||||
return new Matrix3x2 {
|
||||
M11 = 1,
|
||||
M12 = 0,
|
||||
M21 = 0,
|
||||
M22 = 1,
|
||||
M31 = x,
|
||||
M32 = y
|
||||
};
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateTranslation(Vector2 vector)
|
||||
{
|
||||
return CreateTranslation(vector.X, vector.Y);
|
||||
}
|
||||
|
||||
public static Matrix3x2 CreateRotation(double angle)
|
||||
{
|
||||
var cos = (float) Math.Cos(angle);
|
||||
var sin = (float) Math.Sin(angle);
|
||||
return new Matrix3x2 {
|
||||
M11 = cos,
|
||||
M12 = sin,
|
||||
M21 = -sin,
|
||||
M22 = cos,
|
||||
M31 = 0,
|
||||
M32 = 0
|
||||
};
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateScale(float x, float y)
|
||||
{
|
||||
return new Matrix3x2 {
|
||||
M11 = x,
|
||||
M12 = 0,
|
||||
M21 = 0,
|
||||
M22 = y,
|
||||
M31 = 0,
|
||||
M32 = 0
|
||||
};
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateScale(in Vector2 scale)
|
||||
{
|
||||
return CreateScale(scale.X, scale.Y);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#region --- License ---
|
||||
#region --- License ---
|
||||
|
||||
/*
|
||||
Copyright (c) 2006 - 2008 The Open Toolkit library.
|
||||
@@ -26,6 +26,7 @@ SOFTWARE.
|
||||
#endregion --- License ---
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Xml.Serialization;
|
||||
@@ -73,9 +74,9 @@ namespace Robust.Shared.Maths
|
||||
: this(new Vector3(x, y, z), w) { }
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Quaternion(ref Matrix3 matrix)
|
||||
public Quaternion(ref Matrix3x2 matrix)
|
||||
{
|
||||
var scale = Math.Pow(matrix.Determinant, 1.0d / 3.0d);
|
||||
var scale = Math.Pow(matrix.GetDeterminant(), 1.0d / 3.0d);
|
||||
float x, y, z;
|
||||
|
||||
w = (float) (Math.Sqrt(Math.Max(0, scale + matrix[0, 0] + matrix[1, 1] + matrix[2, 2])) / 2);
|
||||
|
||||
@@ -272,4 +272,6 @@ public enum AudioFlags : byte
|
||||
/// Should the audio act as if attached to a grid?
|
||||
/// </summary>
|
||||
GridAudio = 1 << 0,
|
||||
|
||||
NoOcclusion = 1 << 1,
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
@@ -34,6 +35,7 @@ public abstract partial class SharedAudioSystem : EntitySystem
|
||||
[Dependency] protected readonly IPrototypeManager ProtoMan = default!;
|
||||
[Dependency] protected readonly IRobustRandom RandMan = default!;
|
||||
[Dependency] protected readonly MetaDataSystem MetadataSys = default!;
|
||||
[Dependency] protected readonly SharedTransformSystem XformSystem = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Default max range at which the sound can be heard.
|
||||
@@ -92,7 +94,7 @@ public abstract partial class SharedAudioSystem : EntitySystem
|
||||
var currentPos = (entity.Comp.PauseTime ?? Timing.CurTime) - entity.Comp.AudioStart;
|
||||
var timeOffset = TimeSpan.FromSeconds(position - currentPos.TotalSeconds);
|
||||
|
||||
DebugTools.Assert(currentPos > TimeSpan.Zero);
|
||||
DebugTools.Assert(currentPos >= TimeSpan.Zero);
|
||||
|
||||
// Rounding.
|
||||
if (Math.Abs(timeOffset.TotalSeconds) <= 0.01)
|
||||
@@ -145,6 +147,33 @@ public abstract partial class SharedAudioSystem : EntitySystem
|
||||
MetadataSys.AddFlag(audio.Value.Owner, MetaDataFlags.Undetachable);
|
||||
}
|
||||
|
||||
public virtual void SetGridAudio(Entity<AudioComponent>? entity)
|
||||
{
|
||||
if (entity == null)
|
||||
return;
|
||||
|
||||
entity.Value.Comp.Flags |= AudioFlags.GridAudio;
|
||||
var gridUid = Transform(entity.Value).GridUid;
|
||||
|
||||
if (TryComp(gridUid, out PhysicsComponent? gridPhysics))
|
||||
{
|
||||
XformSystem.SetLocalPosition(entity.Value.Owner, gridPhysics.LocalCenter);
|
||||
}
|
||||
|
||||
if (TryComp(gridUid, out MapGridComponent? mapGrid))
|
||||
{
|
||||
var extents = mapGrid.LocalAABB.Extents;
|
||||
var minDistance = MathF.Max(extents.X, extents.Y);
|
||||
|
||||
entity.Value.Comp.Params = entity.Value.Comp.Params
|
||||
.WithMaxDistance(minDistance + DefaultSoundRange)
|
||||
.WithReferenceDistance(minDistance);
|
||||
}
|
||||
|
||||
entity.Value.Comp.Flags |= AudioFlags.NoOcclusion;
|
||||
Dirty(entity.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the shared state for an audio entity.
|
||||
/// </summary>
|
||||
@@ -266,16 +295,16 @@ public abstract partial class SharedAudioSystem : EntitySystem
|
||||
|
||||
#region AudioParams
|
||||
|
||||
protected AudioComponent SetupAudio(EntityUid uid, string? fileName, AudioParams? audioParams, TimeSpan? length = null)
|
||||
protected Entity<AudioComponent> SetupAudio(string? fileName, AudioParams? audioParams, bool initialize = true, TimeSpan? length = null)
|
||||
{
|
||||
DebugTools.Assert((!string.IsNullOrEmpty(fileName) || length is not null));
|
||||
var uid = EntityManager.CreateEntityUninitialized("Audio", MapCoordinates.Nullspace);
|
||||
DebugTools.Assert(!string.IsNullOrEmpty(fileName) || length is not null);
|
||||
audioParams ??= AudioParams.Default;
|
||||
var comp = AddComp<AudioComponent>(uid);
|
||||
comp.FileName = fileName ?? string.Empty;
|
||||
comp.Params = audioParams.Value;
|
||||
comp.AudioStart = Timing.CurTime;
|
||||
|
||||
|
||||
if (!audioParams.Value.Loop)
|
||||
{
|
||||
length ??= GetAudioLength(fileName!);
|
||||
@@ -290,7 +319,12 @@ public abstract partial class SharedAudioSystem : EntitySystem
|
||||
comp.Params.Pitch *= (float) RandMan.NextGaussian(1, comp.Params.Variation.Value);
|
||||
}
|
||||
|
||||
return comp;
|
||||
if (initialize)
|
||||
{
|
||||
EntityManager.InitializeAndStartEntity(uid);
|
||||
}
|
||||
|
||||
return new Entity<AudioComponent>(uid, comp);
|
||||
}
|
||||
|
||||
public static float GainToVolume(float value)
|
||||
@@ -597,7 +631,7 @@ public abstract partial class SharedAudioSystem : EntitySystem
|
||||
[return: NotNullIfNotNull("sound")]
|
||||
public (EntityUid Entity, Components.AudioComponent Component)? PlayStatic(SoundSpecifier? sound, Filter playerFilter, EntityCoordinates coordinates, bool recordReplay, AudioParams? audioParams = null)
|
||||
{
|
||||
return sound == null ? null : PlayStatic(GetSound(sound), playerFilter, coordinates, recordReplay);
|
||||
return sound == null ? null : PlayStatic(GetSound(sound), playerFilter, coordinates, recordReplay, audioParams);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1641,6 +1641,13 @@ namespace Robust.Shared
|
||||
true,
|
||||
CVar.SERVER | CVar.REPLICATED | CVar.ARCHIVE);
|
||||
|
||||
/// <summary>
|
||||
/// How many milliseconds we will spend moving forward from the nearest checkpoint or current position.
|
||||
/// We will spend this time when scrubbing the timeline per game tick. This limits CPU usage / locking up and
|
||||
/// improves responsiveness
|
||||
/// </summary>
|
||||
public static readonly CVarDef<int> ReplayMaxScrubTime = CVarDef.Create("replay.max_scrub_time", 10);
|
||||
|
||||
/// <summary>
|
||||
/// Determines the threshold before visual events (muzzle flashes, chat pop-ups, etc) are suppressed when
|
||||
/// jumping forward in time. Jumps larger than this will simply skip directly to the target tick.
|
||||
|
||||
@@ -357,7 +357,7 @@ public abstract class ComponentTreeSystem<TTreeComp, TComp> : EntitySystem
|
||||
{
|
||||
var (_, treeRot, matrix) = XformSystem.GetWorldPositionRotationInvMatrix(treeUid);
|
||||
var relativeAngle = new Angle(-treeRot.Theta).RotateVec(ray.Direction);
|
||||
var treeRay = new Ray(matrix.Transform(ray.Position), relativeAngle);
|
||||
var treeRay = new Ray(Vector2.Transform(ray.Position, matrix), relativeAngle);
|
||||
comp.Tree.QueryRay(ref queryState, QueryCallback, treeRay);
|
||||
if (returnOnFirstHit && queryState.List.Count > 0)
|
||||
break;
|
||||
|
||||
@@ -140,4 +140,47 @@ namespace Robust.Shared.Configuration
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class CVarSubsCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
|
||||
public override string Command => "cvar_subs";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length < 1)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-cvar_subs-invalid-args"));
|
||||
return;
|
||||
}
|
||||
|
||||
var name = args[0];
|
||||
var subs = ((ConfigurationManager)_cfg).GetSubs(name);
|
||||
|
||||
foreach (var @delegate in subs)
|
||||
{
|
||||
shell.WriteLine(ShowDelegateInfo(@delegate));
|
||||
}
|
||||
}
|
||||
|
||||
private static string ShowDelegateInfo(Delegate del)
|
||||
{
|
||||
return $"{del}: {del.Method} -> {del.Target}";
|
||||
}
|
||||
|
||||
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
{
|
||||
if (args.Length == 1)
|
||||
{
|
||||
return CompletionResult.FromHintOptions(
|
||||
_cfg.GetRegisteredCVars()
|
||||
.Select(c => new CompletionOption(c))
|
||||
.OrderBy(c => c.Value),
|
||||
Loc.GetString("cmd-cvar_subs-arg-name"));
|
||||
}
|
||||
|
||||
return CompletionResult.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,8 +97,23 @@ namespace Robust.Shared.Configuration
|
||||
{
|
||||
// overwrite the value with the saved one
|
||||
var oldValue = GetConfigVarValue(cfgVar);
|
||||
changedInvokes.Add(SetupInvokeValueChanged(cfgVar, value, oldValue));
|
||||
cfgVar.Value = value;
|
||||
|
||||
var convertedValue = value;
|
||||
if (cfgVar.Type != value.GetType())
|
||||
{
|
||||
try
|
||||
{
|
||||
convertedValue = ConvertToCVarType(value, cfgVar.Type!);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_sawmill.Error($"TOML parsed cvar does not match registered cvar type. Name: {cvar}. Code Type: {cfgVar.Type}. Toml type: {value.GetType()}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
changedInvokes.Add(SetupInvokeValueChanged(cfgVar, convertedValue, oldValue));
|
||||
cfgVar.Value = convertedValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -777,6 +792,24 @@ namespace Robust.Shared.Configuration
|
||||
return Convert.ChangeType(value, cVar);
|
||||
}
|
||||
|
||||
internal List<Delegate> GetSubs(string name)
|
||||
{
|
||||
using (Lock.ReadGuard())
|
||||
{
|
||||
var list = new List<Delegate>();
|
||||
|
||||
if (!_configVars.TryGetValue(name, out var cVar))
|
||||
throw new InvalidConfigurationException($"Trying to get unregistered variable '{name}'");
|
||||
|
||||
foreach (var entry in cVar.ValueChanged.Entries)
|
||||
{
|
||||
list.Add((Delegate) entry.Equality!);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the data for a single configuration variable.
|
||||
/// </summary>
|
||||
|
||||
@@ -34,7 +34,7 @@ internal sealed class DumpEventTablesCommand : LocalizedCommands
|
||||
{
|
||||
shell.WriteLine($"{evType}:");
|
||||
|
||||
var idx = comps;
|
||||
var idx = comps.Start;
|
||||
while (idx != -1)
|
||||
{
|
||||
ref var entry = ref table.ComponentLists[idx];
|
||||
|
||||
@@ -56,7 +56,7 @@ internal sealed class TeleportCommand : LocalizedCommands
|
||||
|
||||
if (_map.TryFindGridAt(mapId, position, out var gridUid, out var grid))
|
||||
{
|
||||
var gridPos = xformSystem.GetInvWorldMatrix(gridUid).Transform(position);
|
||||
var gridPos = Vector2.Transform(position, xformSystem.GetInvWorldMatrix(gridUid));
|
||||
|
||||
xformSystem.SetCoordinates(entity, transform, new EntityCoordinates(gridUid, gridPos));
|
||||
}
|
||||
@@ -174,12 +174,7 @@ public sealed class TeleportToCommand : LocalizedCommands
|
||||
|
||||
var hint = args.Length == 1 ? "cmd-tpto-destination-hint" : "cmd-tpto-victim-hint";
|
||||
hint = Loc.GetString(hint);
|
||||
|
||||
var opts = CompletionResult.FromHintOptions(users, hint);
|
||||
if (last != string.Empty && !NetEntity.TryParse(last, out _))
|
||||
return opts;
|
||||
|
||||
return CompletionResult.FromHintOptions(opts.Options.Concat(CompletionHelper.NetEntities(last, _entities)), hint);
|
||||
return CompletionResult.FromHintOptions(users, hint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -189,27 +189,45 @@ public static class CompletionHelper
|
||||
return Components<MapComponent>(string.Empty, entManager);
|
||||
}
|
||||
|
||||
public static IEnumerable<CompletionOption> NetEntities(string text, IEntityManager? entManager = null)
|
||||
/// <summary>
|
||||
/// Return all existing entities as possible completions. You should generally avoid using this unless you need to.
|
||||
/// </summary>
|
||||
public static IEnumerable<CompletionOption> NetEntities(string text, IEntityManager? entManager = null, int limit = 20)
|
||||
{
|
||||
return Components<MetaDataComponent>(text, entManager);
|
||||
}
|
||||
if (!NetEntity.TryParse(text, out _))
|
||||
yield break;
|
||||
|
||||
public static IEnumerable<CompletionOption> Components<T>(string text, IEntityManager? entManager = null) where T : IComponent
|
||||
{
|
||||
IoCManager.Resolve(ref entManager);
|
||||
var query = entManager.AllEntityQueryEnumerator<MetaDataComponent>();
|
||||
|
||||
var query = entManager.AllEntityQueryEnumerator<T, MetaDataComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out _, out var metadata))
|
||||
var i = 0;
|
||||
while (i < limit && query.MoveNext(out var metadata))
|
||||
{
|
||||
if (!entManager.TryGetNetEntity(uid, out var netEntity, metadata: metadata))
|
||||
continue;
|
||||
|
||||
var netString = netEntity.Value.ToString();
|
||||
|
||||
var netString = metadata.NetEntity.ToString();
|
||||
if (!netString.StartsWith(text))
|
||||
continue;
|
||||
|
||||
i++;
|
||||
yield return new CompletionOption(netString, metadata.EntityName);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<CompletionOption> Components<T>(string text, IEntityManager? entManager = null, int limit = 20) where T : IComponent
|
||||
{
|
||||
if (!NetEntity.TryParse(text, out _))
|
||||
yield break;
|
||||
|
||||
IoCManager.Resolve(ref entManager);
|
||||
var query = entManager.AllEntityQueryEnumerator<T, MetaDataComponent>();
|
||||
|
||||
var i = 0;
|
||||
while (i < limit && query.MoveNext(out _, out var metadata))
|
||||
{
|
||||
var netString = metadata.NetEntity.ToString();
|
||||
if (!netString.StartsWith(text))
|
||||
continue;
|
||||
|
||||
i++;
|
||||
yield return new CompletionOption(netString, metadata.EntityName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,14 +49,14 @@ public abstract partial class SharedContainerSystem
|
||||
|
||||
if (!TryComp(container.Owner, out MetaDataComponent? ownerMeta))
|
||||
{
|
||||
Log.Error($"Attempted to insert an entity {ToPrettyString(toInsert)} into a non-existent entity.");
|
||||
Log.Error($"Attempted to insert an entity {ToPrettyString(toInsert)} into a non-existent entity. Trace: {Environment.StackTrace}");
|
||||
QueueDel(toInsert);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ownerMeta.EntityLifeStage >= EntityLifeStage.Terminating)
|
||||
{
|
||||
Log.Error($"Attempted to insert an entity {ToPrettyString(toInsert)} into an entity that is terminating. Entity: {ToPrettyString(container.Owner)}.");
|
||||
Log.Error($"Attempted to insert an entity {ToPrettyString(toInsert)} into an entity that is terminating. Entity: {ToPrettyString(container.Owner)}. Trace: {Environment.StackTrace}");
|
||||
QueueDel(toInsert);
|
||||
return false;
|
||||
}
|
||||
@@ -67,7 +67,7 @@ public abstract partial class SharedContainerSystem
|
||||
|
||||
if (meta.EntityLifeStage >= EntityLifeStage.Terminating)
|
||||
{
|
||||
Log.Error($"Attempted to insert a terminating entity {ToPrettyString(uid)} into a container {container.ID} in entity: {ToPrettyString(container.Owner)}.");
|
||||
Log.Error($"Attempted to insert a terminating entity {ToPrettyString(uid)} into a container {container.ID} in entity: {ToPrettyString(container.Owner)}. Trace: {Environment.StackTrace}");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Robust.Shared.ContentPack
|
||||
String("short").ThenReturn(PrimitiveTypeCode.Int16);
|
||||
|
||||
private static readonly Parser<char, PrimitiveTypeCode> UInt16TypeParser =
|
||||
String("ushort").ThenReturn(PrimitiveTypeCode.UInt32);
|
||||
String("ushort").ThenReturn(PrimitiveTypeCode.UInt16);
|
||||
|
||||
private static readonly Parser<char, PrimitiveTypeCode> Int32TypeParser =
|
||||
String("int").ThenReturn(PrimitiveTypeCode.Int32);
|
||||
|
||||
@@ -84,12 +84,146 @@ Types:
|
||||
- "bool get_HasContents()"
|
||||
Lidgren.Network:
|
||||
NetBuffer:
|
||||
All: True
|
||||
Methods:
|
||||
- "byte[] get_Data()"
|
||||
- "void set_Data(byte[])"
|
||||
- "int get_LengthBytes()"
|
||||
- "void set_LengthBytes(int)"
|
||||
- "int get_LengthBits()"
|
||||
- "void set_LengthBits(int)"
|
||||
- "long get_Position()"
|
||||
- "void set_Position(long)"
|
||||
- "int get_PositionInBytes()"
|
||||
- "byte[] PeekDataBuffer()"
|
||||
- "bool PeekBoolean()"
|
||||
- "byte PeekByte()"
|
||||
- "sbyte PeekSByte()"
|
||||
- "byte PeekByte(int)"
|
||||
- "System.Span`1<byte> PeekBytes(System.Span`1<byte>)"
|
||||
- "byte[] PeekBytes(int)"
|
||||
- "void PeekBytes(byte[], int, int)"
|
||||
- "short PeekInt16()"
|
||||
- "ushort PeekUInt16()"
|
||||
- "int PeekInt32()"
|
||||
- "int PeekInt32(int)"
|
||||
- "uint PeekUInt32()"
|
||||
- "uint PeekUInt32(int)"
|
||||
- "ulong PeekUInt64()"
|
||||
- "long PeekInt64()"
|
||||
- "ulong PeekUInt64(int)"
|
||||
- "long PeekInt64(int)"
|
||||
- "float PeekFloat()"
|
||||
- "System.Half PeekHalf()"
|
||||
- "float PeekSingle()"
|
||||
- "double PeekDouble()"
|
||||
- "string PeekString()"
|
||||
- "int PeekStringSize()"
|
||||
- "bool ReadBoolean()"
|
||||
- "byte ReadByte()"
|
||||
- "bool ReadByte(ref byte)"
|
||||
- "sbyte ReadSByte()"
|
||||
- "byte ReadByte(int)"
|
||||
- "System.Span`1<byte> ReadBytes(System.Span`1<byte>)"
|
||||
- "byte[] ReadBytes(int)"
|
||||
- "bool ReadBytes(int, ref byte[])"
|
||||
- "bool TryReadBytes(System.Span`1<byte>)"
|
||||
- "void ReadBytes(byte[], int, int)"
|
||||
- "void ReadBits(System.Span`1<byte>, int)"
|
||||
- "void ReadBits(byte[], int, int)"
|
||||
- "short ReadInt16()"
|
||||
- "ushort ReadUInt16()"
|
||||
- "int ReadInt32()"
|
||||
- "bool ReadInt32(ref int)"
|
||||
- "int ReadInt32(int)"
|
||||
- "uint ReadUInt32()"
|
||||
- "bool ReadUInt32(ref uint)"
|
||||
- "uint ReadUInt32(int)"
|
||||
- "ulong ReadUInt64()"
|
||||
- "long ReadInt64()"
|
||||
- "ulong ReadUInt64(int)"
|
||||
- "long ReadInt64(int)"
|
||||
- "float ReadFloat()"
|
||||
- "System.Half ReadHalf()"
|
||||
- "float ReadSingle()"
|
||||
- "bool ReadSingle(ref float)"
|
||||
- "double ReadDouble()"
|
||||
- "uint ReadVariableUInt32()"
|
||||
- "bool ReadVariableUInt32(ref uint)"
|
||||
- "int ReadVariableInt32()"
|
||||
- "long ReadVariableInt64()"
|
||||
- "ulong ReadVariableUInt64()"
|
||||
- "float ReadSignedSingle(int)"
|
||||
- "float ReadUnitSingle(int)"
|
||||
- "float ReadRangedSingle(float, float, int)"
|
||||
- "int ReadRangedInteger(int, int)"
|
||||
- "long ReadRangedInteger(long, long)"
|
||||
- "string ReadString()"
|
||||
- "bool ReadString(ref string)"
|
||||
- "double ReadTime(Lidgren.Network.NetConnection, bool)"
|
||||
- "System.Net.IPEndPoint ReadIPEndPoint()"
|
||||
- "void SkipPadBits()"
|
||||
- "void ReadPadBits()"
|
||||
- "void SkipPadBits(int)"
|
||||
- "void EnsureBufferSize(int)"
|
||||
- "void Write(bool)"
|
||||
- "void Write(byte)"
|
||||
- "void WriteAt(int, byte)"
|
||||
- "void Write(sbyte)"
|
||||
- "void Write(byte, int)"
|
||||
- "void Write(byte[])"
|
||||
- "void Write(System.ReadOnlySpan`1<byte>)"
|
||||
- "void Write(byte[], int, int)"
|
||||
- "void Write(ushort)"
|
||||
- "void WriteAt(int, ushort)"
|
||||
- "void Write(ushort, int)"
|
||||
- "void Write(short)"
|
||||
- "void WriteAt(int, short)"
|
||||
- "void Write(int)"
|
||||
- "void WriteAt(int, int)"
|
||||
- "void Write(uint)"
|
||||
- "void WriteAt(int, uint)"
|
||||
- "void Write(uint, int)"
|
||||
- "void Write(int, int)"
|
||||
- "void Write(ulong)"
|
||||
- "void WriteAt(int, ulong)"
|
||||
- "void Write(ulong, int)"
|
||||
- "void Write(long)"
|
||||
- "void Write(long, int)"
|
||||
- "void Write(System.Half)"
|
||||
- "void Write(float)"
|
||||
- "void Write(double)"
|
||||
- "int WriteVariableUInt32(uint)"
|
||||
- "int WriteVariableInt32(int)"
|
||||
- "int WriteVariableInt64(long)"
|
||||
- "int WriteVariableUInt64(ulong)"
|
||||
- "void WriteSignedSingle(float, int)"
|
||||
- "void WriteUnitSingle(float, int)"
|
||||
- "void WriteRangedSingle(float, float, float, int)"
|
||||
- "int WriteRangedInteger(int, int, int)"
|
||||
- "int WriteRangedInteger(long, long, long)"
|
||||
- "void Write(string)"
|
||||
- "void Write(System.Net.IPEndPoint)"
|
||||
- "void WriteTime(bool)"
|
||||
- "void WriteTime(double, bool)"
|
||||
- "void WritePadBits()"
|
||||
- "void WritePadBits(int)"
|
||||
- "void Write(Lidgren.Network.NetBuffer)"
|
||||
- "void Zero(int)"
|
||||
- "void .ctor()"
|
||||
NetDeliveryMethod: { }
|
||||
NetIncomingMessage:
|
||||
All: True
|
||||
Methods:
|
||||
- "Lidgren.Network.NetIncomingMessageType get_MessageType()"
|
||||
- "Lidgren.Network.NetDeliveryMethod get_DeliveryMethod()"
|
||||
- "int get_SequenceChannel()"
|
||||
- "System.Net.IPEndPoint get_SenderEndPoint()"
|
||||
- "Lidgren.Network.NetConnection get_SenderConnection()"
|
||||
- "double get_ReceiveTime()"
|
||||
- "double ReadTime(bool)"
|
||||
- "string ToString()"
|
||||
NetOutgoingMessage:
|
||||
All: True
|
||||
Methods:
|
||||
- "string ToString()"
|
||||
Nett:
|
||||
CommentLocation: { } # Enum
|
||||
Toml:
|
||||
@@ -450,6 +584,7 @@ Types:
|
||||
Vector2: { All: True }
|
||||
Vector3: { All: True }
|
||||
Vector4: { All: True }
|
||||
Matrix3x2: { All: True }
|
||||
System.Reflection:
|
||||
Assembly:
|
||||
Methods:
|
||||
@@ -831,6 +966,7 @@ Types:
|
||||
- "object GetValue(long[])"
|
||||
- "System.Collections.IEnumerator GetEnumerator()"
|
||||
- "System.Collections.ObjectModel.ReadOnlyCollection`1<!!0> AsReadOnly<>(!!0[])"
|
||||
- "void Clear(System.Array)"
|
||||
- "void Clear(System.Array, int, int)"
|
||||
- "void ConstrainedCopy(System.Array, int, System.Array, int, int)"
|
||||
- "void Copy(System.Array, int, System.Array, int, int)"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.ContentPack
|
||||
@@ -135,11 +136,37 @@ namespace Robust.Shared.ContentPack
|
||||
path = path.Directory;
|
||||
|
||||
var fullPath = GetFullPath(path);
|
||||
Process.Start(new ProcessStartInfo
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
UseShellExecute = true,
|
||||
FileName = fullPath,
|
||||
});
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = $"{Environment.GetEnvironmentVariable("SystemRoot")}\\explorer.exe",
|
||||
Arguments = ".",
|
||||
WorkingDirectory = fullPath,
|
||||
});
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "open",
|
||||
Arguments = ".",
|
||||
WorkingDirectory = fullPath,
|
||||
});
|
||||
}
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsFreeBSD())
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "xdg-open",
|
||||
Arguments = ".",
|
||||
WorkingDirectory = fullPath,
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException("Opening OS windows not supported on this OS");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -9,36 +9,19 @@ namespace Robust.Shared.GameObjects;
|
||||
|
||||
public readonly struct CompIdx : IEquatable<CompIdx>
|
||||
{
|
||||
private static readonly ReaderWriterLockSlim SlowStoreLock = new();
|
||||
private static readonly Dictionary<Type, CompIdx> SlowStore = new();
|
||||
|
||||
internal readonly int Value;
|
||||
|
||||
internal static CompIdx Index<T>() => Store<T>.Index;
|
||||
|
||||
internal static CompIdx Index(Type t)
|
||||
{
|
||||
using (SlowStoreLock.ReadGuard())
|
||||
{
|
||||
if (SlowStore.TryGetValue(t, out var idx))
|
||||
return idx;
|
||||
}
|
||||
|
||||
// Doesn't exist in the store, get a write lock and add it.
|
||||
using (SlowStoreLock.WriteGuard())
|
||||
{
|
||||
var idx = (CompIdx)typeof(Store<>)
|
||||
.MakeGenericType(t)
|
||||
.GetField(nameof(Store<int>.Index), BindingFlags.Static | BindingFlags.Public)!
|
||||
.GetValue(null)!;
|
||||
|
||||
SlowStore[t] = idx;
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
internal static int ArrayIndex<T>() => Index<T>().Value;
|
||||
internal static int ArrayIndex(Type type) => Index(type).Value;
|
||||
|
||||
internal static CompIdx GetIndex(Type type)
|
||||
{
|
||||
return (CompIdx)typeof(Store<>)
|
||||
.MakeGenericType(type)
|
||||
.GetField(nameof(Store<int>.Index), BindingFlags.Static | BindingFlags.Public)!
|
||||
.GetValue(null)!;
|
||||
}
|
||||
|
||||
internal static void AssignArray<T>(ref T[] array, CompIdx idx, T value)
|
||||
{
|
||||
|
||||
@@ -24,7 +24,6 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
// Bunch of dictionaries to allow lookups in all directions.
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Mapping of component name to type.
|
||||
/// </summary>
|
||||
private FrozenDictionary<string, ComponentRegistration> _names
|
||||
@@ -63,6 +62,11 @@ namespace Robust.Shared.GameObjects
|
||||
private FrozenDictionary<CompIdx, Type> _idxToType
|
||||
= FrozenDictionary<CompIdx, Type>.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Slow-path for Type -> CompIdx mapping without generics.
|
||||
/// </summary>
|
||||
private FrozenDictionary<Type, CompIdx> _typeToIdx = FrozenDictionary<Type, CompIdx>.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event Action<ComponentRegistration[]>? ComponentsAdded;
|
||||
|
||||
@@ -78,6 +82,7 @@ namespace Robust.Shared.GameObjects
|
||||
private IEnumerable<ComponentRegistration> AllRegistrations => _types.Values;
|
||||
|
||||
private ComponentRegistration Register(Type type,
|
||||
CompIdx idx,
|
||||
Dictionary<string, ComponentRegistration> names,
|
||||
Dictionary<string, string> lowerCaseNames,
|
||||
Dictionary<Type, ComponentRegistration> types,
|
||||
@@ -123,8 +128,6 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
var unsaved = type.HasCustomAttribute<UnsavedComponentAttribute>();
|
||||
|
||||
var idx = CompIdx.Index(type);
|
||||
|
||||
var registration = new ComponentRegistration(name, type, idx, unsaved);
|
||||
|
||||
idxToType[idx] = type;
|
||||
@@ -399,6 +402,20 @@ namespace Robust.Shared.GameObjects
|
||||
RegisterTypesInternal(types, false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[Pure]
|
||||
public CompIdx GetIndex(Type type)
|
||||
{
|
||||
return _typeToIdx[type];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[Pure]
|
||||
public int GetArrayIndex(Type type)
|
||||
{
|
||||
return _typeToIdx[type].Value;
|
||||
}
|
||||
|
||||
private void RegisterTypesInternal(Type[] types, bool overwrite)
|
||||
{
|
||||
var names = _names.ToDictionary();
|
||||
@@ -408,12 +425,19 @@ namespace Robust.Shared.GameObjects
|
||||
var ignored = _ignored.ToHashSet();
|
||||
|
||||
var added = new ComponentRegistration[types.Length];
|
||||
var typeToidx = _typeToIdx.ToDictionary();
|
||||
|
||||
for (int i = 0; i < types.Length; i++)
|
||||
{
|
||||
added[i] = Register(types[i], names, lowerCaseNames, typesDict, idxToType, ignored, overwrite);
|
||||
var type = types[i];
|
||||
var idx = CompIdx.GetIndex(type);
|
||||
typeToidx[type] = idx;
|
||||
|
||||
added[i] = Register(type, idx, names, lowerCaseNames, typesDict, idxToType, ignored, overwrite);
|
||||
}
|
||||
|
||||
var st = RStopwatch.StartNew();
|
||||
_typeToIdx = typeToidx.ToFrozenDictionary();
|
||||
_names = names.ToFrozenDictionary();
|
||||
_lowerCaseNames = lowerCaseNames.ToFrozenDictionary();
|
||||
_types = typesDict.ToFrozenDictionary();
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Numerics;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Animations;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -25,16 +26,26 @@ namespace Robust.Shared.GameObjects
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
// Currently this field just exists for VV. In future, it might become a real field
|
||||
[ViewVariables]
|
||||
[ViewVariables, PublicAPI]
|
||||
private NetEntity NetParent => _entMan.GetNetEntity(_parent);
|
||||
|
||||
[DataField("parent")] internal EntityUid _parent;
|
||||
[DataField("pos")] internal Vector2 _localPosition = Vector2.Zero; // holds offset from grid, or offset from parent
|
||||
|
||||
[DataField("pos")] internal Vector2 _localPosition = Vector2.Zero; // holds offset from parent
|
||||
|
||||
[DataField("rot")] internal Angle _localRotation; // local rotation
|
||||
|
||||
[DataField("noRot")] internal bool _noLocalRotation;
|
||||
|
||||
[DataField("anchored")]
|
||||
internal bool _anchored;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates this entity can traverse grids.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool GridTraversal = true;
|
||||
|
||||
/// <summary>
|
||||
/// The broadphase that this entity is currently stored on, if any.
|
||||
/// </summary>
|
||||
@@ -46,12 +57,12 @@ namespace Robust.Shared.GameObjects
|
||||
internal BroadphaseData? Broadphase;
|
||||
|
||||
internal bool MatricesDirty = true;
|
||||
private Matrix3 _localMatrix = Matrix3.Identity;
|
||||
private Matrix3 _invLocalMatrix = Matrix3.Identity;
|
||||
private Matrix3x2 _localMatrix = Matrix3x2.Identity;
|
||||
private Matrix3x2 _invLocalMatrix = Matrix3x2.Identity;
|
||||
|
||||
// these should just be system methods, but existing component functions like InvWorldMatrix still rely on
|
||||
// getting these so those have to be fully ECS-ed first.
|
||||
public Matrix3 LocalMatrix
|
||||
public Matrix3x2 LocalMatrix
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -60,7 +71,7 @@ namespace Robust.Shared.GameObjects
|
||||
return _localMatrix;
|
||||
}
|
||||
}
|
||||
public Matrix3 InvLocalMatrix
|
||||
public Matrix3x2 InvLocalMatrix
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -207,7 +218,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// Matrix for transforming points from local to world space.
|
||||
/// </summary>
|
||||
[Obsolete("Use the system method instead")]
|
||||
public Matrix3 WorldMatrix
|
||||
public Matrix3x2 WorldMatrix
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -221,7 +232,7 @@ namespace Robust.Shared.GameObjects
|
||||
var parentMatrix = parentXform.LocalMatrix;
|
||||
parent = parentXform.ParentUid;
|
||||
|
||||
Matrix3.Multiply(in myMatrix, in parentMatrix, out var result);
|
||||
var result = Matrix3x2.Multiply(myMatrix, parentMatrix);
|
||||
myMatrix = result;
|
||||
}
|
||||
|
||||
@@ -233,7 +244,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// Matrix for transforming points from world to local space.
|
||||
/// </summary>
|
||||
[Obsolete("Use the system method instead")]
|
||||
public Matrix3 InvWorldMatrix
|
||||
public Matrix3x2 InvWorldMatrix
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -247,7 +258,7 @@ namespace Robust.Shared.GameObjects
|
||||
var parentMatrix = parentXform.InvLocalMatrix;
|
||||
parent = parentXform.ParentUid;
|
||||
|
||||
Matrix3.Multiply(in parentMatrix, in myMatrix, out var result);
|
||||
var result = Matrix3x2.Multiply(parentMatrix, myMatrix);
|
||||
myMatrix = result;
|
||||
}
|
||||
|
||||
@@ -269,7 +280,7 @@ namespace Robust.Shared.GameObjects
|
||||
if (_parent.IsValid())
|
||||
{
|
||||
// parent coords to world coords
|
||||
return _entMan.GetComponent<TransformComponent>(ParentUid).WorldMatrix.Transform(_localPosition);
|
||||
return Vector2.Transform(_localPosition, _entMan.GetComponent<TransformComponent>(ParentUid).WorldMatrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -285,7 +296,7 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
|
||||
// world coords to parent coords
|
||||
var newPos = _entMan.GetComponent<TransformComponent>(ParentUid).InvWorldMatrix.Transform(value);
|
||||
var newPos = Vector2.Transform(value, _entMan.GetComponent<TransformComponent>(ParentUid).InvWorldMatrix);
|
||||
|
||||
LocalPosition = newPos;
|
||||
}
|
||||
@@ -479,7 +490,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// Get the WorldPosition, WorldRotation, and WorldMatrix of this entity faster than each individually.
|
||||
/// </summary>
|
||||
[Obsolete("Use the system method instead")]
|
||||
public (Vector2 WorldPosition, Angle WorldRotation, Matrix3 WorldMatrix) GetWorldPositionRotationMatrix(EntityQuery<TransformComponent> xforms)
|
||||
public (Vector2 WorldPosition, Angle WorldRotation, Matrix3x2 WorldMatrix) GetWorldPositionRotationMatrix(EntityQuery<TransformComponent> xforms)
|
||||
{
|
||||
var parent = _parent;
|
||||
var worldRot = _localRotation;
|
||||
@@ -491,12 +502,12 @@ namespace Robust.Shared.GameObjects
|
||||
var xform = xforms.GetComponent(parent);
|
||||
worldRot += xform.LocalRotation;
|
||||
var parentMatrix = xform.LocalMatrix;
|
||||
Matrix3.Multiply(in worldMatrix, in parentMatrix, out var result);
|
||||
var result = Matrix3x2.Multiply(worldMatrix, parentMatrix);
|
||||
worldMatrix = result;
|
||||
parent = xform.ParentUid;
|
||||
}
|
||||
|
||||
var worldPosition = new Vector2(worldMatrix.R0C2, worldMatrix.R1C2);
|
||||
var worldPosition = worldMatrix.Translation;
|
||||
|
||||
return (worldPosition, worldRot, worldMatrix);
|
||||
}
|
||||
@@ -505,7 +516,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// Get the WorldPosition, WorldRotation, and WorldMatrix of this entity faster than each individually.
|
||||
/// </summary>
|
||||
[Obsolete("Use the system method instead")]
|
||||
public (Vector2 WorldPosition, Angle WorldRotation, Matrix3 WorldMatrix) GetWorldPositionRotationMatrix()
|
||||
public (Vector2 WorldPosition, Angle WorldRotation, Matrix3x2 WorldMatrix) GetWorldPositionRotationMatrix()
|
||||
{
|
||||
var xforms = _entMan.GetEntityQuery<TransformComponent>();
|
||||
return GetWorldPositionRotationMatrix(xforms);
|
||||
@@ -515,7 +526,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// Get the WorldPosition, WorldRotation, and InvWorldMatrix of this entity faster than each individually.
|
||||
/// </summary>
|
||||
[Obsolete("Use the system method instead")]
|
||||
public (Vector2 WorldPosition, Angle WorldRotation, Matrix3 InvWorldMatrix) GetWorldPositionRotationInvMatrix()
|
||||
public (Vector2 WorldPosition, Angle WorldRotation, Matrix3x2 InvWorldMatrix) GetWorldPositionRotationInvMatrix()
|
||||
{
|
||||
var xformQuery = _entMan.GetEntityQuery<TransformComponent>();
|
||||
return GetWorldPositionRotationInvMatrix(xformQuery);
|
||||
@@ -525,7 +536,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// Get the WorldPosition, WorldRotation, and InvWorldMatrix of this entity faster than each individually.
|
||||
/// </summary>
|
||||
[Obsolete("Use the system method instead")]
|
||||
public (Vector2 WorldPosition, Angle WorldRotation, Matrix3 InvWorldMatrix) GetWorldPositionRotationInvMatrix(EntityQuery<TransformComponent> xformQuery)
|
||||
public (Vector2 WorldPosition, Angle WorldRotation, Matrix3x2 InvWorldMatrix) GetWorldPositionRotationInvMatrix(EntityQuery<TransformComponent> xformQuery)
|
||||
{
|
||||
var (worldPos, worldRot, _, invWorldMatrix) = GetWorldPositionRotationMatrixWithInv(xformQuery);
|
||||
return (worldPos, worldRot, invWorldMatrix);
|
||||
@@ -535,7 +546,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// Get the WorldPosition, WorldRotation, WorldMatrix, and InvWorldMatrix of this entity faster than each individually.
|
||||
/// </summary>
|
||||
[Obsolete("Use the system method instead")]
|
||||
public (Vector2 WorldPosition, Angle WorldRotation, Matrix3 WorldMatrix, Matrix3 InvWorldMatrix) GetWorldPositionRotationMatrixWithInv()
|
||||
public (Vector2 WorldPosition, Angle WorldRotation, Matrix3x2 WorldMatrix, Matrix3x2 InvWorldMatrix) GetWorldPositionRotationMatrixWithInv()
|
||||
{
|
||||
var xformQuery = _entMan.GetEntityQuery<TransformComponent>();
|
||||
return GetWorldPositionRotationMatrixWithInv(xformQuery);
|
||||
@@ -545,7 +556,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// Get the WorldPosition, WorldRotation, WorldMatrix, and InvWorldMatrix of this entity faster than each individually.
|
||||
/// </summary>
|
||||
[Obsolete("Use the system method instead")]
|
||||
public (Vector2 WorldPosition, Angle WorldRotation, Matrix3 WorldMatrix, Matrix3 InvWorldMatrix) GetWorldPositionRotationMatrixWithInv(EntityQuery<TransformComponent> xformQuery)
|
||||
public (Vector2 WorldPosition, Angle WorldRotation, Matrix3x2 WorldMatrix, Matrix3x2 InvWorldMatrix) GetWorldPositionRotationMatrixWithInv(EntityQuery<TransformComponent> xformQuery)
|
||||
{
|
||||
var parent = _parent;
|
||||
var worldRot = _localRotation;
|
||||
@@ -559,17 +570,17 @@ namespace Robust.Shared.GameObjects
|
||||
worldRot += xform.LocalRotation;
|
||||
|
||||
var parentMatrix = xform.LocalMatrix;
|
||||
Matrix3.Multiply(in worldMatrix, in parentMatrix, out var result);
|
||||
var result = Matrix3x2.Multiply(worldMatrix, parentMatrix);
|
||||
worldMatrix = result;
|
||||
|
||||
var parentInvMatrix = xform.InvLocalMatrix;
|
||||
Matrix3.Multiply(in parentInvMatrix, in invMatrix, out var invResult);
|
||||
var invResult = Matrix3x2.Multiply(parentInvMatrix, invMatrix);
|
||||
invMatrix = invResult;
|
||||
|
||||
parent = xform.ParentUid;
|
||||
}
|
||||
|
||||
var worldPosition = new Vector2(worldMatrix.R0C2, worldMatrix.R1C2);
|
||||
var worldPosition = worldMatrix.Translation;
|
||||
|
||||
return (worldPosition, worldRot, worldMatrix, invMatrix);
|
||||
}
|
||||
@@ -580,12 +591,12 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
if (!_parent.IsValid()) // Root Node
|
||||
{
|
||||
_localMatrix = Matrix3.Identity;
|
||||
_invLocalMatrix = Matrix3.Identity;
|
||||
_localMatrix = Matrix3x2.Identity;
|
||||
_invLocalMatrix = Matrix3x2.Identity;
|
||||
}
|
||||
|
||||
_localMatrix = Matrix3.CreateTransform(_localPosition, _localRotation);
|
||||
_invLocalMatrix = Matrix3.CreateInverseTransform(_localPosition, _localRotation);
|
||||
_localMatrix = Matrix3Helpers.CreateTransform(_localPosition, _localRotation);
|
||||
_invLocalMatrix = Matrix3Helpers.CreateInverseTransform(_localPosition, _localRotation);
|
||||
}
|
||||
|
||||
public string GetDebugString()
|
||||
|
||||
@@ -5,7 +5,7 @@ using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Shared.GameObjects;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
[RegisterComponent]
|
||||
public sealed partial class ActiveUserInterfaceComponent : Component
|
||||
{
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// Actors that currently have interfaces open.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Dictionary<Enum, List<EntityUid>> Actors = new();
|
||||
public Dictionary<Enum, HashSet<EntityUid>> Actors = new();
|
||||
|
||||
/// <summary>
|
||||
/// Legacy data, new BUIs should be using comp states.
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Robust.Shared.GameObjects;
|
||||
@@ -9,17 +7,13 @@ namespace Robust.Shared.GameObjects;
|
||||
/// <summary>
|
||||
/// Stores data about this entity and what BUIs they have open.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
/// <remarks>
|
||||
/// This component is implicitly networked via <see cref="UserInterfaceComponent"/>.
|
||||
/// I.e., the other component is authoritative about what UIs are open
|
||||
/// </remarks>
|
||||
[RegisterComponent]
|
||||
public sealed partial class UserInterfaceUserComponent : Component
|
||||
{
|
||||
public override bool SessionSpecific => true;
|
||||
|
||||
[DataField]
|
||||
public Dictionary<EntityUid, List<Enum>> OpenInterfaces = new();
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
internal sealed class UserInterfaceUserComponentState : IComponentState
|
||||
{
|
||||
public Dictionary<NetEntity, List<Enum>> OpenInterfaces = new();
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.GameObjects;
|
||||
|
||||
public record struct Entity<T>
|
||||
public record struct Entity<T> : IFluentEntityUid
|
||||
where T : IComponent?
|
||||
{
|
||||
public EntityUid Owner;
|
||||
public T Comp;
|
||||
EntityUid IFluentEntityUid.FluentOwner => Owner;
|
||||
|
||||
public Entity(EntityUid owner, T comp)
|
||||
{
|
||||
@@ -45,12 +47,13 @@ public record struct Entity<T>
|
||||
public override int GetHashCode() => Owner.GetHashCode();
|
||||
}
|
||||
|
||||
public record struct Entity<T1, T2>
|
||||
public record struct Entity<T1, T2> : IFluentEntityUid
|
||||
where T1 : IComponent? where T2 : IComponent?
|
||||
{
|
||||
public EntityUid Owner;
|
||||
public T1 Comp1;
|
||||
public T2 Comp2;
|
||||
EntityUid IFluentEntityUid.FluentOwner => Owner;
|
||||
|
||||
public Entity(EntityUid owner, T1 comp1, T2 comp2)
|
||||
{
|
||||
@@ -110,13 +113,14 @@ public record struct Entity<T1, T2>
|
||||
}
|
||||
}
|
||||
|
||||
public record struct Entity<T1, T2, T3>
|
||||
public record struct Entity<T1, T2, T3> : IFluentEntityUid
|
||||
where T1 : IComponent? where T2 : IComponent? where T3 : IComponent?
|
||||
{
|
||||
public EntityUid Owner;
|
||||
public T1 Comp1;
|
||||
public T2 Comp2;
|
||||
public T3 Comp3;
|
||||
EntityUid IFluentEntityUid.FluentOwner => Owner;
|
||||
|
||||
public Entity(EntityUid owner, T1 comp1, T2 comp2, T3 comp3)
|
||||
{
|
||||
@@ -211,7 +215,7 @@ public record struct Entity<T1, T2, T3>
|
||||
#endregion
|
||||
}
|
||||
|
||||
public record struct Entity<T1, T2, T3, T4>
|
||||
public record struct Entity<T1, T2, T3, T4> : IFluentEntityUid
|
||||
where T1 : IComponent? where T2 : IComponent? where T3 : IComponent? where T4 : IComponent?
|
||||
{
|
||||
public EntityUid Owner;
|
||||
@@ -219,6 +223,7 @@ public record struct Entity<T1, T2, T3, T4>
|
||||
public T2 Comp2;
|
||||
public T3 Comp3;
|
||||
public T4 Comp4;
|
||||
EntityUid IFluentEntityUid.FluentOwner => Owner;
|
||||
|
||||
public Entity(EntityUid owner, T1 comp1, T2 comp2, T3 comp3, T4 comp4)
|
||||
{
|
||||
@@ -336,7 +341,7 @@ public record struct Entity<T1, T2, T3, T4>
|
||||
#endregion
|
||||
}
|
||||
|
||||
public record struct Entity<T1, T2, T3, T4, T5>
|
||||
public record struct Entity<T1, T2, T3, T4, T5> : IFluentEntityUid
|
||||
where T1 : IComponent? where T2 : IComponent? where T3 : IComponent? where T4 : IComponent? where T5 : IComponent?
|
||||
{
|
||||
public EntityUid Owner;
|
||||
@@ -345,6 +350,7 @@ public record struct Entity<T1, T2, T3, T4, T5>
|
||||
public T3 Comp3;
|
||||
public T4 Comp4;
|
||||
public T5 Comp5;
|
||||
EntityUid IFluentEntityUid.FluentOwner => Owner;
|
||||
|
||||
public Entity(EntityUid owner, T1 comp1, T2 comp2, T3 comp3, T4 comp4, T5 comp5)
|
||||
{
|
||||
@@ -485,7 +491,7 @@ public record struct Entity<T1, T2, T3, T4, T5>
|
||||
#endregion
|
||||
}
|
||||
|
||||
public record struct Entity<T1, T2, T3, T4, T5, T6>
|
||||
public record struct Entity<T1, T2, T3, T4, T5, T6> : IFluentEntityUid
|
||||
where T1 : IComponent? where T2 : IComponent? where T3 : IComponent? where T4 : IComponent? where T5 : IComponent? where T6 : IComponent?
|
||||
{
|
||||
public EntityUid Owner;
|
||||
@@ -495,6 +501,7 @@ public record struct Entity<T1, T2, T3, T4, T5, T6>
|
||||
public T4 Comp4;
|
||||
public T5 Comp5;
|
||||
public T6 Comp6;
|
||||
EntityUid IFluentEntityUid.FluentOwner => Owner;
|
||||
|
||||
public Entity(EntityUid owner, T1 comp1, T2 comp2, T3 comp3, T4 comp4, T5 comp5, T6 comp6)
|
||||
{
|
||||
@@ -658,7 +665,7 @@ public record struct Entity<T1, T2, T3, T4, T5, T6>
|
||||
#endregion
|
||||
}
|
||||
|
||||
public record struct Entity<T1, T2, T3, T4, T5, T6, T7>
|
||||
public record struct Entity<T1, T2, T3, T4, T5, T6, T7> : IFluentEntityUid
|
||||
where T1 : IComponent? where T2 : IComponent? where T3 : IComponent? where T4 : IComponent? where T5 : IComponent? where T6 : IComponent? where T7 : IComponent?
|
||||
{
|
||||
public EntityUid Owner;
|
||||
@@ -669,6 +676,7 @@ public record struct Entity<T1, T2, T3, T4, T5, T6, T7>
|
||||
public T5 Comp5;
|
||||
public T6 Comp6;
|
||||
public T7 Comp7;
|
||||
EntityUid IFluentEntityUid.FluentOwner => Owner;
|
||||
|
||||
public Entity(EntityUid owner, T1 comp1, T2 comp2, T3 comp3, T4 comp4, T5 comp5, T6 comp6, T7 comp7)
|
||||
{
|
||||
@@ -855,7 +863,7 @@ public record struct Entity<T1, T2, T3, T4, T5, T6, T7>
|
||||
#endregion
|
||||
}
|
||||
|
||||
public record struct Entity<T1, T2, T3, T4, T5, T6, T7, T8>
|
||||
public record struct Entity<T1, T2, T3, T4, T5, T6, T7, T8> : IFluentEntityUid
|
||||
where T1 : IComponent? where T2 : IComponent? where T3 : IComponent? where T4 : IComponent? where T5 : IComponent? where T6 : IComponent? where T7 : IComponent? where T8 : IComponent?
|
||||
{
|
||||
public EntityUid Owner;
|
||||
@@ -867,6 +875,7 @@ public record struct Entity<T1, T2, T3, T4, T5, T6, T7, T8>
|
||||
public T6 Comp6;
|
||||
public T7 Comp7;
|
||||
public T8 Comp8;
|
||||
EntityUid IFluentEntityUid.FluentOwner => Owner;
|
||||
|
||||
public Entity(EntityUid owner, T1 comp1, T2 comp2, T3 comp3, T4 comp4, T5 comp5, T6 comp6, T7 comp7, T8 comp8)
|
||||
{
|
||||
|
||||
@@ -114,6 +114,15 @@ namespace Robust.Shared.GameObjects
|
||||
private delegate void DirectedEventHandler<TEvent>(EntityUid uid, IComponent comp, ref TEvent args)
|
||||
where TEvent : notnull;
|
||||
|
||||
/// <summary>
|
||||
/// Max size of a components event subscription linked list.
|
||||
/// Used to limit the stackalloc in <see cref="EntDispatch"/>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// SS14 currently requires only 18, I doubt it will ever need to exceed 256.
|
||||
/// </remarks>
|
||||
private const int MaxEventLinkedListSize = 256;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of <see cref="EntityEventBus"/>.
|
||||
/// </summary>
|
||||
@@ -138,7 +147,7 @@ namespace Robust.Shared.GameObjects
|
||||
DispatchComponent<TEvent>(
|
||||
component.Owner,
|
||||
component,
|
||||
CompIdx.Index(component.GetType()),
|
||||
_comFac.GetIndex(component.GetType()),
|
||||
ref unitRef);
|
||||
}
|
||||
|
||||
@@ -161,7 +170,7 @@ namespace Robust.Shared.GameObjects
|
||||
DispatchComponent<TEvent>(
|
||||
component.Owner,
|
||||
component,
|
||||
CompIdx.Index(component.GetType()),
|
||||
_comFac.GetIndex(component.GetType()),
|
||||
ref unitRef);
|
||||
}
|
||||
|
||||
@@ -390,7 +399,7 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
public void OnComponentRemoved(in RemovedComponentEventArgs e)
|
||||
{
|
||||
EntRemoveComponent(e.BaseArgs.Owner, CompIdx.Index(e.BaseArgs.Component.GetType()));
|
||||
EntRemoveComponent(e.BaseArgs.Owner, _comFac.GetIndex(e.BaseArgs.Component.GetType()));
|
||||
}
|
||||
|
||||
private void EntAddSubscription(
|
||||
@@ -488,7 +497,7 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
DebugTools.Assert(eventTable.Free >= 0);
|
||||
|
||||
ref var eventStartIdx = ref CollectionsMarshal.GetValueRefOrAddDefault(
|
||||
ref var indices = ref CollectionsMarshal.GetValueRefOrAddDefault(
|
||||
eventTable.EventIndices,
|
||||
evType,
|
||||
out var exists);
|
||||
@@ -500,10 +509,13 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
// Set it up
|
||||
entry.Component = compType;
|
||||
entry.Next = exists ? eventStartIdx : -1;
|
||||
entry.Next = exists ? indices.Start : -1;
|
||||
|
||||
// Assign new list entry to EventIndices dictionary.
|
||||
eventStartIdx = entryIdx;
|
||||
indices.Start = entryIdx;
|
||||
indices.Count++;
|
||||
if (indices.Count > MaxEventLinkedListSize)
|
||||
throw new NotSupportedException($"Exceeded maximum event linked list size. Need to implement stackalloc fallback.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -541,40 +553,37 @@ namespace Robust.Shared.GameObjects
|
||||
foreach (var evType in compSubs.Keys)
|
||||
{
|
||||
DebugTools.Assert(!_eventData[evType].ComponentEvent);
|
||||
ref var dictIdx = ref CollectionsMarshal.GetValueRefOrNullRef(eventTable.EventIndices, evType);
|
||||
if (Unsafe.IsNullRef(ref dictIdx))
|
||||
ref var indices = ref CollectionsMarshal.GetValueRefOrNullRef(eventTable.EventIndices, evType);
|
||||
if (Unsafe.IsNullRef(ref indices))
|
||||
{
|
||||
DebugTools.Assert("This should not be possible. Were the events for this component never added?");
|
||||
continue;
|
||||
}
|
||||
|
||||
ref var updateNext = ref dictIdx;
|
||||
var entryIdx = indices.Start;
|
||||
ref var entry = ref eventTable.ComponentLists[entryIdx];
|
||||
|
||||
// Go over linked list to find index of component.
|
||||
var entryIdx = dictIdx;
|
||||
ref var entry = ref Unsafe.NullRef<EventTableListEntry>();
|
||||
while (true)
|
||||
{
|
||||
entry = ref eventTable.ComponentLists[entryIdx];
|
||||
if (entry.Component == compType)
|
||||
{
|
||||
// Found
|
||||
break;
|
||||
}
|
||||
|
||||
entryIdx = entry.Next;
|
||||
updateNext = ref entry.Next;
|
||||
}
|
||||
|
||||
if (entry.Next == -1 && Unsafe.AreSame(ref dictIdx, ref updateNext))
|
||||
if (indices.Count == 1)
|
||||
{
|
||||
// Last entry for this event type, remove from dict.
|
||||
DebugTools.AssertEqual(entry.Next, -1);
|
||||
eventTable.EventIndices.Remove(evType);
|
||||
}
|
||||
else
|
||||
{
|
||||
ref var updateNext = ref indices.Start;
|
||||
|
||||
// Go over linked list to find index of component.
|
||||
while (entry.Component != compType)
|
||||
{
|
||||
updateNext = ref entry.Next;
|
||||
entryIdx = entry.Next;
|
||||
entry = ref eventTable.ComponentLists[entryIdx];
|
||||
}
|
||||
|
||||
// Rewrite previous index to point to next in chain.
|
||||
updateNext = entry.Next;
|
||||
indices.Count--;
|
||||
}
|
||||
|
||||
// Push entry back onto free list.
|
||||
@@ -585,15 +594,33 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
private void EntDispatch(EntityUid euid, Type eventType, ref Unit args)
|
||||
{
|
||||
if (!EntTryGetSubscriptions(eventType, euid, out var enumerator))
|
||||
if (!_entEventTables.TryGetValue(euid, out var eventTable))
|
||||
return;
|
||||
|
||||
while (enumerator.MoveNext(out var component, out var reg))
|
||||
{
|
||||
if (component.Deleted)
|
||||
continue;
|
||||
if (!eventTable.EventIndices.TryGetValue(eventType, out var indices))
|
||||
return;
|
||||
|
||||
reg.Handler(euid, component, ref args);
|
||||
DebugTools.Assert(indices.Count > 0);
|
||||
DebugTools.Assert(indices.Start >= 0);
|
||||
|
||||
// First, collect all subscribing components.
|
||||
// This is to avoid infinite loops over the linked list if subscription handlers add or remove components.
|
||||
Span<CompIdx> compIds = stackalloc CompIdx[indices.Count];
|
||||
var idx = indices.Start;
|
||||
for (var index = 0; index < compIds.Length; index++)
|
||||
{
|
||||
DebugTools.Assert(idx >= 0);
|
||||
ref var entry = ref eventTable.ComponentLists[idx];
|
||||
idx = entry.Next;
|
||||
compIds[index] = entry.Component;
|
||||
}
|
||||
|
||||
foreach (var compIdx in compIds)
|
||||
{
|
||||
if (!_entMan.TryGetComponent(euid, compIdx, out var comp))
|
||||
continue;
|
||||
var compSubs = _eventSubs[compIdx.Value];
|
||||
compSubs[eventType].Handler(euid, comp, ref args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,16 +629,30 @@ namespace Robust.Shared.GameObjects
|
||||
Type eventType,
|
||||
ref ValueList<OrderedEventDispatch> found)
|
||||
{
|
||||
if (!EntTryGetSubscriptions(eventType, euid, out var enumerator))
|
||||
if (!_entEventTables.TryGetValue(euid, out var eventTable))
|
||||
return;
|
||||
|
||||
while (enumerator.MoveNext(out var component, out var reg))
|
||||
if (!eventTable.EventIndices.TryGetValue(eventType, out var indices))
|
||||
return;
|
||||
|
||||
DebugTools.Assert(indices.Count > 0);
|
||||
DebugTools.Assert(indices.Start >= 0);
|
||||
var idx = indices.Start;
|
||||
while (idx != -1)
|
||||
{
|
||||
found.Add(new OrderedEventDispatch((ref Unit ev) =>
|
||||
{
|
||||
if (!component.Deleted)
|
||||
reg.Handler(euid, component, ref ev);
|
||||
}, reg.Order));
|
||||
ref var entry = ref eventTable.ComponentLists[idx];
|
||||
idx = entry.Next;
|
||||
var comp = _entMan.GetComponentInternal(euid, entry.Component);
|
||||
var compSubs = _eventSubs[entry.Component.Value];
|
||||
var reg = compSubs[eventType];
|
||||
|
||||
found.Add(new OrderedEventDispatch(
|
||||
(ref Unit ev) =>
|
||||
{
|
||||
if (!comp.Deleted)
|
||||
reg.Handler(euid, comp, ref ev);
|
||||
},
|
||||
reg.Order));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,28 +667,6 @@ namespace Robust.Shared.GameObjects
|
||||
reg.Handler(euid, component, ref args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates all subscriptions for an event on a specific entity, returning the component instances and registrations.
|
||||
/// </summary>
|
||||
private bool EntTryGetSubscriptions(Type eventType, EntityUid euid, out SubscriptionsEnumerator enumerator)
|
||||
{
|
||||
if (!_entEventTables.TryGetValue(euid, out var eventTable))
|
||||
{
|
||||
enumerator = default!;
|
||||
return false;
|
||||
}
|
||||
|
||||
// No subscriptions to this event type, return null.
|
||||
if (!eventTable.EventIndices.TryGetValue(eventType, out var startEntry))
|
||||
{
|
||||
enumerator = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
enumerator = new(eventType, startEntry, eventTable.ComponentLists, _eventSubs, euid, _entMan);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ClearSubscriptions()
|
||||
{
|
||||
_subscriptionLock = false;
|
||||
@@ -678,59 +697,6 @@ namespace Robust.Shared.GameObjects
|
||||
_eventSubsInv = null!;
|
||||
}
|
||||
|
||||
private struct SubscriptionsEnumerator
|
||||
{
|
||||
private readonly Type _eventType;
|
||||
private readonly EntityUid _uid;
|
||||
private readonly FrozenDictionary<Type, DirectedRegistration>[] _subscriptions;
|
||||
private readonly IEntityManager _entityManager;
|
||||
private readonly EventTableListEntry[] _list;
|
||||
private int _idx;
|
||||
|
||||
public SubscriptionsEnumerator(
|
||||
Type eventType,
|
||||
int startEntry,
|
||||
EventTableListEntry[] list,
|
||||
FrozenDictionary<Type, DirectedRegistration>[] subscriptions,
|
||||
EntityUid uid,
|
||||
IEntityManager entityManager)
|
||||
{
|
||||
_eventType = eventType;
|
||||
_list = list;
|
||||
_subscriptions = subscriptions;
|
||||
_idx = startEntry;
|
||||
_entityManager = entityManager;
|
||||
_uid = uid;
|
||||
}
|
||||
|
||||
public bool MoveNext(
|
||||
[NotNullWhen(true)] out IComponent? component,
|
||||
[NotNullWhen(true)] out DirectedRegistration? registration)
|
||||
{
|
||||
if (_idx == -1)
|
||||
{
|
||||
component = null;
|
||||
registration = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
ref var entry = ref _list[_idx];
|
||||
_idx = entry.Next;
|
||||
|
||||
var compType = entry.Component;
|
||||
var compSubs = _subscriptions[compType.Value];
|
||||
|
||||
if (!compSubs.TryGetValue(_eventType, out registration))
|
||||
{
|
||||
component = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
component = _entityManager.GetComponentInternal(_uid, compType);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DirectedRegistration : OrderedRegistration
|
||||
{
|
||||
public readonly Delegate Original;
|
||||
@@ -760,7 +726,7 @@ namespace Robust.Shared.GameObjects
|
||||
// Free contains the first free linked list node, or -1 if there is none.
|
||||
// Free nodes form their own linked list.
|
||||
// ComponentList is the actual region of memory containing linked list nodes.
|
||||
public readonly Dictionary<Type, int> EventIndices = new();
|
||||
public readonly Dictionary<Type, (int Start, int Count)> EventIndices = new();
|
||||
public int Free;
|
||||
public EventTableListEntry[] ComponentLists = new EventTableListEntry[InitialListSize];
|
||||
|
||||
|
||||
@@ -35,6 +35,9 @@ namespace Robust.Shared.GameObjects
|
||||
if (broadcast)
|
||||
CollectBroadcastOrdered(EventSource.Local, subs, ref found);
|
||||
|
||||
// TODO PERF
|
||||
// consider ordering the linked list itself?
|
||||
// Then make broadcast events always a lower priority and replace the valuelist with stackalloc?
|
||||
EntCollectOrdered(uid, eventType, ref found);
|
||||
|
||||
DispatchOrderedEvents(ref unitRef, ref found);
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Log;
|
||||
@@ -125,7 +126,7 @@ namespace Robust.Shared.GameObjects
|
||||
foreach (var comp in comps)
|
||||
{
|
||||
if (comp is { LifeStage: ComponentLifeStage.Added })
|
||||
LifeInitialize(comp, CompIdx.Index(comp.GetType()));
|
||||
LifeInitialize(comp, _componentFactory.GetIndex(comp.GetType()));
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
@@ -998,7 +999,7 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
public EntityQuery<IComponent> GetEntityQuery(Type type)
|
||||
{
|
||||
var comps = _entTraitArray[CompIdx.ArrayIndex(type)];
|
||||
var comps = _entTraitDict[type];
|
||||
DebugTools.Assert(comps != null, $"Unknown component: {type.Name}");
|
||||
return new EntityQuery<IComponent>(comps, _resolveSawmill);
|
||||
}
|
||||
@@ -1563,7 +1564,9 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
|
||||
if (logMissing)
|
||||
_sawmill.Error($"Can't resolve \"{typeof(TComp1)}\" on entity {uid}!\n{new StackTrace(1, true)}");
|
||||
{
|
||||
_sawmill.Error($"Can't resolve \"{typeof(TComp1)}\" on entity {uid}!\n{Environment.StackTrace}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -73,12 +73,12 @@ public partial class EntityManager
|
||||
return ents;
|
||||
}
|
||||
|
||||
public virtual EntityUid SpawnAttachedTo(string? protoName, EntityCoordinates coordinates, ComponentRegistry? overrides = null)
|
||||
public virtual EntityUid SpawnAttachedTo(string? protoName, EntityCoordinates coordinates, ComponentRegistry? overrides = null, Angle rotation = default)
|
||||
{
|
||||
if (!coordinates.IsValid(this))
|
||||
throw new InvalidOperationException($"Tried to spawn entity {protoName} on invalid coordinates {coordinates}.");
|
||||
|
||||
var entity = CreateEntityUninitialized(protoName, coordinates, overrides);
|
||||
var entity = CreateEntityUninitialized(protoName, coordinates, overrides, rotation);
|
||||
InitializeAndStartEntity(entity, coordinates.GetMapId(this));
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Robust.Shared.GameObjects;
|
||||
|
||||
public partial class EntityManager
|
||||
{
|
||||
[Pure]
|
||||
public T System<T>() where T : IEntitySystem
|
||||
{
|
||||
return _entitySystemManager.GetEntitySystem<T>();
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public T? SystemOrNull<T>() where T : IEntitySystem
|
||||
{
|
||||
return _entitySystemManager.GetEntitySystemOrNull<T>();
|
||||
|
||||
@@ -296,10 +296,12 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual EntityUid CreateEntityUninitialized(string? prototypeName, EntityCoordinates coordinates, ComponentRegistry? overrides = null)
|
||||
public virtual EntityUid CreateEntityUninitialized(string? prototypeName, EntityCoordinates coordinates, ComponentRegistry? overrides = null, Angle rotation = default)
|
||||
{
|
||||
var newEntity = CreateEntity(prototypeName, out _, overrides);
|
||||
_xforms.SetCoordinates(newEntity, TransformQuery.GetComponent(newEntity), coordinates, unanchor: false);
|
||||
|
||||
var xformComp = TransformQuery.GetComponent(newEntity);
|
||||
_xforms.SetCoordinates(newEntity, xformComp, coordinates, rotation: rotation, unanchor: false);
|
||||
return newEntity;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using TerraFX.Interop.Windows;
|
||||
|
||||
namespace Robust.Shared.GameObjects;
|
||||
|
||||
@@ -76,6 +75,15 @@ public partial class EntitySystem
|
||||
return LifeStage(uid, metaData) >= EntityLifeStage.Terminating;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the entity is being or has been deleted (or never existed in the first place).
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected bool TerminatingOrDeleted(EntityUid? uid, MetaDataComponent? metaData = null)
|
||||
{
|
||||
return !uid.HasValue || TerminatingOrDeleted(uid.Value, metaData);
|
||||
}
|
||||
|
||||
[Obsolete("Use override without the EntityQuery")]
|
||||
protected bool Deleted(EntityUid uid, EntityQuery<MetaDataComponent> metaQuery) => Deleted(uid);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
@@ -26,8 +27,10 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
var found = EntityManager.TryGetComponent(uid, out component);
|
||||
|
||||
if(logMissing && !found)
|
||||
Log.Error($"Can't resolve \"{typeof(TComp)}\" on entity {ToPrettyString(uid)}!\n{new StackTrace(1, true)}");
|
||||
if (logMissing && !found)
|
||||
{
|
||||
Log.Error($"Can't resolve \"{typeof(TComp)}\" on entity {ToPrettyString(uid)}!\n{Environment.StackTrace}");
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Robust.Shared.GameObjects;
|
||||
|
||||
/// <summary>
|
||||
/// Raised directed on an entity when its name is changed.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public readonly record struct EntityRenamedEvent(string NewName);
|
||||
@@ -77,6 +77,18 @@ namespace Robust.Shared.GameObjects
|
||||
/// <returns>The availability of the component.</returns>
|
||||
ComponentAvailability GetComponentAvailability(string componentName, bool ignoreCase = false);
|
||||
|
||||
/// <summary>
|
||||
/// Slow-path for Type -> CompIdx mapping without generics.
|
||||
/// </summary>
|
||||
[Pure]
|
||||
CompIdx GetIndex(Type type);
|
||||
|
||||
/// <summary>
|
||||
/// Slow-path to get the component index for a specified type.
|
||||
/// </summary>
|
||||
[Pure]
|
||||
int GetArrayIndex(Type type);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a component class with the factory.
|
||||
/// </summary>
|
||||
|
||||
@@ -38,7 +38,7 @@ public partial interface IEntityManager
|
||||
/// <summary>
|
||||
/// Spawns an entity and then parents it to the entity that the given entity coordinates are relative to.
|
||||
/// </summary>
|
||||
EntityUid SpawnAttachedTo(string? protoName, EntityCoordinates coordinates, ComponentRegistry? overrides = null);
|
||||
EntityUid SpawnAttachedTo(string? protoName, EntityCoordinates coordinates, ComponentRegistry? overrides = null, Angle rotation = default);
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the given entity coordinates into world coordinates and spawns an entity at that location. The
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Robust.Shared.GameObjects;
|
||||
|
||||
@@ -9,6 +10,7 @@ public partial interface IEntityManager
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of entity system to find.</typeparam>
|
||||
/// <returns>The <see cref="IEntitySystem"/> instance matching the specified type.</returns>
|
||||
[Pure]
|
||||
T System<T>() where T : IEntitySystem;
|
||||
|
||||
/// <summary>
|
||||
@@ -16,6 +18,7 @@ public partial interface IEntityManager
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of entity system to find.</typeparam>
|
||||
/// <returns>The <see cref="IEntitySystem"/> instance matching the specified type, or null.</returns>
|
||||
[Pure]
|
||||
T? SystemOrNull<T>() where T : IEntitySystem;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <param name="coordinates">Coordinates to set position and parent of the newly spawned entity to.</param>
|
||||
/// <param name="overrides"><inheritdoc cref="CreateEntityUninitialized(string?, MapCoordinates , ComponentRegistry?, Angle)"/></param>
|
||||
/// <returns><inheritdoc cref="CreateEntityUninitialized(string?, MapCoordinates , ComponentRegistry?, Angle)"/></returns>
|
||||
EntityUid CreateEntityUninitialized(string? prototypeName, EntityCoordinates coordinates, ComponentRegistry? overrides = null);
|
||||
EntityUid CreateEntityUninitialized(string? prototypeName, EntityCoordinates coordinates, ComponentRegistry? overrides = null, Angle rotation = default);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an uninitialized entity and puts it on the grid or map at the MapCoordinates provided.
|
||||
|
||||
@@ -49,7 +49,7 @@ public readonly struct NetEntity : IEquatable<NetEntity>, IComparable<NetEntity>
|
||||
public static NetEntity Parse(ReadOnlySpan<char> uid)
|
||||
{
|
||||
if (uid.Length == 0)
|
||||
return default;
|
||||
throw new FormatException($"An empty string is not a valid NetEntity");
|
||||
|
||||
if (uid[0] != 'c')
|
||||
return new NetEntity(int.Parse(uid));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user