From 5d970b0861d5c8327ba8e62fd3dd81333dc125af Mon Sep 17 00:00:00 2001 From: MilenVolf <63782763+MilenVolf@users.noreply.github.com> Date: Sat, 1 Jun 2024 23:34:58 +0300 Subject: [PATCH 01/20] Station event component and system tweaks (#28331) * Make anomaly, artifact and gifts events announcement sound optional * Requested changes + Added new "GameRuleAfterAddedEvent" for StationEventSystem We need to call "Add" in "StationEventSystem" after others GameRule's in case if we need to change StationEventComponent variables. * Fix margins * Makes use of GameRuleComponent.Delay and remove station system handling of delays plus small cleanup * Fix merge --------- Co-authored-by: AJCM --- Content.Server/Chat/Systems/ChatSystem.cs | 4 +- .../Components/StationEventComponent.cs | 19 +- .../StationEvents/Events/AnomalySpawnRule.cs | 8 +- .../Events/BluespaceArtifactRule.cs | 8 +- .../StationEvents/Events/BreakerFlipRule.cs | 9 +- .../StationEvents/Events/CargoGiftsRule.cs | 8 +- .../StationEvents/Events/FalseAlarmRule.cs | 15 +- .../StationEvents/Events/GasLeakRule.cs | 4 +- .../Events/StationEventSystem.cs | 20 +- .../SurveillanceCameraMicrophoneSystem.cs | 4 +- .../station-events/events/anomaly-spawn.ftl | 2 +- .../Prototypes/GameRules/cargo_gifts.yml | 294 +++++++++--------- Resources/Prototypes/GameRules/events.yml | 79 +++-- 13 files changed, 244 insertions(+), 230 deletions(-) diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index 531c4259ef..b79e16a8df 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -823,7 +823,7 @@ public sealed partial class ChatSystem : SharedChatSystem recipients.Add(player, new ICChatRecipientData(-1, true)); } - RaiseLocalEvent(new ExpandICChatRecipientstEvent(source, voiceGetRange, recipients)); + RaiseLocalEvent(new ExpandICChatRecipientsEvent(source, voiceGetRange, recipients)); return recipients; } @@ -868,7 +868,7 @@ public sealed partial class ChatSystem : SharedChatSystem /// This event is raised before chat messages are sent out to clients. This enables some systems to send the chat /// messages to otherwise out-of view entities (e.g. for multiple viewports from cameras). /// -public record ExpandICChatRecipientstEvent(EntityUid Source, float VoiceRange, Dictionary Recipients) +public record ExpandICChatRecipientsEvent(EntityUid Source, float VoiceRange, Dictionary Recipients) { } diff --git a/Content.Server/StationEvents/Components/StationEventComponent.cs b/Content.Server/StationEvents/Components/StationEventComponent.cs index cc17007d90..fdd1d3962e 100644 --- a/Content.Server/StationEvents/Components/StationEventComponent.cs +++ b/Content.Server/StationEvents/Components/StationEventComponent.cs @@ -24,6 +24,12 @@ public sealed partial class StationEventComponent : Component [DataField] public string? EndAnnouncement; + [DataField] + public Color StartAnnouncementColor = Color.Gold; + + [DataField] + public Color EndAnnouncementColor = Color.Gold; + [DataField] public SoundSpecifier? StartAudio; @@ -42,12 +48,6 @@ public sealed partial class StationEventComponent : Component [DataField] public int ReoccurrenceDelay = 30; - /// - /// How long after being added does the event start - /// - [DataField] - public TimeSpan StartDelay = TimeSpan.Zero; - /// /// How long the event lasts. /// @@ -75,13 +75,6 @@ public sealed partial class StationEventComponent : Component [DataField] public int? MaxOccurrences; - /// - /// When the station event starts. - /// - [DataField("startTime", customTypeSerializer: typeof(TimeOffsetSerializer))] - [AutoPausedField] - public TimeSpan StartTime; - /// /// When the station event ends. /// diff --git a/Content.Server/StationEvents/Events/AnomalySpawnRule.cs b/Content.Server/StationEvents/Events/AnomalySpawnRule.cs index 96633834ee..cf66a7c052 100644 --- a/Content.Server/StationEvents/Events/AnomalySpawnRule.cs +++ b/Content.Server/StationEvents/Events/AnomalySpawnRule.cs @@ -1,6 +1,5 @@ using Content.Server.Anomaly; using Content.Server.GameTicking.Components; -using Content.Server.GameTicking.Rules.Components; using Content.Server.Station.Components; using Content.Server.StationEvents.Components; @@ -12,11 +11,14 @@ public sealed class AnomalySpawnRule : StationEventSystem(uid, out var stationEvent)) + return; var str = Loc.GetString("anomaly-spawn-event-announcement", ("sighting", Loc.GetString($"anomaly-spawn-sighting-{RobustRandom.Next(1, 6)}"))); - ChatSystem.DispatchGlobalAnnouncement(str, colorOverride: Color.FromHex("#18abf5")); + stationEvent.StartAnnouncement = str; + + base.Added(uid, component, gameRule, args); } protected override void Started(EntityUid uid, AnomalySpawnRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args) diff --git a/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs b/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs index b3ed10999e..aaa0f0cffc 100644 --- a/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs +++ b/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs @@ -1,5 +1,4 @@ using Content.Server.GameTicking.Components; -using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Robust.Shared.Random; @@ -9,11 +8,14 @@ public sealed class BluespaceArtifactRule : StationEventSystem(uid, out var stationEvent)) + return; var str = Loc.GetString("bluespace-artifact-event-announcement", ("sighting", Loc.GetString(RobustRandom.Pick(component.PossibleSighting)))); - ChatSystem.DispatchGlobalAnnouncement(str, colorOverride: Color.FromHex("#18abf5")); + stationEvent.StartAnnouncement = str; + + base.Added(uid, component, gameRule, args); } protected override void Started(EntityUid uid, BluespaceArtifactRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args) diff --git a/Content.Server/StationEvents/Events/BreakerFlipRule.cs b/Content.Server/StationEvents/Events/BreakerFlipRule.cs index 16d3fd8c95..ef28259389 100644 --- a/Content.Server/StationEvents/Events/BreakerFlipRule.cs +++ b/Content.Server/StationEvents/Events/BreakerFlipRule.cs @@ -1,5 +1,4 @@ using Content.Server.GameTicking.Components; -using Content.Server.GameTicking.Rules.Components; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.Station.Components; @@ -15,10 +14,14 @@ public sealed class BreakerFlipRule : StationEventSystem(uid, out var stationEvent)) + return; var str = Loc.GetString("station-event-breaker-flip-announcement", ("data", Loc.GetString(Loc.GetString($"random-sentience-event-data-{RobustRandom.Next(1, 6)}")))); - ChatSystem.DispatchGlobalAnnouncement(str, playSound: false, colorOverride: Color.Gold); + stationEvent.StartAnnouncement = str; + + base.Added(uid, component, gameRule, args); + } protected override void Started(EntityUid uid, BreakerFlipRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args) diff --git a/Content.Server/StationEvents/Events/CargoGiftsRule.cs b/Content.Server/StationEvents/Events/CargoGiftsRule.cs index c27cd30278..4cddf4674b 100644 --- a/Content.Server/StationEvents/Events/CargoGiftsRule.cs +++ b/Content.Server/StationEvents/Events/CargoGiftsRule.cs @@ -3,7 +3,6 @@ using Content.Server.Cargo.Components; using Content.Server.Cargo.Systems; using Content.Server.GameTicking; using Content.Server.GameTicking.Components; -using Content.Server.GameTicking.Rules.Components; using Content.Server.Station.Components; using Content.Server.StationEvents.Components; using Robust.Shared.Prototypes; @@ -18,11 +17,14 @@ public sealed class CargoGiftsRule : StationEventSystem protected override void Added(EntityUid uid, CargoGiftsRuleComponent component, GameRuleComponent gameRule, GameRuleAddedEvent args) { - base.Added(uid, component, gameRule, args); + if (!TryComp(uid, out var stationEvent)) + return; var str = Loc.GetString(component.Announce, ("sender", Loc.GetString(component.Sender)), ("description", Loc.GetString(component.Description)), ("dest", Loc.GetString(component.Dest))); - ChatSystem.DispatchGlobalAnnouncement(str, colorOverride: Color.FromHex("#18abf5")); + stationEvent.StartAnnouncement = str; + + base.Added(uid, component, gameRule, args); } /// diff --git a/Content.Server/StationEvents/Events/FalseAlarmRule.cs b/Content.Server/StationEvents/Events/FalseAlarmRule.cs index e5317a5449..115b6d905e 100644 --- a/Content.Server/StationEvents/Events/FalseAlarmRule.cs +++ b/Content.Server/StationEvents/Events/FalseAlarmRule.cs @@ -1,9 +1,7 @@ using System.Linq; using Content.Server.GameTicking.Components; -using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using JetBrains.Annotations; -using Robust.Shared.Player; using Robust.Shared.Random; namespace Content.Server.StationEvents.Events; @@ -15,15 +13,16 @@ public sealed class FalseAlarmRule : StationEventSystem protected override void Started(EntityUid uid, FalseAlarmRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args) { - base.Started(uid, component, gameRule, args); + if (!TryComp(uid, out var stationEvent)) + return; var allEv = _event.AllEvents().Select(p => p.Value).ToList(); var picked = RobustRandom.Pick(allEv); - if (picked.StartAnnouncement != null) - { - ChatSystem.DispatchGlobalAnnouncement(Loc.GetString(picked.StartAnnouncement), playSound: false, colorOverride: Color.Gold); - } - Audio.PlayGlobal(picked.StartAudio, Filter.Broadcast(), true); + stationEvent.StartAnnouncement = picked.StartAnnouncement; + stationEvent.StartAudio = picked.StartAudio; + stationEvent.StartAnnouncementColor = picked.StartAnnouncementColor; + + base.Started(uid, component, gameRule, args); } } diff --git a/Content.Server/StationEvents/Events/GasLeakRule.cs b/Content.Server/StationEvents/Events/GasLeakRule.cs index 1221612171..c17f17a827 100644 --- a/Content.Server/StationEvents/Events/GasLeakRule.cs +++ b/Content.Server/StationEvents/Events/GasLeakRule.cs @@ -29,10 +29,10 @@ namespace Content.Server.StationEvents.Events component.LeakGas = RobustRandom.Pick(component.LeakableGases); // Was 50-50 on using normal distribution. var totalGas = RobustRandom.Next(component.MinimumGas, component.MaximumGas); - var startAfter = stationEvent.StartDelay; component.MolesPerSecond = RobustRandom.Next(component.MinimumMolesPerSecond, component.MaximumMolesPerSecond); - stationEvent.EndTime = _timing.CurTime + TimeSpan.FromSeconds(totalGas / component.MolesPerSecond + startAfter.TotalSeconds); + if (gameRule.Delay is {} startAfter) + stationEvent.EndTime = _timing.CurTime + TimeSpan.FromSeconds(totalGas / component.MolesPerSecond + startAfter.Next(RobustRandom)); } // Look technically if you wanted to guarantee a leak you'd do this in announcement but having the announcement diff --git a/Content.Server/StationEvents/Events/StationEventSystem.cs b/Content.Server/StationEvents/Events/StationEventSystem.cs index bd377ec16c..38390cedb1 100644 --- a/Content.Server/StationEvents/Events/StationEventSystem.cs +++ b/Content.Server/StationEvents/Events/StationEventSystem.cs @@ -1,14 +1,11 @@ -using System.Linq; using Content.Server.Administration.Logs; using Content.Server.Chat.Systems; using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules; -using Content.Server.GameTicking.Rules.Components; using Content.Server.Station.Systems; using Content.Server.StationEvents.Components; using Content.Shared.Database; using Robust.Shared.Audio.Systems; -using Robust.Shared.Map; using Robust.Shared.Player; using Robust.Shared.Prototypes; @@ -20,7 +17,6 @@ namespace Content.Server.StationEvents.Events; public abstract class StationEventSystem : GameRuleSystem where T : IComponent { [Dependency] protected readonly IAdminLogManager AdminLogManager = default!; - [Dependency] protected readonly IMapManager MapManager = default!; [Dependency] protected readonly IPrototypeManager PrototypeManager = default!; [Dependency] protected readonly ChatSystem ChatSystem = default!; [Dependency] protected readonly SharedAudioSystem Audio = default!; @@ -43,16 +39,12 @@ public abstract class StationEventSystem : GameRuleSystem where T : ICompo if (!TryComp(uid, out var stationEvent)) return; - AdminLogManager.Add(LogType.EventAnnounced, $"Event added / announced: {ToPrettyString(uid)}"); if (stationEvent.StartAnnouncement != null) - { - ChatSystem.DispatchGlobalAnnouncement(Loc.GetString(stationEvent.StartAnnouncement), playSound: false, colorOverride: Color.Gold); - } + ChatSystem.DispatchGlobalAnnouncement(Loc.GetString(stationEvent.StartAnnouncement), playSound: false, colorOverride: stationEvent.StartAnnouncementColor); Audio.PlayGlobal(stationEvent.StartAudio, Filter.Broadcast(), true); - stationEvent.StartTime = Timing.CurTime + stationEvent.StartDelay; } /// @@ -86,9 +78,7 @@ public abstract class StationEventSystem : GameRuleSystem where T : ICompo AdminLogManager.Add(LogType.EventStopped, $"Event ended: {ToPrettyString(uid)}"); if (stationEvent.EndAnnouncement != null) - { - ChatSystem.DispatchGlobalAnnouncement(Loc.GetString(stationEvent.EndAnnouncement), playSound: false, colorOverride: Color.Gold); - } + ChatSystem.DispatchGlobalAnnouncement(Loc.GetString(stationEvent.EndAnnouncement), playSound: false, colorOverride: stationEvent.EndAnnouncementColor); Audio.PlayGlobal(stationEvent.EndAudio, Filter.Broadcast(), true); } @@ -108,11 +98,7 @@ public abstract class StationEventSystem : GameRuleSystem where T : ICompo if (!GameTicker.IsGameRuleAdded(uid, ruleData)) continue; - if (!GameTicker.IsGameRuleActive(uid, ruleData) && Timing.CurTime >= stationEvent.StartTime) - { - GameTicker.StartGameRule(uid, ruleData); - } - else if (stationEvent.EndTime != null && Timing.CurTime >= stationEvent.EndTime && GameTicker.IsGameRuleActive(uid, ruleData)) + if (stationEvent.EndTime != null && Timing.CurTime >= stationEvent.EndTime && GameTicker.IsGameRuleActive(uid, ruleData)) { GameTicker.EndGameRule(uid, ruleData); } diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMicrophoneSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMicrophoneSystem.cs index f411001bd3..1adab9930d 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMicrophoneSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMicrophoneSystem.cs @@ -16,10 +16,10 @@ public sealed class SurveillanceCameraMicrophoneSystem : EntitySystem SubscribeLocalEvent(OnInit); SubscribeLocalEvent(RelayEntityMessage); SubscribeLocalEvent(CanListen); - SubscribeLocalEvent(OnExpandRecipients); + SubscribeLocalEvent(OnExpandRecipients); } - private void OnExpandRecipients(ExpandICChatRecipientstEvent ev) + private void OnExpandRecipients(ExpandICChatRecipientsEvent ev) { var xformQuery = GetEntityQuery(); var sourceXform = Transform(ev.Source); diff --git a/Resources/Locale/en-US/station-events/events/anomaly-spawn.ftl b/Resources/Locale/en-US/station-events/events/anomaly-spawn.ftl index 0e4b5f6e39..907c14ce56 100644 --- a/Resources/Locale/en-US/station-events/events/anomaly-spawn.ftl +++ b/Resources/Locale/en-US/station-events/events/anomaly-spawn.ftl @@ -1,4 +1,4 @@ -anomaly-spawn-event-announcement = Our readings have detected a dangerous interspacial anomaly. Please inform the research team of { $sighting }. +anomaly-spawn-event-announcement = Our readings have detected a dangerous interspacial anomaly. Please inform the research team about { $sighting }. anomaly-spawn-sighting-1 = low pulsating sounds heard throughout the station anomaly-spawn-sighting-2 = strange sources of light diff --git a/Resources/Prototypes/GameRules/cargo_gifts.yml b/Resources/Prototypes/GameRules/cargo_gifts.yml index 62ec96d6a6..c5a5251297 100644 --- a/Resources/Prototypes/GameRules/cargo_gifts.yml +++ b/Resources/Prototypes/GameRules/cargo_gifts.yml @@ -1,16 +1,30 @@ +- type: entity + id: CargoGiftsBase + parent: BaseGameRule + abstract: true + components: + - type: GameRule + delay: + min: 10 + max: 10 + - type: StationEvent + startColor: "#18abf5" + startAudio: + path: /Audio/Announcements/announce.ogg + - type: CargoGiftsRule + sender: cargo-gift-default-sender + - type: entity id: GiftsPizzaPartySmall - parent: BaseGameRule + parent: CargoGiftsBase noSpawn: true components: - type: StationEvent weight: 5 - startDelay: 10 duration: 120 earliestStart: 20 - type: CargoGiftsRule description: cargo-gift-pizza-small - sender: cargo-gift-default-sender dest: cargo-gift-dest-bar gifts: FoodPizza: 1 # 4 pizzas @@ -20,191 +34,173 @@ - type: entity id: GiftsPizzaPartyLarge - parent: BaseGameRule + parent: CargoGiftsBase noSpawn: true components: - - type: StationEvent - weight: 2 - startDelay: 10 - duration: 240 - earliestStart: 20 - minimumPlayers: 40 - - type: CargoGiftsRule - description: cargo-gift-pizza-large - sender: cargo-gift-default-sender - dest: cargo-gift-dest-bar - gifts: - FoodPizzaLarge: 1 # 16 pizzas - FoodBarSupply: 1 - FoodSoftdrinksLarge: 1 + - type: StationEvent + weight: 2 + duration: 240 + earliestStart: 20 + minimumPlayers: 40 + - type: CargoGiftsRule + description: cargo-gift-pizza-large + dest: cargo-gift-dest-bar + gifts: + FoodPizzaLarge: 1 # 16 pizzas + FoodBarSupply: 1 + FoodSoftdrinksLarge: 1 - type: entity id: GiftsEngineering - parent: BaseGameRule + parent: CargoGiftsBase noSpawn: true components: - - type: StationEvent - weight: 5 - startDelay: 10 - duration: 240 - earliestStart: 30 - minimumPlayers: 10 - - type: CargoGiftsRule - description: cargo-gift-eng - sender: cargo-gift-default-sender - dest: cargo-gift-dest-eng - gifts: - EngineeringCableBulk: 1 - AirlockKit: 1 - MaterialSteel: 1 - MaterialPlasteel: 1 - MaterialGlass: 1 - CrateVendingMachineRestockEngineering: 1 + - type: StationEvent + weight: 5 + duration: 240 + earliestStart: 30 + minimumPlayers: 10 + - type: CargoGiftsRule + description: cargo-gift-eng + dest: cargo-gift-dest-eng + gifts: + EngineeringCableBulk: 1 + AirlockKit: 1 + MaterialSteel: 1 + MaterialPlasteel: 1 + MaterialGlass: 1 + CrateVendingMachineRestockEngineering: 1 - type: entity id: GiftsVendingRestock - parent: BaseGameRule + parent: CargoGiftsBase noSpawn: true components: - - type: StationEvent - weight: 4 - startDelay: 10 - duration: 120 - minimumPlayers: 40 - earliestStart: 30 - - type: CargoGiftsRule - description: cargo-gift-vending - sender: cargo-gift-default-sender - dest: cargo-gift-dest-supp - gifts: - CrateVendingMachineRestockHotDrinks: 3 - CrateVendingMachineRestockBooze: 1 - CrateVendingMachineRestockNutriMax: 1 - CrateVendingMachineRestockRobustSoftdrinks: 2 - CrateVendingMachineRestockVendomat: 1 - CrateVendingMachineRestockGetmoreChocolateCorp: 1 + - type: StationEvent + weight: 4 + duration: 120 + minimumPlayers: 40 + earliestStart: 30 + - type: CargoGiftsRule + description: cargo-gift-vending + dest: cargo-gift-dest-supp + gifts: + CrateVendingMachineRestockHotDrinks: 3 + CrateVendingMachineRestockBooze: 1 + CrateVendingMachineRestockNutriMax: 1 + CrateVendingMachineRestockRobustSoftdrinks: 2 + CrateVendingMachineRestockVendomat: 1 + CrateVendingMachineRestockGetmoreChocolateCorp: 1 - type: entity id: GiftsJanitor - parent: BaseGameRule + parent: CargoGiftsBase noSpawn: true components: - - type: StationEvent - weight: 6 - startDelay: 10 - duration: 120 - minimumPlayers: 30 - earliestStart: 20 - - type: CargoGiftsRule - description: cargo-gift-cleaning - sender: cargo-gift-default-sender - dest: cargo-gift-dest-janitor - gifts: - ServiceJanitorial: 2 - ServiceLightsReplacement: 2 - ServiceJanitorBiosuit: 1 + - type: StationEvent + weight: 6 + duration: 120 + minimumPlayers: 30 + earliestStart: 20 + - type: CargoGiftsRule + description: cargo-gift-cleaning + dest: cargo-gift-dest-janitor + gifts: + ServiceJanitorial: 2 + ServiceLightsReplacement: 2 + ServiceJanitorBiosuit: 1 - type: entity id: GiftsMedical - parent: BaseGameRule + parent: CargoGiftsBase noSpawn: true components: - - type: StationEvent - weight: 8 - startDelay: 10 - duration: 120 - earliestStart: 20 - minimumPlayers: 30 - - type: CargoGiftsRule - description: cargo-gift-medical-supply - sender: cargo-gift-default-sender - dest: cargo-gift-dest-med - gifts: - MedicalSupplies: 1 - MedicalChemistrySupplies: 1 - EmergencyBruteKit: 1 - EmergencyAdvancedKit: 1 - MedicalBiosuit: 1 + - type: StationEvent + weight: 8 + duration: 120 + earliestStart: 20 + minimumPlayers: 30 + - type: CargoGiftsRule + description: cargo-gift-medical-supply + dest: cargo-gift-dest-med + gifts: + MedicalSupplies: 1 + MedicalChemistrySupplies: 1 + EmergencyBruteKit: 1 + EmergencyAdvancedKit: 1 + MedicalBiosuit: 1 - type: entity id: GiftsSpacingSupplies - parent: BaseGameRule + parent: CargoGiftsBase noSpawn: true components: - - type: StationEvent - weight: 4 - startDelay: 10 - duration: 120 - earliestStart: 10 - minimumPlayers: 40 - - type: CargoGiftsRule - description: cargo-gift-space-protection - sender: cargo-gift-default-sender - dest: cargo-gift-dest-supp - gifts: - EmergencyInternalsLarge: 2 - EmergencyInflatablewall: 1 - EmergencyAdvancedKit: 1 - MedicalBiosuit: 1 - EmergencyO2Kit: 1 + - type: StationEvent + weight: 4 + duration: 120 + earliestStart: 10 + minimumPlayers: 40 + - type: CargoGiftsRule + description: cargo-gift-space-protection + dest: cargo-gift-dest-supp + gifts: + EmergencyInternalsLarge: 2 + EmergencyInflatablewall: 1 + EmergencyAdvancedKit: 1 + MedicalBiosuit: 1 + EmergencyO2Kit: 1 - type: entity id: GiftsFireProtection - parent: BaseGameRule + parent: CargoGiftsBase noSpawn: true components: - - type: StationEvent - weight: 4 - startDelay: 10 - duration: 120 - earliestStart: 20 - minimumPlayers: 40 - - type: CargoGiftsRule - description: cargo-gift-fire-protection - sender: cargo-gift-default-sender - dest: cargo-gift-dest-supp - gifts: - EmergencyFire: 2 - EmergencyBurnKit: 1 - EmergencyBruteKit: 1 + - type: StationEvent + weight: 4 + duration: 120 + earliestStart: 20 + minimumPlayers: 40 + - type: CargoGiftsRule + description: cargo-gift-fire-protection + dest: cargo-gift-dest-supp + gifts: + EmergencyFire: 2 + EmergencyBurnKit: 1 + EmergencyBruteKit: 1 - type: entity id: GiftsSecurityGuns - parent: BaseGameRule + parent: CargoGiftsBase noSpawn: true components: - - type: StationEvent - weight: 3 - startDelay: 10 - duration: 120 - earliestStart: 20 - minimumPlayers: 50 - - type: CargoGiftsRule - description: cargo-gift-security-guns - sender: cargo-gift-default-sender - dest: cargo-gift-dest-sec - gifts: - SecurityArmor: 3 - ArmorySmg: 1 - ArmoryShotgun: 1 - ArmoryLaser: 1 + - type: StationEvent + weight: 3 + duration: 120 + earliestStart: 20 + minimumPlayers: 50 + - type: CargoGiftsRule + description: cargo-gift-security-guns + dest: cargo-gift-dest-sec + gifts: + SecurityArmor: 3 + ArmorySmg: 1 + ArmoryShotgun: 1 + ArmoryLaser: 1 - type: entity id: GiftsSecurityRiot - parent: BaseGameRule + parent: CargoGiftsBase noSpawn: true components: - - type: StationEvent - weight: 4 - startDelay: 10 - duration: 120 - earliestStart: 20 - minimumPlayers: 50 - - type: CargoGiftsRule - description: cargo-gift-security-riot - sender: cargo-gift-default-sender - dest: cargo-gift-dest-sec - gifts: - SecurityRiot: 2 - SecurityRestraints: 2 - SecurityNonLethal: 2 + - type: StationEvent + weight: 4 + duration: 120 + earliestStart: 20 + minimumPlayers: 50 + - type: CargoGiftsRule + description: cargo-gift-security-riot + dest: cargo-gift-dest-sec + gifts: + SecurityRiot: 2 + SecurityRestraints: 2 + SecurityNonLethal: 2 diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index 9dabc14a34..9f6e6a8125 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -1,22 +1,63 @@ +- type: entity + id: BaseStationEvent + parent: BaseGameRule + abstract: true + noSpawn: true + components: + - type: GameRule + delay: + min: 10 + max: 20 + +- type: entity + id: BaseStationEventShortDelay + parent: BaseGameRule + abstract: true + noSpawn: true + components: + - type: GameRule + delay: + min: 10 + max: 20 + +- type: entity + id: BaseStationEventLongDelay + parent: BaseGameRule + abstract: true + noSpawn: true + components: + - type: GameRule + delay: + min: 40 + max: 60 + - type: entity id: AnomalySpawn - parent: BaseGameRule + parent: BaseStationEventShortDelay noSpawn: true components: - type: StationEvent + startAnnouncementColor: "#18abf5" + startAudio: + path: /Audio/Announcements/announce.ogg weight: 8 - startDelay: 30 duration: 35 - type: AnomalySpawnRule - type: entity id: BluespaceArtifact - parent: BaseGameRule + parent: BaseStationEventShortDelay noSpawn: true components: + - type: GameRule + delay: + min: 30 + max: 30 - type: StationEvent + startAnnouncementColor: "#18abf5" + startAudio: + path: /Audio/Announcements/announce.ogg weight: 8 - startDelay: 30 duration: 35 - type: BluespaceArtifactRule @@ -148,7 +189,7 @@ - type: entity id: GasLeak - parent: BaseGameRule + parent: BaseStationEventShortDelay noSpawn: true components: - type: StationEvent @@ -157,25 +198,23 @@ path: /Audio/Announcements/attention.ogg endAnnouncement: station-event-gas-leak-end-announcement weight: 8 - startDelay: 20 - type: GasLeakRule - type: entity id: KudzuGrowth - parent: BaseGameRule + parent: BaseStationEventLongDelay noSpawn: true components: - type: StationEvent earliestStart: 15 minimumPlayers: 15 weight: 7 - startDelay: 50 duration: 240 - type: KudzuGrowthRule - type: entity id: MeteorSwarm - parent: BaseGameRule + parent: BaseStationEventLongDelay noSpawn: true components: - type: StationEvent @@ -189,19 +228,17 @@ params: volume: -4 duration: null #ending is handled by MeteorSwarmRule - startDelay: 30 - type: MeteorSwarmRule - type: entity id: MouseMigration - parent: BaseGameRule + parent: BaseStationEventShortDelay noSpawn: true components: - type: StationEvent startAnnouncement: station-event-vent-creatures-start-announcement startAudio: path: /Audio/Announcements/attention.ogg - startDelay: 10 earliestStart: 15 weight: 6 duration: 50 @@ -221,14 +258,13 @@ - type: entity id: CockroachMigration - parent: BaseGameRule + parent: BaseStationEventShortDelay noSpawn: true components: - type: StationEvent startAnnouncement: station-event-vent-creatures-start-announcement startAudio: path: /Audio/Announcements/attention.ogg - startDelay: 10 weight: 6 duration: 50 - type: VentCrittersRule @@ -240,7 +276,7 @@ - type: entity id: PowerGridCheck - parent: BaseGameRule + parent: BaseStationEventShortDelay noSpawn: true components: - type: StationEvent @@ -251,7 +287,6 @@ path: /Audio/Announcements/power_off.ogg params: volume: -4 - startDelay: 24 duration: 60 maxDuration: 120 - type: PowerGridCheckRule @@ -300,7 +335,7 @@ - type: entity id: VentClog - parent: BaseGameRule + parent: BaseStationEventLongDelay noSpawn: true components: - type: StationEvent @@ -310,20 +345,18 @@ earliestStart: 15 minimumPlayers: 15 weight: 5 - startDelay: 50 duration: 60 - type: VentClogRule - type: entity id: SlimesSpawn - parent: BaseGameRule + parent: BaseStationEventShortDelay noSpawn: true components: - type: StationEvent startAnnouncement: station-event-vent-creatures-start-announcement startAudio: path: /Audio/Announcements/attention.ogg - startDelay: 10 earliestStart: 20 minimumPlayers: 15 weight: 5 @@ -339,14 +372,13 @@ - type: entity id: SpiderSpawn - parent: BaseGameRule + parent: BaseStationEventShortDelay noSpawn: true components: - type: StationEvent startAnnouncement: station-event-vent-creatures-start-announcement startAudio: path: /Audio/Announcements/attention.ogg - startDelay: 10 earliestStart: 20 minimumPlayers: 15 weight: 5 @@ -358,14 +390,13 @@ - type: entity id: SpiderClownSpawn - parent: BaseGameRule + parent: BaseStationEventShortDelay noSpawn: true components: - type: StationEvent startAnnouncement: station-event-vent-creatures-start-announcement startAudio: path: /Audio/Announcements/attention.ogg - startDelay: 10 earliestStart: 20 minimumPlayers: 20 weight: 1.5 From ad1fc0cdba0f07f45ff18cee46b28738c226a8b4 Mon Sep 17 00:00:00 2001 From: Kevin Zheng Date: Sat, 1 Jun 2024 12:56:57 -0800 Subject: [PATCH 02/20] Adjust power monitor power display (#28487) --- Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs | 4 +++- .../Locale/en-US/components/power-monitoring-component.ftl | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs b/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs index 25a586a75d..1427df0515 100644 --- a/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs +++ b/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs @@ -102,7 +102,8 @@ public sealed partial class PowerMonitoringWindow button.ToolTip = Loc.GetString(name); // Update power value - button.PowerValue.Text = Loc.GetString("power-monitoring-window-value", ("value", entry.PowerValue)); + // Don't use SI prefixes, just give the number in W, so that it is readily apparent which consumer is using a lot of power. + button.PowerValue.Text = Loc.GetString("power-monitoring-window-button-value", ("value", Math.Round(entry.PowerValue).ToString("N0"))); } private void UpdateEntrySourcesOrLoads(BoxContainer masterContainer, BoxContainer currentContainer, PowerMonitoringConsoleEntry[]? entries, SpriteSpecifier.Texture icon) @@ -480,6 +481,7 @@ public sealed class PowerMonitoringButton : Button PowerValue = new Label() { HorizontalAlignment = HAlignment.Right, + Align = Label.AlignMode.Right, SetWidth = 72f, Margin = new Thickness(10, 0, 0, 0), ClipText = true, diff --git a/Resources/Locale/en-US/components/power-monitoring-component.ftl b/Resources/Locale/en-US/components/power-monitoring-component.ftl index e84c09e60d..9433c9ea9e 100644 --- a/Resources/Locale/en-US/components/power-monitoring-component.ftl +++ b/Resources/Locale/en-US/components/power-monitoring-component.ftl @@ -14,6 +14,7 @@ power-monitoring-window-total-sources = Total generator output power-monitoring-window-total-battery-usage = Total battery usage power-monitoring-window-total-loads = Total network loads power-monitoring-window-value = { POWERWATTS($value) } +power-monitoring-window-button-value = {$value} W power-monitoring-window-show-inactive-consumers = Show Inactive Consumers power-monitoring-window-show-cable-networks = Toggle cable networks From 07dfefc4a29927aa74cfd5c7e75c6cb344d713f6 Mon Sep 17 00:00:00 2001 From: Tornado Tech <54727692+Tornado-Technology@users.noreply.github.com> Date: Sun, 2 Jun 2024 09:49:34 +1000 Subject: [PATCH 03/20] Hiding and clearing department prototype code (#28114) --- .../UI/BanPanel/BanPanel.xaml.cs | 2 +- .../Lobby/UI/HumanoidProfileEditor.xaml.cs | 34 ++++++++++++----- .../Conditions/BuyerDepartmentCondition.cs | 4 +- Content.Shared/Roles/DepartmentPrototype.cs | 37 +++++++++++-------- 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/Content.Client/Administration/UI/BanPanel/BanPanel.xaml.cs b/Content.Client/Administration/UI/BanPanel/BanPanel.xaml.cs index dc263d6055..588d62e560 100644 --- a/Content.Client/Administration/UI/BanPanel/BanPanel.xaml.cs +++ b/Content.Client/Administration/UI/BanPanel/BanPanel.xaml.cs @@ -147,7 +147,7 @@ public sealed partial class BanPanel : DefaultWindow var prototypeManager = IoCManager.Resolve(); foreach (var proto in prototypeManager.EnumeratePrototypes()) { - CreateRoleGroup(proto.ID, proto.Roles, proto.Color); + CreateRoleGroup(proto.ID, proto.Roles.Select(p => p.Id), proto.Color); } CreateRoleGroup("Antagonist", prototypeManager.EnumeratePrototypes().Select(p => p.ID), Color.Red); diff --git a/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs index a0e32a3a49..eb182c83ee 100644 --- a/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs @@ -719,8 +719,17 @@ namespace Content.Client.Lobby.UI _jobPriorities.Clear(); var firstCategory = true; - var departments = _prototypeManager.EnumeratePrototypes().ToArray(); - Array.Sort(departments, DepartmentUIComparer.Instance); + // Get all displayed departments + var departments = new List(); + foreach (var department in _prototypeManager.EnumeratePrototypes()) + { + if (department.EditorHidden) + continue; + + departments.Add(department); + } + + departments.Sort(DepartmentUIComparer.Instance); var items = new[] { @@ -774,7 +783,7 @@ namespace Content.Client.Lobby.UI JobList.AddChild(category); } - var jobs = department.Roles.Select(jobId => _prototypeManager.Index(jobId)) + var jobs = department.Roles.Select(jobId => _prototypeManager.Index(jobId)) .Where(job => job.SetPreference) .ToArray(); @@ -821,13 +830,15 @@ namespace Content.Client.Lobby.UI if (jobId == job.ID) { other.Select(selectedPrio); + continue; } - else if (selectedJobPrio == JobPriority.High && (JobPriority) other.Selected == JobPriority.High) - { - // Lower any other high priorities to medium. - other.Select((int) JobPriority.Medium); - Profile = Profile?.WithJobPriority(jobId, JobPriority.Medium); - } + + if (selectedJobPrio != JobPriority.High || (JobPriority) other.Selected != JobPriority.High) + continue; + + // Lower any other high priorities to medium. + other.Select((int)JobPriority.Medium); + Profile = Profile?.WithJobPriority(jobId, JobPriority.Medium); } // TODO: Only reload on high change (either to or from). @@ -932,6 +943,11 @@ namespace Content.Client.Lobby.UI SetDirty(); ReloadPreview(); }; + + if (Profile is null) + return; + + UpdateJobPriorities(); } private void OnFlavorTextChange(string content) diff --git a/Content.Server/Store/Conditions/BuyerDepartmentCondition.cs b/Content.Server/Store/Conditions/BuyerDepartmentCondition.cs index 4e5e504aec..ea8de4a9cc 100644 --- a/Content.Server/Store/Conditions/BuyerDepartmentCondition.cs +++ b/Content.Server/Store/Conditions/BuyerDepartmentCondition.cs @@ -43,7 +43,7 @@ public sealed partial class BuyerDepartmentCondition : ListingCondition { foreach (var department in prototypeManager.EnumeratePrototypes()) { - if (department.Roles.Contains(job.Prototype) && Blacklist.Contains(department.ID)) + if (department.Roles.Contains(job.Prototype.Value) && Blacklist.Contains(department.ID)) return false; } } @@ -56,7 +56,7 @@ public sealed partial class BuyerDepartmentCondition : ListingCondition { foreach (var department in prototypeManager.EnumeratePrototypes()) { - if (department.Roles.Contains(job.Prototype) && Whitelist.Contains(department.ID)) + if (department.Roles.Contains(job.Prototype.Value) && Whitelist.Contains(department.ID)) { found = true; break; diff --git a/Content.Shared/Roles/DepartmentPrototype.cs b/Content.Shared/Roles/DepartmentPrototype.cs index 024eca37fa..d6288bec90 100644 --- a/Content.Shared/Roles/DepartmentPrototype.cs +++ b/Content.Shared/Roles/DepartmentPrototype.cs @@ -1,28 +1,27 @@ using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Shared.Roles; [Prototype("department")] public sealed partial class DepartmentPrototype : IPrototype { - [IdDataField] public string ID { get; } = default!; + [IdDataField] + public string ID { get; } = string.Empty; /// - /// A description string to display in the character menu as an explanation of the department's function. + /// A description string to display in the character menu as an explanation of the department's function. /// - [DataField("description", required: true)] - public string Description = default!; + [DataField(required: true)] + public string Description = string.Empty; /// - /// A color representing this department to use for text. + /// A color representing this department to use for text. /// - [DataField("color", required: true)] - public Color Color = default!; + [DataField(required: true)] + public Color Color; - [ViewVariables(VVAccess.ReadWrite), - DataField("roles", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List Roles = new(); + [DataField, ViewVariables(VVAccess.ReadWrite)] + public List> Roles = new(); /// /// Whether this is a primary department or not. @@ -34,8 +33,14 @@ public sealed partial class DepartmentPrototype : IPrototype /// /// Departments with a higher weight sorted before other departments in UI. /// - [DataField("weight")] - public int Weight { get; private set; } = 0; + [DataField] + public int Weight { get; private set; } + + /// + /// Toggles the display of the department in the priority setting menu in the character editor. + /// + [DataField] + public bool EditorHidden; } /// @@ -50,14 +55,14 @@ public sealed class DepartmentUIComparer : IComparer { if (ReferenceEquals(x, y)) return 0; + if (ReferenceEquals(null, y)) return 1; + if (ReferenceEquals(null, x)) return -1; var cmp = -x.Weight.CompareTo(y.Weight); - if (cmp != 0) - return cmp; - return string.Compare(x.ID, y.ID, StringComparison.Ordinal); + return cmp != 0 ? cmp : string.Compare(x.ID, y.ID, StringComparison.Ordinal); } } From da6a1bbdd4a0d69b101d2c85e858b0b3cbf7d552 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 03:03:51 +0200 Subject: [PATCH 04/20] Update Credits (#28493) Co-authored-by: PJBot --- Resources/Credits/GitHub.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Credits/GitHub.txt b/Resources/Credits/GitHub.txt index b7ec22c0b0..b3627580b1 100644 --- a/Resources/Credits/GitHub.txt +++ b/Resources/Credits/GitHub.txt @@ -1 +1 @@ -0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, Afrokada, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlexUm418, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, Baptr0b0t, BasedUser, beck-thompson, BellwetherLogic, BGare, bhenrich, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, blueDev2, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CakeQ, Callmore, CaptainSqrBeard, Carbonhell, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, Ciac32, clement-or, Clyybber, Cojoke-dot, ColdAutumnRain, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, deepy, Delete69, deltanedas, DerbyX, DexlerXD, Doctor-Cpu, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DoutorWhite, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, DuskyJay, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, freeman2651, Froffy025, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, Ghagliiarghii, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, gusxyz, Gyrandola, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, hitomishirichan, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Huxellberger, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, Jark255, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, K-Dynamic, KaiShibaa, kalane15, kalanosh, KEEYNy, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, LetterN, Level10Cybermancer, lever1209, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, luckyshotpictures, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, Mangohydra, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, MishaUnity, MisterMecky, Mith-randalf, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OctoRocket, OldDanceJacket, onoira, osjarw, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, pigeonpeas, pissdemon, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, PursuitInAshes, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, RumiTiger, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, shampunj, SignalWalker, Simyon264, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, snebl, Snowni, snowsignal, SonicHDC, SoulFN, SoulSloth, SpaceManiac, SpeltIncorrectyl, SphiraI, spoogemonster, ssdaniel24, Stealthbomber16, StrawberryMoses, Subversionary, superjj18, SweptWasTaken, Szunti, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, Terraspark4941, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, TokenStyle, tom-leys, tomasalves8, Tomeno, tosatur, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UBlueberry, UKNOWH, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Vermidia, Verslebas, VigersRay, Visne, volundr-, Voomra, Vordenburg, vulppine, wafehling, waylon531, weaversam8, whateverusername0, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, Zealith-Gamer, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem +0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, Afrokada, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlexUm418, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, Baptr0b0t, BasedUser, beck-thompson, BellwetherLogic, BGare, bhenrich, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, blueDev2, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CakeQ, Callmore, CaptainSqrBeard, Carbonhell, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, Ciac32, clement-or, Clyybber, Cojoke-dot, ColdAutumnRain, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, deepy, Delete69, deltanedas, DerbyX, DexlerXD, Doctor-Cpu, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DoutorWhite, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, DuskyJay, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, freeman2651, Froffy025, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, Ghagliiarghii, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, gusxyz, Gyrandola, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, hitomishirichan, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Huxellberger, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, Jark255, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, K-Dynamic, KaiShibaa, kalane15, kalanosh, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, LetterN, Level10Cybermancer, lever1209, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, luckyshotpictures, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, Mangohydra, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OctoRocket, OldDanceJacket, onoira, osjarw, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, pigeonpeas, pissdemon, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, PursuitInAshes, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, RumiTiger, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, shampunj, SignalWalker, Simyon264, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, snebl, Snowni, snowsignal, SonicHDC, SoulFN, SoulSloth, SpaceManiac, SpeltIncorrectyl, SphiraI, spoogemonster, ssdaniel24, Stealthbomber16, StrawberryMoses, superjj18, SweptWasTaken, Szunti, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, Terraspark4941, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, TokenStyle, tom-leys, tomasalves8, Tomeno, Tornado-Technology, tosatur, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UBlueberry, UKNOWH, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Vermidia, Verslebas, VigersRay, Visne, volundr-, Voomra, Vordenburg, vulppine, wafehling, waylon531, weaversam8, whateverusername0, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, Zealith-Gamer, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem From 21bc3bfa22b6e234a8ae96c3332bffee6840a66f Mon Sep 17 00:00:00 2001 From: Tornado Tech <54727692+Tornado-Technology@users.noreply.github.com> Date: Sun, 2 Jun 2024 11:11:19 +1000 Subject: [PATCH 05/20] Cleans up tag system (#28272) * Updated tag system * Added params methods * Fixed tag integration tests * Fixed params methods recursion * Revert has All/Any tag one argument realisation * Updated tag integration tests * Shit happens * Added individual List/HashSet methods, docs, tests --- Content.Client/Verbs/VerbSystem.cs | 3 +- Content.IntegrationTests/Tests/Tag/TagTest.cs | 161 +- .../Administration/Toolshed/TagCommand.cs | 11 +- .../Mech/Systems/MechAssemblySystem.cs | 3 +- .../Procedural/DungeonJob.PostGen.cs | 5 +- Content.Server/Procedural/DungeonJob.cs | 5 +- Content.Server/Procedural/DungeonSystem.cs | 4 + .../EntitySystems/RevenantSystem.Abilities.cs | 2 +- Content.Server/Spreader/SpreaderSystem.cs | 10 +- .../SharedChameleonClothingSystem.cs | 5 +- .../Conditions/NoWindowsInTile.cs | 3 +- .../EntitySystems/AnchorableSystem.cs | 11 +- .../MultipleTagsConstructionGraphStep.cs | 13 +- .../Pinpointer/SharedNavMapSystem.cs | 5 +- Content.Shared/Tag/TagComponent.cs | 16 +- Content.Shared/Tag/TagComponentState.cs | 15 - Content.Shared/Tag/TagPrototype.cs | 24 +- Content.Shared/Tag/TagSystem.cs | 1318 +++++++++-------- 18 files changed, 834 insertions(+), 780 deletions(-) delete mode 100644 Content.Shared/Tag/TagComponentState.cs diff --git a/Content.Client/Verbs/VerbSystem.cs b/Content.Client/Verbs/VerbSystem.cs index 2e6c5f5809..5f1f49e5fd 100644 --- a/Content.Client/Verbs/VerbSystem.cs +++ b/Content.Client/Verbs/VerbSystem.cs @@ -123,7 +123,6 @@ namespace Content.Client.Verbs if ((visibility & MenuVisibility.Invisible) == 0) { var spriteQuery = GetEntityQuery(); - var tagQuery = GetEntityQuery(); for (var i = entities.Count - 1; i >= 0; i--) { @@ -131,7 +130,7 @@ namespace Content.Client.Verbs if (!spriteQuery.TryGetComponent(entity, out var spriteComponent) || !spriteComponent.Visible || - _tagSystem.HasTag(entity, "HideContextMenu", tagQuery)) + _tagSystem.HasTag(entity, "HideContextMenu")) { entities.RemoveSwap(i); } diff --git a/Content.IntegrationTests/Tests/Tag/TagTest.cs b/Content.IntegrationTests/Tests/Tag/TagTest.cs index cbcdd1c6c6..e6cd2accaf 100644 --- a/Content.IntegrationTests/Tests/Tag/TagTest.cs +++ b/Content.IntegrationTests/Tests/Tag/TagTest.cs @@ -53,11 +53,13 @@ namespace Content.IntegrationTests.Tests.Tag EntityUid sTagDummy = default; TagComponent sTagComponent = null!; + Entity sTagEntity = default; await server.WaitPost(() => { sTagDummy = sEntityManager.SpawnEntity(TagEntityId, MapCoordinates.Nullspace); sTagComponent = sEntityManager.GetComponent(sTagDummy); + sTagEntity = new Entity(sTagDummy, sTagComponent); }); await server.WaitAssertion(() => @@ -130,49 +132,64 @@ namespace Content.IntegrationTests.Tests.Tag Assert.Multiple(() => { // Cannot add the starting tag again - Assert.That(tagSystem.AddTag(sTagDummy, sTagComponent, StartingTag), Is.False); - Assert.That(tagSystem.AddTags(sTagDummy, sTagComponent, StartingTag, StartingTag), Is.False); - Assert.That(tagSystem.AddTags(sTagDummy, sTagComponent, new List { StartingTag, StartingTag }), Is.False); + Assert.That(tagSystem.AddTag(sTagEntity, StartingTag), Is.False); + + Assert.That(tagSystem.AddTags(sTagEntity, StartingTag, StartingTag), Is.False); + Assert.That(tagSystem.AddTags(sTagEntity, new List> { StartingTag, StartingTag }), Is.False); + Assert.That(tagSystem.AddTags(sTagEntity, new HashSet> { StartingTag, StartingTag }), Is.False); // Has the starting tag Assert.That(tagSystem.HasTag(sTagComponent, StartingTag), Is.True); + Assert.That(tagSystem.HasAllTags(sTagComponent, StartingTag, StartingTag), Is.True); - Assert.That(tagSystem.HasAllTags(sTagComponent, new List { StartingTag, StartingTag }), Is.True); + Assert.That(tagSystem.HasAllTags(sTagComponent, new List> { StartingTag, StartingTag }), Is.True); + Assert.That(tagSystem.HasAllTags(sTagComponent, new HashSet> { StartingTag, StartingTag }), Is.True); + Assert.That(tagSystem.HasAnyTag(sTagComponent, StartingTag, StartingTag), Is.True); - Assert.That(tagSystem.HasAnyTag(sTagComponent, new List { StartingTag, StartingTag }), Is.True); + Assert.That(tagSystem.HasAnyTag(sTagComponent, new List> { StartingTag, StartingTag }), Is.True); + Assert.That(tagSystem.HasAnyTag(sTagComponent, new HashSet> { StartingTag, StartingTag }), Is.True); // Does not have the added tag yet Assert.That(tagSystem.HasTag(sTagComponent, AddedTag), Is.False); + Assert.That(tagSystem.HasAllTags(sTagComponent, AddedTag, AddedTag), Is.False); - Assert.That(tagSystem.HasAllTags(sTagComponent, new List { AddedTag, AddedTag }), Is.False); + Assert.That(tagSystem.HasAllTags(sTagComponent, new List> { AddedTag, AddedTag }), Is.False); + Assert.That(tagSystem.HasAllTags(sTagComponent, new HashSet> { AddedTag, AddedTag }), Is.False); + Assert.That(tagSystem.HasAnyTag(sTagComponent, AddedTag, AddedTag), Is.False); - Assert.That(tagSystem.HasAnyTag(sTagComponent, new List { AddedTag, AddedTag }), Is.False); + Assert.That(tagSystem.HasAnyTag(sTagComponent, new List> { AddedTag, AddedTag }), Is.False); + Assert.That(tagSystem.HasAnyTag(sTagComponent, new HashSet> { AddedTag, AddedTag }), Is.False); // Has a combination of the two tags Assert.That(tagSystem.HasAnyTag(sTagComponent, StartingTag, AddedTag), Is.True); - Assert.That(tagSystem.HasAnyTag(sTagComponent, new List { StartingTag, AddedTag }), Is.True); + Assert.That(tagSystem.HasAnyTag(sTagComponent, new List> { StartingTag, AddedTag }), Is.True); + Assert.That(tagSystem.HasAnyTag(sTagComponent, new HashSet> { StartingTag, AddedTag }), Is.True); // Does not have both tags Assert.That(tagSystem.HasAllTags(sTagComponent, StartingTag, AddedTag), Is.False); - Assert.That(tagSystem.HasAllTags(sTagComponent, new List { StartingTag, AddedTag }), Is.False); + Assert.That(tagSystem.HasAllTags(sTagComponent, new List> { StartingTag, AddedTag }), Is.False); + Assert.That(tagSystem.HasAllTags(sTagComponent, new HashSet> { StartingTag, AddedTag }), Is.False); // Cannot remove a tag that does not exist - Assert.That(tagSystem.RemoveTag(sTagDummy, sTagComponent, AddedTag), Is.False); - Assert.That(tagSystem.RemoveTags(sTagDummy, sTagComponent, AddedTag, AddedTag), Is.False); - Assert.That(tagSystem.RemoveTags(sTagDummy, sTagComponent, new List { AddedTag, AddedTag }), Is.False); + Assert.That(tagSystem.RemoveTag(sTagEntity, AddedTag), Is.False); + + Assert.That(tagSystem.RemoveTags(sTagEntity, AddedTag, AddedTag), Is.False); + Assert.That(tagSystem.RemoveTags(sTagEntity, new List> { AddedTag, AddedTag }), Is.False); + Assert.That(tagSystem.RemoveTags(sTagEntity, new HashSet> { AddedTag, AddedTag }), Is.False); }); // Can add the new tag - Assert.That(tagSystem.AddTag(sTagDummy, sTagComponent, AddedTag), Is.True); + Assert.That(tagSystem.AddTag(sTagEntity, AddedTag), Is.True); Assert.Multiple(() => { // Cannot add it twice - Assert.That(tagSystem.AddTag(sTagDummy, sTagComponent, AddedTag), Is.False); + Assert.That(tagSystem.AddTag(sTagEntity, AddedTag), Is.False); // Cannot add existing tags - Assert.That(tagSystem.AddTags(sTagDummy, sTagComponent, StartingTag, AddedTag), Is.False); - Assert.That(tagSystem.AddTags(sTagDummy, sTagComponent, new List { StartingTag, AddedTag }), Is.False); + Assert.That(tagSystem.AddTags(sTagEntity, StartingTag, AddedTag), Is.False); + Assert.That(tagSystem.AddTags(sTagEntity, new List> { StartingTag, AddedTag }), Is.False); + Assert.That(tagSystem.AddTags(sTagEntity, new HashSet> { StartingTag, AddedTag }), Is.False); // Now has two tags Assert.That(sTagComponent.Tags, Has.Count.EqualTo(2)); @@ -180,65 +197,103 @@ namespace Content.IntegrationTests.Tests.Tag // Has both tags Assert.That(tagSystem.HasTag(sTagComponent, StartingTag), Is.True); Assert.That(tagSystem.HasTag(sTagComponent, AddedTag), Is.True); + Assert.That(tagSystem.HasAllTags(sTagComponent, StartingTag, StartingTag), Is.True); Assert.That(tagSystem.HasAllTags(sTagComponent, AddedTag, StartingTag), Is.True); - Assert.That(tagSystem.HasAllTags(sTagComponent, new List { StartingTag, AddedTag }), Is.True); - Assert.That(tagSystem.HasAllTags(sTagComponent, new List { AddedTag, StartingTag }), Is.True); + Assert.That(tagSystem.HasAllTags(sTagComponent, new List> { StartingTag, AddedTag }), Is.True); + Assert.That(tagSystem.HasAllTags(sTagComponent, new List> { AddedTag, StartingTag }), Is.True); + Assert.That(tagSystem.HasAllTags(sTagComponent, new HashSet> { StartingTag, AddedTag }), Is.True); + Assert.That(tagSystem.HasAllTags(sTagComponent, new HashSet> { AddedTag, StartingTag }), Is.True); + Assert.That(tagSystem.HasAnyTag(sTagComponent, StartingTag, AddedTag), Is.True); Assert.That(tagSystem.HasAnyTag(sTagComponent, AddedTag, StartingTag), Is.True); + Assert.That(tagSystem.HasAnyTag(sTagComponent, new List> { StartingTag, AddedTag }), Is.True); + Assert.That(tagSystem.HasAnyTag(sTagComponent, new List> { AddedTag, StartingTag }), Is.True); + Assert.That(tagSystem.HasAnyTag(sTagComponent, new HashSet> { StartingTag, AddedTag }), Is.True); + Assert.That(tagSystem.HasAnyTag(sTagComponent, new HashSet> { AddedTag, StartingTag }), Is.True); }); Assert.Multiple(() => { // Remove the existing starting tag - Assert.That(tagSystem.RemoveTag(sTagDummy, sTagComponent, StartingTag), Is.True); + Assert.That(tagSystem.RemoveTag(sTagEntity, StartingTag), Is.True); // Remove the existing added tag - Assert.That(tagSystem.RemoveTags(sTagDummy, sTagComponent, AddedTag, AddedTag), Is.True); + Assert.That(tagSystem.RemoveTags(sTagEntity, AddedTag, AddedTag), Is.True); }); Assert.Multiple(() => { // No tags left to remove - Assert.That(tagSystem.RemoveTags(sTagDummy, sTagComponent, new List { StartingTag, AddedTag }), Is.False); + Assert.That(tagSystem.RemoveTags(sTagEntity, new List> { StartingTag, AddedTag }), Is.False); // No tags left in the component Assert.That(sTagComponent.Tags, Is.Empty); }); -#if !DEBUG - return; + // It is run only in DEBUG build, + // as the checks are performed only in DEBUG build. +#if DEBUG + // Has single + Assert.Throws(() => { tagSystem.HasTag(sTagDummy, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.HasTag(sTagComponent, UnregisteredTag); }); + + // HasAny entityUid methods + Assert.Throws(() => { tagSystem.HasAnyTag(sTagDummy, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.HasAnyTag(sTagDummy, UnregisteredTag, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.HasAnyTag(sTagDummy, new List> { UnregisteredTag }); }); + Assert.Throws(() => { tagSystem.HasAnyTag(sTagDummy, new HashSet> { UnregisteredTag }); }); + + // HasAny component methods + Assert.Throws(() => { tagSystem.HasAnyTag(sTagComponent, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.HasAnyTag(sTagComponent, UnregisteredTag, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.HasAnyTag(sTagComponent, new List> { UnregisteredTag }); }); + Assert.Throws(() => { tagSystem.HasAnyTag(sTagComponent, new HashSet> { UnregisteredTag }); }); + + // HasAll entityUid methods + Assert.Throws(() => { tagSystem.HasAllTags(sTagDummy, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.HasAllTags(sTagDummy, UnregisteredTag, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.HasAllTags(sTagDummy, new List> { UnregisteredTag }); }); + Assert.Throws(() => { tagSystem.HasAllTags(sTagDummy, new HashSet> { UnregisteredTag }); }); + + // HasAll component methods + Assert.Throws(() => { tagSystem.HasAllTags(sTagComponent, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.HasAllTags(sTagComponent, UnregisteredTag, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.HasAllTags(sTagComponent, new List> { UnregisteredTag }); }); + Assert.Throws(() => { tagSystem.HasAllTags(sTagComponent, new HashSet> { UnregisteredTag }); }); + + // RemoveTag single + Assert.Throws(() => { tagSystem.RemoveTag(sTagDummy, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.RemoveTag(sTagEntity, UnregisteredTag); }); + + // RemoveTags entityUid methods + Assert.Throws(() => { tagSystem.RemoveTags(sTagDummy, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.RemoveTags(sTagDummy, UnregisteredTag, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.RemoveTags(sTagDummy, new List> { UnregisteredTag }); }); + Assert.Throws(() => { tagSystem.RemoveTags(sTagDummy, new HashSet> { UnregisteredTag }); }); + + // RemoveTags entity methods + Assert.Throws(() => { tagSystem.RemoveTags(sTagEntity, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.RemoveTags(sTagEntity, UnregisteredTag, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.RemoveTags(sTagEntity, new List> { UnregisteredTag }); }); + Assert.Throws(() => { tagSystem.RemoveTags(sTagEntity, new HashSet> { UnregisteredTag }); }); + + // AddTag single + Assert.Throws(() => { tagSystem.AddTag(sTagDummy, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.AddTag(sTagEntity, UnregisteredTag); }); + + // AddTags entityUid methods + Assert.Throws(() => { tagSystem.AddTags(sTagDummy, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.AddTags(sTagDummy, UnregisteredTag, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.AddTags(sTagDummy, new List> { UnregisteredTag }); }); + Assert.Throws(() => { tagSystem.AddTags(sTagDummy, new HashSet> { UnregisteredTag }); }); + + // AddTags entity methods + Assert.Throws(() => { tagSystem.AddTags(sTagEntity, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.AddTags(sTagEntity, UnregisteredTag, UnregisteredTag); }); + Assert.Throws(() => { tagSystem.AddTags(sTagEntity, new List> { UnregisteredTag }); }); + Assert.Throws(() => { tagSystem.AddTags(sTagEntity, new HashSet> { UnregisteredTag }); }); #endif - - // Single - Assert.Throws(() => - { - tagSystem.HasTag(sTagDummy, UnregisteredTag); - }); - Assert.Throws(() => - { - tagSystem.HasTag(sTagComponent, UnregisteredTag); - }); - - // Any - Assert.Throws(() => - { - tagSystem.HasAnyTag(sTagDummy, UnregisteredTag); - }); - Assert.Throws(() => - { - tagSystem.HasAnyTag(sTagComponent, UnregisteredTag); - }); - - // All - Assert.Throws(() => - { - tagSystem.HasAllTags(sTagDummy, UnregisteredTag); - }); - Assert.Throws(() => - { - tagSystem.HasAllTags(sTagComponent, UnregisteredTag); - }); }); await pair.CleanReturnAsync(); } diff --git a/Content.Server/Administration/Toolshed/TagCommand.cs b/Content.Server/Administration/Toolshed/TagCommand.cs index 1af2779766..e1cf53e1b1 100644 --- a/Content.Server/Administration/Toolshed/TagCommand.cs +++ b/Content.Server/Administration/Toolshed/TagCommand.cs @@ -1,6 +1,7 @@ using System.Linq; using Content.Shared.Administration; using Content.Shared.Tag; +using Robust.Shared.Prototypes; using Robust.Shared.Toolshed; using Robust.Shared.Toolshed.Syntax; using Robust.Shared.Toolshed.TypeParsers; @@ -13,14 +14,14 @@ public sealed class TagCommand : ToolshedCommand private TagSystem? _tag; [CommandImplementation("list")] - public IEnumerable List([PipedArgument] IEnumerable ent) + public IEnumerable> List([PipedArgument] IEnumerable ent) { return ent.SelectMany(x => { if (TryComp(x, out var tags)) // Note: Cast is required for C# to figure out the type signature. - return (IEnumerable)tags.Tags; - return Array.Empty(); + return (IEnumerable>)tags.Tags; + return Array.Empty>(); }); } @@ -72,7 +73,7 @@ public sealed class TagCommand : ToolshedCommand ) { _tag ??= GetSys(); - _tag.AddTags(input, @ref.Evaluate(ctx)!); + _tag.AddTags(input, (IEnumerable>)@ref.Evaluate(ctx)!); return input; } @@ -92,7 +93,7 @@ public sealed class TagCommand : ToolshedCommand ) { _tag ??= GetSys(); - _tag.RemoveTags(input, @ref.Evaluate(ctx)!); + _tag.RemoveTags(input, (IEnumerable>)@ref.Evaluate(ctx)!); return input; } diff --git a/Content.Server/Mech/Systems/MechAssemblySystem.cs b/Content.Server/Mech/Systems/MechAssemblySystem.cs index e5b7bfaac3..c1fff819b4 100644 --- a/Content.Server/Mech/Systems/MechAssemblySystem.cs +++ b/Content.Server/Mech/Systems/MechAssemblySystem.cs @@ -14,6 +14,7 @@ namespace Content.Server.Mech.Systems; public sealed class MechAssemblySystem : EntitySystem { [Dependency] private readonly ContainerSystem _container = default!; + [Dependency] private readonly TagSystem _tag = default!; /// public override void Initialize() @@ -44,7 +45,7 @@ public sealed class MechAssemblySystem : EntitySystem foreach (var (tag, val) in component.RequiredParts) { - if (!val && tagComp.Tags.Contains(tag)) + if (!val && _tag.HasTag(tagComp, tag)) { component.RequiredParts[tag] = true; _container.Insert(args.Used, component.PartsContainer); diff --git a/Content.Server/Procedural/DungeonJob.PostGen.cs b/Content.Server/Procedural/DungeonJob.PostGen.cs index b326bcc378..cb9e64f04e 100644 --- a/Content.Server/Procedural/DungeonJob.PostGen.cs +++ b/Content.Server/Procedural/DungeonJob.PostGen.cs @@ -13,6 +13,7 @@ using Robust.Shared.Collections; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; +using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Utility; @@ -24,13 +25,15 @@ public sealed partial class DungeonJob * Run after the main dungeon generation */ + private static readonly ProtoId WallTag = "Wall"; + private bool HasWall(MapGridComponent grid, Vector2i tile) { var anchored = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile); while (anchored.MoveNext(out var uid)) { - if (_tagQuery.TryGetComponent(uid, out var tagComp) && tagComp.Tags.Contains("Wall")) + if (_tag.HasTag(uid.Value, WallTag)) return true; } diff --git a/Content.Server/Procedural/DungeonJob.cs b/Content.Server/Procedural/DungeonJob.cs index 8fecf1c9e8..bf2822ff42 100644 --- a/Content.Server/Procedural/DungeonJob.cs +++ b/Content.Server/Procedural/DungeonJob.cs @@ -28,10 +28,10 @@ public sealed partial class DungeonJob : Job private readonly DecalSystem _decals; private readonly DungeonSystem _dungeon; private readonly EntityLookupSystem _lookup; + private readonly TagSystem _tag; private readonly TileSystem _tile; private readonly SharedMapSystem _maps; private readonly SharedTransformSystem _transform; - private EntityQuery _tagQuery; private readonly DungeonConfigPrototype _gen; private readonly int _seed; @@ -53,6 +53,7 @@ public sealed partial class DungeonJob : Job DecalSystem decals, DungeonSystem dungeon, EntityLookupSystem lookup, + TagSystem tag, TileSystem tile, SharedTransformSystem transform, DungeonConfigPrototype gen, @@ -72,10 +73,10 @@ public sealed partial class DungeonJob : Job _decals = decals; _dungeon = dungeon; _lookup = lookup; + _tag = tag; _tile = tile; _maps = _entManager.System(); _transform = transform; - _tagQuery = _entManager.GetEntityQuery(); _gen = gen; _grid = grid; diff --git a/Content.Server/Procedural/DungeonSystem.cs b/Content.Server/Procedural/DungeonSystem.cs index 069508bcbb..36009896a2 100644 --- a/Content.Server/Procedural/DungeonSystem.cs +++ b/Content.Server/Procedural/DungeonSystem.cs @@ -10,6 +10,7 @@ using Content.Shared.GameTicking; using Content.Shared.Maps; using Content.Shared.Physics; using Content.Shared.Procedural; +using Content.Shared.Tag; using Robust.Server.GameObjects; using Robust.Shared.Configuration; using Robust.Shared.Console; @@ -31,6 +32,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem [Dependency] private readonly AnchorableSystem _anchorable = default!; [Dependency] private readonly DecalSystem _decals = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly TagSystem _tag = default!; [Dependency] private readonly TileSystem _tile = default!; [Dependency] private readonly MapLoaderSystem _loader = default!; [Dependency] private readonly SharedMapSystem _maps = default!; @@ -199,6 +201,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem _decals, this, _lookup, + _tag, _tile, _transform, gen, @@ -231,6 +234,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem _decals, this, _lookup, + _tag, _tile, _transform, gen, diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs index fd7d15ea5d..670c64577a 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs @@ -246,7 +246,7 @@ public sealed partial class RevenantSystem foreach (var ent in lookup) { //break windows - if (tags.HasComponent(ent) && _tag.HasAnyTag(ent, "Window")) + if (tags.HasComponent(ent) && _tag.HasTag(ent, "Window")) { //hardcoded damage specifiers til i die. var dspec = new DamageSpecifier(); diff --git a/Content.Server/Spreader/SpreaderSystem.cs b/Content.Server/Spreader/SpreaderSystem.cs index fe14d86aa1..7de8a43d35 100644 --- a/Content.Server/Spreader/SpreaderSystem.cs +++ b/Content.Server/Spreader/SpreaderSystem.cs @@ -21,6 +21,7 @@ public sealed class SpreaderSystem : EntitySystem [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly SharedMapSystem _map = default!; + [Dependency] private readonly TagSystem _tag = default!; /// /// Cached maximum number of updates per spreader prototype. This is applied per-grid. @@ -37,8 +38,7 @@ public sealed class SpreaderSystem : EntitySystem public const float SpreadCooldownSeconds = 1; - [ValidatePrototypeId] - private const string IgnoredTag = "SpreaderIgnore"; + private static readonly ProtoId IgnoredTag = "SpreaderIgnore"; /// public override void Initialize() @@ -189,7 +189,6 @@ public sealed class SpreaderSystem : EntitySystem var airtightQuery = GetEntityQuery(); var dockQuery = GetEntityQuery(); var xformQuery = GetEntityQuery(); - var tagQuery = GetEntityQuery(); var blockedAtmosDirs = AtmosDirection.Invalid; // Due to docking ports they may not necessarily be opposite directions. @@ -212,7 +211,7 @@ public sealed class SpreaderSystem : EntitySystem // If we're on a blocked tile work out which directions we can go. if (!airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked || - tagQuery.TryGetComponent(ent, out var tags) && tags.Tags.Contains(IgnoredTag)) + _tag.HasTag(ent.Value, IgnoredTag)) { continue; } @@ -250,8 +249,7 @@ public sealed class SpreaderSystem : EntitySystem while (directionEnumerator.MoveNext(out var ent)) { - if (!airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked || - tagQuery.TryGetComponent(ent, out var tags) && tags.Tags.Contains(IgnoredTag)) + if (!airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked || _tag.HasTag(ent.Value, IgnoredTag)) { continue; } diff --git a/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs index a447a54df1..fced03bfab 100644 --- a/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs @@ -12,9 +12,10 @@ public abstract class SharedChameleonClothingSystem : EntitySystem { [Dependency] private readonly IComponentFactory _factory = default!; [Dependency] private readonly IPrototypeManager _proto = default!; - [Dependency] private readonly SharedItemSystem _itemSystem = default!; [Dependency] private readonly ClothingSystem _clothingSystem = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; + [Dependency] private readonly SharedItemSystem _itemSystem = default!; + [Dependency] private readonly TagSystem _tag = default!; public override void Initialize() { @@ -81,7 +82,7 @@ public abstract class SharedChameleonClothingSystem : EntitySystem return false; // check if it is marked as valid chameleon target - if (!proto.TryGetComponent(out TagComponent? tags, _factory) || !tags.Tags.Contains("WhitelistChameleon")) + if (!proto.TryGetComponent(out TagComponent? tag, _factory) || !_tag.HasTag(tag, "WhitelistChameleon")) return false; // check if it's valid clothing diff --git a/Content.Shared/Construction/Conditions/NoWindowsInTile.cs b/Content.Shared/Construction/Conditions/NoWindowsInTile.cs index be6bc2cfac..3ae3b59362 100644 --- a/Content.Shared/Construction/Conditions/NoWindowsInTile.cs +++ b/Content.Shared/Construction/Conditions/NoWindowsInTile.cs @@ -12,13 +12,12 @@ namespace Content.Shared.Construction.Conditions public bool Condition(EntityUid user, EntityCoordinates location, Direction direction) { var entManager = IoCManager.Resolve(); - var tagQuery = entManager.GetEntityQuery(); var sysMan = entManager.EntitySysManager; var tagSystem = sysMan.GetEntitySystem(); foreach (var entity in location.GetEntitiesInTile(LookupFlags.Static)) { - if (tagSystem.HasTag(entity, "Window", tagQuery)) + if (tagSystem.HasTag(entity, "Window")) return false; } diff --git a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs index c041cf1ba0..e9ef053f62 100644 --- a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs +++ b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs @@ -15,6 +15,7 @@ using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Content.Shared.Tag; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Utility; using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem; @@ -32,16 +33,14 @@ public sealed partial class AnchorableSystem : EntitySystem [Dependency] private readonly TagSystem _tagSystem = default!; private EntityQuery _physicsQuery; - private EntityQuery _tagQuery; - public const string Unstackable = "Unstackable"; + public readonly ProtoId Unstackable = "Unstackable"; public override void Initialize() { base.Initialize(); _physicsQuery = GetEntityQuery(); - _tagQuery = GetEntityQuery(); SubscribeLocalEvent(OnInteractUsing, before: new[] { typeof(ItemSlotsSystem) }, after: new[] { typeof(SharedConstructionSystem) }); @@ -312,7 +311,7 @@ public sealed partial class AnchorableSystem : EntitySystem DebugTools.Assert(!Transform(uid).Anchored); // If we are unstackable, iterate through any other entities anchored on the current square - return _tagSystem.HasTag(uid, Unstackable, _tagQuery) && AnyUnstackablesAnchoredAt(location); + return _tagSystem.HasTag(uid, Unstackable) && AnyUnstackablesAnchoredAt(location); } public bool AnyUnstackablesAnchoredAt(EntityCoordinates location) @@ -327,10 +326,8 @@ public sealed partial class AnchorableSystem : EntitySystem while (enumerator.MoveNext(out var entity)) { // If we find another unstackable here, return true. - if (_tagSystem.HasTag(entity.Value, Unstackable, _tagQuery)) - { + if (_tagSystem.HasTag(entity.Value, Unstackable)) return true; - } } return false; diff --git a/Content.Shared/Construction/Steps/MultipleTagsConstructionGraphStep.cs b/Content.Shared/Construction/Steps/MultipleTagsConstructionGraphStep.cs index 668952dac2..07ba46946a 100644 --- a/Content.Shared/Construction/Steps/MultipleTagsConstructionGraphStep.cs +++ b/Content.Shared/Construction/Steps/MultipleTagsConstructionGraphStep.cs @@ -1,14 +1,15 @@ using Content.Shared.Tag; +using Robust.Shared.Prototypes; namespace Content.Shared.Construction.Steps { public sealed partial class MultipleTagsConstructionGraphStep : ArbitraryInsertConstructionGraphStep { [DataField("allTags")] - private List? _allTags; + private List>? _allTags; [DataField("anyTags")] - private List? _anyTags; + private List>? _anyTags; private static bool IsNullOrEmpty(ICollection? list) { @@ -21,16 +22,12 @@ namespace Content.Shared.Construction.Steps if (IsNullOrEmpty(_allTags) && IsNullOrEmpty(_anyTags)) return false; // Step is somehow invalid, we return. - // No tags at all. - if (!entityManager.TryGetComponent(uid, out TagComponent? tags)) - return false; - var tagSystem = entityManager.EntitySysManager.GetEntitySystem(); - if (_allTags != null && !tagSystem.HasAllTags(tags, _allTags)) + if (_allTags != null && !tagSystem.HasAllTags(uid, _allTags)) return false; // We don't have all the tags needed. - if (_anyTags != null && !tagSystem.HasAnyTag(tags, _anyTags)) + if (_anyTags != null && !tagSystem.HasAnyTag(uid, _anyTags)) return false; // We don't have any of the tags needed. // This entity is valid! diff --git a/Content.Shared/Pinpointer/SharedNavMapSystem.cs b/Content.Shared/Pinpointer/SharedNavMapSystem.cs index 7c12321b5d..3ced5f3c9e 100644 --- a/Content.Shared/Pinpointer/SharedNavMapSystem.cs +++ b/Content.Shared/Pinpointer/SharedNavMapSystem.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using Content.Shared.Tag; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -24,7 +25,7 @@ public abstract class SharedNavMapSystem : EntitySystem [Robust.Shared.IoC.Dependency] private readonly TagSystem _tagSystem = default!; - private readonly string[] _wallTags = ["Wall", "Window"]; + private static readonly ProtoId[] WallTags = {"Wall", "Window"}; private EntityQuery _doorQuery; public override void Initialize() @@ -58,7 +59,7 @@ public abstract class SharedNavMapSystem : EntitySystem if (_doorQuery.HasComp(uid)) return NavMapChunkType.Airlock; - if (_tagSystem.HasAnyTag(uid, _wallTags)) + if (_tagSystem.HasAnyTag(uid, WallTags)) return NavMapChunkType.Wall; return NavMapChunkType.Invalid; diff --git a/Content.Shared/Tag/TagComponent.cs b/Content.Shared/Tag/TagComponent.cs index b5b8a48a44..ad4240ba06 100644 --- a/Content.Shared/Tag/TagComponent.cs +++ b/Content.Shared/Tag/TagComponent.cs @@ -1,13 +1,11 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set; +using Robust.Shared.Prototypes; -namespace Content.Shared.Tag +namespace Content.Shared.Tag; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(TagSystem))] +public sealed partial class TagComponent : Component { - [RegisterComponent, NetworkedComponent, Access(typeof(TagSystem))] - public sealed partial class TagComponent : Component - { - [DataField("tags", customTypeSerializer: typeof(PrototypeIdHashSetSerializer))] - [Access(typeof(TagSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends - public HashSet Tags = new(); - } + [DataField, ViewVariables, AutoNetworkedField] + public HashSet> Tags = new(); } diff --git a/Content.Shared/Tag/TagComponentState.cs b/Content.Shared/Tag/TagComponentState.cs deleted file mode 100644 index 9919aba108..0000000000 --- a/Content.Shared/Tag/TagComponentState.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared.Tag -{ - [Serializable, NetSerializable] - public sealed class TagComponentState : ComponentState - { - public TagComponentState(string[] tags) - { - Tags = tags; - } - - public string[] Tags { get; } - } -} diff --git a/Content.Shared/Tag/TagPrototype.cs b/Content.Shared/Tag/TagPrototype.cs index 2a06e22cf9..97f8c1af7d 100644 --- a/Content.Shared/Tag/TagPrototype.cs +++ b/Content.Shared/Tag/TagPrototype.cs @@ -1,17 +1,15 @@ using Robust.Shared.Prototypes; -namespace Content.Shared.Tag +namespace Content.Shared.Tag; + +/// +/// Prototype representing a tag in YAML. +/// Meant to only have an ID property, as that is the only thing that +/// gets saved in TagComponent. +/// +[Prototype("Tag")] +public sealed partial class TagPrototype : IPrototype { - /// - /// Prototype representing a tag in YAML. - /// Meant to only have an ID property, as that is the only thing that - /// gets saved in TagComponent. - /// - [Prototype("Tag")] - public sealed partial class TagPrototype : IPrototype - { - [ViewVariables] - [IdDataField] - public string ID { get; private set; } = default!; - } + [IdDataField, ViewVariables] + public string ID { get; } = string.Empty; } diff --git a/Content.Shared/Tag/TagSystem.cs b/Content.Shared/Tag/TagSystem.cs index 7bcb887a41..f1f620a694 100644 --- a/Content.Shared/Tag/TagSystem.cs +++ b/Content.Shared/Tag/TagSystem.cs @@ -1,11 +1,19 @@ -using System.Diagnostics; -using System.Linq; -using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Shared.Tag; +/// +/// The system that is responsible for working with tags. +/// Checking the existence of the only happens in DEBUG builds, +/// to improve performance, so don't forget to check it. +/// +/// +/// The methods to add or remove a list of tags have only an implementation with the type, +/// it's not much, but it takes away performance, +/// if you need to use them often, it's better to make a proper implementation, +/// you can read more HERE. +/// public sealed class TagSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _proto = default!; @@ -15,685 +23,693 @@ public sealed class TagSystem : EntitySystem public override void Initialize() { base.Initialize(); + _tagQuery = GetEntityQuery(); - SubscribeLocalEvent(OnTagGetState); - SubscribeLocalEvent(OnTagHandleState); #if DEBUG SubscribeLocalEvent(OnTagInit); +#endif } +#if DEBUG private void OnTagInit(EntityUid uid, TagComponent component, ComponentInit args) { foreach (var tag in component.Tags) { AssertValidTag(tag); } + } #endif + + /// + /// Tries to add a tag to an entity if the tag doesn't already exist. + /// + /// + /// true if it was added, false otherwise even if it already existed. + /// + /// + /// Thrown if no exists with the given id. + /// + public bool AddTag(EntityUid entityUid, ProtoId tag) + { + return AddTag((entityUid, EnsureComp(entityUid)), tag); } - - private void OnTagHandleState(EntityUid uid, TagComponent component, ref ComponentHandleState args) + /// + /// Tries to add the given tags to an entity if the tags don't already exist. + /// + /// + /// true if any tags were added, false otherwise even if they all already existed. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool AddTags(EntityUid entityUid, params ProtoId[] tags) { - if (args.Current is not TagComponentState state) - return; + return AddTags(entityUid, (IEnumerable>)tags); + } - component.Tags.Clear(); + /// + /// Tries to add the given tags to an entity if the tags don't already exist. + /// + /// + /// true if any tags were added, false otherwise even if they all already existed. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool AddTags(EntityUid entityUid, IEnumerable> tags) + { + return AddTags((entityUid, EnsureComp(entityUid)), tags); + } - foreach (var tag in state.Tags) + /// + /// Tries to add a tag to an entity if it has a + /// and the tag doesn't already exist. + /// + /// + /// true if it was added, false otherwise even if it already existed. + /// + /// + /// Thrown if no exists with the given id. + /// + public bool TryAddTag(EntityUid entityUid, ProtoId tag) + { + return _tagQuery.TryComp(entityUid, out var component) && + AddTag((entityUid, component), tag); + } + + /// + /// Tries to add the given tags to an entity if it has a + /// and the tags don't already exist. + /// + /// + /// true if any tags were added, false otherwise even if they all already existed. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool TryAddTags(EntityUid entityUid, params ProtoId[] tags) + { + return TryAddTags(entityUid, (IEnumerable>)tags); + } + + /// + /// Tries to add the given tags to an entity if it has a + /// and the tags don't already exist. + /// + /// + /// true if any tags were added, false otherwise even if they all already existed. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool TryAddTags(EntityUid entityUid, IEnumerable> tags) + { + return _tagQuery.TryComp(entityUid, out var component) && + AddTags((entityUid, component), tags); + } + + /// + /// Checks if a tag has been added to an entity. + /// + /// + /// true if it exists, false otherwise. + /// + /// + /// Thrown if no exists with the given id. + /// + public bool HasTag(EntityUid entityUid, ProtoId tag) + { + return _tagQuery.TryComp(entityUid, out var component) && + HasTag(component, tag); + } + + /// + /// Checks if a tag has been added to an entity. + /// + /// + /// true if it exists, false otherwise. + /// + /// + /// Thrown if no exists with the given id. + /// + public bool HasAllTags(EntityUid entityUid, ProtoId tag) => + HasTag(entityUid, tag); + + /// + /// Checks if all of the given tags have been added to an entity. + /// + /// + /// true if they all exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAllTags(EntityUid entityUid, params ProtoId[] tags) + { + return _tagQuery.TryComp(entityUid, out var component) && + HasAllTags(component, tags); + } + + /// + /// Checks if all of the given tags have been added to an entity. + /// + /// + /// true if they all exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAllTags(EntityUid entityUid, HashSet> tags) + { + return _tagQuery.TryComp(entityUid, out var component) && + HasAllTags(component, tags); + } + + /// + /// Checks if all of the given tags have been added to an entity. + /// + /// + /// true if they all exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAllTags(EntityUid entityUid, List> tags) + { + return _tagQuery.TryComp(entityUid, out var component) && + HasAllTags(component, tags); + } + + /// + /// Checks if all of the given tags have been added to an entity. + /// + /// + /// true if they all exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAllTags(EntityUid entityUid, IEnumerable> tags) + { + return _tagQuery.TryComp(entityUid, out var component) && + HasAllTags(component, tags); + } + + /// + /// Checks if a tag has been added to an entity. + /// + /// + /// true if it exists, false otherwise. + /// + /// + /// Thrown if no exists with the given id. + /// + public bool HasAnyTag(EntityUid entityUid, ProtoId tag) => + HasTag(entityUid, tag); + + /// + /// Checks if any of the given tags have been added to an entity. + /// + /// + /// true if any of them exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAnyTag(EntityUid entityUid, params ProtoId[] tags) + { + return _tagQuery.TryComp(entityUid, out var component) && + HasAnyTag(component, tags); + } + + /// + /// Checks if any of the given tags have been added to an entity. + /// + /// + /// true if any of them exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAnyTag(EntityUid entityUid, HashSet> tags) + { + return _tagQuery.TryComp(entityUid, out var component) && + HasAnyTag(component, tags); + } + + /// + /// Checks if any of the given tags have been added to an entity. + /// + /// + /// true if any of them exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAnyTag(EntityUid entityUid, List> tags) + { + return _tagQuery.TryComp(entityUid, out var component) && + HasAnyTag(component, tags); + } + + /// + /// Checks if any of the given tags have been added to an entity. + /// + /// + /// true if any of them exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAnyTag(EntityUid entityUid, IEnumerable> tags) + { + return _tagQuery.TryComp(entityUid, out var component) && + HasAnyTag(component, tags); + } + + /// + /// Checks if a tag has been added to an component. + /// + /// + /// true if it exists, false otherwise. + /// + /// + /// Thrown if no exists with the given id. + /// + public bool HasTag(TagComponent component, ProtoId tag) + { +#if DEBUG + AssertValidTag(tag); +#endif + return component.Tags.Contains(tag); + } + + /// + /// Checks if a tag has been added to an component. + /// + /// + /// true if it exists, false otherwise. + /// + /// + /// Thrown if no exists with the given id. + /// + public bool HasAllTags(TagComponent component, ProtoId tag) => + HasTag(component, tag); + + /// + /// Checks if all of the given tags have been added to an component. + /// + /// + /// true if they all exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAllTags(TagComponent component, params ProtoId[] tags) + { + foreach (var tag in tags) { +#if DEBUG AssertValidTag(tag); - component.Tags.Add(tag); +#endif + if (!component.Tags.Contains(tag)) + return false; } + + return true; } - private static void OnTagGetState(EntityUid uid, TagComponent component, ref ComponentGetState args) + /// + /// Checks if all of the given tags have been added to an component. + /// + /// + /// true if they all exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAllTagsArray(TagComponent component, ProtoId[] tags) { - var tags = new string[component.Tags.Count]; - var i = 0; - - foreach (var tag in component.Tags) + foreach (var tag in tags) { - tags[i] = tag; - i++; +#if DEBUG + AssertValidTag(tag); +#endif + if (!component.Tags.Contains(tag)) + return false; } - args.State = new TagComponentState(tags); + return true; + } + + /// + /// Checks if all of the given tags have been added to an component. + /// + /// + /// true if they all exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAllTags(TagComponent component, List> tags) + { + foreach (var tag in tags) + { +#if DEBUG + AssertValidTag(tag); +#endif + if (!component.Tags.Contains(tag)) + return false; + } + + return true; + } + + /// + /// Checks if all of the given tags have been added to an component. + /// + /// + /// true if they all exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAllTags(TagComponent component, HashSet> tags) + { + foreach (var tag in tags) + { +#if DEBUG + AssertValidTag(tag); +#endif + if (!component.Tags.Contains(tag)) + return false; + } + + return true; + } + + /// + /// Checks if all of the given tags have been added to an component. + /// + /// + /// true if they all exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAllTags(TagComponent component, IEnumerable> tags) + { + foreach (var tag in tags) + { +#if DEBUG + AssertValidTag(tag); +#endif + if (!component.Tags.Contains(tag)) + return false; + } + + return true; + } + + /// + /// Checks if a tag has been added to an component. + /// + /// + /// true if it exists, false otherwise. + /// + /// + /// Thrown if no exists with the given id. + /// + public bool HasAnyTag(TagComponent component, ProtoId tag) => + HasTag(component, tag); + + /// + /// Checks if any of the given tags have been added to an component. + /// + /// + /// true if any of them exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAnyTag(TagComponent component, params ProtoId[] tags) + { + foreach (var tag in tags) + { +#if DEBUG + AssertValidTag(tag); +#endif + if (component.Tags.Contains(tag)) + return true; + } + + return false; + } + + /// + /// Checks if any of the given tags have been added to an component. + /// + /// + /// true if any of them exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAnyTag(TagComponent component, HashSet> tags) + { + foreach (var tag in tags) + { +#if DEBUG + AssertValidTag(tag); +#endif + if (component.Tags.Contains(tag)) + return true; + } + + return false; + } + + /// + /// Checks if any of the given tags have been added to an component. + /// + /// + /// true if any of them exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAnyTag(TagComponent component, List> tags) + { + foreach (var tag in tags) + { +#if DEBUG + AssertValidTag(tag); +#endif + if (component.Tags.Contains(tag)) + return true; + } + + return false; + } + + /// + /// Checks if any of the given tags have been added to an component. + /// + /// + /// true if any of them exist, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAnyTag(TagComponent component, IEnumerable> tags) + { + foreach (var tag in tags) + { +#if DEBUG + AssertValidTag(tag); +#endif + if (component.Tags.Contains(tag)) + return true; + } + + return false; + } + + /// + /// Tries to remove a tag from an entity if it exists. + /// + /// + /// true if it was removed, false otherwise even if it didn't exist. + /// + /// + /// Thrown if no exists with the given id. + /// + public bool RemoveTag(EntityUid entityUid, ProtoId tag) + { + return _tagQuery.TryComp(entityUid, out var component) && + RemoveTag((entityUid, component), tag); + } + + /// + /// Tries to remove a tag from an entity if it exists. + /// + /// + /// true if it was removed, false otherwise even if it didn't exist. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool RemoveTags(EntityUid entityUid, params ProtoId[] tags) + { + return RemoveTags(entityUid, (IEnumerable>)tags); + } + + /// + /// Tries to remove a tag from an entity if it exists. + /// + /// + /// true if it was removed, false otherwise even if it didn't exist. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool RemoveTags(EntityUid entityUid, IEnumerable> tags) + { + return _tagQuery.TryComp(entityUid, out var component) && + RemoveTags((entityUid, component), tags); + } + + /// + /// Tries to add a tag if it doesn't already exist. + /// + /// + /// true if it was added, false if it already existed. + /// + /// + /// Thrown if no exists with the given id. + /// + public bool AddTag(Entity entity, ProtoId tag) + { +#if DEBUG + AssertValidTag(tag); +#endif + if (!entity.Comp.Tags.Add(tag)) + return false; + + Dirty(entity); + return true; + } + + /// + /// Tries to add the given tags if they don't already exist. + /// + /// + /// true if any tags were added, false if they all already existed. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool AddTags(Entity entity, params ProtoId[] tags) + { + return AddTags(entity, (IEnumerable>)tags); + } + + /// + /// Tries to add the given tags if they don't already exist. + /// + /// + /// true if any tags were added, false if they all already existed. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool AddTags(Entity entity, IEnumerable> tags) + { + var update = false; + foreach (var tag in tags) + { +#if DEBUG + AssertValidTag(tag); +#endif + if (entity.Comp.Tags.Add(tag) && !update) + update = true; + } + + if (!update) + return false; + + Dirty(entity); + return true; + } + + /// + /// Tries to remove a tag if it exists. + /// + /// + /// true if it was removed, false otherwise even if it didn't exist. + /// + /// + /// Thrown if no exists with the given id. + /// + public bool RemoveTag(Entity entity, ProtoId tag) + { +#if DEBUG + AssertValidTag(tag); +#endif + + if (!entity.Comp.Tags.Remove(tag)) + return false; + + Dirty(entity); + return true; + } + + /// + /// Tries to remove all of the given tags if they exist. + /// + /// + /// true if any tag was removed, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool RemoveTags(Entity entity, params ProtoId[] tags) + { + return RemoveTags(entity, (IEnumerable>)tags); + } + + /// + /// Tries to remove all of the given tags if they exist. + /// + /// + /// true if any tag was removed, false otherwise. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool RemoveTags(Entity entity, IEnumerable> tags) + { + var update = false; + foreach (var tag in tags) + { +#if DEBUG + AssertValidTag(tag); +#endif + if (entity.Comp.Tags.Remove(tag) && !update) + update = true; + } + + if (!update) + return false; + + Dirty(entity); + return true; } private void AssertValidTag(string id) { DebugTools.Assert(_proto.HasIndex(id), $"Unknown tag: {id}"); } - - /// - /// Tries to add a tag to an entity if the tag doesn't already exist. - /// - /// The entity to add the tag to. - /// The tag to add. - /// - /// true if it was added, false otherwise even if it already existed. - /// - /// - /// Thrown if no exists with the given id. - /// - public bool AddTag(EntityUid entity, string id) - { - return AddTag(entity, EnsureComp(entity), id); - } - - /// - /// Tries to add the given tags to an entity if the tags don't already exist. - /// - /// The entity to add the tag to. - /// The tags to add. - /// - /// true if any tags were added, false otherwise even if they all already existed. - /// - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool AddTags(EntityUid entity, params string[] ids) - { - return AddTags(entity, EnsureComp(entity), ids); - } - - /// - /// Tries to add the given tags to an entity if the tags don't already exist. - /// - /// The entity to add the tag to. - /// The tags to add. - /// - /// true if any tags were added, false otherwise even if they all already existed. - /// - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool AddTags(EntityUid entity, IEnumerable ids) - { - return AddTags(entity, EnsureComp(entity), ids); - } - - /// - /// Tries to add a tag to an entity if it has a - /// and the tag doesn't already exist. - /// - /// The entity to add the tag to. - /// The tag to add. - /// - /// true if it was added, false otherwise even if it already existed. - /// - /// - /// Thrown if no exists with the given id. - /// - public bool TryAddTag(EntityUid entity, string id) - { - return _tagQuery.TryComp(entity, out var component) && - AddTag(entity, component, id); - } - - /// - /// Tries to add the given tags to an entity if it has a - /// and the tags don't already exist. - /// - /// The entity to add the tag to. - /// The tags to add. - /// - /// true if any tags were added, false otherwise even if they all already existed. - /// - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool TryAddTags(EntityUid entity, params string[] ids) - { - return _tagQuery.TryComp(entity, out var component) && - AddTags(entity, component, ids); - } - - /// - /// Tries to add the given tags to an entity if it has a - /// and the tags don't already exist. - /// - /// The entity to add the tag to. - /// The tags to add. - /// - /// true if any tags were added, false otherwise even if they all already existed. - /// - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool TryAddTags(EntityUid entity, IEnumerable ids) - { - return _tagQuery.TryComp(entity, out var component) && - AddTags(entity, component, ids); - } - - /// - /// Checks if a tag has been added to an entity. - /// - /// The entity to check. - /// The tag to check for. - /// true if it exists, false otherwise. - /// - /// Thrown if no exists with the given id. - /// - public bool HasTag(EntityUid entity, string id) - { - return _tagQuery.TryComp(entity, out var component) && - HasTag(component, id); - } - - /// - /// Checks if a tag has been added to an entity. - /// - [Obsolete] - public bool HasTag(EntityUid entity, string id, EntityQuery tagQuery) - { - return tagQuery.TryGetComponent(entity, out var component) && - HasTag(component, id); - } - - /// - /// Checks if all of the given tags have been added to an entity. - /// - /// The entity to check. - /// The tags to check for. - /// true if they all exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAllTags(EntityUid entity, string id) => HasTag(entity, id); - - /// - /// Checks if all of the given tags have been added to an entity. - /// - /// The entity to check. - /// The tags to check for. - /// true if they all exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAllTags(EntityUid entity, List ids) - { - return _tagQuery.TryComp(entity, out var component) && - HasAllTags(component, ids); - } - - /// - /// Checks if all of the given tags have been added to an entity. - /// - /// The entity to check. - /// The tags to check for. - /// true if they all exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAllTags(EntityUid entity, IEnumerable ids) - { - return _tagQuery.TryComp(entity, out var component) && - HasAllTags(component, ids); - } - - /// - /// Checks if all of the given tags have been added to an entity. - /// - /// The entity to check. - /// The tags to check for. - /// true if they all exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAllTags(EntityUid entity, List> ids) - { - return _tagQuery.TryComp(entity, out var component) && - HasAllTags(component, ids); - } - - /// - /// Checks if any of the given tags have been added to an entity. - /// - /// The entity to check. - /// The tags to check for. - /// true if any of them exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAnyTag(EntityUid entity, params string[] ids) - { - return _tagQuery.TryComp(entity, out var component) && - HasAnyTag(component, ids); - } - - /// - /// Checks if any of the given tags have been added to an entity. - /// - /// The entity to check. - /// The tag to check for. - /// true if any of them exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAnyTag(EntityUid entity, string id) => HasTag(entity, id); - - /// - /// Checks if any of the given tags have been added to an entity. - /// - /// The entity to check. - /// The tags to check for. - /// true if any of them exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAnyTag(EntityUid entity, List ids) - { - return _tagQuery.TryComp(entity, out var component) && - HasAnyTag(component, ids); - } - - /// - /// Checks if any of the given tags have been added to an entity. - /// - /// The entity to check. - /// The tags to check for. - /// true if any of them exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAnyTag(EntityUid entity, List> ids) - { - return TryComp(entity, out var component) && - HasAnyTag(component, ids); - } - - /// - /// Checks if any of the given tags have been added to an entity. - /// - /// The entity to check. - /// The tags to check for. - /// true if any of them exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAnyTag(EntityUid entity, IEnumerable ids) - { - return _tagQuery.TryComp(entity, out var component) && - HasAnyTag(component, ids); - } - - /// - /// Tries to remove a tag from an entity if it exists. - /// - /// The entity to remove the tag from. - /// The tag to remove. - /// - /// true if it was removed, false otherwise even if it didn't exist. - /// - /// - /// Thrown if no exists with the given id. - /// - public bool RemoveTag(EntityUid entity, string id) - { - return _tagQuery.TryComp(entity, out var component) && - RemoveTag(entity, component, id); - } - - /// - /// Tries to remove a tag from an entity if it exists. - /// - /// The entity to remove the tag from. - /// The tag to remove. - /// - /// true if it was removed, false otherwise even if it didn't exist. - /// - /// Thrown if one of the ids represents an unregistered . - /// - /// - public bool RemoveTags(EntityUid entity, params string[] ids) - { - return _tagQuery.TryComp(entity, out var component) && - RemoveTags(entity, component, ids); - } - - /// - /// Tries to remove a tag from an entity if it exists. - /// - /// The entity to remove the tag from. - /// The tag to remove. - /// - /// true if it was removed, false otherwise even if it didn't exist. - /// - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool RemoveTags(EntityUid entity, IEnumerable ids) - { - return _tagQuery.TryComp(entity, out var component) && - RemoveTags(entity, component, ids); - } - - /// - /// Tries to add a tag if it doesn't already exist. - /// - /// The tag to add. - /// true if it was added, false if it already existed. - /// - /// Thrown if no exists with the given id. - /// - public bool AddTag(EntityUid uid, TagComponent component, string id) - { - AssertValidTag(id); - var added = component.Tags.Add(id); - - if (added) - { - Dirty(uid, component); - return true; - } - - return false; - } - - /// - /// Tries to add the given tags if they don't already exist. - /// - /// The tags to add. - /// true if any tags were added, false if they all already existed. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool AddTags(EntityUid uid, TagComponent component, params string[] ids) - { - return AddTags(uid, component, ids.AsEnumerable()); - } - - /// - /// Tries to add the given tags if they don't already exist. - /// - /// The tags to add. - /// true if any tags were added, false if they all already existed. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool AddTags(EntityUid uid, TagComponent component, IEnumerable ids) - { - var count = component.Tags.Count; - - foreach (var id in ids) - { - AssertValidTag(id); - component.Tags.Add(id); - } - - if (component.Tags.Count > count) - { - Dirty(uid, component); - return true; - } - - return false; - } - - /// - /// Checks if a tag has been added. - /// - /// The tag to check for. - /// true if it exists, false otherwise. - /// - /// Thrown if no exists with the given id. - /// - public bool HasTag(TagComponent component, string id) - { - AssertValidTag(id); - return component.Tags.Contains(id); - } - - /// - /// Checks if all of the given tags have been added. - /// - /// The tags to check for. - /// true if they all exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAllTags(TagComponent component, params string[] ids) - { - return HasAllTags(component, ids.AsEnumerable()); - } - - /// - /// Checks if all of the given tags have been added. - /// - /// The tag to check for. - /// true if they all exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAllTags(TagComponent component, string id) => HasTag(component, id); - - /// - /// Checks if all of the given tags have been added. - /// - /// The tags to check for. - /// true if they all exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAllTags(TagComponent component, List ids) - { - foreach (var id in ids) - { - AssertValidTag(id); - - if (!component.Tags.Contains(id)) - return false; - } - - return true; - } - - /// - /// Checks if all of the given tags have been added. - /// - /// The tags to check for. - /// true if they all exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAllTags(TagComponent component, IEnumerable ids) - { - foreach (var id in ids) - { - AssertValidTag(id); - - if (!component.Tags.Contains(id)) - return false; - - } - - return true; - } - - /// - /// Checks if all of the given tags have been added. - /// - /// The tags to check for. - /// true if they all exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAllTags(TagComponent component, List> ids) - { - foreach (var id in ids) - { - AssertValidTag(id); - - if (!component.Tags.Contains(id)) - return false; - - } - - return true; - } - - /// - /// Checks if any of the given tags have been added. - /// - /// The tags to check for. - /// true if any of them exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAnyTag(TagComponent component, params string[] ids) - { - foreach (var id in ids) - { - AssertValidTag(id); - - if (component.Tags.Contains(id)) - return true; - } - - return false; - } - - /// - /// Checks if any of the given tags have been added. - /// - /// The tag to check for. - /// true if any of them exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAnyTag(TagComponent component, string id) => HasTag(component, id); - - /// - /// Checks if any of the given tags have been added. - /// - /// The tags to check for. - /// true if any of them exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAnyTag(TagComponent component, List ids) - { - foreach (var id in ids) - { - AssertValidTag(id); - - if (component.Tags.Contains(id)) - { - return true; - } - } - - return false; - } - - /// - /// Checks if any of the given tags have been added. - /// - /// The tags to check for. - /// true if any of them exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAnyTag(TagComponent component, IEnumerable ids) - { - foreach (var id in ids) - { - AssertValidTag(id); - - if (component.Tags.Contains(id)) - { - return true; - } - } - - return false; - } - - /// - /// Checks if any of the given tags have been added. - /// - /// The tags to check for. - /// true if any of them exist, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool HasAnyTag(TagComponent comp, List> ids) - { - foreach (var id in ids) - { - AssertValidTag(id); - - if (comp.Tags.Contains(id)) - return true; - } - - return false; - } - - /// - /// Tries to remove a tag if it exists. - /// - /// - /// true if it was removed, false otherwise even if it didn't exist. - /// - /// - /// Thrown if no exists with the given id. - /// - public bool RemoveTag(EntityUid uid, TagComponent component, string id) - { - AssertValidTag(id); - - if (component.Tags.Remove(id)) - { - Dirty(uid, component); - return true; - } - - return false; - } - - /// - /// Tries to remove all of the given tags if they exist. - /// - /// The tags to remove. - /// - /// true if it was removed, false otherwise even if they didn't exist. - /// - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool RemoveTags(EntityUid uid, TagComponent component, params string[] ids) - { - return RemoveTags(uid, component, ids.AsEnumerable()); - } - - /// - /// Tries to remove all of the given tags if they exist. - /// - /// The tags to remove. - /// true if any tag was removed, false otherwise. - /// - /// Thrown if one of the ids represents an unregistered . - /// - public bool RemoveTags(EntityUid uid, TagComponent component, IEnumerable ids) - { - var count = component.Tags.Count; - - foreach (var id in ids) - { - AssertValidTag(id); - component.Tags.Remove(id); - } - - if (component.Tags.Count < count) - { - Dirty(uid, component); - return true; - } - - return false; - } } From 29e34cae350acde79412f3781c9fcfddbda8b949 Mon Sep 17 00:00:00 2001 From: DrSmugleaf <10968691+DrSmugleaf@users.noreply.github.com> Date: Sat, 1 Jun 2024 18:41:06 -0700 Subject: [PATCH 06/20] Disable rainbow overlay when reduced motion is enabled (#28496) Disable rainbow ovelray when reduced motion is enabled --- Content.Client/Drugs/RainbowOverlay.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Content.Client/Drugs/RainbowOverlay.cs b/Content.Client/Drugs/RainbowOverlay.cs index e62b0dfa66..fb48c91010 100644 --- a/Content.Client/Drugs/RainbowOverlay.cs +++ b/Content.Client/Drugs/RainbowOverlay.cs @@ -1,7 +1,9 @@ +using Content.Shared.CCVar; using Content.Shared.Drugs; using Content.Shared.StatusEffect; using Robust.Client.Graphics; using Robust.Client.Player; +using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.Prototypes; using Robust.Shared.Timing; @@ -10,6 +12,7 @@ namespace Content.Client.Drugs; public sealed class RainbowOverlay : Overlay { + [Dependency] private readonly IConfigurationManager _config = default!; [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; @@ -75,6 +78,10 @@ public sealed class RainbowOverlay : Overlay protected override void Draw(in OverlayDrawArgs args) { + // TODO disable only the motion part or ike's idea (single static frame of the overlay) + if (_config.GetCVar(CCVars.ReducedMotion)) + return; + if (ScreenTexture == null) return; From dce68e48e83d22d76c08bd33c27cd4e8597fa43d Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 2 Jun 2024 01:42:12 +0000 Subject: [PATCH 07/20] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 535a93e87e..0c671f49ee 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: FairlySadPanda - changes: - - message: Food and drink stocks in vending machines has been reduced to encourage - people to use the kitchen and bar. - type: Tweak - id: 6162 - time: '2024-03-15T23:28:01.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/25999 - author: Plykiya changes: - message: Ion storms now have a chance of happening from the start of shift. @@ -3853,3 +3845,11 @@ id: 6661 time: '2024-06-01T17:49:28.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/28434 +- author: DrSmugleaf + changes: + - message: Disabled the seeing rainbows screen effect when reduced motion is enabled + in the options menu. + type: Tweak + id: 6662 + time: '2024-06-02T01:41:06.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/28496 From d6ba166d3bb57f6f6438adee89ffdd7b20fb9635 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Sat, 1 Jun 2024 20:10:24 -0700 Subject: [PATCH 08/20] Replace obsolete EntityWhitelist IsValid usages (#28465) * Replace obsolete whitelist is valid with whitelist system * Consistency * Fix logic * Bork * I figured out how to get whitelists on the client lol * test fail * woops * HELP ME FUNCTIONS * Fix errors * simplify --------- Co-authored-by: plykiya --- Content.Client/Chat/UI/EmotesMenu.xaml.cs | 9 +- .../UI/ConstructionMenuPresenter.cs | 6 +- .../Chat/Systems/ChatSystem.Emote.cs | 4 +- Content.Server/Chat/Systems/ChatSystem.cs | 2 + Content.Server/Gatherable/GatherableSystem.cs | 6 +- .../NPCImprintingOnSpawnBehaviourSystem.cs | 4 +- .../NPC/Systems/NPCUtilitySystem.cs | 4 +- .../Power/EntitySystems/ChargerSystem.cs | 4 +- .../EntitySystems/RevenantSystem.Abilities.cs | 8 +- .../Silicons/Borgs/BorgSystem.Modules.cs | 2 +- Content.Server/Silicons/Borgs/BorgSystem.cs | 8 +- .../Storage/EntitySystems/PickRandomSystem.cs | 6 +- .../XenoArtifacts/ArtifactSystem.Nodes.cs | 11 ++- .../Containers/ItemSlot/ItemSlotsSystem.cs | 5 +- .../Damage/Systems/DamageContactsSystem.cs | 4 +- Content.Shared/Devour/SharedDevourSystem.cs | 4 +- .../Disposal/SharedDisposalUnitSystem.cs | 8 +- .../Implants/SharedImplanterSystem.cs | 5 +- .../Interaction/SmartEquipSystem.cs | 6 +- .../Materials/SharedMaterialStorageSystem.cs | 6 +- .../Systems/SharedChameleonProjectorSystem.cs | 6 +- .../Salvage/Fulton/SharedFultonSystem.cs | 4 +- .../Shuttles/Systems/SharedShuttleSystem.cs | 4 +- .../EntitySystems/MagnetPickupSystem.cs | 5 +- .../SharedEntityStorageSystem.cs | 4 +- .../EntitySystems/SharedStorageSystem.cs | 10 +-- .../Marker/SharedDamageMarkerSystem.cs | 4 +- .../Systems/SharedGunSystem.Ballistic.cs | 5 +- .../Systems/SharedGunSystem.Revolver.cs | 2 +- .../Weapons/Ranged/Systems/SharedGunSystem.cs | 2 + .../Whitelist/EntityWhitelistSystem.cs | 84 +++++++++++++++++++ 31 files changed, 186 insertions(+), 56 deletions(-) diff --git a/Content.Client/Chat/UI/EmotesMenu.xaml.cs b/Content.Client/Chat/UI/EmotesMenu.xaml.cs index a26d319920..3340755343 100644 --- a/Content.Client/Chat/UI/EmotesMenu.xaml.cs +++ b/Content.Client/Chat/UI/EmotesMenu.xaml.cs @@ -1,7 +1,8 @@ -using System.Numerics; +using System.Numerics; using Content.Client.UserInterface.Controls; using Content.Shared.Chat.Prototypes; using Content.Shared.Speech; +using Content.Shared.Whitelist; using Robust.Client.AutoGenerated; using Robust.Client.GameObjects; using Robust.Client.UserInterface.Controls; @@ -19,6 +20,7 @@ public sealed partial class EmotesMenu : RadialMenu [Dependency] private readonly ISharedPlayerManager _playerManager = default!; private readonly SpriteSystem _spriteSystem; + private readonly EntityWhitelistSystem _whitelistSystem; public event Action>? OnPlayEmote; @@ -28,6 +30,7 @@ public sealed partial class EmotesMenu : RadialMenu RobustXamlLoader.Load(this); _spriteSystem = _entManager.System(); + _whitelistSystem = _entManager.System(); var main = FindControl("Main"); @@ -37,8 +40,8 @@ public sealed partial class EmotesMenu : RadialMenu var player = _playerManager.LocalSession?.AttachedEntity; if (emote.Category == EmoteCategory.Invalid || emote.ChatTriggers.Count == 0 || - !(player.HasValue && (emote.Whitelist?.IsValid(player.Value, _entManager) ?? true)) || - (emote.Blacklist?.IsValid(player.Value, _entManager) ?? false)) + !(player.HasValue && _whitelistSystem.IsWhitelistPassOrNull(emote.Whitelist, player.Value)) || + _whitelistSystem.IsBlacklistPass(emote.Blacklist, player.Value)) continue; if (!emote.Available && diff --git a/Content.Client/Construction/UI/ConstructionMenuPresenter.cs b/Content.Client/Construction/UI/ConstructionMenuPresenter.cs index 9a09436176..0c7912e0bc 100644 --- a/Content.Client/Construction/UI/ConstructionMenuPresenter.cs +++ b/Content.Client/Construction/UI/ConstructionMenuPresenter.cs @@ -2,6 +2,7 @@ using System.Linq; using Content.Client.UserInterface.Systems.MenuBar.Widgets; using Content.Shared.Construction.Prototypes; using Content.Shared.Tag; +using Content.Shared.Whitelist; using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Placement; @@ -23,6 +24,7 @@ namespace Content.Client.Construction.UI /// internal sealed class ConstructionMenuPresenter : IDisposable { + [Dependency] private readonly EntityManager _entManager = default!; [Dependency] private readonly IEntitySystemManager _systemManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPlacementManager _placementManager = default!; @@ -30,6 +32,7 @@ namespace Content.Client.Construction.UI [Dependency] private readonly IPlayerManager _playerManager = default!; private readonly IConstructionMenuView _constructionView; + private readonly EntityWhitelistSystem _whitelistSystem; private ConstructionSystem? _constructionSystem; private ConstructionPrototype? _selected; @@ -78,6 +81,7 @@ namespace Content.Client.Construction.UI // This is a lot easier than a factory IoCManager.InjectDependencies(this); _constructionView = new ConstructionMenu(); + _whitelistSystem = _entManager.System(); // This is required so that if we load after the system is initialized, we can bind to it immediately if (_systemManager.TryGetEntitySystem(out var constructionSystem)) @@ -157,7 +161,7 @@ namespace Content.Client.Construction.UI if (_playerManager.LocalSession == null || _playerManager.LocalEntity == null - || (recipe.EntityWhitelist != null && !recipe.EntityWhitelist.IsValid(_playerManager.LocalEntity.Value))) + || _whitelistSystem.IsWhitelistFail(recipe.EntityWhitelist, _playerManager.LocalEntity.Value)) continue; if (!string.IsNullOrEmpty(search)) diff --git a/Content.Server/Chat/Systems/ChatSystem.Emote.cs b/Content.Server/Chat/Systems/ChatSystem.Emote.cs index d120812b88..23e1517d75 100644 --- a/Content.Server/Chat/Systems/ChatSystem.Emote.cs +++ b/Content.Server/Chat/Systems/ChatSystem.Emote.cs @@ -81,9 +81,7 @@ public partial class ChatSystem bool ignoreActionBlocker = false ) { - if (!(emote.Whitelist?.IsValid(source, EntityManager) ?? true)) - return; - if (emote.Blacklist?.IsValid(source, EntityManager) ?? false) + if (_whitelistSystem.IsWhitelistFailOrNull(emote.Whitelist, source) || _whitelistSystem.IsBlacklistPass(emote.Blacklist, source)) return; if (!emote.Available && diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index b79e16a8df..0fe9dcbc4d 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -22,6 +22,7 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Players; using Content.Shared.Radio; using Content.Shared.Speech; +using Content.Shared.Whitelist; using Robust.Server.Player; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; @@ -58,6 +59,7 @@ public sealed partial class ChatSystem : SharedChatSystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly ReplacementAccentSystem _wordreplacement = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; public const int VoiceRange = 10; // how far voice goes in world units public const int WhisperClearRange = 2; // how far whisper goes while still being understandable, in world units diff --git a/Content.Server/Gatherable/GatherableSystem.cs b/Content.Server/Gatherable/GatherableSystem.cs index e24b0da593..d6a3be451b 100644 --- a/Content.Server/Gatherable/GatherableSystem.cs +++ b/Content.Server/Gatherable/GatherableSystem.cs @@ -3,6 +3,7 @@ using Content.Server.Gatherable.Components; using Content.Shared.Interaction; using Content.Shared.Tag; using Content.Shared.Weapons.Melee.Events; +using Content.Shared.Whitelist; using Robust.Server.GameObjects; using Robust.Shared.Audio.Systems; using Robust.Shared.Prototypes; @@ -18,6 +19,7 @@ public sealed partial class GatherableSystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly TransformSystem _transform = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; public override void Initialize() { @@ -30,7 +32,7 @@ public sealed partial class GatherableSystem : EntitySystem private void OnAttacked(Entity gatherable, ref AttackedEvent args) { - if (gatherable.Comp.ToolWhitelist?.IsValid(args.Used, EntityManager) != true) + if (_whitelistSystem.IsWhitelistFailOrNull(gatherable.Comp.ToolWhitelist, args.Used)) return; Gather(gatherable, args.User); @@ -41,7 +43,7 @@ public sealed partial class GatherableSystem : EntitySystem if (args.Handled || !args.Complex) return; - if (gatherable.Comp.ToolWhitelist?.IsValid(args.User, EntityManager) != true) + if (_whitelistSystem.IsWhitelistFailOrNull(gatherable.Comp.ToolWhitelist, args.User)) return; Gather(gatherable, args.User); diff --git a/Content.Server/NPC/Systems/NPCImprintingOnSpawnBehaviourSystem.cs b/Content.Server/NPC/Systems/NPCImprintingOnSpawnBehaviourSystem.cs index cfd3b08c61..c3e0328037 100644 --- a/Content.Server/NPC/Systems/NPCImprintingOnSpawnBehaviourSystem.cs +++ b/Content.Server/NPC/Systems/NPCImprintingOnSpawnBehaviourSystem.cs @@ -1,6 +1,7 @@ using System.Numerics; using Content.Shared.NPC.Components; using Content.Shared.NPC.Systems; +using Content.Shared.Whitelist; using Robust.Shared.Collections; using Robust.Shared.Map; using Robust.Shared.Random; @@ -13,6 +14,7 @@ public sealed partial class NPCImprintingOnSpawnBehaviourSystem : SharedNPCImpri [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly NPCSystem _npc = default!; [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; public override void Initialize() { @@ -27,7 +29,7 @@ public sealed partial class NPCImprintingOnSpawnBehaviourSystem : SharedNPCImpri foreach (var friend in friends) { - if (imprinting.Comp.Whitelist?.IsValid(friend) != false) + if (_whitelistSystem.IsWhitelistPassOrNull(imprinting.Comp.Whitelist, friend)) { AddImprintingTarget(imprinting, friend, imprinting.Comp); } diff --git a/Content.Server/NPC/Systems/NPCUtilitySystem.cs b/Content.Server/NPC/Systems/NPCUtilitySystem.cs index 2e8c628b50..ca74d71335 100644 --- a/Content.Server/NPC/Systems/NPCUtilitySystem.cs +++ b/Content.Server/NPC/Systems/NPCUtilitySystem.cs @@ -19,6 +19,7 @@ using Content.Shared.Tools.Systems; using Content.Shared.Weapons.Melee; using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Whitelist; using Microsoft.Extensions.ObjectPool; using Robust.Server.Containers; using Robust.Shared.Prototypes; @@ -46,6 +47,7 @@ public sealed class NPCUtilitySystem : EntitySystem [Dependency] private readonly SolutionContainerSystem _solutions = default!; [Dependency] private readonly WeldableSystem _weldable = default!; [Dependency] private readonly ExamineSystemShared _examine = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; private EntityQuery _puddleQuery; private EntityQuery _xformQuery; @@ -249,7 +251,7 @@ public sealed class NPCUtilitySystem : EntitySystem return 0f; } - if (heldGun.Whitelist?.IsValid(targetUid, EntityManager) != true) + if (_whitelistSystem.IsWhitelistFailOrNull(heldGun.Whitelist, targetUid)) { return 0f; } diff --git a/Content.Server/Power/EntitySystems/ChargerSystem.cs b/Content.Server/Power/EntitySystems/ChargerSystem.cs index 1ff13a24f2..038295eac1 100644 --- a/Content.Server/Power/EntitySystems/ChargerSystem.cs +++ b/Content.Server/Power/EntitySystems/ChargerSystem.cs @@ -10,6 +10,7 @@ using Robust.Shared.Containers; using System.Diagnostics.CodeAnalysis; using Content.Shared.Storage.Components; using Robust.Server.Containers; +using Content.Shared.Whitelist; namespace Content.Server.Power.EntitySystems; @@ -20,6 +21,7 @@ internal sealed class ChargerSystem : EntitySystem [Dependency] private readonly PowerCellSystem _powerCell = default!; [Dependency] private readonly BatterySystem _battery = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; public override void Initialize() { @@ -208,7 +210,7 @@ internal sealed class ChargerSystem : EntitySystem if (!receiverComponent.Powered) return; - if (component.Whitelist?.IsValid(targetEntity, EntityManager) == false) + if (_whitelistSystem.IsWhitelistFail(component.Whitelist, targetEntity)) return; if (!SearchForBattery(targetEntity, out var batteryUid, out var heldBattery)) diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs index 670c64577a..c889d59f15 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs @@ -28,6 +28,7 @@ using Content.Shared.Revenant.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Utility; using Robust.Shared.Map.Components; +using Content.Shared.Whitelist; namespace Content.Server.Revenant.EntitySystems; @@ -40,6 +41,7 @@ public sealed partial class RevenantSystem [Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!; [Dependency] private readonly GhostSystem _ghost = default!; [Dependency] private readonly TileSystem _tile = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; private void InitializeAbilities() { @@ -331,10 +333,8 @@ public sealed partial class RevenantSystem foreach (var ent in _lookup.GetEntitiesInRange(uid, component.MalfunctionRadius)) { - if (component.MalfunctionWhitelist?.IsValid(ent, EntityManager) == false) - continue; - - if (component.MalfunctionBlacklist?.IsValid(ent, EntityManager) == true) + if (_whitelistSystem.IsWhitelistFail(component.MalfunctionWhitelist, ent) || + _whitelistSystem.IsBlacklistPass(component.MalfunctionBlacklist, ent)) continue; _emag.DoEmagEffect(uid, ent); //it does not emag itself. adorable. diff --git a/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs b/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs index cc57c34c47..5c600be3f6 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs @@ -267,7 +267,7 @@ public sealed partial class BorgSystem return false; } - if (component.ModuleWhitelist?.IsValid(module, EntityManager) == false) + if (_whitelistSystem.IsWhitelistFail(component.ModuleWhitelist, module)) { if (user != null) Popup.PopupEntity(Loc.GetString("borg-module-whitelist-deny"), uid, user.Value); diff --git a/Content.Server/Silicons/Borgs/BorgSystem.cs b/Content.Server/Silicons/Borgs/BorgSystem.cs index 082e38921a..1ab7f5387f 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.cs @@ -22,6 +22,7 @@ using Content.Shared.Roles; using Content.Shared.Silicons.Borgs; using Content.Shared.Silicons.Borgs.Components; using Content.Shared.Throwing; +using Content.Shared.Whitelist; using Content.Shared.Wires; using Robust.Server.GameObjects; using Robust.Shared.Containers; @@ -53,6 +54,8 @@ public sealed partial class BorgSystem : SharedBorgSystem [Dependency] private readonly ThrowingSystem _throwing = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!; [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; + [ValidatePrototypeId] public const string BorgJobId = "Borg"; @@ -104,9 +107,8 @@ public sealed partial class BorgSystem : SharedBorgSystem return; } - if (component.BrainEntity == null && - brain != null && - component.BrainWhitelist?.IsValid(used) != false) + if (component.BrainEntity == null && brain != null && + _whitelistSystem.IsWhitelistPassOrNull(component.BrainWhitelist, used)) { if (_mind.TryGetMind(used, out _, out var mind) && mind.Session != null) { diff --git a/Content.Server/Storage/EntitySystems/PickRandomSystem.cs b/Content.Server/Storage/EntitySystems/PickRandomSystem.cs index dbbe1dd778..f0e986e199 100644 --- a/Content.Server/Storage/EntitySystems/PickRandomSystem.cs +++ b/Content.Server/Storage/EntitySystems/PickRandomSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.Database; using Content.Shared.Hands.EntitySystems; using Content.Shared.Storage; using Content.Shared.Verbs; +using Content.Shared.Whitelist; using Robust.Shared.Containers; using Robust.Shared.Random; @@ -15,6 +16,7 @@ public sealed class PickRandomSystem : EntitySystem [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedHandsSystem _hands = default!; [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; public override void Initialize() { @@ -30,7 +32,7 @@ public sealed class PickRandomSystem : EntitySystem var user = args.User; - var enabled = storage.Container.ContainedEntities.Any(item => comp.Whitelist?.IsValid(item, EntityManager) ?? true); + var enabled = storage.Container.ContainedEntities.Any(item => _whitelistSystem.IsWhitelistPassOrNull(comp.Whitelist, item)); // alt-click / alt-z to pick an item args.Verbs.Add(new AlternativeVerb @@ -48,7 +50,7 @@ public sealed class PickRandomSystem : EntitySystem private void TryPick(EntityUid uid, PickRandomComponent comp, StorageComponent storage, EntityUid user) { - var entities = storage.Container.ContainedEntities.Where(item => comp.Whitelist?.IsValid(item, EntityManager) ?? true).ToArray(); + var entities = storage.Container.ContainedEntities.Where(item => _whitelistSystem.IsWhitelistPassOrNull(comp.Whitelist, item)).ToArray(); if (!entities.Any()) return; diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs index 895bb0217b..65aaabdf0e 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs @@ -1,15 +1,16 @@ using System.Linq; using Content.Server.Xenoarchaeology.XenoArtifacts.Events; +using Content.Shared.Whitelist; using Content.Shared.Xenoarchaeology.XenoArtifacts; using JetBrains.Annotations; -using Robust.Shared.Prototypes; using Robust.Shared.Random; -using Robust.Shared.Serialization.Manager; namespace Content.Server.Xenoarchaeology.XenoArtifacts; public sealed partial class ArtifactSystem { + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; + private const int MaxEdgesPerNode = 4; private readonly HashSet _usedNodeIds = new(); @@ -81,7 +82,8 @@ public sealed partial class ArtifactSystem private string GetRandomTrigger(EntityUid artifact, ref ArtifactNode node) { var allTriggers = _prototype.EnumeratePrototypes() - .Where(x => (x.Whitelist?.IsValid(artifact, EntityManager) ?? true) && (!x.Blacklist?.IsValid(artifact, EntityManager) ?? true)).ToList(); + .Where(x => _whitelistSystem.IsWhitelistPassOrNull(x.Whitelist, artifact) && + _whitelistSystem.IsBlacklistFailOrNull(x.Blacklist, artifact)).ToList(); var validDepth = allTriggers.Select(x => x.TargetDepth).Distinct().ToList(); var weights = GetDepthWeights(validDepth, node.Depth); @@ -95,7 +97,8 @@ public sealed partial class ArtifactSystem private string GetRandomEffect(EntityUid artifact, ref ArtifactNode node) { var allEffects = _prototype.EnumeratePrototypes() - .Where(x => (x.Whitelist?.IsValid(artifact, EntityManager) ?? true) && (!x.Blacklist?.IsValid(artifact, EntityManager) ?? true)).ToList(); + .Where(x => _whitelistSystem.IsWhitelistPassOrNull(x.Whitelist, artifact) && + _whitelistSystem.IsBlacklistFailOrNull(x.Blacklist, artifact)).ToList(); var validDepth = allEffects.Select(x => x.TargetDepth).Distinct().ToList(); var weights = GetDepthWeights(validDepth, node.Depth); diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs index 2e3f9ed461..48f4f07cbe 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs @@ -9,6 +9,7 @@ using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Popups; using Content.Shared.Verbs; +using Content.Shared.Whitelist; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.GameStates; @@ -31,6 +32,7 @@ namespace Content.Shared.Containers.ItemSlots [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; public override void Initialize() { @@ -266,8 +268,7 @@ namespace Content.Shared.Containers.ItemSlots if (slot.ContainerSlot == null) return false; - if ((!slot.Whitelist?.IsValid(usedUid) ?? false) || - (slot.Blacklist?.IsValid(usedUid) ?? false)) + if (_whitelistSystem.IsWhitelistFail(slot.Whitelist, usedUid) || _whitelistSystem.IsBlacklistPass(slot.Blacklist, usedUid)) { if (popup.HasValue && slot.WhitelistFailPopup.HasValue) _popupSystem.PopupClient(Loc.GetString(slot.WhitelistFailPopup), uid, popup.Value); diff --git a/Content.Shared/Damage/Systems/DamageContactsSystem.cs b/Content.Shared/Damage/Systems/DamageContactsSystem.cs index aec3d0766a..b08ef77fed 100644 --- a/Content.Shared/Damage/Systems/DamageContactsSystem.cs +++ b/Content.Shared/Damage/Systems/DamageContactsSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Damage.Components; +using Content.Shared.Whitelist; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; @@ -11,6 +12,7 @@ public sealed class DamageContactsSystem : EntitySystem [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; public override void Initialize() { @@ -63,7 +65,7 @@ public sealed class DamageContactsSystem : EntitySystem if (HasComp(otherUid)) return; - if (component.IgnoreWhitelist?.IsValid(otherUid) ?? false) + if (_whitelistSystem.IsWhitelistFail(component.IgnoreWhitelist, otherUid)) return; var damagedByContact = EnsureComp(otherUid); diff --git a/Content.Shared/Devour/SharedDevourSystem.cs b/Content.Shared/Devour/SharedDevourSystem.cs index 3d73b14dd3..14047fba7d 100644 --- a/Content.Shared/Devour/SharedDevourSystem.cs +++ b/Content.Shared/Devour/SharedDevourSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.DoAfter; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Popups; +using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; @@ -18,6 +19,7 @@ public abstract class SharedDevourSystem : EntitySystem [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; [Dependency] protected readonly SharedContainerSystem ContainerSystem = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; public override void Initialize() { @@ -41,7 +43,7 @@ public abstract class SharedDevourSystem : EntitySystem /// protected void OnDevourAction(EntityUid uid, DevourerComponent component, DevourActionEvent args) { - if (args.Handled || component.Whitelist?.IsValid(args.Target, EntityManager) != true) + if (args.Handled || _whitelistSystem.IsWhitelistFailOrNull(component.Whitelist, args.Target)) return; args.Handled = true; diff --git a/Content.Shared/Disposal/SharedDisposalUnitSystem.cs b/Content.Shared/Disposal/SharedDisposalUnitSystem.cs index c39139f9a5..9fdb4a6a80 100644 --- a/Content.Shared/Disposal/SharedDisposalUnitSystem.cs +++ b/Content.Shared/Disposal/SharedDisposalUnitSystem.cs @@ -6,6 +6,7 @@ using Content.Shared.DragDrop; using Content.Shared.Emag.Systems; using Content.Shared.Item; using Content.Shared.Throwing; +using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; @@ -25,6 +26,7 @@ public abstract class SharedDisposalUnitSystem : EntitySystem [Dependency] protected readonly IGameTiming GameTiming = default!; [Dependency] protected readonly MetaDataSystem Metadata = default!; [Dependency] protected readonly SharedJointSystem Joints = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; protected static TimeSpan ExitAttemptDelay = TimeSpan.FromSeconds(0.5); @@ -113,10 +115,8 @@ public abstract class SharedDisposalUnitSystem : EntitySystem if (!storable && !HasComp(entity)) return false; - if (component.Blacklist?.IsValid(entity, EntityManager) == true) - return false; - - if (component.Whitelist != null && component.Whitelist?.IsValid(entity, EntityManager) != true) + if (_whitelistSystem.IsBlacklistPass(component.Blacklist, entity) || + _whitelistSystem.IsWhitelistFail(component.Whitelist, entity)) return false; if (TryComp(entity, out var physics) && (physics.CanCollide) || storable) diff --git a/Content.Shared/Implants/SharedImplanterSystem.cs b/Content.Shared/Implants/SharedImplanterSystem.cs index d78522b56c..44803e721c 100644 --- a/Content.Shared/Implants/SharedImplanterSystem.cs +++ b/Content.Shared/Implants/SharedImplanterSystem.cs @@ -20,6 +20,7 @@ public abstract class SharedImplanterSystem : EntitySystem [Dependency] private readonly ItemSlotsSystem _itemSlots = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; public override void Initialize() { @@ -105,8 +106,8 @@ public abstract class SharedImplanterSystem : EntitySystem protected bool CheckTarget(EntityUid target, EntityWhitelist? whitelist, EntityWhitelist? blacklist) { - return whitelist?.IsValid(target, EntityManager) != false && - blacklist?.IsValid(target, EntityManager) != true; + return _whitelistSystem.IsWhitelistPassOrNull(whitelist, target) && + _whitelistSystem.IsBlacklistFailOrNull(blacklist, target); } //Draw the implant out of the target diff --git a/Content.Shared/Interaction/SmartEquipSystem.cs b/Content.Shared/Interaction/SmartEquipSystem.cs index fb2bc3c460..bba294db28 100644 --- a/Content.Shared/Interaction/SmartEquipSystem.cs +++ b/Content.Shared/Interaction/SmartEquipSystem.cs @@ -1,4 +1,4 @@ -using Content.Shared.ActionBlocker; +using Content.Shared.ActionBlocker; using Content.Shared.Containers.ItemSlots; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; @@ -7,6 +7,7 @@ using Content.Shared.Inventory; using Content.Shared.Popups; using Content.Shared.Storage; using Content.Shared.Storage.EntitySystems; +using Content.Shared.Whitelist; using Robust.Shared.Containers; using Robust.Shared.Input.Binding; using Robust.Shared.Player; @@ -25,6 +26,7 @@ public sealed class SmartEquipSystem : EntitySystem [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; /// public override void Initialize() @@ -182,7 +184,7 @@ public sealed class SmartEquipSystem : EntitySystem foreach (var slot in slots.Slots.Values) { if (!slot.HasItem - && (slot.Whitelist?.IsValid(handItem.Value, EntityManager) ?? true) + && _whitelistSystem.IsWhitelistPassOrNull(slot.Whitelist, handItem.Value) && slot.Priority > (toInsertTo?.Priority ?? int.MinValue)) { toInsertTo = slot; diff --git a/Content.Shared/Materials/SharedMaterialStorageSystem.cs b/Content.Shared/Materials/SharedMaterialStorageSystem.cs index b1de77d971..af815bdb2b 100644 --- a/Content.Shared/Materials/SharedMaterialStorageSystem.cs +++ b/Content.Shared/Materials/SharedMaterialStorageSystem.cs @@ -2,6 +2,7 @@ using System.Linq; using Content.Shared.Interaction; using Content.Shared.Interaction.Components; using Content.Shared.Stacks; +using Content.Shared.Whitelist; using JetBrains.Annotations; using Robust.Shared.Prototypes; using Robust.Shared.Timing; @@ -17,6 +18,7 @@ public abstract class SharedMaterialStorageSystem : EntitySystem [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; /// /// Default volume for a sheet if the material's entity prototype has no material composition. @@ -121,7 +123,7 @@ public abstract class SharedMaterialStorageSystem : EntitySystem if (!CanTakeVolume(uid, volume, component)) return false; - if (component.MaterialWhiteList != null && !component.MaterialWhiteList.Contains(materialId)) + if (component.MaterialWhiteList == null ? false : component.MaterialWhiteList.Contains(materialId)) return false; var amount = component.Storage.GetValueOrDefault(materialId); @@ -239,7 +241,7 @@ public abstract class SharedMaterialStorageSystem : EntitySystem if (!Resolve(toInsert, ref material, ref composition, false)) return false; - if (storage.Whitelist?.IsValid(toInsert) == false) + if (_whitelistSystem.IsWhitelistFail(storage.Whitelist, toInsert)) return false; if (HasComp(toInsert)) diff --git a/Content.Shared/Polymorph/Systems/SharedChameleonProjectorSystem.cs b/Content.Shared/Polymorph/Systems/SharedChameleonProjectorSystem.cs index c1abfc526f..00096b7d40 100644 --- a/Content.Shared/Polymorph/Systems/SharedChameleonProjectorSystem.cs +++ b/Content.Shared/Polymorph/Systems/SharedChameleonProjectorSystem.cs @@ -6,6 +6,7 @@ using Content.Shared.Popups; using Robust.Shared.Serialization.Manager; using Robust.Shared.Prototypes; using System.Diagnostics.CodeAnalysis; +using Content.Shared.Whitelist; namespace Content.Shared.Polymorph.Systems; @@ -18,6 +19,7 @@ public abstract class SharedChameleonProjectorSystem : EntitySystem [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly ISerializationManager _serMan = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; public override void Initialize() { @@ -49,8 +51,8 @@ public abstract class SharedChameleonProjectorSystem : EntitySystem /// public bool IsInvalid(ChameleonProjectorComponent comp, EntityUid target) { - return (comp.Whitelist?.IsValid(target, EntityManager) == false) - || (comp.Blacklist?.IsValid(target, EntityManager) == true); + return _whitelistSystem.IsWhitelistFail(comp.Whitelist, target) + || _whitelistSystem.IsBlacklistPass(comp.Blacklist, target); } /// diff --git a/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs b/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs index b355ae5873..f94558b0b3 100644 --- a/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs +++ b/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs @@ -6,6 +6,7 @@ using Content.Shared.Interaction; using Content.Shared.Popups; using Content.Shared.Stacks; using Content.Shared.Verbs; +using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; @@ -30,6 +31,7 @@ public abstract partial class SharedFultonSystem : EntitySystem [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedStackSystem _stack = default!; [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; [ValidatePrototypeId] public const string EffectProto = "FultonEffect"; protected static readonly Vector2 EffectOffset = Vector2.Zero; @@ -176,7 +178,7 @@ public abstract partial class SharedFultonSystem : EntitySystem if (!CanFulton(targetUid)) return false; - if (component.Whitelist?.IsValid(targetUid, EntityManager) != true) + if (_whitelistSystem.IsWhitelistFailOrNull(component.Whitelist, targetUid)) return false; return true; diff --git a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs index d859d9f485..a382e943ff 100644 --- a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs +++ b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs @@ -2,6 +2,7 @@ using Content.Shared.Containers.ItemSlots; using Content.Shared.Shuttles.BUIStates; using Content.Shared.Shuttles.Components; using Content.Shared.Shuttles.UI.MapObjects; +using Content.Shared.Whitelist; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Collision.Shapes; @@ -15,6 +16,7 @@ public abstract partial class SharedShuttleSystem : EntitySystem [Dependency] private readonly ItemSlotsSystem _itemSlots = default!; [Dependency] protected readonly SharedMapSystem Maps = default!; [Dependency] protected readonly SharedTransformSystem XformSystem = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; public const float FTLRange = 512f; public const float FTLBufferRange = 8f; @@ -83,7 +85,7 @@ public abstract partial class SharedShuttleSystem : EntitySystem if (HasComp(mapUid)) return false; - return destination.Whitelist?.IsValid(shuttleUid, EntityManager) != false; + return _whitelistSystem.IsWhitelistPassOrNull(destination.Whitelist, shuttleUid); } /// diff --git a/Content.Shared/Storage/EntitySystems/MagnetPickupSystem.cs b/Content.Shared/Storage/EntitySystems/MagnetPickupSystem.cs index 03da2d09b0..7a8961485d 100644 --- a/Content.Shared/Storage/EntitySystems/MagnetPickupSystem.cs +++ b/Content.Shared/Storage/EntitySystems/MagnetPickupSystem.cs @@ -1,5 +1,6 @@ using Content.Server.Storage.Components; using Content.Shared.Inventory; +using Content.Shared.Whitelist; using Robust.Shared.Map; using Robust.Shared.Physics.Components; using Robust.Shared.Timing; @@ -16,6 +17,8 @@ public sealed class MagnetPickupSystem : EntitySystem [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedStorageSystem _storage = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; + private static readonly TimeSpan ScanDelay = TimeSpan.FromSeconds(1); @@ -63,7 +66,7 @@ public sealed class MagnetPickupSystem : EntitySystem foreach (var near in _lookup.GetEntitiesInRange(uid, comp.Range, LookupFlags.Dynamic | LookupFlags.Sundries)) { - if (storage.Whitelist?.IsValid(near, EntityManager) == false) + if (_whitelistSystem.IsWhitelistFail(storage.Whitelist, near)) continue; if (!_physicsQuery.TryGetComponent(near, out var physics) || physics.BodyStatus != BodyStatus.OnGround) diff --git a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs index 0576e46df4..bb49725e04 100644 --- a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs @@ -15,6 +15,7 @@ using Content.Shared.Storage.Components; using Content.Shared.Tools.Systems; using Content.Shared.Verbs; using Content.Shared.Wall; +using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; @@ -45,6 +46,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem [Dependency] protected readonly SharedPopupSystem Popup = default!; [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; [Dependency] private readonly WeldableSystem _weldable = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; public const string ContainerName = "entity_storage"; @@ -432,7 +434,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem var targetIsMob = HasComp(toInsert); var storageIsItem = HasComp(container); - var allowedToEat = component.Whitelist?.IsValid(toInsert) ?? HasComp(toInsert); + var allowedToEat = component.Whitelist == null ? HasComp(toInsert) : _whitelistSystem.IsValid(component.Whitelist, toInsert); // BEFORE REPLACING THIS WITH, I.E. A PROPERTY: // Make absolutely 100% sure you have worked out how to stop people ending up in backpacks. diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs index ee087901f3..d87b57bfc8 100644 --- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs @@ -55,6 +55,7 @@ public abstract class SharedStorageSystem : EntitySystem [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; [Dependency] private readonly SharedUserInterfaceSystem _ui = default!; [Dependency] protected readonly UseDelaySystem UseDelay = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; private EntityQuery _itemQuery; private EntityQuery _stackQuery; @@ -860,13 +861,8 @@ public abstract class SharedStorageSystem : EntitySystem return false; } - if (storageComp.Whitelist?.IsValid(insertEnt, EntityManager) == false) - { - reason = "comp-storage-invalid-container"; - return false; - } - - if (storageComp.Blacklist?.IsValid(insertEnt, EntityManager) == true) + if (_whitelistSystem.IsWhitelistFail(storageComp.Whitelist, insertEnt) || + _whitelistSystem.IsBlacklistPass(storageComp.Blacklist, insertEnt)) { reason = "comp-storage-invalid-container"; return false; diff --git a/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs b/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs index d1814020e6..eab638a9fc 100644 --- a/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs +++ b/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs @@ -1,6 +1,7 @@ using Content.Shared.Damage; using Content.Shared.Projectiles; using Content.Shared.Weapons.Melee.Events; +using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Network; @@ -15,6 +16,7 @@ public abstract class SharedDamageMarkerSystem : EntitySystem [Dependency] private readonly INetManager _netManager = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly DamageableSystem _damageable = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; public override void Initialize() { @@ -58,7 +60,7 @@ public abstract class SharedDamageMarkerSystem : EntitySystem if (!args.OtherFixture.Hard || args.OurFixtureId != SharedProjectileSystem.ProjectileFixture || component.Amount <= 0 || - component.Whitelist?.IsValid(args.OtherEntity, EntityManager) == false || + _whitelistSystem.IsWhitelistFail(component.Whitelist, args.OtherEntity) || !TryComp(uid, out var projectile) || projectile.Weapon == null) { diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs index 784dd0793a..1f9e6cee76 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs @@ -41,7 +41,10 @@ public abstract partial class SharedGunSystem private void OnBallisticInteractUsing(EntityUid uid, BallisticAmmoProviderComponent component, InteractUsingEvent args) { - if (args.Handled || component.Whitelist?.IsValid(args.Used, EntityManager) != true) + if (args.Handled) + return; + + if (_whitelistSystem.IsWhitelistFailOrNull(component.Whitelist, args.Used)) return; if (GetBallisticShots(component) >= component.Capacity) diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Revolver.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Revolver.cs index b8b00799c1..14aaff5bf7 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Revolver.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Revolver.cs @@ -89,7 +89,7 @@ public partial class SharedGunSystem public bool TryRevolverInsert(EntityUid revolverUid, RevolverAmmoProviderComponent component, EntityUid uid, EntityUid? user) { - if (component.Whitelist?.IsValid(uid, EntityManager) == false) + if (_whitelistSystem.IsWhitelistFail(component.Whitelist, uid)) return false; // If it's a speedloader try to get ammo from it. diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index 4debc289be..47648a07ad 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -21,6 +21,7 @@ using Content.Shared.Weapons.Melee; using Content.Shared.Weapons.Melee.Events; using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; @@ -63,6 +64,7 @@ public abstract partial class SharedGunSystem : EntitySystem [Dependency] protected readonly TagSystem TagSystem = default!; [Dependency] protected readonly ThrowingSystem ThrowingSystem = default!; [Dependency] private readonly UseDelaySystem _useDelay = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; private const float InteractNextFire = 0.3f; private const double SafetyNextFire = 0.5; diff --git a/Content.Shared/Whitelist/EntityWhitelistSystem.cs b/Content.Shared/Whitelist/EntityWhitelistSystem.cs index d73646b7e9..f311946cf9 100644 --- a/Content.Shared/Whitelist/EntityWhitelistSystem.cs +++ b/Content.Shared/Whitelist/EntityWhitelistSystem.cs @@ -60,6 +60,90 @@ public sealed class EntityWhitelistSystem : EntitySystem return list.RequireAll; } + /// The following are a list of "helper functions" that are basically the same as each other + /// to help make code that uses EntityWhitelist a bit more readable because at the moment + /// it is quite clunky having to write out component.Whitelist == null ? true : _whitelist.IsValid(component.Whitelist, uid) + /// several times in a row and makes comparisons easier to read + + /// + /// Helper function to determine if Whitelist is not null and entity is on list + /// + public bool IsWhitelistPass(EntityWhitelist? whitelist, EntityUid uid) + { + if (whitelist == null) + return false; + + return IsValid(whitelist, uid); + } + + /// + /// Helper function to determine if Whitelist is not null and entity is not on the list + /// + public bool IsWhitelistFail(EntityWhitelist? whitelist, EntityUid uid) + { + if (whitelist == null) + return false; + + return !IsValid(whitelist, uid); + } + + /// + /// Helper function to determine if Whitelist is either null or the entity is on the list + /// + public bool IsWhitelistPassOrNull(EntityWhitelist? whitelist, EntityUid uid) + { + if (whitelist == null) + return true; + + return IsValid(whitelist, uid); + } + + /// + /// Helper function to determine if Whitelist is either null or the entity is not on the list + /// + public bool IsWhitelistFailOrNull(EntityWhitelist? whitelist, EntityUid uid) + { + if (whitelist == null) + return true; + + return !IsValid(whitelist, uid); + } + + /// + /// Helper function to determine if Blacklist is not null and entity is on list + /// Duplicate of equivalent Whitelist function + /// + public bool IsBlacklistPass(EntityWhitelist? blacklist, EntityUid uid) + { + return IsWhitelistPass(blacklist, uid); + } + + /// + /// Helper function to determine if Blacklist is not null and entity is not on the list + /// Duplicate of equivalent Whitelist function + /// + public bool IsBlacklistFail(EntityWhitelist? blacklist, EntityUid uid) + { + return IsWhitelistFail(blacklist, uid); + } + + /// + /// Helper function to determine if Blacklist is either null or the entity is on the list + /// Duplicate of equivalent Whitelist function + /// + public bool IsBlacklistPassOrNull(EntityWhitelist? blacklist, EntityUid uid) + { + return IsWhitelistPassOrNull(blacklist, uid); + } + + /// + /// Helper function to determine if Blacklist is either null or the entity is not on the list + /// Duplicate of equivalent Whitelist function + /// + public bool IsBlacklistFailOrNull(EntityWhitelist? blacklist, EntityUid uid) + { + return IsWhitelistFailOrNull(blacklist, uid); + } private void EnsureRegistrations(EntityWhitelist list) { From 21d0b1fd558f417c25e0587cf8d0186ec83a294e Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Sat, 1 Jun 2024 23:58:33 -0400 Subject: [PATCH 09/20] Guidebook Tables (#28484) * PJB's cool table control (it probably doesn't work) * ok wait wrong file * Guidebook Tables --- Content.Client/Guidebook/Richtext/Box.cs | 3 + Content.Client/Guidebook/Richtext/ColorBox.cs | 49 +++ Content.Client/Guidebook/Richtext/Table.cs | 27 ++ .../UserInterface/Controls/TableContainer.cs | 285 ++++++++++++++++++ 4 files changed, 364 insertions(+) create mode 100644 Content.Client/Guidebook/Richtext/ColorBox.cs create mode 100644 Content.Client/Guidebook/Richtext/Table.cs create mode 100644 Content.Client/UserInterface/Controls/TableContainer.cs diff --git a/Content.Client/Guidebook/Richtext/Box.cs b/Content.Client/Guidebook/Richtext/Box.cs index ecf6cb21f7..6e18ad9c57 100644 --- a/Content.Client/Guidebook/Richtext/Box.cs +++ b/Content.Client/Guidebook/Richtext/Box.cs @@ -11,6 +11,9 @@ public sealed class Box : BoxContainer, IDocumentTag HorizontalExpand = true; control = this; + if (args.TryGetValue("Margin", out var margin)) + Margin = new Thickness(float.Parse(margin)); + if (args.TryGetValue("Orientation", out var orientation)) Orientation = Enum.Parse(orientation); else diff --git a/Content.Client/Guidebook/Richtext/ColorBox.cs b/Content.Client/Guidebook/Richtext/ColorBox.cs new file mode 100644 index 0000000000..84de300d6e --- /dev/null +++ b/Content.Client/Guidebook/Richtext/ColorBox.cs @@ -0,0 +1,49 @@ +using System.Diagnostics.CodeAnalysis; +using JetBrains.Annotations; +using Robust.Client.Graphics; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; + +namespace Content.Client.Guidebook.Richtext; + +[UsedImplicitly] +public sealed class ColorBox : PanelContainer, IDocumentTag +{ + public bool TryParseTag(Dictionary args, [NotNullWhen(true)] out Control? control) + { + HorizontalExpand = true; + VerticalExpand = true; + control = this; + + if (args.TryGetValue("Margin", out var margin)) + Margin = new Thickness(float.Parse(margin)); + + if (args.TryGetValue("HorizontalAlignment", out var halign)) + HorizontalAlignment = Enum.Parse(halign); + else + HorizontalAlignment = HAlignment.Stretch; + + if (args.TryGetValue("VerticalAlignment", out var valign)) + VerticalAlignment = Enum.Parse(valign); + else + VerticalAlignment = VAlignment.Stretch; + + var styleBox = new StyleBoxFlat(); + if (args.TryGetValue("Color", out var color)) + styleBox.BackgroundColor = Color.FromHex(color); + + if (args.TryGetValue("OutlineThickness", out var outlineThickness)) + styleBox.BorderThickness = new Thickness(float.Parse(outlineThickness)); + else + styleBox.BorderThickness = new Thickness(1); + + if (args.TryGetValue("OutlineColor", out var outlineColor)) + styleBox.BorderColor = Color.FromHex(outlineColor); + else + styleBox.BorderColor = Color.White; + + PanelOverride = styleBox; + + return true; + } +} diff --git a/Content.Client/Guidebook/Richtext/Table.cs b/Content.Client/Guidebook/Richtext/Table.cs new file mode 100644 index 0000000000..b6923c3698 --- /dev/null +++ b/Content.Client/Guidebook/Richtext/Table.cs @@ -0,0 +1,27 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Client.UserInterface.Controls; +using JetBrains.Annotations; +using Robust.Client.UserInterface; + +namespace Content.Client.Guidebook.Richtext; + +[UsedImplicitly] +public sealed class Table : TableContainer, IDocumentTag +{ + public bool TryParseTag(Dictionary args, [NotNullWhen(true)] out Control? control) + { + HorizontalExpand = true; + control = this; + + if (!args.TryGetValue("Columns", out var columns) || !int.TryParse(columns, out var columnsCount)) + { + Logger.Error("Guidebook tag \"Table\" does not specify required property \"Columns.\""); + control = null; + return false; + } + + Columns = columnsCount; + + return true; + } +} diff --git a/Content.Client/UserInterface/Controls/TableContainer.cs b/Content.Client/UserInterface/Controls/TableContainer.cs new file mode 100644 index 0000000000..3e8d476001 --- /dev/null +++ b/Content.Client/UserInterface/Controls/TableContainer.cs @@ -0,0 +1,285 @@ +using System.Numerics; +using Robust.Client.UserInterface.Controls; + +namespace Content.Client.UserInterface.Controls; + +// This control is not part of engine because I quickly wrote it in 2 hours at 2 AM and don't want to deal with +// API stabilization and/or figuring out relation to GridContainer. +// Grid layout is a complicated problem and I don't want to commit another half-baked thing into the engine. +// It's probably sufficient for its use case (RichTextLabel tables for rules/guidebook). +// Despite that, it's still better comment the shit half of you write on a regular basis. +// +// EMO: thank you PJB i was going to kill myself. + +/// +/// Displays children in a tabular grid. Unlike , +/// properly handles layout constraints so putting word-wrapping in it should work. +/// +/// +/// All children are automatically laid out in columns. +/// The first control is in the top left, laid out per row from there. +/// +[Virtual] +public class TableContainer : Container +{ + private int _columns = 1; + + /// + /// The absolute minimum width a column can be forced to. + /// + /// + /// + /// If a column *asks* for less width than this (small contents), it can still be smaller. + /// But if it asks for more it cannot go below this width. + /// + /// + public float MinForcedColumnWidth { get; set; } = 50; + + // Scratch space used while calculating layout, cached to avoid regular allocations during layout pass. + private ColumnData[] _columnDataCache = []; + private RowData[] _rowDataCache = []; + + /// + /// How many columns should be displayed. + /// + public int Columns + { + get => _columns; + set + { + ArgumentOutOfRangeException.ThrowIfLessThan(value, 1, nameof(value)); + + _columns = value; + } + } + + protected override Vector2 MeasureOverride(Vector2 availableSize) + { + ResetCachedArrays(); + + // Do a first pass measuring all child controls as if they're given infinite space. + // This gives us a maximum width the columns want, which we use to proportion them later. + var columnIdx = 0; + foreach (var child in Children) + { + ref var column = ref _columnDataCache[columnIdx]; + + child.Measure(new Vector2(float.PositiveInfinity, float.PositiveInfinity)); + column.MaxWidth = Math.Max(column.MaxWidth, child.DesiredSize.X); + + columnIdx += 1; + if (columnIdx == _columns) + columnIdx = 0; + } + + // Calculate Slack and MinWidth for all columns. Also calculate sums for all columns. + var totalMinWidth = 0f; + var totalMaxWidth = 0f; + var totalSlack = 0f; + + for (var c = 0; c < _columns; c++) + { + ref var column = ref _columnDataCache[c]; + column.MinWidth = Math.Min(column.MaxWidth, MinForcedColumnWidth); + column.Slack = column.MaxWidth - column.MinWidth; + + totalMinWidth += column.MinWidth; + totalMaxWidth += column.MaxWidth; + totalSlack += column.Slack; + } + + if (totalMaxWidth <= availableSize.X) + { + // We want less horizontal space than we're given. Huh, that's convenient. + // Just set assigned width to be however much they asked for. + // We could probably skip the second measure pass in this scenario, + // but that's just an optimization, so I don't care right now. + // + // There's probably a very clever way to make this behavior work with the else block of logic, + // just by fiddling with the math. + // I'm dumb, it's 4:30 AM. Yeah, I *started* at 2 AM. + for (var c = 0; c < _columns; c++) + { + ref var column = ref _columnDataCache[c]; + + column.AssignedWidth = column.MaxWidth; + } + } + else + { + // We don't have enough horizontal space, + // at least without causing *some* sort of word wrapping (assuming text contents). + // + // Assign horizontal space proportional to the wanted maximum size of the columns. + var assignableWidth = Math.Max(0, availableSize.X - totalMinWidth); + for (var c = 0; c < _columns; c++) + { + ref var column = ref _columnDataCache[c]; + + var slackRatio = column.Slack / totalSlack; + column.AssignedWidth = column.MinWidth + slackRatio * assignableWidth; + } + } + + // Go over controls for a second measuring pass, this time giving them their assigned measure width. + // This will give us a height to slot into per-row data. + // We still measure assuming infinite vertical space. + // This control can't properly handle being constrained on the Y axis. + columnIdx = 0; + var rowIdx = 0; + foreach (var child in Children) + { + ref var column = ref _columnDataCache[columnIdx]; + ref var row = ref _rowDataCache[rowIdx]; + + child.Measure(new Vector2(column.AssignedWidth, float.PositiveInfinity)); + row.MeasuredHeight = Math.Max(row.MeasuredHeight, child.DesiredSize.Y); + + columnIdx += 1; + if (columnIdx == _columns) + { + columnIdx = 0; + rowIdx += 1; + } + } + + // Sum up height of all rows to get final measured table height. + var totalHeight = 0f; + for (var r = 0; r < _rowDataCache.Length; r++) + { + ref var row = ref _rowDataCache[r]; + totalHeight += row.MeasuredHeight; + } + + return new Vector2(Math.Min(availableSize.X, totalMaxWidth), totalHeight); + } + + protected override Vector2 ArrangeOverride(Vector2 finalSize) + { + // TODO: Expand to fit given vertical space. + + // Calculate MinWidth and Slack sums again from column data. + // We could've cached these from measure but whatever. + var totalMinWidth = 0f; + var totalSlack = 0f; + + for (var c = 0; c < _columns; c++) + { + ref var column = ref _columnDataCache[c]; + totalMinWidth += column.MinWidth; + totalSlack += column.Slack; + } + + // Calculate new width based on final given size, also assign horizontal positions of all columns. + var assignableWidth = Math.Max(0, finalSize.X - totalMinWidth); + var xPos = 0f; + for (var c = 0; c < _columns; c++) + { + ref var column = ref _columnDataCache[c]; + + var slackRatio = column.Slack / totalSlack; + column.ArrangedWidth = column.MinWidth + slackRatio * assignableWidth; + column.ArrangedX = xPos; + + xPos += column.ArrangedWidth; + } + + // Do actual arrangement row-by-row. + var arrangeY = 0f; + for (var r = 0; r < _rowDataCache.Length; r++) + { + ref var row = ref _rowDataCache[r]; + + for (var c = 0; c < _columns; c++) + { + ref var column = ref _columnDataCache[c]; + var index = c + r * _columns; + + if (index >= ChildCount) // Quit early if we don't actually fill out the row. + break; + var child = GetChild(c + r * _columns); + + child.Arrange(UIBox2.FromDimensions(column.ArrangedX, arrangeY, column.ArrangedWidth, row.MeasuredHeight)); + } + + arrangeY += row.MeasuredHeight; + } + + return finalSize with { Y = arrangeY }; + } + + /// + /// Ensure cached array space is allocated to correct size and is reset to a clean slate. + /// + private void ResetCachedArrays() + { + // 1-argument Array.Clear() is not currently available in sandbox (added in .NET 6). + + if (_columnDataCache.Length != _columns) + _columnDataCache = new ColumnData[_columns]; + + Array.Clear(_columnDataCache, 0, _columnDataCache.Length); + + var rowCount = ChildCount / _columns; + if (ChildCount % _columns != 0) + rowCount += 1; + + if (rowCount != _rowDataCache.Length) + _rowDataCache = new RowData[rowCount]; + + Array.Clear(_rowDataCache, 0, _rowDataCache.Length); + } + + /// + /// Per-column data used during layout. + /// + private struct ColumnData + { + // Measure data. + + /// + /// The maximum width any control in this column wants, if given infinite space. + /// Maximum of all controls on the column. + /// + public float MaxWidth; + + /// + /// The minimum width this column may be given. + /// This is either or . + /// + public float MinWidth; + + /// + /// Difference between max and min width; how much this column can expand from its minimum. + /// + public float Slack; + + /// + /// How much horizontal space this column was assigned at measure time. + /// + public float AssignedWidth; + + // Arrange data. + + /// + /// How much horizontal space this column was assigned at arrange time. + /// + public float ArrangedWidth; + + /// + /// The horizontal position this column was assigned at arrange time. + /// + public float ArrangedX; + } + + private struct RowData + { + // Measure data. + + /// + /// How much height the tallest control on this row was measured at, + /// measuring for infinite vertical space but assigned column width. + /// + public float MeasuredHeight; + } +} From b44b159431630a918356e9625420e8d7fd8d468e Mon Sep 17 00:00:00 2001 From: eoineoineoin Date: Sun, 2 Jun 2024 05:07:41 +0100 Subject: [PATCH 10/20] Replace Matrix3 with System.Numerics.Matrix3x2 (#27443) Replace Matrix3 with Matrix3x2 --- .../SpawnExplosion/ExplosionDebugOverlay.cs | 16 ++++--- .../Atmos/Overlays/AtmosDebugOverlay.cs | 2 +- .../Atmos/Overlays/GasTileOverlay.cs | 4 +- .../Clickable/ClickableComponent.cs | 12 ++--- .../Decals/Overlays/DecalOverlay.cs | 3 +- .../Decals/Overlays/DecalPlacementOverlay.cs | 4 +- Content.Client/DoAfter/DoAfterOverlay.cs | 12 ++--- Content.Client/Explosion/ExplosionOverlay.cs | 5 +- Content.Client/Fluids/PuddleOverlay.cs | 7 +-- Content.Client/Maps/GridDraggingSystem.cs | 4 +- Content.Client/NPC/PathfindingSystem.cs | 8 ++-- .../NodeContainer/NodeVisualizationOverlay.cs | 2 +- .../Overlays/EntityHealthBarOverlay.cs | 12 ++--- .../StencilOverlay.RestrictedRange.cs | 6 +-- .../Overlays/StencilOverlay.Weather.cs | 8 ++-- Content.Client/Overlays/StencilOverlay.cs | 3 +- Content.Client/Paper/UI/StampLabel.xaml.cs | 2 +- Content.Client/Paper/UI/StampWidget.xaml.cs | 2 +- Content.Client/Pinpointer/UI/NavMapControl.cs | 6 +-- Content.Client/Popups/PopupOverlay.cs | 5 +- .../Systems/ShuttleSystem.EmergencyConsole.cs | 3 +- .../Shuttles/UI/BaseShuttleControl.xaml.cs | 7 +-- Content.Client/Shuttles/UI/NavScreen.xaml.cs | 3 +- .../Shuttles/UI/ShuttleDockControl.xaml.cs | 46 +++++++++---------- .../Shuttles/UI/ShuttleMapControl.xaml.cs | 26 +++++------ .../Shuttles/UI/ShuttleNavControl.xaml.cs | 24 +++++----- .../StatusIcon/StatusIconOverlay.cs | 10 ++-- .../Storage/Systems/StorageSystem.cs | 5 +- .../UserInterface/Controls/DirectionIcon.cs | 2 +- .../Controls/MapGridControl.xaml.cs | 2 +- Content.Client/Viewport/ScalingViewport.cs | 18 ++++---- .../Melee/MeleeWeaponSystem.Effects.cs | 2 +- .../Weapons/Ranged/ItemStatus/BulletRender.cs | 4 +- .../EntitySystems/ExplosionGridTileFlood.cs | 13 +++--- .../EntitySystems/ExplosionSystem.GridMap.cs | 12 ++--- .../ExplosionSystem.Processing.cs | 20 ++++---- .../EntitySystems/ExplosionSystem.TileFill.cs | 4 +- .../EntitySystems/ExplosionSystem.Visuals.cs | 3 +- .../Fluids/EntitySystems/AbsorbentSystem.cs | 3 +- .../GameTicking/GameTicker.Spawning.cs | 2 +- .../Medical/SuitSensors/SuitSensorSystem.cs | 5 +- .../Pathfinding/PathfindingSystem.Distance.cs | 2 +- .../NPC/Pathfinding/PathfindingSystem.Grid.cs | 2 +- .../NPC/Pathfinding/PathfindingSystem.cs | 2 +- .../Procedural/DungeonJob.PrefabDunGen.cs | 24 +++++----- .../Procedural/DungeonSystem.Rooms.cs | 16 +++---- .../Systems/RadiationSystem.GridCast.cs | 4 +- Content.Server/Salvage/FultonSystem.cs | 6 ++- .../Shuttles/Events/FTLStartedEvent.cs | 3 +- .../Shuttles/Systems/ArrivalsSystem.cs | 3 +- .../Shuttles/Systems/DockingSystem.Shuttle.cs | 16 +++---- .../Shuttles/Systems/ShuttleSystem.Impact.cs | 5 +- .../EntitySystems/GravityWellSystem.cs | 16 +++---- .../Weapons/Ranged/Systems/GunSystem.cs | 2 +- .../Components/ExplosionVisualsComponent.cs | 7 +-- Content.Shared/Item/SharedItemSystem.cs | 2 +- Content.Shared/Maps/TurfSystem.cs | 2 +- .../Weapons/Melee/SharedMeleeWeaponSystem.cs | 2 +- 58 files changed, 236 insertions(+), 215 deletions(-) diff --git a/Content.Client/Administration/UI/SpawnExplosion/ExplosionDebugOverlay.cs b/Content.Client/Administration/UI/SpawnExplosion/ExplosionDebugOverlay.cs index eede3a6217..d60094ad89 100644 --- a/Content.Client/Administration/UI/SpawnExplosion/ExplosionDebugOverlay.cs +++ b/Content.Client/Administration/UI/SpawnExplosion/ExplosionDebugOverlay.cs @@ -25,7 +25,7 @@ public sealed class ExplosionDebugOverlay : Overlay public override OverlaySpace Space => OverlaySpace.WorldSpace | OverlaySpace.ScreenSpace; - public Matrix3 SpaceMatrix; + public Matrix3x2 SpaceMatrix; public MapId Map; private readonly Font _font; @@ -78,7 +78,8 @@ public sealed class ExplosionDebugOverlay : Overlay if (SpaceTiles == null) return; - gridBounds = Matrix3.Invert(SpaceMatrix).TransformBox(args.WorldBounds); + Matrix3x2.Invert(SpaceMatrix, out var invSpace); + gridBounds = invSpace.TransformBox(args.WorldBounds); DrawText(handle, gridBounds, SpaceMatrix, SpaceTiles, SpaceTileSize); } @@ -86,7 +87,7 @@ public sealed class ExplosionDebugOverlay : Overlay private void DrawText( DrawingHandleScreen handle, Box2 gridBounds, - Matrix3 transform, + Matrix3x2 transform, Dictionary> tileSets, ushort tileSize) { @@ -103,7 +104,7 @@ public sealed class ExplosionDebugOverlay : Overlay if (!gridBounds.Contains(centre)) continue; - var worldCenter = transform.Transform(centre); + var worldCenter = Vector2.Transform(centre, transform); var screenCenter = _eyeManager.WorldToScreen(worldCenter); @@ -119,7 +120,7 @@ public sealed class ExplosionDebugOverlay : Overlay if (tileSets.TryGetValue(0, out var set)) { var epicenter = set.First(); - var worldCenter = transform.Transform((epicenter + Vector2Helpers.Half) * tileSize); + var worldCenter = Vector2.Transform((epicenter + Vector2Helpers.Half) * tileSize, transform); var screenCenter = _eyeManager.WorldToScreen(worldCenter) + new Vector2(-24, -24); var text = $"{Intensity[0]:F2}\nΣ={TotalIntensity:F1}\nΔ={Slope:F1}"; handle.DrawString(_font, screenCenter, text); @@ -148,11 +149,12 @@ public sealed class ExplosionDebugOverlay : Overlay if (SpaceTiles == null) return; - gridBounds = Matrix3.Invert(SpaceMatrix).TransformBox(args.WorldBounds).Enlarged(2); + Matrix3x2.Invert(SpaceMatrix, out var invSpace); + gridBounds = invSpace.TransformBox(args.WorldBounds).Enlarged(2); handle.SetTransform(SpaceMatrix); DrawTiles(handle, gridBounds, SpaceTiles, SpaceTileSize); - handle.SetTransform(Matrix3.Identity); + handle.SetTransform(Matrix3x2.Identity); } private void DrawTiles( diff --git a/Content.Client/Atmos/Overlays/AtmosDebugOverlay.cs b/Content.Client/Atmos/Overlays/AtmosDebugOverlay.cs index 6dfbc326ec..c85dbd2051 100644 --- a/Content.Client/Atmos/Overlays/AtmosDebugOverlay.cs +++ b/Content.Client/Atmos/Overlays/AtmosDebugOverlay.cs @@ -66,7 +66,7 @@ public sealed class AtmosDebugOverlay : Overlay DrawData(msg, handle); } - handle.SetTransform(Matrix3.Identity); + handle.SetTransform(Matrix3x2.Identity); } private void DrawData(DebugMessage msg, diff --git a/Content.Client/Atmos/Overlays/GasTileOverlay.cs b/Content.Client/Atmos/Overlays/GasTileOverlay.cs index f4dc274a4e..17027525e5 100644 --- a/Content.Client/Atmos/Overlays/GasTileOverlay.cs +++ b/Content.Client/Atmos/Overlays/GasTileOverlay.cs @@ -190,7 +190,7 @@ namespace Content.Client.Atmos.Overlays var (_, _, worldMatrix, invMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(); state.drawHandle.SetTransform(worldMatrix); - var floatBounds = invMatrix.TransformBox(in state.WorldBounds).Enlarged(grid.TileSize); + var floatBounds = invMatrix.TransformBox(state.WorldBounds).Enlarged(grid.TileSize); var localBounds = new Box2i( (int) MathF.Floor(floatBounds.Left), (int) MathF.Floor(floatBounds.Bottom), @@ -249,7 +249,7 @@ namespace Content.Client.Atmos.Overlays }); drawHandle.UseShader(null); - drawHandle.SetTransform(Matrix3.Identity); + drawHandle.SetTransform(Matrix3x2.Identity); } private void DrawMapOverlay( diff --git a/Content.Client/Clickable/ClickableComponent.cs b/Content.Client/Clickable/ClickableComponent.cs index cfbd1a99d6..6f75df4683 100644 --- a/Content.Client/Clickable/ClickableComponent.cs +++ b/Content.Client/Clickable/ClickableComponent.cs @@ -38,9 +38,9 @@ namespace Content.Client.Clickable renderOrder = sprite.RenderOrder; var (spritePos, spriteRot) = transform.GetWorldPositionRotation(xformQuery); var spriteBB = sprite.CalculateRotatedBoundingBox(spritePos, spriteRot, eye.Rotation); - bottom = Matrix3.CreateRotation(eye.Rotation).TransformBox(spriteBB).Bottom; + bottom = Matrix3Helpers.CreateRotation(eye.Rotation).TransformBox(spriteBB).Bottom; - var invSpriteMatrix = Matrix3.Invert(sprite.GetLocalMatrix()); + Matrix3x2.Invert(sprite.GetLocalMatrix(), out var invSpriteMatrix); // This should have been the rotation of the sprite relative to the screen, but this is not the case with no-rot or directional sprites. var relativeRotation = (spriteRot + eye.Rotation).Reduced().FlipPositive(); @@ -48,8 +48,8 @@ namespace Content.Client.Clickable Angle cardinalSnapping = sprite.SnapCardinals ? relativeRotation.GetCardinalDir().ToAngle() : Angle.Zero; // First we get `localPos`, the clicked location in the sprite-coordinate frame. - var entityXform = Matrix3.CreateInverseTransform(transform.WorldPosition, sprite.NoRotation ? -eye.Rotation : spriteRot - cardinalSnapping); - var localPos = invSpriteMatrix.Transform(entityXform.Transform(worldPos)); + var entityXform = Matrix3Helpers.CreateInverseTransform(transform.WorldPosition, sprite.NoRotation ? -eye.Rotation : spriteRot - cardinalSnapping); + var localPos = Vector2.Transform(Vector2.Transform(worldPos, entityXform), invSpriteMatrix); // Check explicitly defined click-able bounds if (CheckDirBound(sprite, relativeRotation, localPos)) @@ -79,8 +79,8 @@ namespace Content.Client.Clickable // convert to layer-local coordinates layer.GetLayerDrawMatrix(dir, out var matrix); - var inverseMatrix = Matrix3.Invert(matrix); - var layerLocal = inverseMatrix.Transform(localPos); + Matrix3x2.Invert(matrix, out var inverseMatrix); + var layerLocal = Vector2.Transform(localPos, inverseMatrix); // Convert to image coordinates var layerImagePos = (Vector2i) (layerLocal * EyeManager.PixelsPerMeter * new Vector2(1, -1) + rsiState.Size / 2f); diff --git a/Content.Client/Decals/Overlays/DecalOverlay.cs b/Content.Client/Decals/Overlays/DecalOverlay.cs index d9904ae80b..0de3301e58 100644 --- a/Content.Client/Decals/Overlays/DecalOverlay.cs +++ b/Content.Client/Decals/Overlays/DecalOverlay.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Content.Shared.Decals; using Robust.Client.GameObjects; using Robust.Client.Graphics; @@ -113,7 +114,7 @@ namespace Content.Client.Decals.Overlays handle.DrawTexture(cache.Texture, decal.Coordinates, angle, decal.Color); } - handle.SetTransform(Matrix3.Identity); + handle.SetTransform(Matrix3x2.Identity); } } } diff --git a/Content.Client/Decals/Overlays/DecalPlacementOverlay.cs b/Content.Client/Decals/Overlays/DecalPlacementOverlay.cs index be277448ed..845bd7c03d 100644 --- a/Content.Client/Decals/Overlays/DecalPlacementOverlay.cs +++ b/Content.Client/Decals/Overlays/DecalPlacementOverlay.cs @@ -51,7 +51,7 @@ public sealed class DecalPlacementOverlay : Overlay var handle = args.WorldHandle; handle.SetTransform(worldMatrix); - var localPos = invMatrix.Transform(mousePos.Position); + var localPos = Vector2.Transform(mousePos.Position, invMatrix); if (snap) { @@ -63,6 +63,6 @@ public sealed class DecalPlacementOverlay : Overlay var box = new Box2Rotated(aabb, rotation, localPos); handle.DrawTextureRect(_sprite.Frame0(decal.Sprite), box, color); - handle.SetTransform(Matrix3.Identity); + handle.SetTransform(Matrix3x2.Identity); } } diff --git a/Content.Client/DoAfter/DoAfterOverlay.cs b/Content.Client/DoAfter/DoAfterOverlay.cs index 45981159f0..dfbbf10891 100644 --- a/Content.Client/DoAfter/DoAfterOverlay.cs +++ b/Content.Client/DoAfter/DoAfterOverlay.cs @@ -56,8 +56,8 @@ public sealed class DoAfterOverlay : Overlay // If you use the display UI scale then need to set max(1f, displayscale) because 0 is valid. const float scale = 1f; - var scaleMatrix = Matrix3.CreateScale(new Vector2(scale, scale)); - var rotationMatrix = Matrix3.CreateRotation(-rotation); + var scaleMatrix = Matrix3Helpers.CreateScale(new Vector2(scale, scale)); + var rotationMatrix = Matrix3Helpers.CreateRotation(-rotation); var curTime = _timing.CurTime; @@ -91,9 +91,9 @@ public sealed class DoAfterOverlay : Overlay ? curTime - _meta.GetPauseTime(uid, meta) : curTime; - var worldMatrix = Matrix3.CreateTranslation(worldPosition); - Matrix3.Multiply(scaleMatrix, worldMatrix, out var scaledWorld); - Matrix3.Multiply(rotationMatrix, scaledWorld, out var matty); + var worldMatrix = Matrix3Helpers.CreateTranslation(worldPosition); + var scaledWorld = Matrix3x2.Multiply(scaleMatrix, worldMatrix); + var matty = Matrix3x2.Multiply(rotationMatrix, scaledWorld); handle.SetTransform(matty); var offset = 0f; @@ -151,7 +151,7 @@ public sealed class DoAfterOverlay : Overlay } handle.UseShader(null); - handle.SetTransform(Matrix3.Identity); + handle.SetTransform(Matrix3x2.Identity); } public Color GetProgressColor(float progress, float alpha = 1f) diff --git a/Content.Client/Explosion/ExplosionOverlay.cs b/Content.Client/Explosion/ExplosionOverlay.cs index 2d8c15f1b9..8cf7447a5d 100644 --- a/Content.Client/Explosion/ExplosionOverlay.cs +++ b/Content.Client/Explosion/ExplosionOverlay.cs @@ -48,7 +48,7 @@ public sealed class ExplosionOverlay : Overlay DrawExplosion(drawHandle, args.WorldBounds, visuals, index, xforms, textures); } - drawHandle.SetTransform(Matrix3.Identity); + drawHandle.SetTransform(Matrix3x2.Identity); drawHandle.UseShader(null); } @@ -78,7 +78,8 @@ public sealed class ExplosionOverlay : Overlay if (visuals.SpaceTiles == null) return; - gridBounds = Matrix3.Invert(visuals.SpaceMatrix).TransformBox(worldBounds).Enlarged(2); + Matrix3x2.Invert(visuals.SpaceMatrix, out var invSpace); + gridBounds = invSpace.TransformBox(worldBounds).Enlarged(2); drawHandle.SetTransform(visuals.SpaceMatrix); DrawTiles(drawHandle, gridBounds, index, visuals.SpaceTiles, visuals, visuals.SpaceTileSize, textures); diff --git a/Content.Client/Fluids/PuddleOverlay.cs b/Content.Client/Fluids/PuddleOverlay.cs index ac6661cfdd..a8c1d35510 100644 --- a/Content.Client/Fluids/PuddleOverlay.cs +++ b/Content.Client/Fluids/PuddleOverlay.cs @@ -1,4 +1,5 @@ -using Content.Shared.FixedPoint; +using System.Numerics; +using Content.Shared.FixedPoint; using Robust.Client.Graphics; using Robust.Client.ResourceManagement; using Robust.Shared.Enums; @@ -73,7 +74,7 @@ public sealed class PuddleOverlay : Overlay } } - drawHandle.SetTransform(Matrix3.Identity); + drawHandle.SetTransform(Matrix3x2.Identity); } private void DrawScreen(in OverlayDrawArgs args) @@ -99,7 +100,7 @@ public sealed class PuddleOverlay : Overlay if (!gridBounds.Contains(centre)) continue; - var screenCenter = _eyeManager.WorldToScreen(matrix.Transform(centre)); + var screenCenter = _eyeManager.WorldToScreen(Vector2.Transform(centre, matrix)); drawHandle.DrawString(_font, screenCenter, debugOverlayData.CurrentVolume.ToString(), Color.White); } diff --git a/Content.Client/Maps/GridDraggingSystem.cs b/Content.Client/Maps/GridDraggingSystem.cs index e82786847e..5e9250f0ce 100644 --- a/Content.Client/Maps/GridDraggingSystem.cs +++ b/Content.Client/Maps/GridDraggingSystem.cs @@ -101,7 +101,7 @@ public sealed class GridDraggingSystem : SharedGridDraggingSystem if (!_mapManager.TryFindGridAt(mousePos, out var gridUid, out var grid)) return; - StartDragging(gridUid, Transform(gridUid).InvWorldMatrix.Transform(mousePos.Position)); + StartDragging(gridUid, Vector2.Transform(mousePos.Position, Transform(gridUid).InvWorldMatrix)); } if (!TryComp(_dragging, out TransformComponent? xform)) @@ -116,7 +116,7 @@ public sealed class GridDraggingSystem : SharedGridDraggingSystem return; } - var localToWorld = xform.WorldMatrix.Transform(_localPosition); + var localToWorld = Vector2.Transform(_localPosition, xform.WorldMatrix); if (localToWorld.EqualsApprox(mousePos.Position, 0.01f)) return; diff --git a/Content.Client/NPC/PathfindingSystem.cs b/Content.Client/NPC/PathfindingSystem.cs index 709601a57b..d3ae509152 100644 --- a/Content.Client/NPC/PathfindingSystem.cs +++ b/Content.Client/NPC/PathfindingSystem.cs @@ -223,7 +223,7 @@ namespace Content.Client.NPC foreach (var crumb in chunk.Value) { - var crumbMapPos = worldMatrix.Transform(_system.GetCoordinate(chunk.Key, crumb.Coordinates)); + var crumbMapPos = Vector2.Transform(_system.GetCoordinate(chunk.Key, crumb.Coordinates), worldMatrix); var distance = (crumbMapPos - mouseWorldPos.Position).Length(); if (distance < nearestDistance) @@ -292,7 +292,7 @@ namespace Content.Client.NPC foreach (var poly in tile) { - if (poly.Box.Contains(invGridMatrix.Transform(mouseWorldPos.Position))) + if (poly.Box.Contains(Vector2.Transform(mouseWorldPos.Position, invGridMatrix))) { nearest = poly; break; @@ -488,7 +488,7 @@ namespace Content.Client.NPC if (neighborMap.MapId != args.MapId) continue; - neighborPos = invMatrix.Transform(neighborMap.Position); + neighborPos = Vector2.Transform(neighborMap.Position, invMatrix); } else { @@ -576,7 +576,7 @@ namespace Content.Client.NPC } } - worldHandle.SetTransform(Matrix3.Identity); + worldHandle.SetTransform(Matrix3x2.Identity); } } } diff --git a/Content.Client/NodeContainer/NodeVisualizationOverlay.cs b/Content.Client/NodeContainer/NodeVisualizationOverlay.cs index 691bcb41db..4e8a4a10ca 100644 --- a/Content.Client/NodeContainer/NodeVisualizationOverlay.cs +++ b/Content.Client/NodeContainer/NodeVisualizationOverlay.cs @@ -199,7 +199,7 @@ namespace Content.Client.NodeContainer } - handle.SetTransform(Matrix3.Identity); + handle.SetTransform(Matrix3x2.Identity); _gridIndex.Clear(); } diff --git a/Content.Client/Overlays/EntityHealthBarOverlay.cs b/Content.Client/Overlays/EntityHealthBarOverlay.cs index 2b2ff14a22..758bb562f9 100644 --- a/Content.Client/Overlays/EntityHealthBarOverlay.cs +++ b/Content.Client/Overlays/EntityHealthBarOverlay.cs @@ -42,8 +42,8 @@ public sealed class EntityHealthBarOverlay : Overlay var xformQuery = _entManager.GetEntityQuery(); const float scale = 1f; - var scaleMatrix = Matrix3.CreateScale(new Vector2(scale, scale)); - var rotationMatrix = Matrix3.CreateRotation(-rotation); + var scaleMatrix = Matrix3Helpers.CreateScale(new Vector2(scale, scale)); + var rotationMatrix = Matrix3Helpers.CreateRotation(-rotation); var query = _entManager.AllEntityQueryEnumerator(); while (query.MoveNext(out var uid, @@ -83,10 +83,10 @@ public sealed class EntityHealthBarOverlay : Overlay continue; var worldPosition = _transform.GetWorldPosition(xform); - var worldMatrix = Matrix3.CreateTranslation(worldPosition); + var worldMatrix = Matrix3Helpers.CreateTranslation(worldPosition); - Matrix3.Multiply(scaleMatrix, worldMatrix, out var scaledWorld); - Matrix3.Multiply(rotationMatrix, scaledWorld, out var matty); + var scaledWorld = Matrix3x2.Multiply(scaleMatrix, worldMatrix); + var matty = Matrix3x2.Multiply(rotationMatrix, scaledWorld); handle.SetTransform(matty); @@ -115,7 +115,7 @@ public sealed class EntityHealthBarOverlay : Overlay handle.DrawRect(pixelDarken, Black.WithAlpha(128)); } - handle.SetTransform(Matrix3.Identity); + handle.SetTransform(Matrix3x2.Identity); } /// diff --git a/Content.Client/Overlays/StencilOverlay.RestrictedRange.cs b/Content.Client/Overlays/StencilOverlay.RestrictedRange.cs index 9581fec37b..d29564caa9 100644 --- a/Content.Client/Overlays/StencilOverlay.RestrictedRange.cs +++ b/Content.Client/Overlays/StencilOverlay.RestrictedRange.cs @@ -7,7 +7,7 @@ namespace Content.Client.Overlays; public sealed partial class StencilOverlay { - private void DrawRestrictedRange(in OverlayDrawArgs args, RestrictedRangeComponent rangeComp, Matrix3 invMatrix) + private void DrawRestrictedRange(in OverlayDrawArgs args, RestrictedRangeComponent rangeComp, Matrix3x2 invMatrix) { var worldHandle = args.WorldHandle; var renderScale = args.Viewport.RenderScale.X; @@ -16,7 +16,7 @@ public sealed partial class StencilOverlay var length = zoom.X; var bufferRange = MathF.Min(10f, rangeComp.Range); - var pixelCenter = invMatrix.Transform(rangeComp.Origin); + var pixelCenter = Vector2.Transform(rangeComp.Origin, invMatrix); // Something something offset? var vertical = args.Viewport.Size.Y; @@ -44,7 +44,7 @@ public sealed partial class StencilOverlay worldHandle.DrawRect(localAABB, Color.White); }, Color.Transparent); - worldHandle.SetTransform(Matrix3.Identity); + worldHandle.SetTransform(Matrix3x2.Identity); worldHandle.UseShader(_protoManager.Index("StencilMask").Instance()); worldHandle.DrawTextureRect(_blep!.Texture, worldBounds); var curTime = _timing.RealTime; diff --git a/Content.Client/Overlays/StencilOverlay.Weather.cs b/Content.Client/Overlays/StencilOverlay.Weather.cs index 31bc88af45..29ed157a79 100644 --- a/Content.Client/Overlays/StencilOverlay.Weather.cs +++ b/Content.Client/Overlays/StencilOverlay.Weather.cs @@ -10,7 +10,7 @@ public sealed partial class StencilOverlay { private List> _grids = new(); - private void DrawWeather(in OverlayDrawArgs args, WeatherPrototype weatherProto, float alpha, Matrix3 invMatrix) + private void DrawWeather(in OverlayDrawArgs args, WeatherPrototype weatherProto, float alpha, Matrix3x2 invMatrix) { var worldHandle = args.WorldHandle; var mapId = args.MapId; @@ -32,7 +32,7 @@ public sealed partial class StencilOverlay foreach (var grid in _grids) { var matrix = _transform.GetWorldMatrix(grid, xformQuery); - Matrix3.Multiply(in matrix, in invMatrix, out var matty); + var matty = Matrix3x2.Multiply(matrix, invMatrix); worldHandle.SetTransform(matty); foreach (var tile in grid.Comp.GetTilesIntersecting(worldAABB)) @@ -52,7 +52,7 @@ public sealed partial class StencilOverlay }, Color.Transparent); - worldHandle.SetTransform(Matrix3.Identity); + worldHandle.SetTransform(Matrix3x2.Identity); worldHandle.UseShader(_protoManager.Index("StencilMask").Instance()); worldHandle.DrawTextureRect(_blep!.Texture, worldBounds); var curTime = _timing.RealTime; @@ -62,7 +62,7 @@ public sealed partial class StencilOverlay worldHandle.UseShader(_protoManager.Index("StencilDraw").Instance()); _parallax.DrawParallax(worldHandle, worldAABB, sprite, curTime, position, Vector2.Zero, modulate: (weatherProto.Color ?? Color.White).WithAlpha(alpha)); - worldHandle.SetTransform(Matrix3.Identity); + worldHandle.SetTransform(Matrix3x2.Identity); worldHandle.UseShader(null); } } diff --git a/Content.Client/Overlays/StencilOverlay.cs b/Content.Client/Overlays/StencilOverlay.cs index e475dca759..78b1c4d2b1 100644 --- a/Content.Client/Overlays/StencilOverlay.cs +++ b/Content.Client/Overlays/StencilOverlay.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Content.Client.Parallax; using Content.Client.Weather; using Content.Shared.Salvage; @@ -72,6 +73,6 @@ public sealed partial class StencilOverlay : Overlay } args.WorldHandle.UseShader(null); - args.WorldHandle.SetTransform(Matrix3.Identity); + args.WorldHandle.SetTransform(Matrix3x2.Identity); } } diff --git a/Content.Client/Paper/UI/StampLabel.xaml.cs b/Content.Client/Paper/UI/StampLabel.xaml.cs index 6a8eb5f98f..be6d52baea 100644 --- a/Content.Client/Paper/UI/StampLabel.xaml.cs +++ b/Content.Client/Paper/UI/StampLabel.xaml.cs @@ -50,7 +50,7 @@ public sealed partial class StampLabel : Label base.Draw(handle); // Restore a sane transform+shader - handle.SetTransform(Matrix3.Identity); + handle.SetTransform(Matrix3x2.Identity); handle.UseShader(null); } } diff --git a/Content.Client/Paper/UI/StampWidget.xaml.cs b/Content.Client/Paper/UI/StampWidget.xaml.cs index a04508aeba..487e0732b4 100644 --- a/Content.Client/Paper/UI/StampWidget.xaml.cs +++ b/Content.Client/Paper/UI/StampWidget.xaml.cs @@ -53,7 +53,7 @@ public sealed partial class StampWidget : PanelContainer base.Draw(handle); // Restore a sane transform+shader - handle.SetTransform(Matrix3.Identity); + handle.SetTransform(Matrix3x2.Identity); handle.UseShader(null); } } diff --git a/Content.Client/Pinpointer/UI/NavMapControl.cs b/Content.Client/Pinpointer/UI/NavMapControl.cs index f4d2f8e2fb..3c99a18818 100644 --- a/Content.Client/Pinpointer/UI/NavMapControl.cs +++ b/Content.Client/Pinpointer/UI/NavMapControl.cs @@ -218,7 +218,7 @@ public partial class NavMapControl : MapGridControl // Convert to a world position var unscaledPosition = (localPosition - MidPointVector) / MinimapScale; - var worldPosition = _transformSystem.GetWorldMatrix(_xform).Transform(new Vector2(unscaledPosition.X, -unscaledPosition.Y) + offset); + var worldPosition = Vector2.Transform(new Vector2(unscaledPosition.X, -unscaledPosition.Y) + offset, _transformSystem.GetWorldMatrix(_xform)); // Find closest tracked entity in range var closestEntity = NetEntity.Invalid; @@ -401,7 +401,7 @@ public partial class NavMapControl : MapGridControl if (mapPos.MapId != MapId.Nullspace) { - var position = _transformSystem.GetInvWorldMatrix(_xform).Transform(mapPos.Position) - offset; + var position = Vector2.Transform(mapPos.Position, _transformSystem.GetInvWorldMatrix(_xform)) - offset; position = ScalePosition(new Vector2(position.X, -position.Y)); handle.DrawCircle(position, float.Sqrt(MinimapScale) * 2f, value.Color); @@ -422,7 +422,7 @@ public partial class NavMapControl : MapGridControl if (mapPos.MapId != MapId.Nullspace) { - var position = _transformSystem.GetInvWorldMatrix(_xform).Transform(mapPos.Position) - offset; + var position = Vector2.Transform(mapPos.Position, _transformSystem.GetInvWorldMatrix(_xform)) - offset; position = ScalePosition(new Vector2(position.X, -position.Y)); var scalingCoefficient = MinmapScaleModifier * float.Sqrt(MinimapScale); diff --git a/Content.Client/Popups/PopupOverlay.cs b/Content.Client/Popups/PopupOverlay.cs index fb6bb3bf56..77eeb611f5 100644 --- a/Content.Client/Popups/PopupOverlay.cs +++ b/Content.Client/Popups/PopupOverlay.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Content.Shared.Examine; using Robust.Client.Graphics; using Robust.Client.Player; @@ -55,7 +56,7 @@ public sealed class PopupOverlay : Overlay if (args.ViewportControl == null) return; - args.DrawingHandle.SetTransform(Matrix3.Identity); + args.DrawingHandle.SetTransform(Matrix3x2.Identity); args.DrawingHandle.UseShader(_shader); var scale = _configManager.GetCVar(CVars.DisplayUIScale); @@ -90,7 +91,7 @@ public sealed class PopupOverlay : Overlay e => e == popup.InitialPos.EntityId || e == ourEntity, entMan: _entManager)) continue; - var pos = matrix.Transform(mapPos.Position); + var pos = Vector2.Transform(mapPos.Position, matrix); _controller.DrawPopup(popup, worldHandle, pos, scale); } } diff --git a/Content.Client/Shuttles/Systems/ShuttleSystem.EmergencyConsole.cs b/Content.Client/Shuttles/Systems/ShuttleSystem.EmergencyConsole.cs index 7086fd0541..d5154a87be 100644 --- a/Content.Client/Shuttles/Systems/ShuttleSystem.EmergencyConsole.cs +++ b/Content.Client/Shuttles/Systems/ShuttleSystem.EmergencyConsole.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Content.Shared.Shuttles.Events; using Content.Shared.Shuttles.Systems; using Robust.Client.Graphics; @@ -75,6 +76,6 @@ public sealed class EmergencyShuttleOverlay : Overlay args.WorldHandle.SetTransform(xform.WorldMatrix); args.WorldHandle.DrawRect(Position.Value, Color.Red.WithAlpha(100)); - args.WorldHandle.SetTransform(Matrix3.Identity); + args.WorldHandle.SetTransform(Matrix3x2.Identity); } } diff --git a/Content.Client/Shuttles/UI/BaseShuttleControl.xaml.cs b/Content.Client/Shuttles/UI/BaseShuttleControl.xaml.cs index 8774c1dfb5..b50d8fa6b2 100644 --- a/Content.Client/Shuttles/UI/BaseShuttleControl.xaml.cs +++ b/Content.Client/Shuttles/UI/BaseShuttleControl.xaml.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Content.Client.UserInterface.Controls; using Content.Shared.Shuttles.Components; using Robust.Client.AutoGenerated; @@ -115,7 +116,7 @@ public partial class BaseShuttleControl : MapGridControl } } - protected void DrawGrid(DrawingHandleScreen handle, Matrix3 matrix, Entity grid, Color color, float alpha = 0.01f) + protected void DrawGrid(DrawingHandleScreen handle, Matrix3x2 matrix, Entity grid, Color color, float alpha = 0.01f) { var rator = Maps.GetAllTilesEnumerator(grid.Owner, grid.Comp); var minimapScale = MinimapScale; @@ -289,7 +290,7 @@ public partial class BaseShuttleControl : MapGridControl public float MinimapScale; public Vector2 MidPoint; - public Matrix3 Matrix; + public Matrix3x2 Matrix; public List Vertices; public Vector2[] ScaledVertices; @@ -297,7 +298,7 @@ public partial class BaseShuttleControl : MapGridControl public void Execute(int index) { var vert = Vertices[index]; - var adjustedVert = Matrix.Transform(vert); + var adjustedVert = Vector2.Transform(vert, Matrix); adjustedVert = adjustedVert with { Y = -adjustedVert.Y }; var scaledVert = ScalePosition(adjustedVert, MinimapScale, MidPoint); diff --git a/Content.Client/Shuttles/UI/NavScreen.xaml.cs b/Content.Client/Shuttles/UI/NavScreen.xaml.cs index b7b757ea48..91d95aaa04 100644 --- a/Content.Client/Shuttles/UI/NavScreen.xaml.cs +++ b/Content.Client/Shuttles/UI/NavScreen.xaml.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Content.Shared.Shuttles.BUIStates; using Robust.Client.AutoGenerated; using Robust.Client.Graphics; @@ -68,7 +69,7 @@ public sealed partial class NavScreen : BoxContainer } var (_, worldRot, worldMatrix) = _xformSystem.GetWorldPositionRotationMatrix(gridXform); - var worldPos = worldMatrix.Transform(gridBody.LocalCenter); + var worldPos = Vector2.Transform(gridBody.LocalCenter, worldMatrix); // Get the positive reduced angle. var displayRot = -worldRot.Reduced(); diff --git a/Content.Client/Shuttles/UI/ShuttleDockControl.xaml.cs b/Content.Client/Shuttles/UI/ShuttleDockControl.xaml.cs index f03c440295..31f0eecad7 100644 --- a/Content.Client/Shuttles/UI/ShuttleDockControl.xaml.cs +++ b/Content.Client/Shuttles/UI/ShuttleDockControl.xaml.cs @@ -108,10 +108,10 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl var gridNent = EntManager.GetNetEntity(GridEntity); var mapPos = _xformSystem.ToMapCoordinates(_coordinates.Value); var ourGridMatrix = _xformSystem.GetWorldMatrix(gridXform.Owner); - var dockMatrix = Matrix3.CreateTransform(_coordinates.Value.Position, Angle.Zero); - Matrix3.Multiply(dockMatrix, ourGridMatrix, out var offsetMatrix); + var dockMatrix = Matrix3Helpers.CreateTransform(_coordinates.Value.Position, Angle.Zero); + var worldFromDock = Matrix3x2.Multiply(dockMatrix, ourGridMatrix); - offsetMatrix = offsetMatrix.Invert(); + Matrix3x2.Invert(worldFromDock, out var offsetMatrix); // Draw nearby grids var controlBounds = PixelSizeBox; @@ -137,7 +137,7 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl continue; var gridMatrix = _xformSystem.GetWorldMatrix(grid.Owner); - Matrix3.Multiply(in gridMatrix, in offsetMatrix, out var matty); + var matty = Matrix3x2.Multiply(gridMatrix, offsetMatrix); var color = _shuttles.GetIFFColor(grid.Owner, grid.Owner == GridEntity, component: iffComp); DrawGrid(handle, matty, grid, color); @@ -151,23 +151,23 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl if (ViewedDock == dock.Entity) continue; - var position = matty.Transform(dock.Coordinates.Position); + var position = Vector2.Transform(dock.Coordinates.Position, matty); - var otherDockRotation = Matrix3.CreateRotation(dock.Angle); + var otherDockRotation = Matrix3Helpers.CreateRotation(dock.Angle); var scaledPos = ScalePosition(position with {Y = -position.Y}); if (!controlBounds.Contains(scaledPos.Floored())) continue; // Draw the dock's collision - var collisionBL = matty.Transform(dock.Coordinates.Position + - otherDockRotation.Transform(new Vector2(-0.2f, -0.7f))); - var collisionBR = matty.Transform(dock.Coordinates.Position + - otherDockRotation.Transform(new Vector2(0.2f, -0.7f))); - var collisionTR = matty.Transform(dock.Coordinates.Position + - otherDockRotation.Transform(new Vector2(0.2f, -0.5f))); - var collisionTL = matty.Transform(dock.Coordinates.Position + - otherDockRotation.Transform(new Vector2(-0.2f, -0.5f))); + var collisionBL = Vector2.Transform(dock.Coordinates.Position + + Vector2.Transform(new Vector2(-0.2f, -0.7f), otherDockRotation), matty); + var collisionBR = Vector2.Transform(dock.Coordinates.Position + + Vector2.Transform(new Vector2(0.2f, -0.7f), otherDockRotation), matty); + var collisionTR = Vector2.Transform(dock.Coordinates.Position + + Vector2.Transform(new Vector2(0.2f, -0.5f), otherDockRotation), matty); + var collisionTL = Vector2.Transform(dock.Coordinates.Position + + Vector2.Transform(new Vector2(-0.2f, -0.5f), otherDockRotation), matty); var verts = new[] { @@ -195,10 +195,10 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl handle.DrawPrimitives(DrawPrimitiveTopology.LineList, verts, otherDockConnection); // Draw the dock itself - var dockBL = matty.Transform(dock.Coordinates.Position + new Vector2(-0.5f, -0.5f)); - var dockBR = matty.Transform(dock.Coordinates.Position + new Vector2(0.5f, -0.5f)); - var dockTR = matty.Transform(dock.Coordinates.Position + new Vector2(0.5f, 0.5f)); - var dockTL = matty.Transform(dock.Coordinates.Position + new Vector2(-0.5f, 0.5f)); + var dockBL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, -0.5f), matty); + var dockBR = Vector2.Transform(dock.Coordinates.Position + new Vector2(0.5f, -0.5f), matty); + var dockTR = Vector2.Transform(dock.Coordinates.Position + new Vector2(0.5f, 0.5f), matty); + var dockTL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, 0.5f), matty); verts = new[] { @@ -308,14 +308,14 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl // Draw the dock's collision var invertedPosition = Vector2.Zero; invertedPosition.Y = -invertedPosition.Y; - var rotation = Matrix3.CreateRotation(-_angle.Value + MathF.PI); + var rotation = Matrix3Helpers.CreateRotation(-_angle.Value + MathF.PI); var ourDockConnection = new UIBox2( - ScalePosition(rotation.Transform(new Vector2(-0.2f, -0.7f))), - ScalePosition(rotation.Transform(new Vector2(0.2f, -0.5f)))); + ScalePosition(Vector2.Transform(new Vector2(-0.2f, -0.7f), rotation)), + ScalePosition(Vector2.Transform(new Vector2(0.2f, -0.5f), rotation))); var ourDock = new UIBox2( - ScalePosition(rotation.Transform(new Vector2(-0.5f, 0.5f))), - ScalePosition(rotation.Transform(new Vector2(0.5f, -0.5f)))); + ScalePosition(Vector2.Transform(new Vector2(-0.5f, 0.5f), rotation)), + ScalePosition(Vector2.Transform(new Vector2(0.5f, -0.5f), rotation))); var dockColor = Color.Magenta; var connectionColor = Color.Pink; diff --git a/Content.Client/Shuttles/UI/ShuttleMapControl.xaml.cs b/Content.Client/Shuttles/UI/ShuttleMapControl.xaml.cs index 2f35a8dffd..8bd4a338cb 100644 --- a/Content.Client/Shuttles/UI/ShuttleMapControl.xaml.cs +++ b/Content.Client/Shuttles/UI/ShuttleMapControl.xaml.cs @@ -114,7 +114,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl var beaconsOnly = EntManager.TryGetComponent(mapUid, out FTLDestinationComponent? destComp) && destComp.BeaconsOnly; - var mapTransform = Matrix3.CreateInverseTransform(Offset, Angle.Zero); + var mapTransform = Matrix3Helpers.CreateInverseTransform(Offset, Angle.Zero); if (beaconsOnly && TryGetBeacon(_beacons, mapTransform, args.RelativePixelPosition, PixelRect, out var foundBeacon, out _)) { @@ -203,7 +203,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl /// /// /// - private List GetViewportMapObjects(Matrix3 matty, List mapObjects) + private List GetViewportMapObjects(Matrix3x2 matty, List mapObjects) { var results = new List(); var enlargement = new Vector2i((int) (16 * UIScale), (int) (16 * UIScale)); @@ -217,7 +217,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl var mapCoords = _shuttles.GetMapCoordinates(mapObj); - var relativePos = matty.Transform(mapCoords.Position); + var relativePos = Vector2.Transform(mapCoords.Position, matty); relativePos = relativePos with { Y = -relativePos.Y }; var uiPosition = ScalePosition(relativePos); @@ -250,7 +250,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl DrawParallax(handle); var viewedMapUid = _mapManager.GetMapEntityId(ViewingMap); - var matty = Matrix3.CreateInverseTransform(Offset, Angle.Zero); + var matty = Matrix3Helpers.CreateInverseTransform(Offset, Angle.Zero); var realTime = _timing.RealTime; var viewBox = new Box2(Offset - WorldRangeVector, Offset + WorldRangeVector); var viewportObjects = GetViewportMapObjects(matty, mapObjects); @@ -267,7 +267,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl var (gridPos, gridRot) = _xformSystem.GetWorldPositionRotation(shuttleXform); gridPos = Maps.GetGridPosition((gridUid, gridPhysics), gridPos, gridRot); - var gridRelativePos = matty.Transform(gridPos); + var gridRelativePos = Vector2.Transform(gridPos, matty); gridRelativePos = gridRelativePos with { Y = -gridRelativePos.Y }; var gridUiPos = ScalePosition(gridRelativePos); @@ -296,7 +296,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl continue; } - var adjustedPos = matty.Transform(mapCoords.Position); + var adjustedPos = Vector2.Transform(mapCoords.Position, matty); var localPos = ScalePosition(adjustedPos with { Y = -adjustedPos.Y}); handle.DrawCircle(localPos, exclusion.Range * MinimapScale, exclusionColor.WithAlpha(0.05f)); handle.DrawCircle(localPos, exclusion.Range * MinimapScale, exclusionColor, filled: false); @@ -319,7 +319,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl foreach (var (beaconName, coords, mapO) in GetBeacons(viewportObjects, matty, controlLocalBounds)) { - var localPos = matty.Transform(coords.Position); + var localPos = Vector2.Transform(coords.Position, matty); localPos = localPos with { Y = -localPos.Y }; var beaconUiPos = ScalePosition(localPos); var mapObject = GetMapObject(localPos, Angle.Zero, scale: 0.75f, scalePosition: true); @@ -360,7 +360,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl var (gridPos, gridRot) = _xformSystem.GetWorldPositionRotation(grid.Owner); gridPos = Maps.GetGridPosition((grid, gridPhysics), gridPos, gridRot); - var gridRelativePos = matty.Transform(gridPos); + var gridRelativePos = Vector2.Transform(gridPos, matty); gridRelativePos = gridRelativePos with { Y = -gridRelativePos.Y }; var gridUiPos = ScalePosition(gridRelativePos); @@ -439,7 +439,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl var color = ftlFree ? Color.LimeGreen : Color.Magenta; - var gridRelativePos = matty.Transform(gridPos); + var gridRelativePos = Vector2.Transform(gridPos, matty); gridRelativePos = gridRelativePos with { Y = -gridRelativePos.Y }; var gridUiPos = ScalePosition(gridRelativePos); @@ -512,7 +512,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl /// /// Returns the beacons that intersect the viewport. /// - private IEnumerable<(string Beacon, MapCoordinates Coordinates, IMapObject MapObject)> GetBeacons(List mapObjs, Matrix3 mapTransform, UIBox2i area) + private IEnumerable<(string Beacon, MapCoordinates Coordinates, IMapObject MapObject)> GetBeacons(List mapObjs, Matrix3x2 mapTransform, UIBox2i area) { foreach (var mapO in mapObjs) { @@ -520,7 +520,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl continue; var beaconCoords = EntManager.GetCoordinates(beacon.Coordinates).ToMap(EntManager, _xformSystem); - var position = mapTransform.Transform(beaconCoords.Position); + var position = Vector2.Transform(beaconCoords.Position, mapTransform); var localPos = ScalePosition(position with {Y = -position.Y}); // If beacon not on screen then ignore it. @@ -557,7 +557,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl return mapObj; } - private bool TryGetBeacon(IEnumerable mapObjects, Matrix3 mapTransform, Vector2 mousePos, UIBox2i area, out ShuttleBeaconObject foundBeacon, out Vector2 foundLocalPos) + private bool TryGetBeacon(IEnumerable mapObjects, Matrix3x2 mapTransform, Vector2 mousePos, UIBox2i area, out ShuttleBeaconObject foundBeacon, out Vector2 foundLocalPos) { // In pixels const float BeaconSnapRange = 32f; @@ -579,7 +579,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl if (!_shuttles.CanFTLBeacon(beaconObj.Coordinates)) continue; - var position = mapTransform.Transform(beaconCoords.Position); + var position = Vector2.Transform(beaconCoords.Position, mapTransform); var localPos = ScalePosition(position with {Y = -position.Y}); // If beacon not on screen then ignore it. diff --git a/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs b/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs index 00ee6890b2..0b8720add2 100644 --- a/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs +++ b/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs @@ -137,10 +137,10 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl var mapPos = _transform.ToMapCoordinates(_coordinates.Value); var offset = _coordinates.Value.Position; - var posMatrix = Matrix3.CreateTransform(offset, _rotation.Value); + var posMatrix = Matrix3Helpers.CreateTransform(offset, _rotation.Value); var (_, ourEntRot, ourEntMatrix) = _transform.GetWorldPositionRotationMatrix(_coordinates.Value.EntityId); - Matrix3.Multiply(posMatrix, ourEntMatrix, out var ourWorldMatrix); - var ourWorldMatrixInvert = ourWorldMatrix.Invert(); + var ourWorldMatrix = Matrix3x2.Multiply(posMatrix, ourEntMatrix); + Matrix3x2.Invert(ourWorldMatrix, out var ourWorldMatrixInvert); // Draw our grid in detail var ourGridId = xform.GridUid; @@ -148,7 +148,7 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl fixturesQuery.HasComponent(ourGridId.Value)) { var ourGridMatrix = _transform.GetWorldMatrix(ourGridId.Value); - Matrix3.Multiply(in ourGridMatrix, in ourWorldMatrixInvert, out var matrix); + var matrix = Matrix3x2.Multiply(ourGridMatrix, ourWorldMatrixInvert); var color = _shuttles.GetIFFColor(ourGridId.Value, self: true); DrawGrid(handle, matrix, (ourGridId.Value, ourGrid), color); @@ -194,7 +194,7 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl continue; var gridMatrix = _transform.GetWorldMatrix(gUid); - Matrix3.Multiply(in gridMatrix, in ourWorldMatrixInvert, out var matty); + var matty = Matrix3x2.Multiply(gridMatrix, ourWorldMatrixInvert); var color = _shuttles.GetIFFColor(grid, self: false, iff); // Others default: @@ -207,7 +207,7 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl { var gridBounds = grid.Comp.LocalAABB; - var gridCentre = matty.Transform(gridBody.LocalCenter); + var gridCentre = Vector2.Transform(gridBody.LocalCenter, matty); gridCentre.Y = -gridCentre.Y; var distance = gridCentre.Length(); var labelText = Loc.GetString("shuttle-console-iff-label", ("name", labelName), @@ -242,7 +242,7 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl } } - private void DrawDocks(DrawingHandleScreen handle, EntityUid uid, Matrix3 matrix) + private void DrawDocks(DrawingHandleScreen handle, EntityUid uid, Matrix3x2 matrix) { if (!ShowDocks) return; @@ -255,7 +255,7 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl foreach (var state in docks) { var position = state.Coordinates.Position; - var uiPosition = matrix.Transform(position); + var uiPosition = Vector2.Transform(position, matrix); if (uiPosition.Length() > (WorldRange * 2f) - DockScale) continue; @@ -264,10 +264,10 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl var verts = new[] { - matrix.Transform(position + new Vector2(-DockScale, -DockScale)), - matrix.Transform(position + new Vector2(DockScale, -DockScale)), - matrix.Transform(position + new Vector2(DockScale, DockScale)), - matrix.Transform(position + new Vector2(-DockScale, DockScale)), + Vector2.Transform(position + new Vector2(-DockScale, -DockScale), matrix), + Vector2.Transform(position + new Vector2(DockScale, -DockScale), matrix), + Vector2.Transform(position + new Vector2(DockScale, DockScale), matrix), + Vector2.Transform(position + new Vector2(-DockScale, DockScale), matrix), }; for (var i = 0; i < verts.Length; i++) diff --git a/Content.Client/StatusIcon/StatusIconOverlay.cs b/Content.Client/StatusIcon/StatusIconOverlay.cs index 56107cbc02..f1473bda7a 100644 --- a/Content.Client/StatusIcon/StatusIconOverlay.cs +++ b/Content.Client/StatusIcon/StatusIconOverlay.cs @@ -39,8 +39,8 @@ public sealed class StatusIconOverlay : Overlay var eyeRot = args.Viewport.Eye?.Rotation ?? default; var xformQuery = _entity.GetEntityQuery(); - var scaleMatrix = Matrix3.CreateScale(new Vector2(1, 1)); - var rotationMatrix = Matrix3.CreateRotation(-eyeRot); + var scaleMatrix = Matrix3Helpers.CreateScale(new Vector2(1, 1)); + var rotationMatrix = Matrix3Helpers.CreateRotation(-eyeRot); var query = _entity.AllEntityQueryEnumerator(); while (query.MoveNext(out var uid, out var comp, out var sprite, out var xform, out var meta)) @@ -59,9 +59,9 @@ public sealed class StatusIconOverlay : Overlay if (icons.Count == 0) continue; - var worldMatrix = Matrix3.CreateTranslation(worldPos); - Matrix3.Multiply(scaleMatrix, worldMatrix, out var scaledWorld); - Matrix3.Multiply(rotationMatrix, scaledWorld, out var matty); + var worldMatrix = Matrix3Helpers.CreateTranslation(worldPos); + var scaledWorld = Matrix3x2.Multiply(scaleMatrix, worldMatrix); + var matty = Matrix3x2.Multiply(rotationMatrix, scaledWorld); handle.SetTransform(matty); var countL = 0; diff --git a/Content.Client/Storage/Systems/StorageSystem.cs b/Content.Client/Storage/Systems/StorageSystem.cs index 8bf0dcd981..b80a855f98 100644 --- a/Content.Client/Storage/Systems/StorageSystem.cs +++ b/Content.Client/Storage/Systems/StorageSystem.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.Linq; +using System.Numerics; using Content.Client.Animations; using Content.Shared.Hands; using Content.Shared.Storage; @@ -149,7 +150,7 @@ public sealed class StorageSystem : SharedStorageSystem } var finalMapPos = finalCoords.ToMapPos(EntityManager, TransformSystem); - var finalPos = TransformSystem.GetInvWorldMatrix(initialCoords.EntityId).Transform(finalMapPos); + var finalPos = Vector2.Transform(finalMapPos, TransformSystem.GetInvWorldMatrix(initialCoords.EntityId)); _entityPickupAnimation.AnimateEntityPickup(item, initialCoords, finalPos, initialAngle); } diff --git a/Content.Client/UserInterface/Controls/DirectionIcon.cs b/Content.Client/UserInterface/Controls/DirectionIcon.cs index a6cc428091..c8fd63b43c 100644 --- a/Content.Client/UserInterface/Controls/DirectionIcon.cs +++ b/Content.Client/UserInterface/Controls/DirectionIcon.cs @@ -65,7 +65,7 @@ public sealed class DirectionIcon : TextureRect if (_rotation != null) { var offset = (-_rotation.Value).RotateVec(Size * UIScale / 2) - Size * UIScale / 2; - handle.SetTransform(Matrix3.CreateTransform(GlobalPixelPosition - offset, -_rotation.Value)); + handle.SetTransform(Matrix3Helpers.CreateTransform(GlobalPixelPosition - offset, -_rotation.Value)); } base.Draw(handle); diff --git a/Content.Client/UserInterface/Controls/MapGridControl.xaml.cs b/Content.Client/UserInterface/Controls/MapGridControl.xaml.cs index f6b0929f3b..a10155f3e8 100644 --- a/Content.Client/UserInterface/Controls/MapGridControl.xaml.cs +++ b/Content.Client/UserInterface/Controls/MapGridControl.xaml.cs @@ -169,7 +169,7 @@ public partial class MapGridControl : LayoutContainer var inversePos = (value - MidPointVector) / MinimapScale; inversePos = inversePos with { Y = -inversePos.Y }; - inversePos = Matrix3.CreateTransform(Offset, Angle.Zero).Transform(inversePos); + inversePos = Vector2.Transform(inversePos, Matrix3Helpers.CreateTransform(Offset, Angle.Zero)); return inversePos; } diff --git a/Content.Client/Viewport/ScalingViewport.cs b/Content.Client/Viewport/ScalingViewport.cs index 1fa8f17161..ccd9636d77 100644 --- a/Content.Client/Viewport/ScalingViewport.cs +++ b/Content.Client/Viewport/ScalingViewport.cs @@ -277,8 +277,8 @@ namespace Content.Client.Viewport EnsureViewportCreated(); - var matrix = Matrix3.Invert(GetLocalToScreenMatrix()); - coords = matrix.Transform(coords); + Matrix3x2.Invert(GetLocalToScreenMatrix(), out var matrix); + coords = Vector2.Transform(coords, matrix); return _viewport!.LocalToWorld(coords); } @@ -291,8 +291,8 @@ namespace Content.Client.Viewport EnsureViewportCreated(); - var matrix = Matrix3.Invert(GetLocalToScreenMatrix()); - coords = matrix.Transform(coords); + Matrix3x2.Invert(GetLocalToScreenMatrix(), out var matrix); + coords = Vector2.Transform(coords, matrix); var ev = new PixelToMapEvent(coords, this, _viewport!); _entityManager.EventBus.RaiseEvent(EventSource.Local, ref ev); @@ -311,16 +311,16 @@ namespace Content.Client.Viewport var matrix = GetLocalToScreenMatrix(); - return matrix.Transform(vpLocal); + return Vector2.Transform(vpLocal, matrix); } - public Matrix3 GetWorldToScreenMatrix() + public Matrix3x2 GetWorldToScreenMatrix() { EnsureViewportCreated(); return _viewport!.GetWorldToLocalMatrix() * GetLocalToScreenMatrix(); } - public Matrix3 GetLocalToScreenMatrix() + public Matrix3x2 GetLocalToScreenMatrix() { EnsureViewportCreated(); @@ -329,9 +329,9 @@ namespace Content.Client.Viewport if (scaleFactor.X == 0 || scaleFactor.Y == 0) // Basically a nonsense scenario, at least make sure to return something that can be inverted. - return Matrix3.Identity; + return Matrix3x2.Identity; - return Matrix3.CreateTransform(GlobalPixelPosition + drawBox.TopLeft, 0, scaleFactor); + return Matrix3Helpers.CreateTransform(GlobalPixelPosition + drawBox.TopLeft, 0, scaleFactor); } private void EnsureViewportCreated() diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.Effects.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.Effects.cs index baac42d193..3e1a4b1906 100644 --- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.Effects.cs +++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.Effects.cs @@ -81,7 +81,7 @@ public sealed partial class MeleeWeaponSystem case WeaponArcAnimation.None: var (mapPos, mapRot) = TransformSystem.GetWorldPositionRotation(userXform); var worldPos = mapPos + (mapRot - userXform.LocalRotation).RotateVec(localPos); - var newLocalPos = TransformSystem.GetInvWorldMatrix(xform.ParentUid).Transform(worldPos); + var newLocalPos = Vector2.Transform(worldPos, TransformSystem.GetInvWorldMatrix(xform.ParentUid)); TransformSystem.SetLocalPositionNoLerp(animationUid, newLocalPos, xform); if (arcComponent.Fadeout) _animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey); diff --git a/Content.Client/Weapons/Ranged/ItemStatus/BulletRender.cs b/Content.Client/Weapons/Ranged/ItemStatus/BulletRender.cs index 8aea5d7ee6..e6cb596b94 100644 --- a/Content.Client/Weapons/Ranged/ItemStatus/BulletRender.cs +++ b/Content.Client/Weapons/Ranged/ItemStatus/BulletRender.cs @@ -1,4 +1,4 @@ -using System.Numerics; +using System.Numerics; using Content.Client.Resources; using Robust.Client.Graphics; using Robust.Client.ResourceManagement; @@ -53,7 +53,7 @@ public abstract class BaseBulletRenderer : Control { // Scale rendering in this control by UIScale. var currentTransform = handle.GetTransform(); - handle.SetTransform(Matrix3.CreateScale(new Vector2(UIScale)) * currentTransform); + handle.SetTransform(Matrix3Helpers.CreateScale(new Vector2(UIScale)) * currentTransform); var countPerRow = CountPerRow(Size.X); diff --git a/Content.Server/Explosion/EntitySystems/ExplosionGridTileFlood.cs b/Content.Server/Explosion/EntitySystems/ExplosionGridTileFlood.cs index 7db1f513f7..2ddcc052d8 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionGridTileFlood.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionGridTileFlood.cs @@ -14,7 +14,7 @@ public sealed class ExplosionGridTileFlood : ExplosionTileFlood public MapGridComponent Grid; private bool _needToTransform = false; - private Matrix3 _matrix = Matrix3.Identity; + private Matrix3x2 _matrix = Matrix3x2.Identity; private Vector2 _offset; // Tiles which neighbor an exploding tile, but have not yet had the explosion spread to them due to an @@ -44,7 +44,7 @@ public sealed class ExplosionGridTileFlood : ExplosionTileFlood int typeIndex, Dictionary edgeTiles, EntityUid? referenceGrid, - Matrix3 spaceMatrix, + Matrix3x2 spaceMatrix, Angle spaceAngle) { Grid = grid; @@ -72,9 +72,10 @@ public sealed class ExplosionGridTileFlood : ExplosionTileFlood var transform = IoCManager.Resolve().GetComponent(Grid.Owner); var size = (float) Grid.TileSize; - _matrix.R0C2 = size / 2; - _matrix.R1C2 = size / 2; - _matrix *= transform.WorldMatrix * Matrix3.Invert(spaceMatrix); + _matrix.M31 = size / 2; + _matrix.M32 = size / 2; + Matrix3x2.Invert(spaceMatrix, out var invSpace); + _matrix *= transform.WorldMatrix * invSpace; var relativeAngle = transform.WorldRotation - spaceAngle; _offset = relativeAngle.RotateVec(new Vector2(size / 4, size / 4)); } @@ -228,7 +229,7 @@ public sealed class ExplosionGridTileFlood : ExplosionTileFlood return; } - var center = _matrix.Transform(tile); + var center = Vector2.Transform(tile, _matrix); SpaceJump.Add(new((int) MathF.Floor(center.X + _offset.X), (int) MathF.Floor(center.Y + _offset.Y))); SpaceJump.Add(new((int) MathF.Floor(center.X - _offset.Y), (int) MathF.Floor(center.Y + _offset.X))); SpaceJump.Add(new((int) MathF.Floor(center.X - _offset.X), (int) MathF.Floor(center.Y - _offset.Y))); diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs index 719a2eca79..556fe7c141 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs @@ -60,7 +60,7 @@ public sealed partial class ExplosionSystem : EntitySystem { Dictionary transformedEdges = new(); - var targetMatrix = Matrix3.Identity; + var targetMatrix = Matrix3x2.Identity; Angle targetAngle = new(); var tileSize = DefaultTileSize; var maxDistanceSq = (int) (maxDistance * maxDistance); @@ -75,9 +75,9 @@ public sealed partial class ExplosionSystem : EntitySystem tileSize = targetGrid.TileSize; } - var offsetMatrix = Matrix3.Identity; - offsetMatrix.R0C2 = tileSize / 2f; - offsetMatrix.R1C2 = tileSize / 2f; + var offsetMatrix = Matrix3x2.Identity; + offsetMatrix.M31 = tileSize / 2f; + offsetMatrix.M32 = tileSize / 2f; // Here we can end up with a triple nested for loop: // foreach other grid @@ -106,7 +106,7 @@ public sealed partial class ExplosionSystem : EntitySystem var xform = xforms.GetComponent(gridToTransform); var (_, gridWorldRotation, gridWorldMatrix, invGridWorldMatrid) = xform.GetWorldPositionRotationMatrixWithInv(xforms); - var localEpicentre = (Vector2i) invGridWorldMatrid.Transform(epicentre.Position); + var localEpicentre = (Vector2i) Vector2.Transform(epicentre.Position, invGridWorldMatrid); var matrix = offsetMatrix * gridWorldMatrix * targetMatrix; var angle = gridWorldRotation - targetAngle; @@ -119,7 +119,7 @@ public sealed partial class ExplosionSystem : EntitySystem if (delta.X * delta.X + delta.Y * delta.Y > maxDistanceSq) // no Vector2.Length??? continue; - var center = matrix.Transform(tile); + var center = Vector2.Transform(tile, matrix); if ((dir & NeighborFlag.Cardinal) == 0) { diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs index bce3dc21c2..c30a9ce300 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs @@ -298,8 +298,8 @@ public sealed partial class ExplosionSystem /// Same as , but for SPAAAAAAACE. /// internal void ExplodeSpace(BroadphaseComponent lookup, - Matrix3 spaceMatrix, - Matrix3 invSpaceMatrix, + Matrix3x2 spaceMatrix, + Matrix3x2 invSpaceMatrix, Vector2i tile, float throwForce, DamageSpecifier damage, @@ -341,7 +341,7 @@ public sealed partial class ExplosionSystem } private static bool SpaceQueryCallback( - ref (List<(EntityUid, TransformComponent)> List, HashSet Processed, Matrix3 InvSpaceMatrix, EntityUid LookupOwner, EntityQuery XformQuery, Box2 GridBox, SharedTransformSystem System) state, + ref (List<(EntityUid, TransformComponent)> List, HashSet Processed, Matrix3x2 InvSpaceMatrix, EntityUid LookupOwner, EntityQuery XformQuery, Box2 GridBox, SharedTransformSystem System) state, in EntityUid uid) { if (state.Processed.Contains(uid)) @@ -352,7 +352,7 @@ public sealed partial class ExplosionSystem if (xform.ParentUid == state.LookupOwner) { // parented directly to the map, use local position - if (state.GridBox.Contains(state.InvSpaceMatrix.Transform(xform.LocalPosition))) + if (state.GridBox.Contains(Vector2.Transform(xform.LocalPosition, state.InvSpaceMatrix))) state.List.Add((uid, xform)); return true; @@ -360,14 +360,14 @@ public sealed partial class ExplosionSystem // finally check if it intersects our tile var wpos = state.System.GetWorldPosition(xform); - if (state.GridBox.Contains(state.InvSpaceMatrix.Transform(wpos))) + if (state.GridBox.Contains(Vector2.Transform(wpos, state.InvSpaceMatrix))) state.List.Add((uid, xform)); return true; } private static bool SpaceQueryCallback( - ref (List<(EntityUid, TransformComponent)> List, HashSet Processed, Matrix3 InvSpaceMatrix, EntityUid LookupOwner, EntityQuery XformQuery, Box2 GridBox, SharedTransformSystem System) state, + ref (List<(EntityUid, TransformComponent)> List, HashSet Processed, Matrix3x2 InvSpaceMatrix, EntityUid LookupOwner, EntityQuery XformQuery, Box2 GridBox, SharedTransformSystem System) state, in FixtureProxy proxy) { var uid = proxy.Entity; @@ -585,12 +585,12 @@ sealed class Explosion /// /// The matrix that defines the reference frame for the explosion in space. /// - private readonly Matrix3 _spaceMatrix; + private readonly Matrix3x2 _spaceMatrix; /// /// Inverse of /// - private readonly Matrix3 _invSpaceMatrix; + private readonly Matrix3x2 _invSpaceMatrix; /// /// Have all the tiles on all the grids been processed? @@ -656,7 +656,7 @@ sealed class Explosion List gridData, List tileSetIntensity, MapCoordinates epicenter, - Matrix3 spaceMatrix, + Matrix3x2 spaceMatrix, int area, float tileBreakScale, int maxTileBreak, @@ -695,7 +695,7 @@ sealed class Explosion }); _spaceMatrix = spaceMatrix; - _invSpaceMatrix = Matrix3.Invert(spaceMatrix); + Matrix3x2.Invert(spaceMatrix, out _invSpaceMatrix); } foreach (var grid in gridData) diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs index a42dd11083..8b4c0e14c5 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs @@ -26,7 +26,7 @@ public sealed partial class ExplosionSystem : EntitySystem /// The maximum intensity that the explosion can have at any given tile. This /// effectively caps the damage that this explosion can do. /// A list of tile-sets and a list of intensity values which describe the explosion. - private (int, List, ExplosionSpaceTileFlood?, Dictionary, Matrix3)? GetExplosionTiles( + private (int, List, ExplosionSpaceTileFlood?, Dictionary, Matrix3x2)? GetExplosionTiles( MapCoordinates epicenter, string typeID, float totalIntensity, @@ -84,7 +84,7 @@ public sealed partial class ExplosionSystem : EntitySystem Dictionary>? previousGridJump; // variables for transforming between grid and space-coordinates - var spaceMatrix = Matrix3.Identity; + var spaceMatrix = Matrix3x2.Identity; var spaceAngle = Angle.Zero; if (referenceGrid != null) { diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs index d332531502..5db8b55bf9 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Content.Shared.Explosion; using Content.Shared.Explosion.Components; using Robust.Server.GameObjects; @@ -35,7 +36,7 @@ public sealed partial class ExplosionSystem : EntitySystem /// /// Constructor for the shared using the server-exclusive explosion classes. /// - private EntityUid CreateExplosionVisualEntity(MapCoordinates epicenter, string prototype, Matrix3 spaceMatrix, ExplosionSpaceTileFlood? spaceData, IEnumerable gridData, List iterationIntensity) + private EntityUid CreateExplosionVisualEntity(MapCoordinates epicenter, string prototype, Matrix3x2 spaceMatrix, ExplosionSpaceTileFlood? spaceData, IEnumerable gridData, List iterationIntensity) { var explosionEntity = Spawn(null, MapCoordinates.Nullspace); var comp = AddComp(explosionEntity); diff --git a/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs b/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs index a3717fd94c..52afdcf8b4 100644 --- a/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs +++ b/Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Popups; using Content.Shared.Chemistry.Components; @@ -317,7 +318,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem var userXform = Transform(user); var targetPos = _transform.GetWorldPosition(target); - var localPos = _transform.GetInvWorldMatrix(userXform).Transform(targetPos); + var localPos = Vector2.Transform(targetPos, _transform.GetInvWorldMatrix(userXform)); localPos = userXform.LocalRotation.RotateVec(localPos); _melee.DoLunge(user, used, Angle.Zero, localPos, null, false); diff --git a/Content.Server/GameTicking/GameTicker.Spawning.cs b/Content.Server/GameTicking/GameTicker.Spawning.cs index 22d368e57b..5e2ef0c02c 100644 --- a/Content.Server/GameTicking/GameTicker.Spawning.cs +++ b/Content.Server/GameTicking/GameTicker.Spawning.cs @@ -417,7 +417,7 @@ namespace Content.Server.GameTicking { var gridXform = Transform(gridUid); - return new EntityCoordinates(gridUid, gridXform.InvWorldMatrix.Transform(toMap.Position)); + return new EntityCoordinates(gridUid, Vector2.Transform(toMap.Position, gridXform.InvWorldMatrix)); } return spawn; diff --git a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs index 38e88f6e1e..1acbf292f0 100644 --- a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs +++ b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Content.Server.Access.Systems; using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Components; @@ -366,8 +367,8 @@ public sealed class SuitSensorSystem : EntitySystem if (transform.GridUid != null) { coordinates = new EntityCoordinates(transform.GridUid.Value, - _transform.GetInvWorldMatrix(xformQuery.GetComponent(transform.GridUid.Value), xformQuery) - .Transform(_transform.GetWorldPosition(transform, xformQuery))); + Vector2.Transform(_transform.GetWorldPosition(transform, xformQuery), + _transform.GetInvWorldMatrix(xformQuery.GetComponent(transform.GridUid.Value), xformQuery))); } else if (transform.MapUid != null) { diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.Distance.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.Distance.cs index 5daf38c420..b986ed5259 100644 --- a/Content.Server/NPC/Pathfinding/PathfindingSystem.Distance.cs +++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.Distance.cs @@ -36,7 +36,7 @@ public sealed partial class PathfindingSystem return Vector2.Zero; } - endPos = startXform.InvWorldMatrix.Transform(endXform.WorldMatrix.Transform(endPos)); + endPos = Vector2.Transform(Vector2.Transform(endPos, endXform.WorldMatrix), startXform.InvWorldMatrix); } // TODO: Numerics when we changeover. diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs index 52f7db77ed..f4af65c617 100644 --- a/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs +++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs @@ -395,7 +395,7 @@ public sealed partial class PathfindingSystem private Vector2i GetOrigin(EntityCoordinates coordinates, EntityUid gridUid) { - var localPos = _transform.GetInvWorldMatrix(gridUid).Transform(coordinates.ToMapPos(EntityManager, _transform)); + var localPos = Vector2.Transform(coordinates.ToMapPos(EntityManager, _transform), _transform.GetInvWorldMatrix(gridUid)); return new Vector2i((int) Math.Floor(localPos.X / ChunkSize), (int) Math.Floor(localPos.Y / ChunkSize)); } diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.cs index 3672ad047b..b2958f0ccb 100644 --- a/Content.Server/NPC/Pathfinding/PathfindingSystem.cs +++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.cs @@ -405,7 +405,7 @@ namespace Content.Server.NPC.Pathfinding return null; } - var localPos = xform.InvWorldMatrix.Transform(coordinates.ToMapPos(EntityManager, _transform)); + var localPos = Vector2.Transform(coordinates.ToMapPos(EntityManager, _transform), xform.InvWorldMatrix); var origin = GetOrigin(localPos); if (!TryGetChunk(origin, comp, out var chunk)) diff --git a/Content.Server/Procedural/DungeonJob.PrefabDunGen.cs b/Content.Server/Procedural/DungeonJob.PrefabDunGen.cs index 1783a56790..a19f7e4701 100644 --- a/Content.Server/Procedural/DungeonJob.PrefabDunGen.cs +++ b/Content.Server/Procedural/DungeonJob.PrefabDunGen.cs @@ -19,7 +19,7 @@ public sealed partial class DungeonJob var gen = _prototype.Index(preset); var dungeonRotation = _dungeon.GetDungeonRotation(seed); - var dungeonTransform = Matrix3.CreateTransform(_position, dungeonRotation); + var dungeonTransform = Matrix3Helpers.CreateTransform(_position, dungeonRotation); var roomPackProtos = new Dictionary>(); foreach (var pack in _prototype.EnumeratePrototypes()) @@ -69,7 +69,7 @@ public sealed partial class DungeonJob var dungeon = new Dungeon(); var availablePacks = new List(); var chosenPacks = new DungeonRoomPackPrototype?[gen.RoomPacks.Count]; - var packTransforms = new Matrix3[gen.RoomPacks.Count]; + var packTransforms = new Matrix3x2[gen.RoomPacks.Count]; var packRotations = new Angle[gen.RoomPacks.Count]; // Actually pick the room packs and rooms @@ -97,7 +97,7 @@ public sealed partial class DungeonJob // Iterate every pack random.Shuffle(availablePacks); - Matrix3 packTransform = default!; + Matrix3x2 packTransform = default!; var found = false; DungeonRoomPackPrototype pack = default!; @@ -128,7 +128,7 @@ public sealed partial class DungeonJob var aRotation = dir.AsDir().ToAngle(); // Use this pack - packTransform = Matrix3.CreateTransform(bounds.Center, aRotation); + packTransform = Matrix3Helpers.CreateTransform(bounds.Center, aRotation); packRotations[i] = aRotation; pack = aPack; break; @@ -168,7 +168,7 @@ public sealed partial class DungeonJob { var roomDimensions = new Vector2i(roomSize.Width, roomSize.Height); Angle roomRotation = Angle.Zero; - Matrix3 matty; + Matrix3x2 matty; if (!roomProtos.TryGetValue(roomDimensions, out var roomProto)) { @@ -176,13 +176,13 @@ public sealed partial class DungeonJob if (!roomProtos.TryGetValue(roomDimensions, out roomProto)) { - Matrix3.Multiply(packTransform, dungeonTransform, out matty); + matty = Matrix3x2.Multiply(packTransform, dungeonTransform); for (var x = roomSize.Left; x < roomSize.Right; x++) { for (var y = roomSize.Bottom; y < roomSize.Top; y++) { - var index = matty.Transform(new Vector2(x, y) + grid.TileSizeHalfVector - packCenter).Floored(); + var index = Vector2.Transform(new Vector2(x, y) + grid.TileSizeHalfVector - packCenter, matty).Floored(); tiles.Add((index, new Tile(_tileDefManager["FloorPlanetGrass"].TileId))); } } @@ -209,10 +209,10 @@ public sealed partial class DungeonJob roomRotation += Math.PI; } - var roomTransform = Matrix3.CreateTransform(roomSize.Center - packCenter, roomRotation); + var roomTransform = Matrix3Helpers.CreateTransform(roomSize.Center - packCenter, roomRotation); - Matrix3.Multiply(roomTransform, packTransform, out matty); - Matrix3.Multiply(matty, dungeonTransform, out var dungeonMatty); + matty = Matrix3x2.Multiply(roomTransform, packTransform); + var dungeonMatty = Matrix3x2.Multiply(matty, dungeonTransform); // The expensive bit yippy. _dungeon.SpawnRoom(gridUid, grid, dungeonMatty, room); @@ -232,7 +232,7 @@ public sealed partial class DungeonJob continue; } - var tilePos = dungeonMatty.Transform(new Vector2i(x + room.Offset.X, y + room.Offset.Y) + tileOffset); + var tilePos = Vector2.Transform(new Vector2i(x + room.Offset.X, y + room.Offset.Y) + tileOffset, dungeonMatty); exterior.Add(tilePos.Floored()); } } @@ -244,7 +244,7 @@ public sealed partial class DungeonJob for (var y = 0; y < room.Size.Y; y++) { var roomTile = new Vector2i(x + room.Offset.X, y + room.Offset.Y); - var tilePos = dungeonMatty.Transform(roomTile + tileOffset); + var tilePos = Vector2.Transform(roomTile + tileOffset, dungeonMatty); var tileIndex = tilePos.Floored(); roomTiles.Add(tileIndex); diff --git a/Content.Server/Procedural/DungeonSystem.Rooms.cs b/Content.Server/Procedural/DungeonSystem.Rooms.cs index 03bcc2b4b1..5b4de34906 100644 --- a/Content.Server/Procedural/DungeonSystem.Rooms.cs +++ b/Content.Server/Procedural/DungeonSystem.Rooms.cs @@ -67,7 +67,7 @@ public sealed partial class DungeonSystem bool clearExisting = false, bool rotation = false) { - var originTransform = Matrix3.CreateTranslation(origin); + var originTransform = Matrix3Helpers.CreateTranslation(origin.X, origin.Y); var roomRotation = Angle.Zero; if (rotation) @@ -75,8 +75,8 @@ public sealed partial class DungeonSystem roomRotation = GetRoomRotation(room, random); } - var roomTransform = Matrix3.CreateTransform((Vector2) room.Size / 2f, roomRotation); - Matrix3.Multiply(roomTransform, originTransform, out var finalTransform); + var roomTransform = Matrix3Helpers.CreateTransform((Vector2) room.Size / 2f, roomRotation); + var finalTransform = Matrix3x2.Multiply(roomTransform, originTransform); SpawnRoom(gridUid, grid, finalTransform, room, clearExisting); } @@ -101,7 +101,7 @@ public sealed partial class DungeonSystem public void SpawnRoom( EntityUid gridUid, MapGridComponent grid, - Matrix3 roomTransform, + Matrix3x2 roomTransform, DungeonRoomPrototype room, bool clearExisting = false) { @@ -116,7 +116,7 @@ public sealed partial class DungeonSystem // go BRRNNTTT on existing stuff if (clearExisting) { - var gridBounds = new Box2(roomTransform.Transform(Vector2.Zero), roomTransform.Transform(room.Size)); + var gridBounds = new Box2(Vector2.Transform(Vector2.Zero, roomTransform), Vector2.Transform(room.Size, roomTransform)); _entitySet.Clear(); // Polygon skin moment gridBounds = gridBounds.Enlarged(-0.05f); @@ -148,7 +148,7 @@ public sealed partial class DungeonSystem var indices = new Vector2i(x + room.Offset.X, y + room.Offset.Y); var tileRef = _maps.GetTileRef(templateMapUid, templateGrid, indices); - var tilePos = roomTransform.Transform(indices + tileOffset); + var tilePos = Vector2.Transform(indices + tileOffset, roomTransform); var rounded = tilePos.Floored(); _tiles.Add((rounded, tileRef.Tile)); } @@ -164,7 +164,7 @@ public sealed partial class DungeonSystem foreach (var templateEnt in _lookup.GetEntitiesIntersecting(templateMapUid, bounds, LookupFlags.Uncontained)) { var templateXform = _xformQuery.GetComponent(templateEnt); - var childPos = roomTransform.Transform(templateXform.LocalPosition - roomCenter); + var childPos = Vector2.Transform(templateXform.LocalPosition - roomCenter, roomTransform); var childRot = templateXform.LocalRotation + finalRoomRotation; var protoId = _metaQuery.GetComponent(templateEnt).EntityPrototype?.ID; @@ -192,7 +192,7 @@ public sealed partial class DungeonSystem // Offset by 0.5 because decals are offset from bot-left corner // So we convert it to center of tile then convert it back again after transform. // Do these shenanigans because 32x32 decals assume as they are centered on bottom-left of tiles. - var position = roomTransform.Transform(decal.Coordinates + Vector2Helpers.Half - roomCenter); + var position = Vector2.Transform(decal.Coordinates + Vector2Helpers.Half - roomCenter, roomTransform); position -= Vector2Helpers.Half; // Umm uhh I love decals so uhhhh idk what to do about this diff --git a/Content.Server/Radiation/Systems/RadiationSystem.GridCast.cs b/Content.Server/Radiation/Systems/RadiationSystem.GridCast.cs index b8193c4d2f..ccee7cf227 100644 --- a/Content.Server/Radiation/Systems/RadiationSystem.GridCast.cs +++ b/Content.Server/Radiation/Systems/RadiationSystem.GridCast.cs @@ -195,11 +195,11 @@ public partial class RadiationSystem Vector2 srcLocal = sourceTrs.ParentUid == grid.Owner ? sourceTrs.LocalPosition - : gridTrs.InvLocalMatrix.Transform(ray.Source); + : Vector2.Transform(ray.Source, gridTrs.InvLocalMatrix); Vector2 dstLocal = destTrs.ParentUid == grid.Owner ? destTrs.LocalPosition - : gridTrs.InvLocalMatrix.Transform(ray.Destination); + : Vector2.Transform(ray.Destination, gridTrs.InvLocalMatrix); Vector2i sourceGrid = new( (int) Math.Floor(srcLocal.X / grid.Comp.TileSize), diff --git a/Content.Server/Salvage/FultonSystem.cs b/Content.Server/Salvage/FultonSystem.cs index ad998e5359..e2c0a6b4c5 100644 --- a/Content.Server/Salvage/FultonSystem.cs +++ b/Content.Server/Salvage/FultonSystem.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Content.Shared.Salvage.Fulton; using Robust.Shared.Containers; using Robust.Shared.Map; @@ -61,8 +62,9 @@ public sealed class FultonSystem : SharedFultonSystem var metadata = MetaData(uid); var oldCoords = xform.Coordinates; var offset = _random.NextVector2(1.5f); - var localPos = TransformSystem.GetInvWorldMatrix(beaconXform.ParentUid) - .Transform(TransformSystem.GetWorldPosition(beaconXform)) + offset; + var localPos = Vector2.Transform( + TransformSystem.GetWorldPosition(beaconXform), + TransformSystem.GetInvWorldMatrix(beaconXform.ParentUid)) + offset; TransformSystem.SetCoordinates(uid, new EntityCoordinates(beaconXform.ParentUid, localPos)); diff --git a/Content.Server/Shuttles/Events/FTLStartedEvent.cs b/Content.Server/Shuttles/Events/FTLStartedEvent.cs index 965da7f0c5..eafbeddd5c 100644 --- a/Content.Server/Shuttles/Events/FTLStartedEvent.cs +++ b/Content.Server/Shuttles/Events/FTLStartedEvent.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Robust.Shared.Map; namespace Content.Server.Shuttles.Events; @@ -6,4 +7,4 @@ namespace Content.Server.Shuttles.Events; /// Raised when a shuttle has moved to FTL space. /// [ByRefEvent] -public readonly record struct FTLStartedEvent(EntityUid Entity, EntityCoordinates TargetCoordinates, EntityUid? FromMapUid, Matrix3 FTLFrom, Angle FromRotation); +public readonly record struct FTLStartedEvent(EntityUid Entity, EntityCoordinates TargetCoordinates, EntityUid? FromMapUid, Matrix3x2 FTLFrom, Angle FromRotation); diff --git a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs index e87e781e62..eb1f9796b2 100644 --- a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs +++ b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs @@ -1,4 +1,5 @@ using System.Linq; +using System.Numerics; using Content.Server.Administration; using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; @@ -277,7 +278,7 @@ public sealed class ArrivalsSystem : EntitySystem foreach (var (ent, xform) in toDump) { var rotation = xform.LocalRotation; - _transform.SetCoordinates(ent, new EntityCoordinates(args.FromMapUid!.Value, args.FTLFrom.Transform(xform.LocalPosition))); + _transform.SetCoordinates(ent, new EntityCoordinates(args.FromMapUid!.Value, Vector2.Transform(xform.LocalPosition, args.FTLFrom))); _transform.SetWorldRotation(ent, args.FromRotation + rotation); } } diff --git a/Content.Server/Shuttles/Systems/DockingSystem.Shuttle.cs b/Content.Server/Shuttles/Systems/DockingSystem.Shuttle.cs index e46a7c715f..1a95ef9cb2 100644 --- a/Content.Server/Shuttles/Systems/DockingSystem.Shuttle.cs +++ b/Content.Server/Shuttles/Systems/DockingSystem.Shuttle.cs @@ -46,13 +46,13 @@ public sealed partial class DockingSystem FixturesComponent shuttleFixtures, MapGridComponent grid, bool isMap, - out Matrix3 matty, + out Matrix3x2 matty, out Box2 shuttleDockedAABB, out Angle gridRotation) { shuttleDockedAABB = Box2.UnitCentered; gridRotation = Angle.Zero; - matty = Matrix3.Identity; + matty = Matrix3x2.Identity; if (shuttleDock.Docked || gridDock.Docked || @@ -71,9 +71,9 @@ public sealed partial class DockingSystem var gridDockAngle = gridDockXform.LocalRotation.Opposite(); var offsetAngle = gridDockAngle - shuttleDockAngle; - var stationDockMatrix = Matrix3.CreateInverseTransform(stationDockPos, shuttleDockAngle); - var gridXformMatrix = Matrix3.CreateTransform(gridDockXform.LocalPosition, gridDockAngle); - Matrix3.Multiply(in stationDockMatrix, in gridXformMatrix, out matty); + var stationDockMatrix = Matrix3Helpers.CreateInverseTransform(stationDockPos, shuttleDockAngle); + var gridXformMatrix = Matrix3Helpers.CreateTransform(gridDockXform.LocalPosition, gridDockAngle); + matty = Matrix3x2.Multiply(stationDockMatrix, gridXformMatrix); if (!ValidSpawn(grid, matty, offsetAngle, shuttleFixtures, isMap)) return false; @@ -193,7 +193,7 @@ public sealed partial class DockingSystem } // Can't just use the AABB as we want to get bounds as tight as possible. - var gridPosition = new EntityCoordinates(targetGrid, matty.Transform(Vector2.Zero)); + var gridPosition = new EntityCoordinates(targetGrid, Vector2.Transform(Vector2.Zero, matty)); var spawnPosition = new EntityCoordinates(targetGridXform.MapUid!.Value, gridPosition.ToMapPos(EntityManager, _transform)); // TODO: use tight bounds @@ -303,9 +303,9 @@ public sealed partial class DockingSystem /// /// Checks whether the shuttle can warp to the specified position. /// - private bool ValidSpawn(MapGridComponent grid, Matrix3 matty, Angle angle, FixturesComponent shuttleFixturesComp, bool isMap) + private bool ValidSpawn(MapGridComponent grid, Matrix3x2 matty, Angle angle, FixturesComponent shuttleFixturesComp, bool isMap) { - var transform = new Transform(matty.Transform(Vector2.Zero), angle); + var transform = new Transform(Vector2.Transform(Vector2.Zero, matty), angle); // Because some docking bounds are tight af need to check each chunk individually foreach (var fix in shuttleFixturesComp.Fixtures.Values) diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.Impact.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.Impact.cs index f346398cda..8a8d2d883d 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.Impact.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.Impact.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Content.Server.Shuttles.Components; using Content.Shared.Audio; using Robust.Shared.Audio; @@ -38,8 +39,8 @@ public sealed partial class ShuttleSystem var otherXform = Transform(args.OtherEntity); - var ourPoint = ourXform.InvWorldMatrix.Transform(args.WorldPoint); - var otherPoint = otherXform.InvWorldMatrix.Transform(args.WorldPoint); + var ourPoint = Vector2.Transform(args.WorldPoint, ourXform.InvWorldMatrix); + var otherPoint = Vector2.Transform(args.WorldPoint, otherXform.InvWorldMatrix); var ourVelocity = _physics.GetLinearVelocity(uid, ourPoint, ourBody, ourXform); var otherVelocity = _physics.GetLinearVelocity(args.OtherEntity, otherPoint, otherBody, otherXform); diff --git a/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs b/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs index f1d0af6f90..779b2f5971 100644 --- a/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs +++ b/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Content.Server.Atmos.Components; using Content.Server.Singularity.Components; using Content.Shared.Ghost; @@ -126,7 +127,7 @@ public sealed class GravityWellSystem : SharedGravityWellSystem /// The minimum distance at which entities can be affected by the gravity pulse. /// The base velocity added to any entities within affected by the gravity pulse scaled by the displacement of those entities from the epicenter. /// (optional) The transform of the entity at the epicenter of the gravitational pulse. - public void GravPulse(EntityUid uid, float maxRange, float minRange, in Matrix3 baseMatrixDeltaV, TransformComponent? xform = null) + public void GravPulse(EntityUid uid, float maxRange, float minRange, in Matrix3x2 baseMatrixDeltaV, TransformComponent? xform = null) { if (Resolve(uid, ref xform)) GravPulse(xform.Coordinates, maxRange, minRange, in baseMatrixDeltaV); @@ -154,7 +155,7 @@ public sealed class GravityWellSystem : SharedGravityWellSystem /// The maximum distance at which entities can be affected by the gravity pulse. /// The minimum distance at which entities can be affected by the gravity pulse. /// The base velocity added to any entities within affected by the gravity pulse scaled by the displacement of those entities from the epicenter. - public void GravPulse(EntityCoordinates entityPos, float maxRange, float minRange, in Matrix3 baseMatrixDeltaV) + public void GravPulse(EntityCoordinates entityPos, float maxRange, float minRange, in Matrix3x2 baseMatrixDeltaV) => GravPulse(entityPos.ToMap(EntityManager, _transform), maxRange, minRange, in baseMatrixDeltaV); /// @@ -175,7 +176,7 @@ public sealed class GravityWellSystem : SharedGravityWellSystem /// The maximum distance at which entities can be affected by the gravity pulse. /// The minimum distance at which entities can be affected by the gravity pulse. Exists to prevent div/0 errors. /// The base velocity added to any entities within affected by the gravity pulse scaled by the displacement of those entities from the epicenter. - public void GravPulse(MapCoordinates mapPos, float maxRange, float minRange, in Matrix3 baseMatrixDeltaV) + public void GravPulse(MapCoordinates mapPos, float maxRange, float minRange, in Matrix3x2 baseMatrixDeltaV) { if (mapPos == MapCoordinates.Nullspace) return; // No gravpulses in nullspace please. @@ -205,7 +206,7 @@ public sealed class GravityWellSystem : SharedGravityWellSystem continue; var scaling = (1f / distance2) * physics.Mass; // TODO: Variable falloff gradiants. - _physics.ApplyLinearImpulse(entity, (displacement * baseMatrixDeltaV) * scaling, body: physics); + _physics.ApplyLinearImpulse(entity, Vector2.Transform(displacement, baseMatrixDeltaV) * scaling, body: physics); } } @@ -218,10 +219,9 @@ public sealed class GravityWellSystem : SharedGravityWellSystem /// The base amount of velocity that will be added to entities in range towards the epicenter of the pulse. /// The base amount of velocity that will be added to entities in range counterclockwise relative to the epicenter of the pulse. public void GravPulse(MapCoordinates mapPos, float maxRange, float minRange = 0.0f, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f) - => GravPulse(mapPos, maxRange, minRange, new Matrix3( - baseRadialDeltaV, +baseTangentialDeltaV, 0.0f, - -baseTangentialDeltaV, baseRadialDeltaV, 0.0f, - 0.0f, 0.0f, 1.0f + => GravPulse(mapPos, maxRange, minRange, new Matrix3x2( + baseRadialDeltaV, -baseTangentialDeltaV, 0.0f, + +baseTangentialDeltaV, baseRadialDeltaV, 0.0f )); #endregion GravPulse diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs index 7247109e37..cb893299a9 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs @@ -396,7 +396,7 @@ public sealed partial class GunSystem : SharedGunSystem var (_, gridRot, gridInvMatrix) = TransformSystem.GetWorldPositionRotationInvMatrix(gridXform, xformQuery); fromCoordinates = new EntityCoordinates(gridUid.Value, - gridInvMatrix.Transform(fromCoordinates.ToMapPos(EntityManager, TransformSystem))); + Vector2.Transform(fromCoordinates.ToMapPos(EntityManager, TransformSystem), gridInvMatrix)); // Use the fallback angle I guess? angle -= gridRot; diff --git a/Content.Shared/Explosion/Components/ExplosionVisualsComponent.cs b/Content.Shared/Explosion/Components/ExplosionVisualsComponent.cs index 7477b6c26e..88e81c93c5 100644 --- a/Content.Shared/Explosion/Components/ExplosionVisualsComponent.cs +++ b/Content.Shared/Explosion/Components/ExplosionVisualsComponent.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Serialization; @@ -15,7 +16,7 @@ public sealed partial class ExplosionVisualsComponent : Component public Dictionary>> Tiles = new(); public List Intensity = new(); public string ExplosionType = string.Empty; - public Matrix3 SpaceMatrix; + public Matrix3x2 SpaceMatrix; public ushort SpaceTileSize; } @@ -27,7 +28,7 @@ public sealed class ExplosionVisualsState : ComponentState public Dictionary>> Tiles; public List Intensity; public string ExplosionType = string.Empty; - public Matrix3 SpaceMatrix; + public Matrix3x2 SpaceMatrix; public ushort SpaceTileSize; public ExplosionVisualsState( @@ -36,7 +37,7 @@ public sealed class ExplosionVisualsState : ComponentState List intensity, Dictionary>? spaceTiles, Dictionary>> tiles, - Matrix3 spaceMatrix, + Matrix3x2 spaceMatrix, ushort spaceTileSize) { Epicenter = epicenter; diff --git a/Content.Shared/Item/SharedItemSystem.cs b/Content.Shared/Item/SharedItemSystem.cs index 29e82f8ade..5eaa25f484 100644 --- a/Content.Shared/Item/SharedItemSystem.cs +++ b/Content.Shared/Item/SharedItemSystem.cs @@ -192,7 +192,7 @@ public abstract class SharedItemSystem : EntitySystem var shapes = GetItemShape(entity); var boundingShape = shapes.GetBoundingBox(); var boundingCenter = ((Box2) boundingShape).Center; - var matty = Matrix3.CreateTransform(boundingCenter, rotation); + var matty = Matrix3Helpers.CreateTransform(boundingCenter, rotation); var drift = boundingShape.BottomLeft - matty.TransformBox(boundingShape).BottomLeft; var adjustedShapes = new List(); diff --git a/Content.Shared/Maps/TurfSystem.cs b/Content.Shared/Maps/TurfSystem.cs index ad8b3ddea8..8a4bbf68be 100644 --- a/Content.Shared/Maps/TurfSystem.cs +++ b/Content.Shared/Maps/TurfSystem.cs @@ -44,7 +44,7 @@ public sealed class TurfSystem : EntitySystem var size = grid.TileSize; var localPos = new Vector2(indices.X * size + (size / 2f), indices.Y * size + (size / 2f)); - var worldPos = matrix.Transform(localPos); + var worldPos = Vector2.Transform(localPos, matrix); // This is scaled to 95 % so it doesn't encompass walls on other tiles. var tileAabb = Box2.UnitCentered.Scale(0.95f * size); diff --git a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs index 2d9993096b..b67acdea4f 100644 --- a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs +++ b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs @@ -751,7 +751,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem return; var invMatrix = TransformSystem.GetInvWorldMatrix(userXform); - var localPos = invMatrix.Transform(coordinates.Position); + var localPos = Vector2.Transform(coordinates.Position, invMatrix); if (localPos.LengthSquared() <= 0f) return; From 6235fa1ac69f72d0ed9ef4b089245f04e7ca01f9 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Sun, 2 Jun 2024 16:08:15 +1200 Subject: [PATCH 11/20] Content changes for entity categories PR (#27232) * Content changes for entity categories PR * Poke tests * Why are tests suddenly working? --- Content.IntegrationTests/Tests/EntityTest.cs | 11 +++-------- .../Rules/Components/NukeOperativeSpawnerComponent.cs | 5 +++-- .../Roles/Components/GhostRoleMobSpawnerComponent.cs | 2 +- .../Components/RandomHumanoidSpawnerComponent.cs | 2 +- .../Components/ConditionalSpawnerComponent.cs | 2 +- .../Spawners/Components/RandomSpawnerComponent.cs | 2 +- .../Spawners/Components/TimedSpawnerComponent.cs | 2 +- Content.Shared/Actions/BaseActionComponent.cs | 4 +++- .../Body/Prototypes/BodyPrototypeSerializer.cs | 2 +- Content.Shared/Dragon/SharedDragonRiftComponent.cs | 3 ++- Resources/Locale/en-US/entity-categories.ftl | 1 + Resources/Prototypes/Alerts/alerts.yml | 2 +- Resources/Prototypes/Alerts/revenant.yml | 2 +- .../Prototypes/Entities/Objects/Devices/flatpack.yml | 2 +- .../Entities/Structures/Machines/flatpacker.yml | 2 +- Resources/Prototypes/Entities/categories.yml | 4 ++++ 16 files changed, 26 insertions(+), 22 deletions(-) create mode 100644 Resources/Locale/en-US/entity-categories.ftl create mode 100644 Resources/Prototypes/Entities/categories.yml diff --git a/Content.IntegrationTests/Tests/EntityTest.cs b/Content.IntegrationTests/Tests/EntityTest.cs index 54af64122b..926374cf05 100644 --- a/Content.IntegrationTests/Tests/EntityTest.cs +++ b/Content.IntegrationTests/Tests/EntityTest.cs @@ -19,6 +19,8 @@ namespace Content.IntegrationTests.Tests [TestOf(typeof(EntityUid))] public sealed class EntityTest { + private static readonly ProtoId SpawnerCategory = "Spawner"; + [Test] public async Task SpawnAndDeleteAllEntitiesOnDifferentMaps() { @@ -234,14 +236,6 @@ namespace Content.IntegrationTests.Tests "StationEvent", "TimedDespawn", - // Spawner entities - "DragonRift", - "RandomHumanoidSpawner", - "RandomSpawner", - "ConditionalSpawner", - "GhostRoleMobSpawner", - "NukeOperativeSpawner", - "TimedSpawner", // makes an announcement on mapInit. "AnnounceOnSpawn", }; @@ -253,6 +247,7 @@ namespace Content.IntegrationTests.Tests .Where(p => !p.Abstract) .Where(p => !pair.IsTestPrototype(p)) .Where(p => !excluded.Any(p.Components.ContainsKey)) + .Where(p => p.Categories.All(x => x.ID != SpawnerCategory)) .Select(p => p.ID) .ToList(); diff --git a/Content.Server/GameTicking/Rules/Components/NukeOperativeSpawnerComponent.cs b/Content.Server/GameTicking/Rules/Components/NukeOperativeSpawnerComponent.cs index bb1b7c8746..54eaa6e32e 100644 --- a/Content.Server/GameTicking/Rules/Components/NukeOperativeSpawnerComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/NukeOperativeSpawnerComponent.cs @@ -1,3 +1,5 @@ +using Robust.Shared.Prototypes; + namespace Content.Server.GameTicking.Rules.Components; /// @@ -5,6 +7,5 @@ namespace Content.Server.GameTicking.Rules.Components; /// and providing loadout + name for the operative on spawn. /// TODO: Remove once systems can request spawns from the ghost role system directly. /// -[RegisterComponent] +[RegisterComponent, EntityCategory("Spawner")] public sealed partial class NukeOperativeSpawnerComponent : Component; - diff --git a/Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs b/Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs index 6c2a6986fc..6116173f90 100644 --- a/Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs +++ b/Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs @@ -5,7 +5,7 @@ namespace Content.Server.Ghost.Roles.Components /// /// Allows a ghost to take this role, spawning a new entity. /// - [RegisterComponent] + [RegisterComponent, EntityCategory("Spawner")] [Access(typeof(GhostRoleSystem))] public sealed partial class GhostRoleMobSpawnerComponent : Component { diff --git a/Content.Server/Humanoid/Components/RandomHumanoidSpawnerComponent.cs b/Content.Server/Humanoid/Components/RandomHumanoidSpawnerComponent.cs index b56664fe19..bb38e94e04 100644 --- a/Content.Server/Humanoid/Components/RandomHumanoidSpawnerComponent.cs +++ b/Content.Server/Humanoid/Components/RandomHumanoidSpawnerComponent.cs @@ -8,7 +8,7 @@ namespace Content.Server.Humanoid.Components; /// This is added to a marker entity in order to spawn a randomized /// humanoid ingame. /// -[RegisterComponent] +[RegisterComponent, EntityCategory("Spawner")] public sealed partial class RandomHumanoidSpawnerComponent : Component { [DataField("settings", customTypeSerializer: typeof(PrototypeIdSerializer))] diff --git a/Content.Server/Spawners/Components/ConditionalSpawnerComponent.cs b/Content.Server/Spawners/Components/ConditionalSpawnerComponent.cs index 5b98989bb3..1b06367b0d 100644 --- a/Content.Server/Spawners/Components/ConditionalSpawnerComponent.cs +++ b/Content.Server/Spawners/Components/ConditionalSpawnerComponent.cs @@ -2,7 +2,7 @@ using Robust.Shared.Prototypes; namespace Content.Server.Spawners.Components { - [RegisterComponent] + [RegisterComponent, EntityCategory("Spawner")] [Virtual] public partial class ConditionalSpawnerComponent : Component { diff --git a/Content.Server/Spawners/Components/RandomSpawnerComponent.cs b/Content.Server/Spawners/Components/RandomSpawnerComponent.cs index 9bf4d6d253..e6a597f365 100644 --- a/Content.Server/Spawners/Components/RandomSpawnerComponent.cs +++ b/Content.Server/Spawners/Components/RandomSpawnerComponent.cs @@ -2,7 +2,7 @@ using Robust.Shared.Prototypes; namespace Content.Server.Spawners.Components { - [RegisterComponent] + [RegisterComponent, EntityCategory("Spawner")] public sealed partial class RandomSpawnerComponent : ConditionalSpawnerComponent { [ViewVariables(VVAccess.ReadWrite)] diff --git a/Content.Server/Spawners/Components/TimedSpawnerComponent.cs b/Content.Server/Spawners/Components/TimedSpawnerComponent.cs index b60afbc88b..828e541717 100644 --- a/Content.Server/Spawners/Components/TimedSpawnerComponent.cs +++ b/Content.Server/Spawners/Components/TimedSpawnerComponent.cs @@ -9,7 +9,7 @@ namespace Content.Server.Spawners.Components; /// Can configure the set of entities, spawn timing, spawn chance, /// and min/max number of entities to spawn. /// -[RegisterComponent] +[RegisterComponent, EntityCategory("Spawner")] public sealed partial class TimedSpawnerComponent : Component, ISerializationHooks { /// diff --git a/Content.Shared/Actions/BaseActionComponent.cs b/Content.Shared/Actions/BaseActionComponent.cs index 57c145a0ec..9156f747f5 100644 --- a/Content.Shared/Actions/BaseActionComponent.cs +++ b/Content.Shared/Actions/BaseActionComponent.cs @@ -1,14 +1,16 @@ using Robust.Shared.Audio; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Utility; namespace Content.Shared.Actions; -// TODO ACTIONS make this a seprate component and remove the inheritance stuff. +// TODO ACTIONS make this a separate component and remove the inheritance stuff. // TODO ACTIONS convert to auto comp state? // TODO add access attribute. Need to figure out what to do with decal & mapping actions. // [Access(typeof(SharedActionsSystem))] +[EntityCategory("Actions")] public abstract partial class BaseActionComponent : Component { public abstract BaseActionEvent? BaseEvent { get; } diff --git a/Content.Shared/Body/Prototypes/BodyPrototypeSerializer.cs b/Content.Shared/Body/Prototypes/BodyPrototypeSerializer.cs index e2b54bf951..ae09976704 100644 --- a/Content.Shared/Body/Prototypes/BodyPrototypeSerializer.cs +++ b/Content.Shared/Body/Prototypes/BodyPrototypeSerializer.cs @@ -182,7 +182,7 @@ public sealed class BodyPrototypeSerializer : ITypeReader(), organs ?? new Dictionary()); + var slot = new BodyPrototypeSlot(part, connections ?? new HashSet(), organs ?? new Dictionary()); slots.Add(slotId, slot); } diff --git a/Content.Shared/Dragon/SharedDragonRiftComponent.cs b/Content.Shared/Dragon/SharedDragonRiftComponent.cs index 0d2bf44018..8377dbfee7 100644 --- a/Content.Shared/Dragon/SharedDragonRiftComponent.cs +++ b/Content.Shared/Dragon/SharedDragonRiftComponent.cs @@ -1,9 +1,10 @@ using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.Dragon; -[NetworkedComponent] +[NetworkedComponent, EntityCategory("Spawner")] public abstract partial class SharedDragonRiftComponent : Component { [DataField("state")] diff --git a/Resources/Locale/en-US/entity-categories.ftl b/Resources/Locale/en-US/entity-categories.ftl new file mode 100644 index 0000000000..190fe5713a --- /dev/null +++ b/Resources/Locale/en-US/entity-categories.ftl @@ -0,0 +1 @@ +entity-category-name-actions = Actions diff --git a/Resources/Prototypes/Alerts/alerts.yml b/Resources/Prototypes/Alerts/alerts.yml index 7881cddd4a..72412fde7c 100644 --- a/Resources/Prototypes/Alerts/alerts.yml +++ b/Resources/Prototypes/Alerts/alerts.yml @@ -28,7 +28,7 @@ - type: entity id: AlertSpriteView - categories: [ hideSpawnMenu ] + categories: [ HideSpawnMenu ] components: - type: Sprite layers: diff --git a/Resources/Prototypes/Alerts/revenant.yml b/Resources/Prototypes/Alerts/revenant.yml index 7f3f98949e..38933df4fe 100644 --- a/Resources/Prototypes/Alerts/revenant.yml +++ b/Resources/Prototypes/Alerts/revenant.yml @@ -16,7 +16,7 @@ - type: entity id: AlertEssenceSpriteView - categories: [ hideSpawnMenu ] + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: /Textures/Interface/Alerts/essence_counter.rsi diff --git a/Resources/Prototypes/Entities/Objects/Devices/flatpack.yml b/Resources/Prototypes/Entities/Objects/Devices/flatpack.yml index e3e77d5c88..b9c2b752db 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/flatpack.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/flatpack.yml @@ -4,7 +4,7 @@ name: base flatpack description: A flatpack used for constructing something. categories: - - hideSpawnMenu + - HideSpawnMenu components: - type: Item size: Large diff --git a/Resources/Prototypes/Entities/Structures/Machines/flatpacker.yml b/Resources/Prototypes/Entities/Structures/Machines/flatpacker.yml index b4f05cf68a..78f1504003 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/flatpacker.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/flatpacker.yml @@ -84,7 +84,7 @@ - type: entity id: FlatpackerNoBoardEffect categories: - - hideSpawnMenu + - HideSpawnMenu components: - type: Sprite sprite: Structures/Machines/autolathe.rsi diff --git a/Resources/Prototypes/Entities/categories.yml b/Resources/Prototypes/Entities/categories.yml new file mode 100644 index 0000000000..2fb56818f9 --- /dev/null +++ b/Resources/Prototypes/Entities/categories.yml @@ -0,0 +1,4 @@ +- type: entityCategory + id: Actions + name: entity-category-name-actions + hideSpawnMenu: true From 4c667b2d8f898abc4f7b9fcf9d8753f9cbee9afd Mon Sep 17 00:00:00 2001 From: Cojoke <83733158+Cojoke-dot@users.noreply.github.com> Date: Sat, 1 Jun 2024 23:13:12 -0500 Subject: [PATCH 12/20] Fix Lasers Being Blocked by External Airlocks and Shuttle Airlocks (#28065) --- .../Structures/Doors/Airlocks/external.yml | 11 +++++ .../Structures/Doors/Airlocks/shuttle.yml | 47 +++---------------- 2 files changed, 17 insertions(+), 41 deletions(-) diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/external.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/external.yml index 293aaac273..3197ba417f 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/external.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/external.yml @@ -33,3 +33,14 @@ sprite: Structures/Doors/Airlocks/Glass/external.rsi - type: PaintableAirlock group: ExternalGlass + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.49,-0.49,0.49,0.49" # don't want this colliding with walls or they won't close + density: 100 + mask: + - FullTileMask + layer: #removed opaque from the layer, allowing lasers to pass through glass airlocks + - GlassAirlockLayer diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml index 43d1228a40..5d27cec181 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml @@ -82,29 +82,17 @@ components: - type: Sprite sprite: Structures/Doors/Airlocks/Glass/shuttle.rsi - snapCardinals: false - layers: - - state: closed - map: ["enum.DoorVisualLayers.Base"] - - state: closed_unlit - shader: unshaded - map: ["enum.DoorVisualLayers.BaseUnlit"] - - state: welded - map: ["enum.WeldableLayers.BaseWelded"] - - state: bolted_unlit - shader: unshaded - map: ["enum.DoorVisualLayers.BaseBolted"] - - state: emergency_unlit - shader: unshaded - map: ["enum.DoorVisualLayers.BaseEmergencyAccess"] - - state: panel_open - map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Occluder enabled: false - type: PaintableAirlock group: ShuttleGlass - type: Door occludes: false + - type: Fixtures + fixtures: + fix1: + layer: #removed opaque from the layer, allowing lasers to pass through glass airlocks + - GlassAirlockLayer - type: entity id: AirlockShuttleAssembly @@ -126,36 +114,13 @@ - type: entity id: AirlockGlassShuttleSyndicate - parent: AirlockShuttle + parent: AirlockGlassShuttle name: external airlock suffix: Glass, Docking description: Necessary for connecting two space craft together. components: - type: Sprite sprite: Structures/Doors/Airlocks/Glass/shuttle_syndicate.rsi - snapCardinals: false - layers: - - state: closed - map: ["enum.DoorVisualLayers.Base"] - - state: closed_unlit - shader: unshaded - map: ["enum.DoorVisualLayers.BaseUnlit"] - - state: welded - map: ["enum.WeldableLayers.BaseWelded"] - - state: bolted_unlit - shader: unshaded - map: ["enum.DoorVisualLayers.BaseBolted"] - - state: emergency_unlit - shader: unshaded - map: ["enum.DoorVisualLayers.BaseEmergencyAccess"] - - state: panel_open - map: ["enum.WiresVisualLayers.MaintenancePanel"] - - type: Occluder - enabled: false - - type: PaintableAirlock - group: ShuttleGlass - - type: Door - occludes: false - type: entity parent: AirlockShuttle From f5bc921bdd7e0c2c0c8a4ea7620b6022aa4e503e Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 2 Jun 2024 04:14:18 +0000 Subject: [PATCH 13/20] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 0c671f49ee..de9e112c59 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Plykiya - changes: - - message: Ion storms now have a chance of happening from the start of shift. - type: Tweak - id: 6163 - time: '2024-03-16T03:47:14.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26165 - author: Krunk changes: - message: Zombies and animals can be stripped once again. @@ -3853,3 +3846,10 @@ id: 6662 time: '2024-06-02T01:41:06.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/28496 +- author: Cojoke-dot + changes: + - message: Lasers now pass through Glass External Airlocks and Glass Shuttle Airlocks + type: Fix + id: 6663 + time: '2024-06-02T04:13:12.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/28065 From 12839893464ef4af1bf3279e9f76f92e82b0afe1 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Sun, 2 Jun 2024 06:17:53 +0200 Subject: [PATCH 14/20] Flash overlay rework and bugfixes (#27369) --- Content.Client/Entry/EntryPoint.cs | 1 - Content.Client/Flash/FlashOverlay.cs | 78 +++++++++------ Content.Client/Flash/FlashSystem.cs | 99 ++++++++++--------- .../Components/DamagedByFlashingComponent.cs | 3 +- .../Components/FlashImmunityComponent.cs | 19 ++-- Content.Server/Flash/FlashSystem.cs | 84 ++++++++-------- .../Flash/Components/FlashComponent.cs | 11 ++- .../Flash/Components/FlashedComponent.cs | 9 ++ Content.Shared/Flash/FlashableComponent.cs | 40 -------- Content.Shared/Flash/SharedFlashSystem.cs | 15 +-- .../Mobs/Cyborgs/base_borg_chassis.yml | 2 +- .../Entities/Mobs/NPCs/argocyte.yml | 1 - .../Prototypes/Entities/Mobs/NPCs/pets.yml | 2 - .../Entities/Mobs/NPCs/simplemob.yml | 2 + .../Prototypes/Entities/Mobs/Species/base.yml | 21 +--- .../Entities/Objects/base_shadow.yml | 3 - Resources/Prototypes/status_effects.yml | 3 + .../Textures/Shaders/flashed_effect.swsl | 2 +- 18 files changed, 187 insertions(+), 208 deletions(-) create mode 100644 Content.Shared/Flash/Components/FlashedComponent.cs delete mode 100644 Content.Shared/Flash/FlashableComponent.cs diff --git a/Content.Client/Entry/EntryPoint.cs b/Content.Client/Entry/EntryPoint.cs index b28c6a11fb..51210a8a93 100644 --- a/Content.Client/Entry/EntryPoint.cs +++ b/Content.Client/Entry/EntryPoint.cs @@ -152,7 +152,6 @@ namespace Content.Client.Entry _parallaxManager.LoadDefaultParallax(); _overlayManager.AddOverlay(new SingularityOverlay()); - _overlayManager.AddOverlay(new FlashOverlay()); _overlayManager.AddOverlay(new RadiationPulseOverlay()); _chatManager.Initialize(); _clientPreferencesManager.Initialize(); diff --git a/Content.Client/Flash/FlashOverlay.cs b/Content.Client/Flash/FlashOverlay.cs index fe9c888227..9ea00275e8 100644 --- a/Content.Client/Flash/FlashOverlay.cs +++ b/Content.Client/Flash/FlashOverlay.cs @@ -1,12 +1,11 @@ -using System.Numerics; +using Content.Shared.Flash; +using Content.Shared.Flash.Components; +using Content.Shared.StatusEffect; using Content.Client.Viewport; using Robust.Client.Graphics; using Robust.Client.State; using Robust.Client.Player; using Robust.Shared.Enums; -using Robust.Shared.Graphics; -using Robust.Shared.IoC; -using Robust.Shared.Maths; using Robust.Shared.Prototypes; using Robust.Shared.Timing; using SixLabors.ImageSharp.PixelFormats; @@ -17,66 +16,87 @@ namespace Content.Client.Flash { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IClyde _displayManager = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IStateManager _stateManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + private readonly StatusEffectsSystem _statusSys; public override OverlaySpace Space => OverlaySpace.WorldSpace; private readonly ShaderInstance _shader; - private double _startTime = -1; - private double _lastsFor = 1; - private Texture? _screenshotTexture; + public float PercentComplete = 0.0f; + public Texture? ScreenshotTexture; public FlashOverlay() { IoCManager.InjectDependencies(this); - _shader = _prototypeManager.Index("FlashedEffect").Instance().Duplicate(); + _shader = _prototypeManager.Index("FlashedEffect").InstanceUnique(); + _statusSys = _entityManager.System(); } - public void ReceiveFlash(double duration) + protected override void FrameUpdate(FrameEventArgs args) + { + var playerEntity = _playerManager.LocalEntity; + + if (playerEntity == null) + return; + + if (!_entityManager.HasComponent(playerEntity) + || !_entityManager.TryGetComponent(playerEntity, out var status)) + return; + + if (!_statusSys.TryGetTime(playerEntity.Value, SharedFlashSystem.FlashedKey, out var time, status)) + return; + + var curTime = _timing.CurTime; + var lastsFor = (float) (time.Value.Item2 - time.Value.Item1).TotalSeconds; + var timeDone = (float) (curTime - time.Value.Item1).TotalSeconds; + + PercentComplete = timeDone / lastsFor; + } + + public void ReceiveFlash() { if (_stateManager.CurrentState is IMainViewportState state) { + // take a screenshot + // note that the callback takes a while and ScreenshotTexture will be null the first few Draws state.Viewport.Viewport.Screenshot(image => { var rgba32Image = image.CloneAs(SixLabors.ImageSharp.Configuration.Default); - _screenshotTexture = _displayManager.LoadTextureFromImage(rgba32Image); + ScreenshotTexture = _displayManager.LoadTextureFromImage(rgba32Image); }); } + } - _startTime = _gameTiming.CurTime.TotalSeconds; - _lastsFor = duration; + protected override bool BeforeDraw(in OverlayDrawArgs args) + { + if (!_entityManager.TryGetComponent(_playerManager.LocalEntity, out EyeComponent? eyeComp)) + return false; + if (args.Viewport.Eye != eyeComp.Eye) + return false; + + return PercentComplete < 1.0f; } protected override void Draw(in OverlayDrawArgs args) { - if (!_entityManager.TryGetComponent(_playerManager.LocalEntity, out EyeComponent? eyeComp)) - return; - - if (args.Viewport.Eye != eyeComp.Eye) - return; - - var percentComplete = (float) ((_gameTiming.CurTime.TotalSeconds - _startTime) / _lastsFor); - if (percentComplete >= 1.0f) + if (ScreenshotTexture == null) return; var worldHandle = args.WorldHandle; + _shader.SetParameter("percentComplete", PercentComplete); worldHandle.UseShader(_shader); - _shader.SetParameter("percentComplete", percentComplete); - - if (_screenshotTexture != null) - { - worldHandle.DrawTextureRectRegion(_screenshotTexture, args.WorldBounds); - } - + worldHandle.DrawTextureRectRegion(ScreenshotTexture, args.WorldBounds); worldHandle.UseShader(null); } protected override void DisposeBehavior() { base.DisposeBehavior(); - _screenshotTexture = null; + ScreenshotTexture = null; + PercentComplete = 1.0f; } } } diff --git a/Content.Client/Flash/FlashSystem.cs b/Content.Client/Flash/FlashSystem.cs index ad8f8b0b82..9a0579f6aa 100644 --- a/Content.Client/Flash/FlashSystem.cs +++ b/Content.Client/Flash/FlashSystem.cs @@ -1,62 +1,67 @@ using Content.Shared.Flash; +using Content.Shared.Flash.Components; +using Content.Shared.StatusEffect; using Robust.Client.Graphics; using Robust.Client.Player; -using Robust.Shared.GameStates; -using Robust.Shared.Timing; +using Robust.Shared.Player; -namespace Content.Client.Flash +namespace Content.Client.Flash; + +public sealed class FlashSystem : SharedFlashSystem { - public sealed class FlashSystem : SharedFlashSystem + [Dependency] private readonly IPlayerManager _player = default!; + [Dependency] private readonly IOverlayManager _overlayMan = default!; + + private FlashOverlay _overlay = default!; + + public override void Initialize() { - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IPlayerManager _playerManager = default!; - [Dependency] private readonly IOverlayManager _overlayManager = default!; + base.Initialize(); - public override void Initialize() + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); + SubscribeLocalEvent(OnStatusAdded); + + _overlay = new(); + } + + private void OnPlayerAttached(EntityUid uid, FlashedComponent component, LocalPlayerAttachedEvent args) + { + _overlayMan.AddOverlay(_overlay); + } + + private void OnPlayerDetached(EntityUid uid, FlashedComponent component, LocalPlayerDetachedEvent args) + { + _overlay.PercentComplete = 1.0f; + _overlay.ScreenshotTexture = null; + _overlayMan.RemoveOverlay(_overlay); + } + + private void OnInit(EntityUid uid, FlashedComponent component, ComponentInit args) + { + if (_player.LocalEntity == uid) { - base.Initialize(); - - SubscribeLocalEvent(OnFlashableHandleState); + _overlayMan.AddOverlay(_overlay); } + } - private void OnFlashableHandleState(EntityUid uid, FlashableComponent component, ref ComponentHandleState args) + private void OnShutdown(EntityUid uid, FlashedComponent component, ComponentShutdown args) + { + if (_player.LocalEntity == uid) { - if (args.Current is not FlashableComponentState state) - return; + _overlay.PercentComplete = 1.0f; + _overlay.ScreenshotTexture = null; + _overlayMan.RemoveOverlay(_overlay); + } + } - // Yes, this code is awful. I'm just porting it to an entity system so don't blame me. - if (_playerManager.LocalEntity != uid) - { - return; - } - - if (state.Time == default) - { - return; - } - - // Few things here: - // 1. If a shorter duration flash is applied then don't do anything - // 2. If the client-side time is later than when the flash should've ended don't do anything - var currentTime = _gameTiming.CurTime.TotalSeconds; - var newEndTime = state.Time.TotalSeconds + state.Duration; - var currentEndTime = component.LastFlash.TotalSeconds + component.Duration; - - if (currentEndTime > newEndTime) - { - return; - } - - if (currentTime > newEndTime) - { - return; - } - - component.LastFlash = state.Time; - component.Duration = state.Duration; - - var overlay = _overlayManager.GetOverlay(); - overlay.ReceiveFlash(component.Duration); + private void OnStatusAdded(EntityUid uid, FlashedComponent component, StatusEffectAddedEvent args) + { + if (_player.LocalEntity == uid && args.Key == FlashedKey) + { + _overlay.ReceiveFlash(); } } } diff --git a/Content.Server/Flash/Components/DamagedByFlashingComponent.cs b/Content.Server/Flash/Components/DamagedByFlashingComponent.cs index 2a9024607d..ef33454295 100644 --- a/Content.Server/Flash/Components/DamagedByFlashingComponent.cs +++ b/Content.Server/Flash/Components/DamagedByFlashingComponent.cs @@ -3,7 +3,6 @@ using Robust.Shared.Prototypes; namespace Content.Server.Flash.Components; -// Also needed FlashableComponent on entity to work [RegisterComponent, Access(typeof(DamagedByFlashingSystem))] public sealed partial class DamagedByFlashingComponent : Component { @@ -11,5 +10,5 @@ public sealed partial class DamagedByFlashingComponent : Component /// damage from flashing /// [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] - public DamageSpecifier FlashDamage = new (); + public DamageSpecifier FlashDamage = new(); } diff --git a/Content.Server/Flash/Components/FlashImmunityComponent.cs b/Content.Server/Flash/Components/FlashImmunityComponent.cs index 80bbdd1282..a982a9059f 100644 --- a/Content.Server/Flash/Components/FlashImmunityComponent.cs +++ b/Content.Server/Flash/Components/FlashImmunityComponent.cs @@ -1,10 +1,13 @@ -namespace Content.Server.Flash.Components +namespace Content.Server.Flash.Components; + +/// +/// Makes the entity immune to being flashed. +/// When given to clothes in the "head", "eyes" or "mask" slot it protects the wearer. +/// +[RegisterComponent, Access(typeof(FlashSystem))] +public sealed partial class FlashImmunityComponent : Component { - [RegisterComponent, Access(typeof(FlashSystem))] - public sealed partial class FlashImmunityComponent : Component - { - [ViewVariables(VVAccess.ReadWrite)] - [DataField("enabled")] - public bool Enabled { get; set; } = true; - } + [ViewVariables(VVAccess.ReadWrite)] + [DataField("enabled")] + public bool Enabled { get; set; } = true; } diff --git a/Content.Server/Flash/FlashSystem.cs b/Content.Server/Flash/FlashSystem.cs index dd8cdab426..ccb58e94f8 100644 --- a/Content.Server/Flash/FlashSystem.cs +++ b/Content.Server/Flash/FlashSystem.cs @@ -9,18 +9,17 @@ using Content.Shared.Charges.Systems; using Content.Shared.Eye.Blinding.Components; using Content.Shared.Flash; using Content.Shared.IdentityManagement; -using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Inventory; -using Content.Shared.Physics; using Content.Shared.Tag; using Content.Shared.Traits.Assorted; using Content.Shared.Weapons.Melee.Events; +using Content.Shared.StatusEffect; +using Content.Shared.Examine; using Robust.Server.Audio; using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Random; -using Robust.Shared.Timing; using InventoryComponent = Content.Shared.Inventory.InventoryComponent; namespace Content.Server.Flash @@ -31,14 +30,14 @@ namespace Content.Server.Flash [Dependency] private readonly AudioSystem _audio = default!; [Dependency] private readonly SharedChargesSystem _charges = default!; [Dependency] private readonly EntityLookupSystem _entityLookup = default!; - [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly SharedInteractionSystem _interaction = default!; + [Dependency] private readonly ExamineSystemShared _examine = default!; [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly StunSystem _stun = default!; [Dependency] private readonly TagSystem _tag = default!; [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; public override void Initialize() { @@ -46,7 +45,7 @@ namespace Content.Server.Flash SubscribeLocalEvent(OnFlashMeleeHit); // ran before toggling light for extra-bright lantern - SubscribeLocalEvent(OnFlashUseInHand, before: new []{ typeof(HandheldLightSystem) }); + SubscribeLocalEvent(OnFlashUseInHand, before: new[] { typeof(HandheldLightSystem) }); SubscribeLocalEvent(OnInventoryFlashAttempt); SubscribeLocalEvent(OnFlashImmunityFlashAttempt); SubscribeLocalEvent(OnPermanentBlindnessFlashAttempt); @@ -114,19 +113,35 @@ namespace Content.Server.Flash float flashDuration, float slowTo, bool displayPopup = true, - FlashableComponent? flashable = null, bool melee = false, TimeSpan? stunDuration = null) { - if (!Resolve(target, ref flashable, false)) - return; - var attempt = new FlashAttemptEvent(target, user, used); RaiseLocalEvent(target, attempt, true); if (attempt.Cancelled) return; + // don't paralyze, slowdown or convert to rev if the target is immune to flashes + if (!_statusEffectsSystem.TryAddStatusEffect(target, FlashedKey, TimeSpan.FromSeconds(flashDuration / 1000f), true)) + return; + + if (stunDuration != null) + { + _stun.TryParalyze(target, stunDuration.Value, true); + } + else + { + _stun.TrySlowdown(target, TimeSpan.FromSeconds(flashDuration / 1000f), true, + slowTo, slowTo); + } + + if (displayPopup && user != null && target != user && Exists(user.Value)) + { + _popup.PopupEntity(Loc.GetString("flash-component-user-blinds-you", + ("user", Identity.Entity(user.Value, EntityManager))), target, target); + } + if (melee) { var ev = new AfterFlashedEvent(target, user, used); @@ -135,48 +150,31 @@ namespace Content.Server.Flash if (used != null) RaiseLocalEvent(used.Value, ref ev); } - - flashable.LastFlash = _timing.CurTime; - flashable.Duration = flashDuration / 1000f; // TODO: Make this sane... - Dirty(target, flashable); - - if (stunDuration != null) - { - _stun.TryParalyze(target, stunDuration.Value, true); - } - else - { - _stun.TrySlowdown(target, TimeSpan.FromSeconds(flashDuration/1000f), true, - slowTo, slowTo); - } - - if (displayPopup && user != null && target != user && Exists(user.Value)) - { - _popup.PopupEntity(Loc.GetString("flash-component-user-blinds-you", - ("user", Identity.Entity(user.Value, EntityManager))), target, target); - } } public void FlashArea(Entity source, EntityUid? user, float range, float duration, float slowTo = 0.8f, bool displayPopup = false, float probability = 1f, SoundSpecifier? sound = null) { var transform = Transform(source); var mapPosition = _transform.GetMapCoordinates(transform); - var flashableQuery = GetEntityQuery(); + var statusEffectsQuery = GetEntityQuery(); + var damagedByFlashingQuery = GetEntityQuery(); foreach (var entity in _entityLookup.GetEntitiesInRange(transform.Coordinates, range)) { if (!_random.Prob(probability)) continue; - if (!flashableQuery.TryGetComponent(entity, out var flashable)) + // Is the entity affected by the flash either through status effects or by taking damage? + if (!statusEffectsQuery.HasComponent(entity) && !damagedByFlashingQuery.HasComponent(entity)) continue; - // Check for unobstructed entities while ignoring the mobs with flashable components. - if (!_interaction.InRangeUnobstructed(entity, mapPosition, range, flashable.CollisionGroup, predicate: (e) => flashableQuery.HasComponent(e) || e == source.Owner)) + // Check for entites in view + // put damagedByFlashingComponent in the predicate because shadow anomalies block vision. + if (!_examine.InRangeUnOccluded(entity, mapPosition, range, predicate: (e) => damagedByFlashingQuery.HasComponent(e))) continue; // They shouldn't have flash removed in between right? - Flash(entity, user, source, duration, slowTo, displayPopup, flashableQuery.GetComponent(entity)); + Flash(entity, user, source, duration, slowTo, displayPopup); } _audio.PlayPvs(sound, source, AudioParams.Default.WithVolume(1f).WithMaxDistance(3f)); @@ -195,13 +193,15 @@ namespace Content.Server.Flash private void OnFlashImmunityFlashAttempt(EntityUid uid, FlashImmunityComponent component, FlashAttemptEvent args) { - if(component.Enabled) + if (component.Enabled) args.Cancel(); } private void OnPermanentBlindnessFlashAttempt(EntityUid uid, PermanentBlindnessComponent component, FlashAttemptEvent args) { - args.Cancel(); + // check for total blindness + if (component.Blindness == 0) + args.Cancel(); } private void OnTemporaryBlindnessFlashAttempt(EntityUid uid, TemporaryBlindnessComponent component, FlashAttemptEvent args) @@ -210,6 +210,10 @@ namespace Content.Server.Flash } } + /// + /// Called before a flash is used to check if the attempt is cancelled by blindness, items or FlashImmunityComponent. + /// Raised on the target hit by the flash, the user of the flash and the flash used. + /// public sealed class FlashAttemptEvent : CancellableEntityEventArgs { public readonly EntityUid Target; @@ -224,8 +228,8 @@ namespace Content.Server.Flash } } /// - /// Called after a flash is used via melee on another person to check for rev conversion. - /// Raised on the user of the flash, the target hit by the flash, and the flash used. + /// Called after a flash is used via melee on another person to check for rev conversion. + /// Raised on the target hit by the flash, the user of the flash and the flash used. /// [ByRefEvent] public readonly struct AfterFlashedEvent @@ -241,6 +245,4 @@ namespace Content.Server.Flash Used = used; } } - - } diff --git a/Content.Shared/Flash/Components/FlashComponent.cs b/Content.Shared/Flash/Components/FlashComponent.cs index a9098bc85a..29f92eb94f 100644 --- a/Content.Shared/Flash/Components/FlashComponent.cs +++ b/Content.Shared/Flash/Components/FlashComponent.cs @@ -1,6 +1,6 @@ -using Content.Shared.Flash; using Robust.Shared.Audio; using Robust.Shared.GameStates; +using Robust.Shared.Serialization; namespace Content.Shared.Flash.Components { @@ -43,4 +43,13 @@ namespace Content.Shared.Flash.Components [DataField] public float Probability = 1f; } + + [Serializable, NetSerializable] + public enum FlashVisuals : byte + { + BaseLayer, + LightLayer, + Burnt, + Flashing, + } } diff --git a/Content.Shared/Flash/Components/FlashedComponent.cs b/Content.Shared/Flash/Components/FlashedComponent.cs new file mode 100644 index 0000000000..75bbb12304 --- /dev/null +++ b/Content.Shared/Flash/Components/FlashedComponent.cs @@ -0,0 +1,9 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Flash.Components; + +/// +/// Exists for use as a status effect. Adds a shader to the client that obstructs vision. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class FlashedComponent : Component { } diff --git a/Content.Shared/Flash/FlashableComponent.cs b/Content.Shared/Flash/FlashableComponent.cs deleted file mode 100644 index c4f8074cea..0000000000 --- a/Content.Shared/Flash/FlashableComponent.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Content.Shared.Physics; -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; - -namespace Content.Shared.Flash -{ - [RegisterComponent, NetworkedComponent] - public sealed partial class FlashableComponent : Component - { - public float Duration; - public TimeSpan LastFlash; - - [DataField] - public CollisionGroup CollisionGroup = CollisionGroup.Opaque; - - public override bool SendOnlyToOwner => true; - } - - [Serializable, NetSerializable] - public sealed class FlashableComponentState : ComponentState - { - public float Duration { get; } - public TimeSpan Time { get; } - - public FlashableComponentState(float duration, TimeSpan time) - { - Duration = duration; - Time = time; - } - } - - [Serializable, NetSerializable] - public enum FlashVisuals : byte - { - BaseLayer, - LightLayer, - Burnt, - Flashing, - } -} diff --git a/Content.Shared/Flash/SharedFlashSystem.cs b/Content.Shared/Flash/SharedFlashSystem.cs index 16fdbfc2f3..f83f02a310 100644 --- a/Content.Shared/Flash/SharedFlashSystem.cs +++ b/Content.Shared/Flash/SharedFlashSystem.cs @@ -1,19 +1,10 @@ -using Robust.Shared.GameStates; +using Content.Shared.StatusEffect; namespace Content.Shared.Flash { public abstract class SharedFlashSystem : EntitySystem { - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnFlashableGetState); - } - - private static void OnFlashableGetState(EntityUid uid, FlashableComponent component, ref ComponentGetState args) - { - args.State = new FlashableComponentState(component.Duration, component.LastFlash); - } + [ValidatePrototypeId] + public const string FlashedKey = "Flashed"; } } diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index 8bf55e48bd..baea453cb8 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -126,6 +126,7 @@ - Stun - KnockedDown - SlowedDown + - Flashed - type: TypingIndicator proto: robot - type: Speech @@ -147,7 +148,6 @@ locked: true - type: ActivatableUIRequiresLock - type: LockedWiresPanel - - type: Flashable - type: Damageable damageContainer: Silicon - type: Destructible diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/argocyte.yml b/Resources/Prototypes/Entities/Mobs/NPCs/argocyte.yml index 39e68b63a7..3b6c4e8ed9 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/argocyte.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/argocyte.yml @@ -48,7 +48,6 @@ sprite: Mobs/Effects/onfire.rsi normalState: Generic_mob_burning - type: Climbing - - type: Flashable - type: NameIdentifier group: GenericNumber diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml index 23eb462db1..c1cfa40836 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml @@ -781,7 +781,6 @@ amount: 3 - id: DrinkTequilaBottleFull amount: 1 - - type: Flashable - type: Tag tags: - CannotSuicide @@ -808,7 +807,6 @@ # name: ghost-role-information-tropico-name # description: ghost-role-information-tropico-description # - type: GhostTakeoverAvailable -# - type: Flashable - type: Tag tags: - VimPilot diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml index 12ea40b1e3..4936d883e5 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml @@ -25,6 +25,7 @@ - ForcedSleep - TemporaryBlindness - Pacified + - Flashed - type: Buckle - type: StandingState - type: Tag @@ -99,6 +100,7 @@ - TemporaryBlindness - Pacified - StaminaModifier + - Flashed - type: Bloodstream bloodMaxVolume: 150 - type: MobPrice diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml index a49f8ff34c..eeabecef8b 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/base.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml @@ -140,6 +140,7 @@ - TemporaryBlindness - Pacified - StaminaModifier + - Flashed - type: Reflect enabled: false reflectProb: 0 @@ -234,7 +235,6 @@ id: BaseMobSpeciesOrganic abstract: true components: - - type: Flashable - type: Barotrauma damage: types: @@ -249,24 +249,7 @@ Heat: -0.07 groups: Brute: -0.07 - # Organs - - type: StatusEffects - allowed: - - Stun - - KnockedDown - - SlowedDown - - Stutter - - SeeingRainbows - - Electrocution - - ForcedSleep - - TemporaryBlindness - - Drunk - - SlurredSpeech - - RatvarianLanguage - - PressureImmunity - - Muted - - Pacified - - StaminaModifier + - type: Blindable # Other - type: Temperature diff --git a/Resources/Prototypes/Entities/Objects/base_shadow.yml b/Resources/Prototypes/Entities/Objects/base_shadow.yml index 2375855bf9..1cefef9e56 100644 --- a/Resources/Prototypes/Entities/Objects/base_shadow.yml +++ b/Resources/Prototypes/Entities/Objects/base_shadow.yml @@ -15,9 +15,6 @@ path: /Audio/Items/hiss.ogg params: variation: 0.08 - - type: Flashable - collisionGroup: - - None - type: DamagedByFlashing flashDamage: types: diff --git a/Resources/Prototypes/status_effects.yml b/Resources/Prototypes/status_effects.yml index a991bf4035..27609b1bb5 100644 --- a/Resources/Prototypes/status_effects.yml +++ b/Resources/Prototypes/status_effects.yml @@ -59,3 +59,6 @@ - type: statusEffect id: StaminaModifier + +- type: statusEffect + id: Flashed diff --git a/Resources/Textures/Shaders/flashed_effect.swsl b/Resources/Textures/Shaders/flashed_effect.swsl index ec486ab531..519a9fdd99 100644 --- a/Resources/Textures/Shaders/flashed_effect.swsl +++ b/Resources/Textures/Shaders/flashed_effect.swsl @@ -11,7 +11,7 @@ void fragment() { highp vec4 textureMix = mix(tex1, tex2, 0.5); - // Gradually mixes between the texture mix and a full-white texture, causing the "blinding" effect + // Gradually mixes between the texture mix and a full-black texture, causing the "blinding" effect highp vec4 mixed = mix(vec4(0.0, 0.0, 0.0, 1.0), textureMix, percentComplete); COLOR = vec4(mixed.rgb, remaining); From 827211369cd18c9377a9994ec97fd242a74b87fd Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 2 Jun 2024 04:18:59 +0000 Subject: [PATCH 15/20] Automatic changelog update --- Resources/Changelog/Changelog.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index de9e112c59..a6e7cbbc71 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,13 +1,4 @@ Entries: -- author: Krunk - changes: - - message: Zombies and animals can be stripped once again. - type: Fix - - message: Dead or critical mobs can no longer be stripped instantly. - type: Fix - id: 6164 - time: '2024-03-16T03:50:53.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26166 - author: metalgearsloth changes: - message: Fix store refunds. @@ -3853,3 +3844,12 @@ id: 6663 time: '2024-06-02T04:13:12.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/28065 +- author: slarticodefast + changes: + - message: Fixed the flash effect getting darker with each appearence. + type: Fix + - message: Fixed short-sightedness making you immune to flashes. + type: Fix + id: 6664 + time: '2024-06-02T04:17:53.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/27369 From 452b53988c336ba6c45c16e9082f5bc91108bce1 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Sun, 2 Jun 2024 16:26:42 +1200 Subject: [PATCH 16/20] Add debug asserts to ensure that network groups are up to date (#28495) --- .../Power/Pow3r/BatteryRampPegSolver.cs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/Content.Server/Power/Pow3r/BatteryRampPegSolver.cs b/Content.Server/Power/Pow3r/BatteryRampPegSolver.cs index 0afd86679b..12118968b7 100644 --- a/Content.Server/Power/Pow3r/BatteryRampPegSolver.cs +++ b/Content.Server/Power/Pow3r/BatteryRampPegSolver.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using Robust.Shared.Utility; using System.Linq; using Robust.Shared.Threading; @@ -37,6 +38,7 @@ namespace Content.Server.Power.Pow3r DebugTools.Assert(state.GroupedNets.Select(x => x.Count).Sum() == state.Networks.Count); _networkJob.State = state; _networkJob.FrameTime = frameTime; + ValidateNetworkGroups(state, state.GroupedNets); // Each network height layer can be run in parallel without issues. foreach (var group in state.GroupedNets) @@ -321,9 +323,69 @@ namespace Content.Server.Power.Pow3r RecursivelyEstimateNetworkDepth(state, network, groupedNetworks); } + ValidateNetworkGroups(state, groupedNetworks); return groupedNetworks; } + /// + /// Validate that network grouping is up to date. I.e., that it is safe to solve each networking in a given + /// group in parallel. This assumes that batteries are the only device that connects to multiple networks, and + /// is thus the only obstacle to solving everything in parallel. + /// + [Conditional("DEBUG")] + private void ValidateNetworkGroups(PowerState state, List> groupedNetworks) + { + HashSet nets = new(); + HashSet netIds = new(); + foreach (var layer in groupedNetworks) + { + nets.Clear(); + netIds.Clear(); + + foreach (var net in layer) + { + foreach (var batteryId in net.BatteryLoads) + { + var battery = state.Batteries[batteryId]; + if (battery.LinkedNetworkDischarging == default) + continue; + + var subNet = state.Networks[battery.LinkedNetworkDischarging]; + if (battery.LinkedNetworkDischarging == net.Id) + { + DebugTools.Assert(subNet == net); + continue; + } + + DebugTools.Assert(!nets.Contains(subNet)); + DebugTools.Assert(!netIds.Contains(subNet.Id)); + DebugTools.Assert(subNet.Height < net.Height); + } + + foreach (var batteryId in net.BatterySupplies) + { + var battery = state.Batteries[batteryId]; + if (battery.LinkedNetworkCharging == default) + continue; + + var parentNet = state.Networks[battery.LinkedNetworkCharging]; + if (battery.LinkedNetworkCharging == net.Id) + { + DebugTools.Assert(parentNet == net); + continue; + } + + DebugTools.Assert(!nets.Contains(parentNet)); + DebugTools.Assert(!netIds.Contains(parentNet.Id)); + DebugTools.Assert(parentNet.Height > net.Height); + } + + DebugTools.Assert(nets.Add(net)); + DebugTools.Assert(netIds.Add(net.Id)); + } + } + } + private static void RecursivelyEstimateNetworkDepth(PowerState state, Network network, List> groupedNetworks) { network.Height = -2; From 79e841056ba2b4eb7f32c6c46c3c0c7d547c0f53 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Sun, 2 Jun 2024 16:27:48 +1200 Subject: [PATCH 17/20] Update engine to v224.0.0 (#28502) --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index c89c529ba4..ff4548f108 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit c89c529ba4fa7516e2265f3c47549da35ab6c3d8 +Subproject commit ff4548f108a5b11e1a81cb7c01f7462400e4af2b From ba04f94e480f9aed5f72eec0953396945f5d5d88 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Sat, 1 Jun 2024 23:21:07 -0700 Subject: [PATCH 18/20] Emergency Fix for Whitelist logic (#28510) fix issue Co-authored-by: plykiya --- Content.Shared/Materials/SharedMaterialStorageSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/Materials/SharedMaterialStorageSystem.cs b/Content.Shared/Materials/SharedMaterialStorageSystem.cs index af815bdb2b..a27e0fb9cf 100644 --- a/Content.Shared/Materials/SharedMaterialStorageSystem.cs +++ b/Content.Shared/Materials/SharedMaterialStorageSystem.cs @@ -123,7 +123,7 @@ public abstract class SharedMaterialStorageSystem : EntitySystem if (!CanTakeVolume(uid, volume, component)) return false; - if (component.MaterialWhiteList == null ? false : component.MaterialWhiteList.Contains(materialId)) + if (component.MaterialWhiteList == null ? false : !component.MaterialWhiteList.Contains(materialId)) return false; var amount = component.Storage.GetValueOrDefault(materialId); From 16be126ca1e65ebc94a0d688d7d5eca749fc272d Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Sun, 2 Jun 2024 20:11:48 +1200 Subject: [PATCH 19/20] Remove `noSpawn: true` from action entity prototypes (#28508) --- Resources/Prototypes/Actions/borgs.yml | 1 - Resources/Prototypes/Actions/crit.yml | 3 --- Resources/Prototypes/Actions/diona.yml | 2 -- Resources/Prototypes/Actions/internals.yml | 1 - Resources/Prototypes/Actions/mech.yml | 3 --- Resources/Prototypes/Actions/ninja.yml | 6 ----- Resources/Prototypes/Actions/polymorph.yml | 4 --- Resources/Prototypes/Actions/revenant.yml | 5 ---- Resources/Prototypes/Actions/speech.yml | 1 - Resources/Prototypes/Actions/spider.yml | 2 -- Resources/Prototypes/Actions/types.yml | 27 ------------------- .../Clothing/Masks/base_clothingmask.yml | 3 +-- .../Entities/Clothing/Neck/misc.yml | 1 - .../Entities/Clothing/Shoes/magboots.yml | 5 ---- .../Entities/Clothing/Shoes/misc.yml | 1 - .../Entities/Mobs/NPCs/regalrat.yml | 6 ----- .../Entities/Mobs/Player/admin_ghost.yml | 6 ----- .../Entities/Mobs/Player/dragon.yml | 3 --- .../Entities/Mobs/Player/guardian.yml | 1 - .../Entities/Mobs/Player/observer.yml | 5 ---- .../Objects/Devices/chameleon_projector.yml | 2 -- .../Prototypes/Entities/Objects/Fun/pai.yml | 2 -- .../Objects/Specific/Chapel/bibles.yml | 1 - .../Specific/Robotics/borg_modules.yml | 1 - .../Entities/Objects/Tools/jetpacks.yml | 1 - Resources/Prototypes/Magic/event_spells.yml | 1 - .../Prototypes/Magic/forcewall_spells.yml | 1 - Resources/Prototypes/Magic/knock_spell.yml | 1 - .../Prototypes/Magic/projectile_spells.yml | 3 --- Resources/Prototypes/Magic/rune_spells.yml | 4 --- Resources/Prototypes/Magic/smite_spells.yml | 1 - Resources/Prototypes/Magic/spawn_spells.yml | 1 - Resources/Prototypes/Magic/staves.yml | 1 - .../Prototypes/Magic/teleport_spells.yml | 1 - Resources/Prototypes/Magic/utility_spells.yml | 1 - .../Prototypes/Roles/Jobs/Civilian/mime.yml | 1 - 36 files changed, 1 insertion(+), 108 deletions(-) diff --git a/Resources/Prototypes/Actions/borgs.yml b/Resources/Prototypes/Actions/borgs.yml index 6d35c69cf6..a0168ef00f 100644 --- a/Resources/Prototypes/Actions/borgs.yml +++ b/Resources/Prototypes/Actions/borgs.yml @@ -2,7 +2,6 @@ id: ActionViewLaws name: View Laws description: View the laws that you must follow. - noSpawn: true components: - type: InstantAction itemIconStyle: NoItem diff --git a/Resources/Prototypes/Actions/crit.yml b/Resources/Prototypes/Actions/crit.yml index 705ee6ee6b..c5712844bf 100644 --- a/Resources/Prototypes/Actions/crit.yml +++ b/Resources/Prototypes/Actions/crit.yml @@ -3,7 +3,6 @@ id: ActionCritSuccumb name: Succumb description: Accept your fate. - noSpawn: true components: - type: InstantAction itemIconStyle: NoItem @@ -18,7 +17,6 @@ id: ActionCritFakeDeath name: Fake Death description: Pretend to take your final breath while staying alive. - noSpawn: true components: - type: InstantAction itemIconStyle: NoItem @@ -34,7 +32,6 @@ id: ActionCritLastWords name: Say Last Words description: Whisper your last words to anyone nearby, and then succumb to your fate. You only have 30 characters to work with. - noSpawn: true components: - type: InstantAction itemIconStyle: NoItem diff --git a/Resources/Prototypes/Actions/diona.yml b/Resources/Prototypes/Actions/diona.yml index 11db30386a..9f80f18178 100644 --- a/Resources/Prototypes/Actions/diona.yml +++ b/Resources/Prototypes/Actions/diona.yml @@ -2,7 +2,6 @@ id: DionaGibAction name: Gib Yourself! description: Split apart into 3 nymphs. - noSpawn: true components: - type: InstantAction icon: @@ -16,7 +15,6 @@ id: DionaReformAction name: Reform description: Reform back into a whole Diona. - noSpawn: true components: - type: InstantAction icon: diff --git a/Resources/Prototypes/Actions/internals.yml b/Resources/Prototypes/Actions/internals.yml index dd83a45332..5982c3daa2 100644 --- a/Resources/Prototypes/Actions/internals.yml +++ b/Resources/Prototypes/Actions/internals.yml @@ -2,7 +2,6 @@ id: ActionToggleInternals name: Toggle Internals description: Breathe from the equipped gas tank. Also requires equipped breath mask. - noSpawn: true components: - type: InstantAction icon: diff --git a/Resources/Prototypes/Actions/mech.yml b/Resources/Prototypes/Actions/mech.yml index 2005133a70..48092f9c5a 100644 --- a/Resources/Prototypes/Actions/mech.yml +++ b/Resources/Prototypes/Actions/mech.yml @@ -2,7 +2,6 @@ id: ActionMechCycleEquipment name: Cycle description: Cycles currently selected equipment - noSpawn: true components: - type: InstantAction itemIconStyle: NoItem @@ -16,7 +15,6 @@ id: ActionMechOpenUI name: Control Panel description: Opens the control panel for the mech - noSpawn: true components: - type: InstantAction itemIconStyle: NoItem @@ -30,7 +28,6 @@ id: ActionMechEject name: Eject description: Ejects the pilot from the mech - noSpawn: true components: - type: InstantAction itemIconStyle: NoItem diff --git a/Resources/Prototypes/Actions/ninja.yml b/Resources/Prototypes/Actions/ninja.yml index 5fe6f23b27..adaf563692 100644 --- a/Resources/Prototypes/Actions/ninja.yml +++ b/Resources/Prototypes/Actions/ninja.yml @@ -3,7 +3,6 @@ id: ActionToggleNinjaGloves name: Toggle ninja gloves description: Toggles all glove actions on left click. Includes your doorjack, draining power, stunning enemies, downloading research and calling in a threat. - noSpawn: true components: - type: InstantAction priority: -13 @@ -14,7 +13,6 @@ id: ActionCreateThrowingStar name: Create throwing star description: Channels suit power into creating a throwing star that deals extra stamina damage. - noSpawn: true components: - type: InstantAction useDelay: 0.5 @@ -29,7 +27,6 @@ id: ActionRecallKatana name: Recall katana description: Teleports the Energy Katana linked to this suit to its wearer, cost based on distance. - noSpawn: true components: - type: InstantAction useDelay: 1 @@ -44,7 +41,6 @@ id: ActionNinjaEmp name: EM Burst description: Disable any nearby technology with an electro-magnetic pulse. - noSpawn: true components: - type: InstantAction icon: @@ -58,7 +54,6 @@ id: ActionTogglePhaseCloak name: Phase cloak description: Toggles your suit's phase cloak. Beware that if you are hit, all abilities are disabled for 5 seconds, including your cloak! - noSpawn: true components: - type: InstantAction # have to plan (un)cloaking ahead of time @@ -71,7 +66,6 @@ id: ActionEnergyKatanaDash name: Katana dash description: Teleport to anywhere you can see, if your Energy Katana is in your hand. - noSpawn: true components: - type: WorldTargetAction icon: diff --git a/Resources/Prototypes/Actions/polymorph.yml b/Resources/Prototypes/Actions/polymorph.yml index 445dc8d9f5..81feba4eac 100644 --- a/Resources/Prototypes/Actions/polymorph.yml +++ b/Resources/Prototypes/Actions/polymorph.yml @@ -2,14 +2,12 @@ id: ActionRevertPolymorph name: Revert description: Revert back into your original form. - noSpawn: true components: - type: InstantAction event: !type:RevertPolymorphActionEvent - type: entity id: ActionPolymorph - noSpawn: true components: - type: InstantAction event: !type:PolymorphActionEvent @@ -19,7 +17,6 @@ id: ActionPolymorphWizardSpider name: Spider Polymorph description: Polymorphs you into a Spider. - noSpawn: true components: - type: InstantAction useDelay: 60 @@ -34,7 +31,6 @@ id: ActionPolymorphWizardRod name: Rod Form description: CLANG! - noSpawn: true components: - type: InstantAction useDelay: 60 diff --git a/Resources/Prototypes/Actions/revenant.yml b/Resources/Prototypes/Actions/revenant.yml index da7b4ba56f..dca491a99b 100644 --- a/Resources/Prototypes/Actions/revenant.yml +++ b/Resources/Prototypes/Actions/revenant.yml @@ -2,7 +2,6 @@ id: ActionRevenantShop name: Shop description: Opens the ability shop. - noSpawn: true components: - type: InstantAction icon: Interface/Actions/shop.png @@ -12,7 +11,6 @@ id: ActionRevenantDefile name: Defile description: Costs 30 Essence. - noSpawn: true components: - type: InstantAction icon: Interface/Actions/defile.png @@ -23,7 +21,6 @@ id: ActionRevenantOverloadLights name: Overload Lights description: Costs 40 Essence. - noSpawn: true components: - type: InstantAction icon: Interface/Actions/overloadlight.png @@ -34,7 +31,6 @@ # id: ActionRevenantBlight # name: Blight # description: Costs 50 Essence. -# noSpawn: true # components: # - type: InstantAction # icon: Interface/Actions/blight.png @@ -45,7 +41,6 @@ id: ActionRevenantMalfunction name: Malfunction description: Costs 60 Essence. - noSpawn: true components: - type: InstantAction icon: Interface/Actions/malfunction.png diff --git a/Resources/Prototypes/Actions/speech.yml b/Resources/Prototypes/Actions/speech.yml index 39db04b1b3..c71ec74880 100644 --- a/Resources/Prototypes/Actions/speech.yml +++ b/Resources/Prototypes/Actions/speech.yml @@ -2,7 +2,6 @@ id: ActionConfigureMeleeSpeech name: Set Battlecry description: Set a custom battlecry for when you attack! - noSpawn: true components: - type: InstantAction itemIconStyle: BigItem diff --git a/Resources/Prototypes/Actions/spider.yml b/Resources/Prototypes/Actions/spider.yml index 14b9fb6ccb..fe37085eca 100644 --- a/Resources/Prototypes/Actions/spider.yml +++ b/Resources/Prototypes/Actions/spider.yml @@ -2,7 +2,6 @@ id: ActionSpiderWeb name: Spider Web description: Spawns a web that slows your prey down. - noSpawn: true components: - type: InstantAction icon: Interface/Actions/web.png @@ -13,7 +12,6 @@ id: ActionSericulture name: Weave silk description: Weave a bit of silk for use in arts and crafts. - noSpawn: true components: - type: InstantAction icon: Interface/Actions/web.png diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml index fb156a732e..4b3d75bf92 100644 --- a/Resources/Prototypes/Actions/types.yml +++ b/Resources/Prototypes/Actions/types.yml @@ -13,7 +13,6 @@ id: ActionScream name: Scream description: AAAAAAAAAAAAAAAAAAAAAAAAA - noSpawn: true components: - type: InstantAction useDelay: 10 @@ -25,7 +24,6 @@ id: ActionTurnUndead name: Turn Undead description: Succumb to your infection and become a zombie. - noSpawn: true components: - type: InstantAction checkCanInteract: false @@ -37,7 +35,6 @@ id: ActionToggleLight name: Toggle Light description: Turn the light on and off. - noSpawn: true components: - type: InstantAction icon: { sprite: Objects/Tools/flashlight.rsi, state: flashlight } @@ -48,7 +45,6 @@ id: ActionOpenStorageImplant name: Open Storage Implant description: Opens the storage implant embedded under your skin - noSpawn: true components: - type: InstantAction itemIconStyle: BigAction @@ -63,7 +59,6 @@ id: ActionActivateMicroBomb name: Activate Microbomb description: Activates your internal microbomb, completely destroying you and your equipment - noSpawn: true components: - type: InstantAction checkCanInteract: false @@ -80,7 +75,6 @@ id: ActionActivateDeathAcidifier name: Activate Death-Acidifier description: Activates your death-acidifier, completely melting you and your equipment - noSpawn: true components: - type: InstantAction checkCanInteract: false @@ -96,7 +90,6 @@ id: ActionActivateFreedomImplant name: Break Free description: Activating your freedom implant will free you from any hand restraints - noSpawn: true components: - type: InstantAction charges: 3 @@ -112,7 +105,6 @@ id: ActionOpenUplinkImplant name: Open Uplink description: Opens the syndicate uplink embedded under your skin - noSpawn: true components: - type: InstantAction itemIconStyle: BigAction @@ -126,7 +118,6 @@ id: ActionActivateEmpImplant name: Activate EMP description: Triggers a small EMP pulse around you - noSpawn: true components: - type: InstantAction checkCanInteract: false @@ -143,7 +134,6 @@ id: ActionActivateScramImplant name: SCRAM! description: Randomly teleports you within a large distance. - noSpawn: true components: - type: InstantAction checkCanInteract: false @@ -160,7 +150,6 @@ id: ActionActivateDnaScramblerImplant name: Scramble DNA description: Randomly changes your name and appearance. - noSpawn: true components: - type: InstantAction charges: 1 @@ -175,7 +164,6 @@ id: ActionMorphGeras name: Morph into Geras description: Morphs you into a Geras - a miniature version of you which allows you to move fast, at the cost of your inventory. - noSpawn: true components: - type: InstantAction itemIconStyle: BigAction @@ -190,7 +178,6 @@ id: ActionToggleSuitPiece name: Toggle Suit Piece description: Remember to equip the important pieces of your suit before going into action. - noSpawn: true components: - type: InstantAction itemIconStyle: BigItem @@ -201,7 +188,6 @@ id: ActionCombatModeToggle name: "[color=red]Combat Mode[/color]" description: Enter combat mode - noSpawn: true components: - type: InstantAction checkCanInteract: false @@ -216,7 +202,6 @@ parent: ActionCombatModeToggle name: "[color=red]Combat Mode[/color]" description: Enter combat mode - noSpawn: true components: - type: InstantAction enabled: false @@ -227,7 +212,6 @@ id: ActionChangeVoiceMask name: Set name description: Change the name others hear to something else. - noSpawn: true components: - type: InstantAction icon: { sprite: Interface/Actions/voice-mask.rsi, state: icon } @@ -237,7 +221,6 @@ id: ActionVendingThrow name: Dispense Item description: Randomly dispense an item from your stock. - noSpawn: true components: - type: InstantAction useDelay: 30 @@ -247,7 +230,6 @@ id: ActionArtifactActivate name: Activate Artifact description: Immediately activates your current artifact node. - noSpawn: true components: - type: InstantAction icon: @@ -260,7 +242,6 @@ id: ActionToggleBlock name: Block description: Raise or lower your shield. - noSpawn: true components: - type: InstantAction icon: { sprite: Objects/Weapons/Melee/shields.rsi, state: teleriot-icon } @@ -271,7 +252,6 @@ id: ActionClearNetworkLinkOverlays name: Clear network link overlays description: Clear network link overlays. - noSpawn: true components: - type: InstantAction clientExclusive: true @@ -285,7 +265,6 @@ id: ActionAnimalLayEgg name: Lay egg description: Uses hunger to lay an egg. - noSpawn: true components: - type: InstantAction icon: { sprite: Objects/Consumable/Food/egg.rsi, state: icon } @@ -296,7 +275,6 @@ id: ActionSleep name: Sleep description: Go to sleep. - noSpawn: true components: - type: InstantAction checkCanInteract: false @@ -308,7 +286,6 @@ id: ActionWake name: Wake up description: Stop sleeping. - noSpawn: true components: - type: InstantAction icon: { sprite: Clothing/Head/Hats/pyjamasyndicatered.rsi, state: icon } @@ -320,7 +297,6 @@ id: ActionActivateHonkImplant name: Honk description: Activates your honking implant, which will produce the signature sound of the clown. - noSpawn: true components: - type: InstantAction icon: { sprite: Objects/Fun/bikehorn.rsi, state: icon } @@ -331,7 +307,6 @@ id: ActionFireStarter name: Ignite description: Ignites enemies in a radius around you. - noSpawn: true components: - type: InstantAction priority: -1 @@ -343,7 +318,6 @@ id: ActionToggleEyes name: Open/Close eyes description: Close your eyes to protect your peepers, or open your eyes to enjoy the pretty lights. - noSpawn: true components: - type: InstantAction icon: Interface/Actions/eyeopen.png @@ -357,7 +331,6 @@ id: ActionToggleWagging name: action-name-toggle-wagging description: action-description-toggle-wagging - noSpawn: true components: - type: InstantAction icon: { sprite: Mobs/Customization/reptilian_parts.rsi, state: tail_smooth_behind } diff --git a/Resources/Prototypes/Entities/Clothing/Masks/base_clothingmask.yml b/Resources/Prototypes/Entities/Clothing/Masks/base_clothingmask.yml index 3531a26a6c..00dcd8263f 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/base_clothingmask.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/base_clothingmask.yml @@ -21,7 +21,6 @@ id: ActionToggleMask name: Toggle Mask description: Handy, but prevents insertion of pie into your pie hole. - noSpawn: true components: - type: InstantAction icon: { sprite: Clothing/Mask/gas.rsi, state: icon } @@ -49,4 +48,4 @@ Quantity: 10 - type: Tag tags: - - ClothMade \ No newline at end of file + - ClothMade diff --git a/Resources/Prototypes/Entities/Clothing/Neck/misc.yml b/Resources/Prototypes/Entities/Clothing/Neck/misc.yml index 51325c0bbb..8dfc709bc4 100644 --- a/Resources/Prototypes/Entities/Clothing/Neck/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/Neck/misc.yml @@ -70,7 +70,6 @@ - type: entity id: ActionStethoscope name: Listen with stethoscope - noSpawn: true components: - type: EntityTargetAction icon: diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml index 485d530ea5..e80ed74305 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml @@ -132,7 +132,6 @@ id: ActionBaseToggleMagboots name: Toggle Magboots description: Toggles the magboots on and off. - noSpawn: true components: - type: InstantAction itemIconStyle: NoItem @@ -141,7 +140,6 @@ - type: entity id: ActionToggleMagboots parent: ActionBaseToggleMagboots - noSpawn: true components: - type: InstantAction icon: { sprite: Clothing/Shoes/Boots/magboots.rsi, state: icon } @@ -150,7 +148,6 @@ - type: entity id: ActionToggleMagbootsAdvanced parent: ActionBaseToggleMagboots - noSpawn: true components: - type: InstantAction icon: { sprite: Clothing/Shoes/Boots/magboots-advanced.rsi, state: icon } @@ -159,7 +156,6 @@ - type: entity id: ActionToggleMagbootsSci parent: ActionBaseToggleMagboots - noSpawn: true components: - type: InstantAction icon: { sprite: Clothing/Shoes/Boots/magboots-science.rsi, state: icon } @@ -168,7 +164,6 @@ - type: entity id: ActionToggleMagbootsSyndie parent: ActionBaseToggleMagboots - noSpawn: true components: - type: InstantAction icon: { sprite: Clothing/Shoes/Boots/magboots-syndicate.rsi, state: icon } diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml b/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml index d5a695c7c0..cbea9d319d 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml @@ -128,7 +128,6 @@ id: ActionToggleSpeedBoots name: Toggle Speed Boots description: Toggles the speed boots on and off. - noSpawn: true components: - type: InstantAction itemIconStyle: NoItem diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml index aa12eac1c2..38debe2a9a 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml @@ -301,7 +301,6 @@ id: ActionRatKingRaiseArmy name: Raise Army description: Spend some hunger to summon an allied rat to help defend you. - noSpawn: true components: - type: InstantAction useDelay: 4 @@ -314,7 +313,6 @@ id: ActionRatKingDomain name: Rat King's Domain description: Spend some hunger to release a cloud of ammonia into the air. - noSpawn: true components: - type: InstantAction useDelay: 6 @@ -327,7 +325,6 @@ id: ActionRatKingOrderStay name: Stay description: Command your army to stand in place. - noSpawn: true components: - type: InstantAction useDelay: 1 @@ -346,7 +343,6 @@ id: ActionRatKingOrderFollow name: Follow description: Command your army to follow you around. - noSpawn: true components: - type: InstantAction useDelay: 1 @@ -365,7 +361,6 @@ id: ActionRatKingOrderCheeseEm name: Cheese 'Em description: Command your army to attack whoever you point at. - noSpawn: true components: - type: InstantAction useDelay: 1 @@ -384,7 +379,6 @@ id: ActionRatKingOrderLoose name: Loose description: Command your army to act at their own will. - noSpawn: true components: - type: InstantAction useDelay: 1 diff --git a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml index 0fa85fc84f..4a83593bc3 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml @@ -97,7 +97,6 @@ id: ActionAGhostShowSolar name: Solar Control Interface description: View a solar control interface. - noSpawn: true components: - type: InstantAction icon: { sprite: Structures/Machines/parts.rsi, state: box_0 } @@ -110,7 +109,6 @@ id: ActionAGhostShowCommunications name: Communications Interface description: View a communications interface. - noSpawn: true components: - type: InstantAction icon: { sprite: Structures/Machines/parts.rsi, state: box_0 } @@ -123,7 +121,6 @@ id: ActionAGhostShowRadar name: Mass Scanner Interface description: View a mass scanner interface. - noSpawn: true components: - type: InstantAction icon: { sprite: Structures/Machines/parts.rsi, state: box_0 } @@ -136,7 +133,6 @@ id: ActionAGhostShowCargo name: Cargo Ordering Interface description: View a cargo ordering interface. - noSpawn: true components: - type: InstantAction icon: { sprite: Structures/Machines/parts.rsi, state: box_0 } @@ -149,7 +145,6 @@ id: ActionAGhostShowCrewMonitoring name: Crew Monitoring Interface description: View a crew monitoring interface. - noSpawn: true components: - type: InstantAction icon: { sprite: Structures/Machines/parts.rsi, state: box_0 } @@ -162,7 +157,6 @@ id: ActionAGhostShowStationRecords name: Station Records Interface description: View a station records Interface - noSpawn: true components: - type: InstantAction icon: { sprite: Structures/Machines/parts.rsi, state: box_0 } diff --git a/Resources/Prototypes/Entities/Mobs/Player/dragon.yml b/Resources/Prototypes/Entities/Mobs/Player/dragon.yml index 258488af9b..869fb88084 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/dragon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/dragon.yml @@ -203,7 +203,6 @@ id: ActionSpawnRift name: Summon Carp Rift description: Summons a carp rift that will periodically spawns carps. - noSpawn: true components: - type: InstantAction icon: @@ -217,7 +216,6 @@ id: ActionDevour name: "[color=red]Devour[/color]" description: Attempt to break a structure with your jaws or swallow a creature. - noSpawn: true components: - type: EntityTargetAction icon: { sprite : Interface/Actions/devour.rsi, state: icon } @@ -226,7 +224,6 @@ priority: 1 - type: entity - noSpawn: true id: ActionDragonsBreath name: "[color=orange]Dragon's Breath[/color]" description: Spew out flames at anyone foolish enough to attack you! diff --git a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml index 80ee2c55b8..9ccfdf4e50 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml @@ -259,7 +259,6 @@ id: ActionToggleGuardian name: Toggle Guardian description: Either manifests the guardian or recalls it back into your body - noSpawn: true components: - type: InstantAction icon: Interface/Actions/manifest.png diff --git a/Resources/Prototypes/Entities/Mobs/Player/observer.yml b/Resources/Prototypes/Entities/Mobs/Player/observer.yml index 114c3fa747..85be42cc02 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/observer.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/observer.yml @@ -53,7 +53,6 @@ id: ActionGhostBoo name: Boo! description: Scare your crew members because of boredom! - noSpawn: true components: - type: InstantAction icon: Interface/Actions/scream.png @@ -65,7 +64,6 @@ id: ActionToggleLighting name: Toggle All Lighting description: Toggle all light rendering to better observe dark areas. - noSpawn: true components: - type: InstantAction icon: Interface/VerbIcons/light.svg.192dpi.png @@ -77,7 +75,6 @@ id: ActionToggleFov name: Toggle FoV description: Toggles field-of-view in order to see what players see. - noSpawn: true components: - type: InstantAction icon: Interface/VerbIcons/vv.svg.192dpi.png @@ -89,7 +86,6 @@ id: ActionToggleGhosts name: Toggle Ghosts description: Toggle the visibility of other ghosts. - noSpawn: true components: - type: InstantAction icon: { sprite: Mobs/Ghosts/ghost_human.rsi, state: icon } @@ -101,7 +97,6 @@ id: ActionToggleGhostHearing name: Toggle Ghost Hearing description: Toggle between hearing all messages and hearing only radio & nearby messages. - noSpawn: true components: - type: InstantAction checkCanInteract: false diff --git a/Resources/Prototypes/Entities/Objects/Devices/chameleon_projector.yml b/Resources/Prototypes/Entities/Objects/Devices/chameleon_projector.yml index e021281021..20e138f81a 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/chameleon_projector.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/chameleon_projector.yml @@ -49,7 +49,6 @@ # actions - type: entity - noSpawn: true id: ActionDisguiseNoRot name: Toggle Rotation description: Use this to prevent your disguise from rotating, making it easier to hide in some scenarios. @@ -59,7 +58,6 @@ event: !type:DisguiseToggleNoRotEvent - type: entity - noSpawn: true id: ActionDisguiseAnchor name: Toggle Anchored description: For many objects you will want to be anchored to not be completely obvious. diff --git a/Resources/Prototypes/Entities/Objects/Fun/pai.yml b/Resources/Prototypes/Entities/Objects/Fun/pai.yml index 1b9c5303c6..02bbce2843 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/pai.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/pai.yml @@ -136,7 +136,6 @@ id: ActionPAIPlayMidi name: Play MIDI description: Open your portable MIDI interface to soothe your owner. - noSpawn: true components: - type: InstantAction checkCanInteract: false @@ -149,7 +148,6 @@ id: ActionPAIOpenMap name: Open Map description: Open your map interface and guide your owner. - noSpawn: true components: - type: InstantAction checkCanInteract: false diff --git a/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml b/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml index f6b2b0a70c..58f7e01550 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml @@ -80,7 +80,6 @@ id: ActionBibleSummon name: Summon familiar description: Summon a familiar that will aid you and gain humanlike intelligence once inhabited by a soul. - noSpawn: true components: - type: InstantAction icon: { sprite: Clothing/Head/Hats/witch.rsi, state: icon } diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml index 07206711d9..74e91a768c 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml @@ -32,7 +32,6 @@ id: ActionBorgSwapModule name: Swap Module description: Select this module, enabling you to use the tools it provides. - noSpawn: true components: - type: InstantAction itemIconStyle: BigItem diff --git a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml index 04f8b9f9f6..6fee48daf1 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml @@ -62,7 +62,6 @@ id: ActionToggleJetpack name: Toggle jetpack description: Toggles the jetpack, giving you movement outside the station. - noSpawn: true components: - type: InstantAction icon: diff --git a/Resources/Prototypes/Magic/event_spells.yml b/Resources/Prototypes/Magic/event_spells.yml index e59e1b2db8..01006b4ffe 100644 --- a/Resources/Prototypes/Magic/event_spells.yml +++ b/Resources/Prototypes/Magic/event_spells.yml @@ -2,7 +2,6 @@ id: ActionSummonGhosts name: Summon Ghosts description: Makes all current ghosts permanently invisible - noSpawn: true components: - type: InstantAction useDelay: 120 diff --git a/Resources/Prototypes/Magic/forcewall_spells.yml b/Resources/Prototypes/Magic/forcewall_spells.yml index d3d8fef760..f1865cf722 100644 --- a/Resources/Prototypes/Magic/forcewall_spells.yml +++ b/Resources/Prototypes/Magic/forcewall_spells.yml @@ -2,7 +2,6 @@ id: ActionForceWall name: Forcewall description: Creates a magical barrier. - noSpawn: true components: - type: InstantAction useDelay: 10 diff --git a/Resources/Prototypes/Magic/knock_spell.yml b/Resources/Prototypes/Magic/knock_spell.yml index e2c3dcfd4c..5ba456d3be 100644 --- a/Resources/Prototypes/Magic/knock_spell.yml +++ b/Resources/Prototypes/Magic/knock_spell.yml @@ -2,7 +2,6 @@ id: ActionKnock name: Knock description: This spell opens nearby doors. - noSpawn: true components: - type: InstantAction useDelay: 10 diff --git a/Resources/Prototypes/Magic/projectile_spells.yml b/Resources/Prototypes/Magic/projectile_spells.yml index b8db7557bb..71bbc096c5 100644 --- a/Resources/Prototypes/Magic/projectile_spells.yml +++ b/Resources/Prototypes/Magic/projectile_spells.yml @@ -2,7 +2,6 @@ id: ActionFireball name: Fireball description: Fires an explosive fireball towards the clicked location. - noSpawn: true components: - type: Magic - type: WorldTargetAction @@ -29,7 +28,6 @@ parent: ActionFireball name: Fireball II description: Fires a fireball, but faster! - noSpawn: true components: - type: WorldTargetAction useDelay: 10 @@ -52,7 +50,6 @@ parent: ActionFireball name: Fireball III description: The fastest fireball in the west! - noSpawn: true components: - type: WorldTargetAction useDelay: 8 diff --git a/Resources/Prototypes/Magic/rune_spells.yml b/Resources/Prototypes/Magic/rune_spells.yml index 42022f5785..7ba357e7c1 100644 --- a/Resources/Prototypes/Magic/rune_spells.yml +++ b/Resources/Prototypes/Magic/rune_spells.yml @@ -2,7 +2,6 @@ id: ActionFlashRune name: Flash Rune description: Summons a rune that flashes if used. - noSpawn: true components: - type: InstantAction useDelay: 10 @@ -17,7 +16,6 @@ id: ActionExplosionRune name: Explosion Rune description: Summons a rune that explodes if used. - noSpawn: true components: - type: InstantAction useDelay: 20 @@ -32,7 +30,6 @@ id: ActionIgniteRune name: Ignite Rune description: Summons a rune that ignites if used. - noSpawn: true components: - type: InstantAction useDelay: 15 @@ -47,7 +44,6 @@ id: ActionStunRune name: Stun Rune description: Summons a rune that stuns if used. - noSpawn: true components: - type: InstantAction useDelay: 10 diff --git a/Resources/Prototypes/Magic/smite_spells.yml b/Resources/Prototypes/Magic/smite_spells.yml index e629e56505..10f5bdd538 100644 --- a/Resources/Prototypes/Magic/smite_spells.yml +++ b/Resources/Prototypes/Magic/smite_spells.yml @@ -2,7 +2,6 @@ id: ActionSmite name: Smite description: Instantly gibs a target. - noSpawn: true components: - type: EntityTargetAction useDelay: 60 diff --git a/Resources/Prototypes/Magic/spawn_spells.yml b/Resources/Prototypes/Magic/spawn_spells.yml index 3f8148b83c..76674d5bfa 100644 --- a/Resources/Prototypes/Magic/spawn_spells.yml +++ b/Resources/Prototypes/Magic/spawn_spells.yml @@ -2,7 +2,6 @@ id: ActionSpawnMagicarpSpell name: Summon Magicarp description: This spell summons three Magi-Carp to your aid! May or may not turn on user. - noSpawn: true components: - type: WorldTargetAction useDelay: 10 diff --git a/Resources/Prototypes/Magic/staves.yml b/Resources/Prototypes/Magic/staves.yml index ef94a3910f..ccabb516fd 100644 --- a/Resources/Prototypes/Magic/staves.yml +++ b/Resources/Prototypes/Magic/staves.yml @@ -34,7 +34,6 @@ - type: entity id: ActionRgbLight - noSpawn: true components: - type: EntityTargetAction whitelist: { components: [ PointLight ] } diff --git a/Resources/Prototypes/Magic/teleport_spells.yml b/Resources/Prototypes/Magic/teleport_spells.yml index cc89cf8ee0..6f1ed9a6e4 100644 --- a/Resources/Prototypes/Magic/teleport_spells.yml +++ b/Resources/Prototypes/Magic/teleport_spells.yml @@ -2,7 +2,6 @@ id: ActionBlink name: Blink description: Teleport to the clicked location. - noSpawn: true components: - type: WorldTargetAction useDelay: 10 diff --git a/Resources/Prototypes/Magic/utility_spells.yml b/Resources/Prototypes/Magic/utility_spells.yml index dccdda3789..90bcdc7487 100644 --- a/Resources/Prototypes/Magic/utility_spells.yml +++ b/Resources/Prototypes/Magic/utility_spells.yml @@ -2,7 +2,6 @@ id: ActionChargeSpell name: Charge description: Adds a charge back to your wand - noSpawn: true components: - type: InstantAction useDelay: 30 diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml b/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml index 1eac292eee..27a164210b 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml @@ -33,7 +33,6 @@ id: ActionMimeInvisibleWall name: Create Invisible Wall description: Create an invisible wall in front of you, if placeable there. - noSpawn: true components: - type: InstantAction priority: -1 From 77a3d6c6f12e10031f6a6e5723705c515389279b Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Mon, 3 Jun 2024 02:59:22 +1200 Subject: [PATCH 20/20] Update engine to v224.0.1 (#28520) --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index ff4548f108..f648218756 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit ff4548f108a5b11e1a81cb7c01f7462400e4af2b +Subproject commit f64821875655dfec4e2c951d5c22c0db873fe86e