diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3246875c3..9f4b7fbe0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -48,7 +48,6 @@ /Content.*/Actions/ @ElectroJr /Content.*/Explosion/ @ElectroJr -/Content.IntegrationTests/ @Wrexbe /Content.YAMLLinter @PaulRitter @DrSmugleaf /Content.*/Inventory @PaulRitter /Content.*/Arcade @PaulRitter diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 438fa3c31..577e27a21 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,7 +1,7 @@ contact_links: - name: Report a Security Exploit url: https://discord.gg/MwDDf6t - about: Please report serious security exploits and vulnerabilities to @PJB3005. (PJB#3482 on discord). + about: Please report serious security exploits and vulnerabilities to @PJB3005. (PJB#3005/97089048065097728 on discord). - name: Request a Feature - url: https://hackmd.io/@ss14/docs - about: Submit feature requests on our [discord server](https://discord.gg/ZBFGnb3) or checkout our design documentation on HackMD. + url: https://discord.gg/rGvu9hKffJ + about: Submit feature requests on our [discord server](https://discord.gg/rGvu9hKffJ). diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9f8491fa5..19e9d2de2 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -3,9 +3,20 @@ ## About the PR -**Screenshots** - +**Media** + + +- [ ] I have added screenshots/videos to this PR showcasing its changes ingame, **or** this PR does not require an ingame showcase **Changelog** - - + + + + + + - + diff --git a/Content.Client/Mech/Ui/MechEquipmentControl.xaml.cs b/Content.Client/Mech/Ui/MechEquipmentControl.xaml.cs new file mode 100644 index 000000000..125389047 --- /dev/null +++ b/Content.Client/Mech/Ui/MechEquipmentControl.xaml.cs @@ -0,0 +1,28 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Mech.Ui; + +[GenerateTypedNameReferences] +public sealed partial class MechEquipmentControl : Control +{ + public event Action? OnRemoveButtonPressed; + + public MechEquipmentControl(string itemName, SpriteComponent? sprite, Control? fragment) + { + RobustXamlLoader.Load(this); + EquipmentName.SetMessage(itemName); + EquipmentView.Sprite = sprite; + RemoveButton.TexturePath = "/Textures/Interface/Nano/cross.svg.png"; + + if (fragment != null) + { + Separator.Visible = true; + CustomControlContainer.AddChild(fragment); + } + + RemoveButton.OnPressed += _ => OnRemoveButtonPressed?.Invoke(); + } +} diff --git a/Content.Client/Mech/Ui/MechMenu.xaml b/Content.Client/Mech/Ui/MechMenu.xaml new file mode 100644 index 000000000..2ed82eba1 --- /dev/null +++ b/Content.Client/Mech/Ui/MechMenu.xaml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Content.Client/Mech/Ui/MechMenu.xaml.cs b/Content.Client/Mech/Ui/MechMenu.xaml.cs new file mode 100644 index 000000000..7c757c57f --- /dev/null +++ b/Content.Client/Mech/Ui/MechMenu.xaml.cs @@ -0,0 +1,72 @@ +using Content.Client.UserInterface.Controls; +using Content.Client.UserInterface.Fragments; +using Content.Shared.Mech.Components; +using Robust.Client.AutoGenerated; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Mech.Ui; + +[GenerateTypedNameReferences] +public sealed partial class MechMenu : FancyWindow +{ + [Dependency] private readonly IEntityManager _ent = default!; + + private readonly EntityUid _mech; + + public event Action? OnRemoveButtonPressed; + + public MechMenu(EntityUid mech) + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + + _mech = mech; + + if (!_ent.TryGetComponent(mech, out var sprite)) + return; + + MechView.Sprite = sprite; + } + + public void UpdateMechStats() + { + if (!_ent.TryGetComponent(_mech, out var mechComp)) + return; + + var integrityPercent = mechComp.Integrity / mechComp.MaxIntegrity; + IntegrityDisplayBar.Value = integrityPercent.Float(); + IntegrityDisplay.Text = Loc.GetString("mech-integrity-display", ("amount", (integrityPercent*100).Int())); + + var energyPercent = mechComp.Energy / mechComp.MaxEnergy; + EnergyDisplayBar.Value = energyPercent.Float(); + EnergyDisplay.Text = Loc.GetString("mech-energy-display", ("amount", (energyPercent*100).Int())); + + SlotDisplay.Text = Loc.GetString("mech-slot-display", + ("amount", mechComp.MaxEquipmentAmount - mechComp.EquipmentContainer.ContainedEntities.Count)); + } + + public void UpdateEquipmentView() + { + if (!_ent.TryGetComponent(_mech, out var mechComp)) + return; + + EquipmentControlContainer.Children.Clear(); + foreach (var ent in mechComp.EquipmentContainer.ContainedEntities) + { + if (!_ent.TryGetComponent(ent, out var sprite) || + !_ent.TryGetComponent(ent, out var metaData)) + continue; + + var uicomp = _ent.GetComponentOrNull(ent); + var ui = uicomp?.Ui?.GetUIFragmentRoot(); + + var control = new MechEquipmentControl(metaData.EntityName, sprite, ui); + + control.OnRemoveButtonPressed += () => OnRemoveButtonPressed?.Invoke(ent); + + EquipmentControlContainer.AddChild(control); + } + } +} + diff --git a/Content.Client/Medical/Cryogenics/CryoPodComponent.cs b/Content.Client/Medical/Cryogenics/CryoPodComponent.cs new file mode 100644 index 000000000..79a5d8a5e --- /dev/null +++ b/Content.Client/Medical/Cryogenics/CryoPodComponent.cs @@ -0,0 +1,7 @@ +using Content.Shared.DragDrop; +using Content.Shared.Medical.Cryogenics; + +namespace Content.Client.Medical.Cryogenics; + +[RegisterComponent] +public sealed class CryoPodComponent : SharedCryoPodComponent { } diff --git a/Content.Client/Medical/Cryogenics/CryoPodSystem.cs b/Content.Client/Medical/Cryogenics/CryoPodSystem.cs new file mode 100644 index 000000000..0c6b86aef --- /dev/null +++ b/Content.Client/Medical/Cryogenics/CryoPodSystem.cs @@ -0,0 +1,83 @@ +using Content.Shared.Destructible; +using Content.Shared.Emag.Systems; +using Content.Shared.Medical.Cryogenics; +using Content.Shared.Verbs; +using Robust.Client.GameObjects; +using DrawDepth = Content.Shared.DrawDepth.DrawDepth; + +namespace Content.Client.Medical.Cryogenics; + +public sealed class CryoPodSystem: SharedCryoPodSystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent>(AddAlternativeVerbs); + SubscribeLocalEvent(OnEmagged); + SubscribeLocalEvent(DoInsertCryoPod); + SubscribeLocalEvent(DoInsertCancelCryoPod); + SubscribeLocalEvent(OnCryoPodPryFinished); + SubscribeLocalEvent(OnCryoPodPryInterrupted); + + SubscribeLocalEvent(OnAppearanceChange); + SubscribeLocalEvent(OnCryoPodInsertion); + SubscribeLocalEvent(OnCryoPodRemoval); + } + + private void OnCryoPodInsertion(EntityUid uid, InsideCryoPodComponent component, ComponentStartup args) + { + if (!TryComp(uid, out var spriteComponent)) + { + return; + } + + component.PreviousOffset = spriteComponent.Offset; + spriteComponent.Offset = new Vector2(0, 1); + } + + private void OnCryoPodRemoval(EntityUid uid, InsideCryoPodComponent component, ComponentRemove args) + { + if (!TryComp(uid, out var spriteComponent)) + { + return; + } + + spriteComponent.Offset = component.PreviousOffset; + } + + private void OnAppearanceChange(EntityUid uid, SharedCryoPodComponent component, ref AppearanceChangeEvent args) + { + if (args.Sprite == null) + { + return; + } + + if (!args.Component.TryGetData(SharedCryoPodComponent.CryoPodVisuals.ContainsEntity, out bool isOpen) + || !args.Component.TryGetData(SharedCryoPodComponent.CryoPodVisuals.IsOn, out bool isOn)) + { + return; + } + + if (isOpen) + { + args.Sprite.LayerSetState(CryoPodVisualLayers.Base, "pod-open"); + args.Sprite.LayerSetVisible(CryoPodVisualLayers.Cover, false); + args.Sprite.DrawDepth = (int) DrawDepth.Objects; + } + else + { + args.Sprite.DrawDepth = (int) DrawDepth.Mobs; + args.Sprite.LayerSetState(CryoPodVisualLayers.Base, isOn ? "pod-on" : "pod-off"); + args.Sprite.LayerSetState(CryoPodVisualLayers.Cover, isOn ? "cover-on" : "cover-off"); + args.Sprite.LayerSetVisible(CryoPodVisualLayers.Cover, true); + } + } +} + +public enum CryoPodVisualLayers : byte +{ + Base, + Cover, +} diff --git a/Content.Client/MobState/Overlays/DamageOverlay.cs b/Content.Client/MobState/Overlays/DamageOverlay.cs index 9825d15f9..94e67dfb1 100644 --- a/Content.Client/MobState/Overlays/DamageOverlay.cs +++ b/Content.Client/MobState/Overlays/DamageOverlay.cs @@ -15,7 +15,7 @@ public sealed class DamageOverlay : Overlay [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; - public override OverlaySpace Space => OverlaySpace.ScreenSpace; + public override OverlaySpace Space => OverlaySpace.WorldSpace; private readonly ShaderInstance _critShader; private readonly ShaderInstance _oxygenShader; @@ -71,8 +71,8 @@ protected override void Draw(in OverlayDrawArgs args) * The crit overlay also occasionally reduces its alpha as a "blink" */ - var viewport = args.ViewportBounds; - var handle = args.ScreenHandle; + var viewport = args.WorldAABB; + var handle = args.WorldHandle; var distance = args.ViewportBounds.Width; var time = (float) _timing.RealTime.TotalSeconds; diff --git a/Content.Client/Movement/Components/ClimbableComponent.cs b/Content.Client/Movement/Components/ClimbableComponent.cs deleted file mode 100644 index 1c695ac79..000000000 --- a/Content.Client/Movement/Components/ClimbableComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Content.Client.Movement.Systems; -using Content.Shared.Climbing; - -namespace Content.Client.Movement.Components; - -[RegisterComponent] -[Access(typeof(ClimbSystem))] -[ComponentReference(typeof(SharedClimbableComponent))] -public sealed class ClimbableComponent : SharedClimbableComponent { } diff --git a/Content.Client/Movement/Components/ClimbingComponent.cs b/Content.Client/Movement/Components/ClimbingComponent.cs deleted file mode 100644 index ef5ada952..000000000 --- a/Content.Client/Movement/Components/ClimbingComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Content.Client.Movement.Systems; -using Content.Shared.Climbing; - -namespace Content.Client.Movement.Components; - -[RegisterComponent] -[Access(typeof(ClimbSystem))] -[ComponentReference(typeof(SharedClimbingComponent))] -public sealed class ClimbingComponent : SharedClimbingComponent { } diff --git a/Content.Client/Movement/Systems/ClimbSystem.cs b/Content.Client/Movement/Systems/ClimbSystem.cs index 0354ee020..1f7b757ba 100644 --- a/Content.Client/Movement/Systems/ClimbSystem.cs +++ b/Content.Client/Movement/Systems/ClimbSystem.cs @@ -1,5 +1,4 @@ using Content.Client.Interactable; -using Content.Client.Movement.Components; using Content.Shared.Climbing; using Content.Shared.DragDrop; using Robust.Shared.GameStates; @@ -18,14 +17,14 @@ public override void Initialize() private static void OnClimbingState(EntityUid uid, ClimbingComponent component, ref ComponentHandleState args) { - if (args.Current is not SharedClimbingComponent.ClimbModeComponentState climbModeState) + if (args.Current is not ClimbingComponent.ClimbModeComponentState climbModeState) return; component.IsClimbing = climbModeState.Climbing; component.OwnerIsTransitioning = climbModeState.IsTransitioning; } - protected override void OnCanDragDropOn(EntityUid uid, SharedClimbableComponent component, CanDragDropOnEvent args) + protected override void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, CanDragDropOnEvent args) { base.OnCanDragDropOn(uid, component, args); diff --git a/Content.Client/Movement/Systems/JetpackSystem.cs b/Content.Client/Movement/Systems/JetpackSystem.cs index 02cfb0709..637de44e0 100644 --- a/Content.Client/Movement/Systems/JetpackSystem.cs +++ b/Content.Client/Movement/Systems/JetpackSystem.cs @@ -46,10 +46,11 @@ public override void Update(float frameTime) foreach (var comp in EntityQuery()) { - comp.Accumulator += frameTime; + if (_timing.CurTime < comp.TargetTime) + continue; + + comp.TargetTime = _timing.CurTime + TimeSpan.FromSeconds(comp.EffectCooldown); - if (comp.Accumulator < comp.EffectCooldown) continue; - comp.Accumulator -= comp.EffectCooldown; CreateParticles(comp.Owner); } } @@ -68,7 +69,7 @@ private void CreateParticles(EntityUid uid) if (_mapManager.TryGetGrid(gridUid, out var grid)) { - coordinates = new EntityCoordinates(grid.GridEntityId, grid.WorldToLocal(coordinates.ToMapPos(EntityManager))); + coordinates = new EntityCoordinates(grid.Owner, grid.WorldToLocal(coordinates.ToMapPos(EntityManager))); } else if (uidXform.MapUid != null) { diff --git a/Content.Client/NPC/NPCSteeringComponent.cs b/Content.Client/NPC/NPCSteeringComponent.cs new file mode 100644 index 000000000..3ae227fd7 --- /dev/null +++ b/Content.Client/NPC/NPCSteeringComponent.cs @@ -0,0 +1,14 @@ +namespace Content.Client.NPC; + +[RegisterComponent] +public sealed class NPCSteeringComponent : Component +{ + /* Not hooked up to the server component as it's used for debugging only. + */ + + public Vector2 Direction; + + public float[] DangerMap = Array.Empty(); + public float[] InterestMap = Array.Empty(); + public List DangerPoints = new(); +} diff --git a/Content.Client/NPC/NPCSteeringSystem.cs b/Content.Client/NPC/NPCSteeringSystem.cs new file mode 100644 index 000000000..8bfdcea84 --- /dev/null +++ b/Content.Client/NPC/NPCSteeringSystem.cs @@ -0,0 +1,120 @@ +using Content.Client.Physics.Controllers; +using Content.Shared.Movement.Components; +using Content.Shared.NPC; +using Content.Shared.NPC.Events; +using Robust.Client.Graphics; +using Robust.Shared.Enums; + +namespace Content.Client.NPC; + +public sealed class NPCSteeringSystem : SharedNPCSteeringSystem +{ + [Dependency] private readonly IOverlayManager _overlay = default!; + + public bool DebugEnabled + { + get => _debugEnabled; + set + { + if (_debugEnabled == value) + return; + + _debugEnabled = value; + + if (_debugEnabled) + { + _overlay.AddOverlay(new NPCSteeringOverlay(EntityManager)); + RaiseNetworkEvent(new RequestNPCSteeringDebugEvent() + { + Enabled = true + }); + } + else + { + _overlay.RemoveOverlay(); + RaiseNetworkEvent(new RequestNPCSteeringDebugEvent() + { + Enabled = false + }); + + foreach (var comp in EntityQuery(true)) + { + RemCompDeferred(comp.Owner); + } + } + } + } + + private bool _debugEnabled; + + public override void Initialize() + { + base.Initialize(); + SubscribeNetworkEvent(OnDebugEvent); + } + + private void OnDebugEvent(NPCSteeringDebugEvent ev) + { + if (!DebugEnabled) + return; + + foreach (var data in ev.Data) + { + if (!Exists(data.EntityUid)) + continue; + + var comp = EnsureComp(data.EntityUid); + comp.Direction = data.Direction; + comp.DangerMap = data.Danger; + comp.InterestMap = data.Interest; + comp.DangerPoints = data.DangerPoints; + } + } +} + +public sealed class NPCSteeringOverlay : Overlay +{ + public override OverlaySpace Space => OverlaySpace.WorldSpace; + + private readonly IEntityManager _entManager; + + public NPCSteeringOverlay(IEntityManager entManager) + { + _entManager = entManager; + } + + protected override void Draw(in OverlayDrawArgs args) + { + foreach (var (comp, mover, xform) in _entManager.EntityQuery(true)) + { + if (xform.MapID != args.MapId) + { + continue; + } + + var (worldPos, worldRot) = xform.GetWorldPositionRotation(); + + if (!args.WorldAABB.Contains(worldPos)) + continue; + + args.WorldHandle.DrawCircle(worldPos, 1f, Color.Green, false); + var rotationOffset = _entManager.System().GetParentGridAngle(mover); + + foreach (var point in comp.DangerPoints) + { + args.WorldHandle.DrawCircle(point, 0.1f, Color.Red.WithAlpha(0.6f)); + } + + for (var i = 0; i < SharedNPCSteeringSystem.InterestDirections; i++) + { + var danger = comp.DangerMap[i]; + var interest = comp.InterestMap[i]; + var angle = Angle.FromDegrees(i * (360 / SharedNPCSteeringSystem.InterestDirections)); + args.WorldHandle.DrawLine(worldPos, worldPos + (rotationOffset + angle).RotateVec(new Vector2(interest, 0f)), Color.LimeGreen); + args.WorldHandle.DrawLine(worldPos, worldPos + (rotationOffset + angle).RotateVec(new Vector2(danger, 0f)), Color.Red); + } + + args.WorldHandle.DrawLine(worldPos, worldPos + rotationOffset.RotateVec(comp.Direction), Color.Cyan); + } + } +} diff --git a/Content.Client/NPC/PathfindingSystem.cs b/Content.Client/NPC/PathfindingSystem.cs index 1495f2004..bacf2d250 100644 --- a/Content.Client/NPC/PathfindingSystem.cs +++ b/Content.Client/NPC/PathfindingSystem.cs @@ -164,6 +164,7 @@ private void DrawScreen(OverlayDrawArgs args, DrawingHandleScreen screenHandle) var mousePos = _inputManager.MouseScreenPosition; var mouseWorldPos = _eyeManager.ScreenToMap(mousePos); var aabb = new Box2(mouseWorldPos.Position - SharedPathfindingSystem.ChunkSize, mouseWorldPos.Position + SharedPathfindingSystem.ChunkSize); + var xformQuery = _entManager.GetEntityQuery(); if ((_system.Modes & PathfindingDebugMode.Crumb) != 0x0 && mouseWorldPos.MapId == args.MapId) @@ -172,11 +173,11 @@ private void DrawScreen(OverlayDrawArgs args, DrawingHandleScreen screenHandle) foreach (var grid in _mapManager.FindGridsIntersecting(mouseWorldPos.MapId, aabb)) { - if (found || !_system.Breadcrumbs.TryGetValue(grid.GridEntityId, out var crumbs)) + if (found || !_system.Breadcrumbs.TryGetValue(grid.Owner, out var crumbs) || !xformQuery.TryGetComponent(grid.Owner, out var gridXform)) continue; - var localAABB = grid.InvWorldMatrix.TransformBox(aabb.Enlarged(float.Epsilon - SharedPathfindingSystem.ChunkSize)); - var worldMatrix = grid.WorldMatrix; + var (_, _, worldMatrix, invWorldMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(); + var localAABB = invWorldMatrix.TransformBox(aabb.Enlarged(float.Epsilon - SharedPathfindingSystem.ChunkSize)); foreach (var chunk in crumbs) { @@ -242,12 +243,12 @@ private void DrawScreen(OverlayDrawArgs args, DrawingHandleScreen screenHandle) if ((_system.Modes & PathfindingDebugMode.Poly) != 0x0 && mouseWorldPos.MapId == args.MapId) { - if (!_mapManager.TryFindGridAt(mouseWorldPos, out var grid)) + if (!_mapManager.TryFindGridAt(mouseWorldPos, out var grid) || !xformQuery.TryGetComponent(grid.Owner, out var gridXform)) return; var found = false; - if (!_system.Polys.TryGetValue(grid.GridEntityId, out var data)) + if (!_system.Polys.TryGetValue(grid.Owner, out var data)) return; var tileRef = grid.GetTileRef(mouseWorldPos); @@ -261,7 +262,7 @@ private void DrawScreen(OverlayDrawArgs args, DrawingHandleScreen screenHandle) return; } - var invGridMatrix = grid.InvWorldMatrix; + var invGridMatrix = gridXform.InvWorldMatrix; DebugPathPoly? nearest = null; var nearestDistance = float.MaxValue; @@ -316,17 +317,20 @@ private void DrawWorld(OverlayDrawArgs args, DrawingHandleWorld worldHandle) var mousePos = _inputManager.MouseScreenPosition; var mouseWorldPos = _eyeManager.ScreenToMap(mousePos); var aabb = new Box2(mouseWorldPos.Position - Vector2.One / 4f, mouseWorldPos.Position + Vector2.One / 4f); + var xformQuery = _entManager.GetEntityQuery(); if ((_system.Modes & PathfindingDebugMode.Breadcrumbs) != 0x0 && mouseWorldPos.MapId == args.MapId) { foreach (var grid in _mapManager.FindGridsIntersecting(mouseWorldPos.MapId, aabb)) { - if (!_system.Breadcrumbs.TryGetValue(grid.GridEntityId, out var crumbs)) + if (!_system.Breadcrumbs.TryGetValue(grid.Owner, out var crumbs) || + !xformQuery.TryGetComponent(grid.Owner, out var gridXform)) continue; - worldHandle.SetTransform(grid.WorldMatrix); - var localAABB = grid.InvWorldMatrix.TransformBox(aabb); + var (_, _, worldMatrix, invWorldMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(); + worldHandle.SetTransform(worldMatrix); + var localAABB = invWorldMatrix.TransformBox(aabb); foreach (var chunk in crumbs) { @@ -374,11 +378,13 @@ private void DrawWorld(OverlayDrawArgs args, DrawingHandleWorld worldHandle) { foreach (var grid in _mapManager.FindGridsIntersecting(args.MapId, aabb)) { - if (!_system.Polys.TryGetValue(grid.GridEntityId, out var data)) + if (!_system.Polys.TryGetValue(grid.Owner, out var data) || + !xformQuery.TryGetComponent(grid.Owner, out var gridXform)) continue; - worldHandle.SetTransform(grid.WorldMatrix); - var localAABB = grid.InvWorldMatrix.TransformBox(aabb); + var (_, _, worldMatrix, invWorldMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(); + worldHandle.SetTransform(worldMatrix); + var localAABB = invWorldMatrix.TransformBox(aabb); foreach (var chunk in data) { @@ -406,8 +412,8 @@ private void DrawWorld(OverlayDrawArgs args, DrawingHandleWorld worldHandle) { foreach (var grid in _mapManager.FindGridsIntersecting(args.MapId, aabb)) { - if (!_system.Polys.TryGetValue(grid.GridEntityId, out var data) || - !_entManager.TryGetComponent(grid.GridEntityId, out var gridXform)) + if (!_system.Polys.TryGetValue(grid.Owner, out var data) || + !xformQuery.TryGetComponent(grid.Owner, out var gridXform)) continue; var (_, _, worldMatrix, invMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(); @@ -460,11 +466,13 @@ private void DrawWorld(OverlayDrawArgs args, DrawingHandleWorld worldHandle) { foreach (var grid in _mapManager.FindGridsIntersecting(args.MapId, args.WorldBounds)) { - if (!_system.Breadcrumbs.TryGetValue(grid.GridEntityId, out var crumbs)) + if (!_system.Breadcrumbs.TryGetValue(grid.Owner, out var crumbs) || + !xformQuery.TryGetComponent(grid.Owner, out var gridXform)) continue; - worldHandle.SetTransform(grid.WorldMatrix); - var localAABB = grid.InvWorldMatrix.TransformBox(args.WorldBounds); + var (_, _, worldMatrix, invWorldMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(); + worldHandle.SetTransform(worldMatrix); + var localAABB = invWorldMatrix.TransformBox(args.WorldBounds); foreach (var chunk in crumbs) { diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkOverlay.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkOverlay.cs index 3cd0df721..23404b884 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkOverlay.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkOverlay.cs @@ -2,7 +2,7 @@ using Robust.Client.Graphics; using Robust.Shared.Enums; using Robust.Shared.Random; -using Robust.Shared.Utility; +using Robust.Shared.Map; namespace Content.Client.NetworkConfigurator; @@ -48,6 +48,12 @@ protected override void Draw(in OverlayDrawArgs args) } var sourceTransform = _entityManager.GetComponent(tracker.Owner); + if (sourceTransform.MapID == MapId.Nullspace) + { + // Can happen if the item is outside the client's view. In that case, + // we don't have a sensible transform to draw, so we need to skip it. + continue; + } foreach (var device in _deviceListSystem.GetAllDevices(tracker.Owner, deviceList)) { @@ -57,6 +63,10 @@ protected override void Draw(in OverlayDrawArgs args) } var linkTransform = _entityManager.GetComponent(device); + if (linkTransform.MapID == MapId.Nullspace) + { + continue; + } args.WorldHandle.DrawLine(sourceTransform.WorldPosition, linkTransform.WorldPosition, _colors[tracker.Owner]); } diff --git a/Content.Client/NodeContainer/NodeVisualizationOverlay.cs b/Content.Client/NodeContainer/NodeVisualizationOverlay.cs index 88a1da1ad..cbbe5b978 100644 --- a/Content.Client/NodeContainer/NodeVisualizationOverlay.cs +++ b/Content.Client/NodeContainer/NodeVisualizationOverlay.cs @@ -113,12 +113,12 @@ private void DrawWorld(in OverlayDrawArgs overlayDrawArgs) foreach (var grid in _mapManager.FindGridsIntersecting(map, worldAABB)) { - foreach (var entity in _lookup.GetEntitiesIntersecting(grid.GridEntityId, worldAABB)) + foreach (var entity in _lookup.GetEntitiesIntersecting(grid.Owner, worldAABB)) { if (!_system.Entities.TryGetValue(entity, out var nodeData)) continue; - var gridDict = _gridIndex.GetOrNew(grid.GridEntityId); + var gridDict = _gridIndex.GetOrNew(grid.Owner); var coords = xformQuery.GetComponent(entity).Coordinates; // TODO: This probably shouldn't be capable of returning NaN... @@ -140,7 +140,9 @@ private void DrawWorld(in OverlayDrawArgs overlayDrawArgs) foreach (var (gridId, gridDict) in _gridIndex) { var grid = _mapManager.GetGrid(gridId); - var lCursorBox = grid.InvWorldMatrix.TransformBox(cursorBox); + var (_, _, worldMatrix, invMatrix) = _entityManager.GetComponent(grid.Owner).GetWorldPositionRotationMatrixWithInv(); + + var lCursorBox = invMatrix.TransformBox(cursorBox); foreach (var (pos, list) in gridDict) { var centerPos = (Vector2) pos + grid.TileSize / 2f; @@ -159,7 +161,7 @@ private void DrawWorld(in OverlayDrawArgs overlayDrawArgs) } } - handle.SetTransform(grid.WorldMatrix); + handle.SetTransform(worldMatrix); foreach (var nodeRenderData in _nodeIndex.Values) { diff --git a/Content.Client/Options/UI/Tabs/AudioTab.xaml b/Content.Client/Options/UI/Tabs/AudioTab.xaml index d6da27f63..ccf4d16ed 100644 --- a/Content.Client/Options/UI/Tabs/AudioTab.xaml +++ b/Content.Client/Options/UI/Tabs/AudioTab.xaml @@ -9,7 +9,7 @@ StyleClasses="LabelKeyText"/> -