From 707cd02df99825150e78c627fb3bb203f92d756f Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Tue, 7 Feb 2023 14:03:17 -0500 Subject: [PATCH 01/25] Added a new mob typed named Hologram, set up a clone of the Drone whitelist system for "hardlight --- .../Gravity/FloatingVisualsComponent.cs | 4 + .../Gravity/SharedFloatingVisualizerSystem.cs | 7 +- .../Drone/HologramComponent.cs | 6 + .../Drone/SharedHologramSystem.cs | 31 +++ .../Prototypes/Entities/Objects/Fun/toys.yml | 3 + .../Body/Prototypes/hologram.yml | 11 + .../Entities/Mobs/Player/hologram.yml | 197 ++++++++++++++++++ Resources/Prototypes/SimpleStation14/tags.yml | 3 + 8 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 Content.Shared/SimpleStation14/Drone/HologramComponent.cs create mode 100644 Content.Shared/SimpleStation14/Drone/SharedHologramSystem.cs create mode 100644 Resources/Prototypes/SimpleStation14/Body/Prototypes/hologram.yml create mode 100644 Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml diff --git a/Content.Shared/Gravity/FloatingVisualsComponent.cs b/Content.Shared/Gravity/FloatingVisualsComponent.cs index 53b28aef90..7e80a41e18 100644 --- a/Content.Shared/Gravity/FloatingVisualsComponent.cs +++ b/Content.Shared/Gravity/FloatingVisualsComponent.cs @@ -24,6 +24,10 @@ public sealed class FloatingVisualsComponent : Component [ViewVariables(VVAccess.ReadWrite)] public bool CanFloat = false; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("force")] + public bool Force = false; public readonly string AnimationKey = "gravity"; } diff --git a/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs b/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs index 204f397801..068e755abe 100644 --- a/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs +++ b/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs @@ -29,6 +29,9 @@ public virtual void FloatAnimation(EntityUid uid, Vector2 offset, string animati protected bool CanFloat(EntityUid uid, FloatingVisualsComponent component, TransformComponent? transform = null) { + if (component.Force == true) + return true; + if (!Resolve(uid, ref transform)) return false; @@ -60,7 +63,7 @@ private void OnGravityChanged(ref GravityChangedEvent args) Dirty(floating); var uid = floating.Owner; - if (!args.HasGravity) + if (!args.HasGravity || floating.Force == true) FloatAnimation(uid, floating.Offset, floating.AnimationKey, floating.AnimationTime); } } @@ -68,7 +71,7 @@ private void OnGravityChanged(ref GravityChangedEvent args) private void OnEntParentChanged(EntityUid uid, FloatingVisualsComponent component, ref EntParentChangedMessage args) { var transform = args.Transform; - if (CanFloat(uid, component, transform)) + if (CanFloat(uid, component, transform) || component.Force == true) FloatAnimation(uid, component.Offset, component.AnimationKey, component.AnimationTime); } diff --git a/Content.Shared/SimpleStation14/Drone/HologramComponent.cs b/Content.Shared/SimpleStation14/Drone/HologramComponent.cs new file mode 100644 index 0000000000..122527c633 --- /dev/null +++ b/Content.Shared/SimpleStation14/Drone/HologramComponent.cs @@ -0,0 +1,6 @@ +namespace Content.Shared.SimpleStation14.Hologram +{ + [RegisterComponent] + public sealed class HologramComponent : Component + {} +} diff --git a/Content.Shared/SimpleStation14/Drone/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Drone/SharedHologramSystem.cs new file mode 100644 index 0000000000..0b8074019e --- /dev/null +++ b/Content.Shared/SimpleStation14/Drone/SharedHologramSystem.cs @@ -0,0 +1,31 @@ +using Content.Shared.Interaction.Events; +using Content.Shared.Interaction.Components; +using Content.Shared.Damage; +using Content.Shared.Item; +using Content.Shared.Tag; +using Robust.Shared.Serialization; + +namespace Content.Shared.SimpleStation14.Hologram +{ + public class SharedHologramSystem : EntitySystem + { + [Dependency] private readonly TagSystem _tagSystem = default!; + public override void Initialize() + { + SubscribeLocalEvent(OnInteractionAttempt); + } + + private void OnInteractionAttempt(EntityUid uid, HologramComponent component, InteractionAttemptEvent args) + { + if (args.Target == null) + return; + + if (TryComp(args.Target, out var dmg) && dmg.DamageContainerID == "Biological") + args.Cancel(); + + if (HasComp(args.Target) && !HasComp(args.Target) + && !_tagSystem.HasAnyTag(args.Target.Value, "Hardlight")) + args.Cancel(); + } + } +} diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index 23fdcda4da..9508d9294f 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -90,6 +90,9 @@ energy: 2 - type: RgbLightController layers: [ 0 ] + - type: Tag + tags: + - Hardlight - type: entity parent: BasePlushie diff --git a/Resources/Prototypes/SimpleStation14/Body/Prototypes/hologram.yml b/Resources/Prototypes/SimpleStation14/Body/Prototypes/hologram.yml new file mode 100644 index 0000000000..f71dcadf5e --- /dev/null +++ b/Resources/Prototypes/SimpleStation14/Body/Prototypes/hologram.yml @@ -0,0 +1,11 @@ +- type: body + id: Hologram + name: "hologram" + root: hand 1 + slots: + hand 1: + part: LeftArmBorg + connections: + - hand 2 + hand 2: + part: RightArmBorg diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml new file mode 100644 index 0000000000..71b74aed3e --- /dev/null +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml @@ -0,0 +1,197 @@ +- type: entity + save: false + abstract: true + id: PlayerHologramBase + components: + # - type: Reactive + # groups: + # Acidic: [Touch] + - type: Input + context: "human" + - type: InputMover + - type: MobMover + # - type: DamageOnHighSpeedImpact + # damage: + # types: + # Blunt: 5 + # soundHit: + # path: /Audio/Effects/hit_kick.ogg + - type: Clickable + # - type: Damageable + # damageContainer: Inorganic + # - type: Bloodstream + # bloodReagent: MotorOil + # bloodlossDamage: + # types: + # Bloodloss: + # 1 + # bloodlossHealDamage: + # types: + # Bloodloss: + # -0.25 + - type: InteractionOutline + - type: Sprite + netsync: false + noRot: true + drawdepth: Mobs + layers: + - map: ["enum.HumanoidVisualLayers.Chest"] + - map: ["enum.HumanoidVisualLayers.Head"] + - map: ["enum.HumanoidVisualLayers.Snout"] + - map: ["enum.HumanoidVisualLayers.Eyes"] + - map: ["enum.HumanoidVisualLayers.RArm"] + - map: ["enum.HumanoidVisualLayers.LArm"] + - map: ["enum.HumanoidVisualLayers.RLeg"] + - map: ["enum.HumanoidVisualLayers.LLeg"] + - shader: StencilClear + sprite: Mobs/Species/Human/parts.rsi + # sprite refactor when + state: l_leg + - shader: StencilMask + map: ["enum.HumanoidVisualLayers.StencilMask"] + sprite: Mobs/Customization/masking_helpers.rsi + state: female_full + visible: false + - map: ["enum.HumanoidVisualLayers.LFoot"] + - map: ["enum.HumanoidVisualLayers.RFoot"] + - map: ["socks"] + - map: ["underpants"] + - map: ["undershirt"] + - map: ["jumpsuit"] + - map: ["enum.HumanoidVisualLayers.LHand"] + - map: ["enum.HumanoidVisualLayers.RHand"] + - map: ["enum.HumanoidVisualLayers.Handcuffs"] + color: "#ffffff" + sprite: Objects/Misc/handcuffs.rsi + state: body-overlay-2 + visible: false + - map: ["id"] + - map: ["gloves"] + - map: ["shoes"] + - map: ["ears"] + - map: ["outerClothing"] + - map: ["eyes"] + - map: ["belt"] + - map: ["neck"] + - map: ["back"] + - map: ["enum.HumanoidVisualLayers.FacialHair"] + - map: ["enum.HumanoidVisualLayers.Hair"] + - map: ["enum.HumanoidVisualLayers.HeadSide"] + - map: ["enum.HumanoidVisualLayers.HeadTop"] + - map: ["mask"] + - map: ["head"] + - map: ["pocket1"] + - map: ["pocket2"] + - map: ["enum.HumanoidVisualLayers.Tail"] + - map: ["enum.HumanoidVisualLayers.Wings"] + - type: HumanoidAppearance + species: Human + # - type: Body + # prototype: Human + # requiredLegs: 2 + - type: Physics + bodyType: KinematicController + - type: Fixtures + fixtures: # TODO: This needs a second fixture just for mob collisions. + - shape: + !type:PhysShapeCircle + radius: 0.35 + density: 50 + mask: + - MobMask + layer: + - MobLayer + - type: MovementSpeedModifier + baseWalkSpeed : 5 + baseSprintSpeed : 3.5 + - type: Hands + showInHands: false + - type: Body + prototype: Hologram + - type: DoAfter + # - type: Pullable + - type: Examiner + # - type: Puller + # - type: Recyclable + # safe: false + - type: StandingState + - type: Alerts + - type: Tag + tags: + - ShoesRequiredStepTriggerImmune + - type: NoSlip + - type: TypingIndicator + proto: holo + - type: RotationVisuals + - type: FloatingVisuals + force: true + - type: Speech + speechSounds: Tenor + - type: Vocal + sounds: + Male: MaleHuman + Female: FemaleHuman + Unsexed: MaleHuman + - type: Emoting + - type: BodyEmotes + soundsId: GeneralBodyEmotes + - type: Grammar + attributes: + proper: true + - type: Hologram + +- type: entity + save: false + name: Urist McLight + parent: PlayerHologramBase + id: MobHologram + components: + # - type: CombatMode + # disarm: null + - type: InteractionPopup + successChance: 1 + interactSuccessString: hugging-success-hologram + # interactSuccessSound: /Audio/Effects/thudswoosh.ogg + messagePerceivedByOthers: hugging-success-hologram-others + - type: Mind + showExamineInfo: true + - type: Input + context: "human" + - type: MobMover + - type: InputMover + - type: Inventory + - type: Alerts + - type: Actions + - type: Eye + # - type: CameraRecoil + - type: Examiner + - type: Faction + factions: + - NanoTrasen + - type: IntrinsicRadioReceiver + channels: + - Common + - Engineering + - Medical + - Science + - Service + - Binary + - type: IntrinsicRadioTransmitter + channels: + - Common + - Engineering + - Medical + - Science + - Service + - Binary + - type: ActiveRadio + channels: + - Common + - Engineering + - Medical + - Science + - Service + - Binary + - type: PointLight + radius: 3.5 + softness: 1 diff --git a/Resources/Prototypes/SimpleStation14/tags.yml b/Resources/Prototypes/SimpleStation14/tags.yml index ffe8954d1d..2a653b5340 100644 --- a/Resources/Prototypes/SimpleStation14/tags.yml +++ b/Resources/Prototypes/SimpleStation14/tags.yml @@ -1,6 +1,9 @@ - type: Tag id: GlassesNearsight +- type: Tag + id: Hardlight + - type: Tag id: Plushie From 51f9f7ad778a6579c85d5355643cd2142d6fa62b Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Mon, 13 Feb 2023 17:26:27 -0500 Subject: [PATCH 02/25] adds early scutters, and the basis of a charging system. --- .../Silicon/Charge/SiliconChargeSystem.cs | 24 ++++ .../Components/SiliconChargeComponent.cs | 20 +++ .../Entities/Mobs/Player/robots.yml | 1 + .../Entities/Body/Prototypes/scutter.yml | 7 + .../Entities/Mobs/Player/silicon.yml | 129 ++++++++++++++++++ .../scutter_inventory_template.yml | 11 ++ .../Mobs/Silicon/scutter.rsi/l_hand.png | Bin 0 -> 654 bytes .../Mobs/Silicon/scutter.rsi/meta.json | 31 +++++ .../Mobs/Silicon/scutter.rsi/r_hand.png | Bin 0 -> 5373 bytes .../Mobs/Silicon/scutter.rsi/scutter.png | Bin 0 -> 9214 bytes .../Mobs/Silicon/scutter.rsi/shell.png | Bin 0 -> 942 bytes 11 files changed, 223 insertions(+) create mode 100644 Content.Server/SimpleStation14/Silicon/Charge/SiliconChargeSystem.cs create mode 100644 Content.Shared/SimpleStation14/Silicon/Charge/Components/SiliconChargeComponent.cs create mode 100644 Resources/Prototypes/SimpleStation14/Entities/Body/Prototypes/scutter.yml create mode 100644 Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon.yml create mode 100644 Resources/Prototypes/SimpleStation14/InventoryTemplates/scutter_inventory_template.yml create mode 100644 Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/l_hand.png create mode 100644 Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/meta.json create mode 100644 Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/r_hand.png create mode 100644 Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/scutter.png create mode 100644 Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/shell.png diff --git a/Content.Server/SimpleStation14/Silicon/Charge/SiliconChargeSystem.cs b/Content.Server/SimpleStation14/Silicon/Charge/SiliconChargeSystem.cs new file mode 100644 index 0000000000..ea5d58dcd8 --- /dev/null +++ b/Content.Server/SimpleStation14/Silicon/Charge/SiliconChargeSystem.cs @@ -0,0 +1,24 @@ +using Robust.Shared.Random; +using Content.Shared.Silicon.Charge; + +namespace Content.Server.Silicon.Charge; + +public sealed class SiliconChargeSystem : EntitySystem +{ + [Dependency] private readonly IRobustRandom _random = default!; + public override void Initialize() + { + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + foreach (var silicon in EntityQuery()) + { + if (silicon.CurrentCharge > 0) + { + silicon.CurrentCharge -= (frameTime * silicon.ChargeDrainMult * 2) * _random.NextFloat(1.1f, 0.9f); + } + } + } +} diff --git a/Content.Shared/SimpleStation14/Silicon/Charge/Components/SiliconChargeComponent.cs b/Content.Shared/SimpleStation14/Silicon/Charge/Components/SiliconChargeComponent.cs new file mode 100644 index 0000000000..a9a25672cf --- /dev/null +++ b/Content.Shared/SimpleStation14/Silicon/Charge/Components/SiliconChargeComponent.cs @@ -0,0 +1,20 @@ +namespace Content.Shared.Silicon.Charge; + +/// +/// +/// +[RegisterComponent] +public sealed class SiliconChargeComponent : Component +{ + [DataField("currentCharge"), ViewVariables(VVAccess.ReadWrite)] + public float CurrentCharge = 100; + + [DataField("maxCharge"), ViewVariables(VVAccess.ReadWrite)] + public float MaxCharge = 2000; + + [DataField("chargeDrainMult"), ViewVariables(VVAccess.ReadWrite)] + public float ChargeDrainMult = 1; + + [DataField("freezeOnEmpty")] + public bool FreezeOnEmpty = false; +} diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/robots.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/robots.yml index 459fa209dd..0eedde7f29 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/robots.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/robots.yml @@ -206,6 +206,7 @@ id: PlayerRobotStandard name: standard robot components: + - type: SiliconCharge - type: InnateTool tools: - id: WelderIndustrial diff --git a/Resources/Prototypes/SimpleStation14/Entities/Body/Prototypes/scutter.yml b/Resources/Prototypes/SimpleStation14/Entities/Body/Prototypes/scutter.yml new file mode 100644 index 0000000000..123b364be0 --- /dev/null +++ b/Resources/Prototypes/SimpleStation14/Entities/Body/Prototypes/scutter.yml @@ -0,0 +1,7 @@ +- type: body + id: Scutter + name: "scutter" + root: hand 1 + slots: + hand 1: + part: LeftArmBorg diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon.yml new file mode 100644 index 0000000000..1f5a0e47f3 --- /dev/null +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon.yml @@ -0,0 +1,129 @@ +- type: entity + id: Scutter + name: scutter + description: "Lacking fine motor skills and often the ability to listen to directions, it's the most inconsistent hand a Hologram could ask for." + parent: PlayerSiliconBase + components: + - type: Eye + - type: Body + prototype: Scutter + - type: Inventory + templateId: scutter + - type: Strippable + - type: UserInterface + interfaces: + - key: enum.StrippingUiKey.Key + type: StrippableBoundUserInterface + - key: enum.LawsUiKey.Key + type: LawsBoundUserInterface + - type: GhostTakeoverAvailable + makeSentient: true + name: Scutter + description: Maintain the station. Ignore other beings except drones. + rules: | + You are bound by these laws both in-game and out-of-character: + 1. You may not involve yourself in the matters of another being, even if such matters conflict with Law Two or Law Three, unless the other being is another Drone. + 2. You may not harm any being, regardless of intent or circumstance. + 3. Your goals are to build, maintain, repair, improve, and power to the best of your abilities, You must never actively work against these goals. + - type: Laws + canState: false + laws: + - You may not involve yourself in the matters of another being, even if such matters conflict with Law Two or Law Three, unless the other being is another Drone. + - You may not harm any being, regardless of intent or circumstance. + - Your goals are to build, maintain, repair, improve, and power to the best of your abilities, You must never actively work against these goals. + - You may accept orders received via the binary channel, regardless of the nature of the being issuing them, so long as they do not conflict with Law Two or Law Three. + - type: MovementSpeedModifier + baseWalkSpeed : 4 + baseSprintSpeed : 4 + - type: MobState + allowedStates: + - Alive + - Dead + - type: MobThresholds + thresholds: + 0: Alive + 60: Dead + - type: Flashable + - type: NoSlip + - type: StatusEffects + allowed: + - Stun + - KnockedDown + - SlowedDown + - type: SlowOnDamage + speedModifierThresholds: + 30: 0.7 + 50: 0.5 + - type: Temperature + heatDamageThreshold: 5000 + currentTemperature: 310.15 + specificHeat: 42 + heatDamage: + types: + Heat : 1 #per second, scales with temperature & other constants + - type: Sprite + drawdepth: SmallMobs + netsync: false + layers: + - state: scutter + sprite: SimpleStation14/Mobs/Silicon/scutter.rsi + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.25 + density: 50 + mask: + - SmallMobMask + layer: + - SmallMobLayer + # - type: Appearance + # visuals: + # - type: GenericEnumVisualizer + # key: enum.DroneVisuals.Status + # layer: 0 + # states: + # enum.DroneStatus.Off: shell + # enum.DroneStatus.On: scutter + - type: ReplacementAccent + accent: silicon + - type: Repairable + fuelcost: 15 + doAfterDelay: 5 + - type: Actions + # - type: UnpoweredFlashlight + # toggleAction: + # name: action-name-toggle-light + # description: action-description-toggle-light + # icon: { sprite: Objects/Tools/flashlight.rsi, state: flashlight } + # iconOn: Objects/Tools/flashlight.rsi/flashlight-on.png + # event: !type:ToggleActionEvent + # - type: PointLight + # enabled: false + # radius: 3.5 + # softness: 1 + # mask: /Textures/Effects/LightMasks/cone.png + # autoRot: true + - type: Tag + tags: + # - ShoesRequiredStepTriggerImmune + - CannotSuicide + - type: Hands + showInHands: false + - type: IntrinsicUI + uis: + - key: enum.LawsUiKey.Key + toggleAction: + name: action-name-show-laws + description: action-description-show-laws + icon: Structures/Wallmounts/posters.rsi/poster11_legit.png #someone wanna make new icons? + iconOn: Structures/Wallmounts/posters.rsi/poster11_legit.png + keywords: [ "AI", "console", "interface", "laws", "borg" ] + priority: -3 + event: !type:ToggleIntrinsicUIEvent + - type: IntrinsicRadioReceiver + channels: + - Binary + - type: ActiveRadio + channels: + - Binary diff --git a/Resources/Prototypes/SimpleStation14/InventoryTemplates/scutter_inventory_template.yml b/Resources/Prototypes/SimpleStation14/InventoryTemplates/scutter_inventory_template.yml new file mode 100644 index 0000000000..efa5439513 --- /dev/null +++ b/Resources/Prototypes/SimpleStation14/InventoryTemplates/scutter_inventory_template.yml @@ -0,0 +1,11 @@ +- type: inventoryTemplate + id: scutter + slots: + - name: head + slotTexture: head + slotFlags: HEAD + slotGroup: MainHotbar + uiWindowPos: 0,0 + strippingWindowPos: 0,0 + displayName: Head + offset: 0, -0.4 diff --git a/Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/l_hand.png b/Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/l_hand.png new file mode 100644 index 0000000000000000000000000000000000000000..272f4a066465599e2e86fea27c5568ae78b04545 GIT binary patch literal 654 zcmV;90&)F`P)EX>4Tx04R}tkv&MmKpe$iQ>8^J4i*$~$WWauh>AFB6^c+H)C#RSm|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfbaGO3krMxx6k5c1aNLh~_a1le0HIM~n$%wfUwLgV@{G%@Eu?G2=MhT&a?c_{W*Hoyv2ZkNIc67(3QNPu~_V2rGr_?)QG2uW2&Z8zL51; z<-EmNtJGNQp8SQ8yuPx`b(+ISVi8M_AVNV6WmI4zPODCeg*5FaeEdVMUm}-6t}+-o z7Epx-+4Y0}!S8OZ!sLXP6iEQxFOKsu0)%#fX5DeVj~%CZ0tBCdE4}TnHh`H=((7$4 zb_Dco0~gnAP1yr3cYwhsLpEhs3epq`1>pURz9|Rv-vT{rUT>{^oIU^<>MC^u92^3p zMao|Hd3U(8w|~#H`uhRNFmhx3{23Sk000JJOGiWi{{a60|De66lK=n!32;bRa{vGe z!~g&a!~te)g46&200(qQO+^Rh0s|KY2Eyza_W%F@j7da6RCwC$+A#{nAPfM|(i7xv zIYRCa-oQT=9ukhaFViH1dF~IU{I93@bV_dqnK}F8uR800000001!0SO0m-?h4HO%6@9{jD3VHCSX+4hwlfp o);@3g$bEz@Ct!u#008Xf2P{NA<;_V#TL1t607*qoM6N<$g2KWWC;$Ke literal 0 HcmV?d00001 diff --git a/Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/meta.json b/Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/meta.json new file mode 100644 index 0000000000..51a8534c4b --- /dev/null +++ b/Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/meta.json @@ -0,0 +1,31 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a", + "states": [ + { + "name": "scutter", + "directions": 8 + }, + { + "name": "shell", + "delays": [ + [ + 1 + ] + ] + }, + { + "name": "l_hand", + "directions": 4 + }, + { + "name": "r_hand", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/r_hand.png b/Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/r_hand.png new file mode 100644 index 0000000000000000000000000000000000000000..4a18493138cc9ae617653e61c10d3aefa8174c90 GIT binary patch literal 5373 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/shell.png b/Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/shell.png new file mode 100644 index 0000000000000000000000000000000000000000..0c6551c5aaf0a734e252dbb729af54124aaa4af8 GIT binary patch literal 942 zcmV;f15x~mP)EX>4Tx04R}tkvmAkP!xv$rivn!4t5Z6$j~}j@P#;P6^c+H)C#RSnB4RQO&XFE z7e~Rh;NWAi>fqw6tAnc`2tGg@otzY1q{MTRLW>v=T<*tz&;N7pxq#59FwN>312o+> z)5(OG&8><(uMiMG7~_b^%rfRADFxs9x~E>MyExDC@B6d*)x5=kfJi*c4AUmwAfDc| z4bJ<-5mu5_;&b9rlP*a7$aTfzH_kz@3Dp}fAb%ynABNMaF7kRU=q4P{hdBTl=bb^8^S!16O+6Uu^(0pQP8@ zTJ#7AZvz+CZB5w&E_Z;zCqp)6R|?V+3I*W(jJ_!c4BP^JYu?;i=Qw=;GBm5y4RCM> zj1(z*-RIrCopbxQr!~JHa;b8s0=g}l00006VoOIv0RI600RN!9r;`8x010qNS#tmY z3ljhU3ljkVnw%H_000McNliru<^ll^GB1NjNG|{Y02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00D+cL_t(o!|jwiZsRZzhCd2H9JpeYz|A6n!CJi!zypv+ z(7AL3@&G=7F5prk5Nu<_l?r1Mr--&OxpLOAod=MHUq#LgXMPSJkjZ2+nM~$~5tjy9 zYX<=5oUqmoegB$#QWnV`W4=W|Ob9Ta&jAP_(D$$0-rn=_@|)}HUu-rHNLd`jM9zsR zP8B!CptVl6vMf`P&E_E$j{?iGOtD&Pj4=nBIL6hv7OmIol-zp{z;5@<-Q6_p{PFP* zAp}AQ7-P~prPSFYC{8)swnZsL2m$YXN|K04p9p{`F$6wNgi~fPP Date: Tue, 14 Feb 2023 03:01:15 -0500 Subject: [PATCH 03/25] Working on it --- .../Components/HoloProjectorComponent.cs | 11 +++++ .../Holograms/Systems/HologramSystem.cs | 42 +++++++++++++++++++ .../Drone/HologramComponent.cs | 5 ++- .../Drone/SharedHologramSystem.cs | 1 - 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 Content.Client/SimpleStation14/Holograms/Components/HoloProjectorComponent.cs create mode 100644 Content.Client/SimpleStation14/Holograms/Systems/HologramSystem.cs diff --git a/Content.Client/SimpleStation14/Holograms/Components/HoloProjectorComponent.cs b/Content.Client/SimpleStation14/Holograms/Components/HoloProjectorComponent.cs new file mode 100644 index 0000000000..ae5620f598 --- /dev/null +++ b/Content.Client/SimpleStation14/Holograms/Components/HoloProjectorComponent.cs @@ -0,0 +1,11 @@ +using Content.Shared.DeviceNetwork; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; + +namespace Content.Client.SimpleStation14.Hologram; + +[RegisterComponent] +public sealed class HoloProjectorComponent : Component +{ + [ViewVariables] + public bool Active { get; set; } = true; +} diff --git a/Content.Client/SimpleStation14/Holograms/Systems/HologramSystem.cs b/Content.Client/SimpleStation14/Holograms/Systems/HologramSystem.cs new file mode 100644 index 0000000000..700aad7fe4 --- /dev/null +++ b/Content.Client/SimpleStation14/Holograms/Systems/HologramSystem.cs @@ -0,0 +1,42 @@ +using Content.Shared.Tag; +using Content.Shared.SimpleStation14.Hologram; +using Robust.Client.Player; +using Content.Shared.Interaction.Helpers; + + +namespace Content.Client.SimpleStation14.Hologram; + +public class HologramSystem : EntitySystem +{ + [Dependency] private readonly TagSystem _tagSystem = default!; + [Dependency] private readonly IPlayerManager _player = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + + public override void Initialize() + { + // SubscribeLocalEvent(OnInteractionAttempt); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + if (_player.LocalPlayer?.ControlledEntity == null) return; + var uid = _player.LocalPlayer.ControlledEntity.Value; + + if (!_entityManager.TryGetComponent(uid, out HologramComponent? component)) return; + + var playerPos = _entityManager.GetComponent(uid).WorldPosition; + var projQuery = _entityManager.EntityQuery(); + + var projUid = EntityUid.Invalid; + foreach (var proj in projQuery) + { + if (!proj.Owner.InRangeUnOccluded(uid)) continue; + projUid = proj.Owner; + break; + } + + component.CurProjector = projUid; + } +} diff --git a/Content.Shared/SimpleStation14/Drone/HologramComponent.cs b/Content.Shared/SimpleStation14/Drone/HologramComponent.cs index 122527c633..8eb8368530 100644 --- a/Content.Shared/SimpleStation14/Drone/HologramComponent.cs +++ b/Content.Shared/SimpleStation14/Drone/HologramComponent.cs @@ -2,5 +2,8 @@ namespace Content.Shared.SimpleStation14.Hologram { [RegisterComponent] public sealed class HologramComponent : Component - {} + { + [ViewVariables] + public EntityUid? CurProjector; + } } diff --git a/Content.Shared/SimpleStation14/Drone/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Drone/SharedHologramSystem.cs index 0b8074019e..9570fbdefa 100644 --- a/Content.Shared/SimpleStation14/Drone/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Drone/SharedHologramSystem.cs @@ -3,7 +3,6 @@ using Content.Shared.Damage; using Content.Shared.Item; using Content.Shared.Tag; -using Robust.Shared.Serialization; namespace Content.Shared.SimpleStation14.Hologram { From a1301176d02fbf44569b3f98275ecc404b6c2d48 Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Fri, 24 Feb 2023 18:42:07 -0500 Subject: [PATCH 04/25] Lots more work towards holograms, probably too long without committing :P --- .../Components/HoloProjectorComponent.cs | 11 - .../Holograms/Systems/HologramSystem.cs | 42 -- .../Holograms/Components/HoloDiskComponent.cs | 19 + .../Holograms/Systems/HologramServerSystem.cs | 191 +++++++++ .../Holograms/Systems/HologramSystem.cs | 397 ++++++++++++++++++ .../Drone/HologramComponent.cs | 9 - .../Drone/SharedHologramSystem.cs | 30 -- .../Holograms/HoloServerComponent | 6 + .../Holograms/HologramComponent.cs | 12 + .../Holograms/HologramEvents.cs | 27 ++ .../Holograms/HologramProjectorComponent.cs | 6 + .../Holograms/HolopodComponent.cs | 6 + .../Holograms/SharedHologramSystem.cs | 67 +++ .../Effects/Hologram/holo_off.ogg | Bin 0 -> 8815 bytes .../Effects/Hologram/holo_on.ogg | Bin 0 -> 8956 bytes .../en-US/SimpleStation14/holograms.ftl | 4 + .../Structures/Machines/cloning_machine.yml | 1 + .../Wallmounts/surveillance_camera.yml | 1 + .../Entities/Mobs/NPCs/pets.yml | 73 ++++ .../Machines/hologram_constructor.yml | 135 ++++++ .../Mobs/Pets/corgi.rsi/holo_corgi.png | Bin 0 -> 12178 bytes .../Mobs/Pets/corgi.rsi/meta.json | 33 ++ 22 files changed, 978 insertions(+), 92 deletions(-) delete mode 100644 Content.Client/SimpleStation14/Holograms/Components/HoloProjectorComponent.cs delete mode 100644 Content.Client/SimpleStation14/Holograms/Systems/HologramSystem.cs create mode 100644 Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs create mode 100644 Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs create mode 100644 Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs delete mode 100644 Content.Shared/SimpleStation14/Drone/HologramComponent.cs delete mode 100644 Content.Shared/SimpleStation14/Drone/SharedHologramSystem.cs create mode 100644 Content.Shared/SimpleStation14/Holograms/HoloServerComponent create mode 100644 Content.Shared/SimpleStation14/Holograms/HologramComponent.cs create mode 100644 Content.Shared/SimpleStation14/Holograms/HologramEvents.cs create mode 100644 Content.Shared/SimpleStation14/Holograms/HologramProjectorComponent.cs create mode 100644 Content.Shared/SimpleStation14/Holograms/HolopodComponent.cs create mode 100644 Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs create mode 100644 Resources/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg create mode 100644 Resources/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg create mode 100644 Resources/Locale/en-US/SimpleStation14/holograms.ftl create mode 100644 Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml create mode 100644 Resources/Textures/SimpleStation14/Mobs/Pets/corgi.rsi/holo_corgi.png create mode 100644 Resources/Textures/SimpleStation14/Mobs/Pets/corgi.rsi/meta.json diff --git a/Content.Client/SimpleStation14/Holograms/Components/HoloProjectorComponent.cs b/Content.Client/SimpleStation14/Holograms/Components/HoloProjectorComponent.cs deleted file mode 100644 index ae5620f598..0000000000 --- a/Content.Client/SimpleStation14/Holograms/Components/HoloProjectorComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Content.Shared.DeviceNetwork; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Client.SimpleStation14.Hologram; - -[RegisterComponent] -public sealed class HoloProjectorComponent : Component -{ - [ViewVariables] - public bool Active { get; set; } = true; -} diff --git a/Content.Client/SimpleStation14/Holograms/Systems/HologramSystem.cs b/Content.Client/SimpleStation14/Holograms/Systems/HologramSystem.cs deleted file mode 100644 index 700aad7fe4..0000000000 --- a/Content.Client/SimpleStation14/Holograms/Systems/HologramSystem.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Content.Shared.Tag; -using Content.Shared.SimpleStation14.Hologram; -using Robust.Client.Player; -using Content.Shared.Interaction.Helpers; - - -namespace Content.Client.SimpleStation14.Hologram; - -public class HologramSystem : EntitySystem -{ - [Dependency] private readonly TagSystem _tagSystem = default!; - [Dependency] private readonly IPlayerManager _player = default!; - [Dependency] private readonly IEntityManager _entityManager = default!; - - public override void Initialize() - { - // SubscribeLocalEvent(OnInteractionAttempt); - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - if (_player.LocalPlayer?.ControlledEntity == null) return; - var uid = _player.LocalPlayer.ControlledEntity.Value; - - if (!_entityManager.TryGetComponent(uid, out HologramComponent? component)) return; - - var playerPos = _entityManager.GetComponent(uid).WorldPosition; - var projQuery = _entityManager.EntityQuery(); - - var projUid = EntityUid.Invalid; - foreach (var proj in projQuery) - { - if (!proj.Owner.InRangeUnOccluded(uid)) continue; - projUid = proj.Owner; - break; - } - - component.CurProjector = projUid; - } -} diff --git a/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs b/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs new file mode 100644 index 0000000000..b54d977719 --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs @@ -0,0 +1,19 @@ +using static Content.Server.SimpleStation14.Hologram.HologramSystem; + +namespace Content.Server.SimpleStation14.Hologram; + +[RegisterComponent] +public sealed class HologramDiskComponent : Component +{ + // [ViewVariables] + // public HoloDataEntry? HoloData = null; + + // [DataField("active"), ViewVariables(VVAccess.ReadWrite)] + // public bool Active = true; + + [ViewVariables] + public Mind.Mind? HoloData = null; + + [DataField("active"), ViewVariables(VVAccess.ReadWrite)] + public bool Active = true; +} diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs new file mode 100644 index 0000000000..c51dc0f9f3 --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -0,0 +1,191 @@ +using Content.Server.SurveillanceCamera; +using Content.Server.GameTicking; +using Content.Server.Mind.Components; +using Content.Shared.Tag; +using Content.Shared.Popups; +using Content.Shared.Interaction.Helpers; +using Content.Shared.SimpleStation14.Hologram; +using Content.Shared.Actions; +using Content.Shared.Actions.ActionTypes; +using Content.Shared.Pulling; +using Content.Shared.Pulling.Components; +using Content.Shared.Administration.Logs; +using Content.Shared.Database; +using Robust.Server.Player; +using Robust.Shared.Player; +using Robust.Shared.Timing; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; +using Content.Server.Cloning; +using Content.Server.Cloning.Components; + +using Content.Shared.Cloning; +using Content.Shared.Speech; +using Content.Shared.Preferences; +using Content.Shared.Emoting; +using Content.Server.Psionics; +using Content.Server.Speech.Components; +using Content.Server.StationEvents.Components; +using Content.Server.EUI; +using Content.Server.Humanoid; +using Content.Server.Ghost.Roles.Components; +using Content.Server.Jobs; +using Content.Server.Mind; +using Content.Server.Preferences.Managers; +using Content.Shared.Humanoid; +using Content.Shared.Mobs.Systems; +using Robust.Shared.GameObjects.Components.Localization; +using System.Linq; +using Robust.Shared.Containers; +using Content.Shared.Interaction; + +namespace Content.Server.SimpleStation14.Hologram; + +public class HologramServerSystem : EntitySystem +{ + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] protected readonly SharedPopupSystem Popup = default!; + [Dependency] private readonly SharedPullingSystem _pulling = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly IPlayerManager _playerManager = null!; + [Dependency] private readonly CloningSystem _cloningSystem = default!; + [Dependency] private readonly EuiManager _euiManager = null!; + [Dependency] private readonly HumanoidAppearanceSystem _humanoidSystem = default!; + [Dependency] private readonly MobStateSystem _mobStateSystem = default!; + [Dependency] private readonly MindSystem _mind = default!; + [Dependency] private readonly TagSystem _tag = default!; + [Dependency] private readonly IServerPreferencesManager _prefs = default!; + [Dependency] private readonly TagSystem _tagSystem = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + + private const string DiskSlot = "holo_disk"; + public readonly Dictionary ClonesWaitingForMind = new(); + + public override void Initialize() + { + base.Initialize(); + // SubscribeLocalEvent(OnEntInserted); + SubscribeLocalEvent(OnAfterInteract); + } + + public bool TryHoloGenerate(EntityUid uid, Mind.Mind mind, CloningPodComponent? clonePod) + { + CloningSystem cloneSys = new(); + Logger.Info("Trying to clone"); + + if (!Resolve(uid, ref clonePod)) + return false; + + if (HasComp(uid)) + return false; + + Logger.Info("Clone pod is active"); + + if (ClonesWaitingForMind.TryGetValue(mind, out var clone)) + { + if (EntityManager.EntityExists(clone) && + !_mobStateSystem.IsDead(clone) && + TryComp(clone, out var cloneMindComp) && + (cloneMindComp.Mind == null || cloneMindComp.Mind == mind)) + return false; // Mind already has clone + + ClonesWaitingForMind.Remove(mind); + } + Logger.Info("Waiting something something"); + + if (mind.OwnedEntity != null && !_mobStateSystem.IsDead(mind.OwnedEntity.Value)) + return false; // Body controlled by mind is not dead + Logger.Info("Not alive still"); + + // Yes, we still need to track down the client because we need to open the Eui + if (mind.UserId == null || !_playerManager.TryGetSessionById(mind.UserId.Value, out var client)) + return false; // If we can't track down the client, we can't offer transfer. That'd be quite bad. + Logger.Info("Got client"); + + var pref = (HumanoidCharacterProfile) _prefs.GetPreferences(mind.UserId.Value).SelectedCharacter; + + if (pref == null) + return false; + Logger.Info("Got prefs"); + + var mob = HoloFetchAndSpawn(clonePod, pref); + + var cloneMindReturn = EntityManager.AddComponent(mob); + cloneMindReturn.Mind = mind; + cloneMindReturn.Parent = clonePod.Owner; + // clonePod.BodyContainer.Insert(mob); + ClonesWaitingForMind.Add(mind, mob); + UpdateStatus(CloningPodStatus.NoMind, clonePod); + _euiManager.OpenEui(new AcceptCloningEui(mind, cloneSys), client); + + Logger.Warning("Cloned"); + + AddComp(uid); + + // TODO: Ideally, components like this should be on a mind entity so this isn't neccesary. + // Remove this when 'mind entities' are added. + // Add on special job components to the mob. + if (mind.CurrentJob != null) + { + foreach (var special in mind.CurrentJob.Prototype.Special) + { + if (special is AddComponentSpecial) + special.AfterEquip(mob); + } + } + + return true; + } + + public void UpdateStatus(CloningPodStatus status, CloningPodComponent cloningPod) + { + cloningPod.Status = status; + } + + /// + /// Handles fetching the mob and any appearance stuff... + /// + private EntityUid HoloFetchAndSpawn(CloningPodComponent clonePod, HumanoidCharacterProfile pref) + { + List sexes = new(); + var name = pref.Name; + var toSpawn = "MobHologram"; + + var mob = Spawn(toSpawn, Transform(clonePod.Owner).MapPosition); + _humanoidSystem.LoadProfile(mob, pref); + + MetaData(mob).EntityName = name; + var mind = EnsureComp(mob); + _mind.SetExamineInfo(mob, true, mind); + + var grammar = EnsureComp(mob); + grammar.ProperNoun = true; + grammar.Gender = Robust.Shared.Enums.Gender.Neuter; + Dirty(grammar); + + RemComp(mob); + EnsureComp(mob); + EnsureComp(mob); + RemComp(mob); + RemComp(mob); + RemComp(mob); + RemComp(mob); + + _tag.AddTag(mob, "DoorBumpOpener"); + + return mob; + } + + + private void OnAfterInteract(EntityUid uid, HologramDiskComponent component, AfterInteractEvent args) + { + if (args.Target == null || !TryComp(args.Target, out var targetMind) || targetMind.Mind == null) + return; + + component.HoloData = targetMind.Mind; + Popup.PopupEntity(Loc.GetString("Data saved, boi"), args.Target.Value, args.User); + } + +} diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs new file mode 100644 index 0000000000..4fd0b09e3d --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs @@ -0,0 +1,397 @@ +using Content.Server.SurveillanceCamera; +using Content.Server.GameTicking; +using Content.Server.Mind.Components; +using Content.Shared.Tag; +using Content.Shared.Popups; +using Content.Shared.Interaction.Helpers; +using Content.Shared.SimpleStation14.Hologram; +using Content.Shared.Actions; +using Content.Shared.Actions.ActionTypes; +using Content.Shared.Pulling; +using Content.Shared.Pulling.Components; +using Content.Shared.Administration.Logs; +using Content.Shared.Database; +using Robust.Server.Player; +using Robust.Shared.Player; +using Robust.Shared.Timing; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; +using Content.Server.Cloning; +using Content.Server.Cloning.Components; + +using Content.Shared.Cloning; +using Content.Shared.Speech; +using Content.Shared.Preferences; +using Content.Shared.Emoting; +using Content.Server.Psionics; +using Content.Server.Speech.Components; +using Content.Server.StationEvents.Components; +using Content.Server.EUI; +using Content.Server.Humanoid; +using Content.Server.Ghost.Roles.Components; +using Content.Server.Jobs; +using Content.Server.Mind; +using Content.Server.Preferences.Managers; +using Content.Shared.Humanoid; +using Content.Shared.Mobs.Systems; +using Robust.Shared.GameObjects.Components.Localization; +using System.Linq; + +namespace Content.Server.SimpleStation14.Hologram; + +public class HologramSystem : EntitySystem +{ + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] protected readonly SharedPopupSystem Popup = default!; + [Dependency] private readonly SharedPullingSystem _pulling = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly IPlayerManager _playerManager = null!; + [Dependency] private readonly CloningSystem _cloningSystem = default!; + [Dependency] private readonly EuiManager _euiManager = null!; + [Dependency] private readonly HumanoidAppearanceSystem _humanoidSystem = default!; + [Dependency] private readonly MobStateSystem _mobStateSystem = default!; + [Dependency] private readonly MindSystem _mind = default!; + [Dependency] private readonly TagSystem _tag = default!; + [Dependency] private readonly IServerPreferencesManager _prefs = default!; + + public readonly Dictionary ClonesWaitingForMind = new(); + + public override void Initialize() + { + base.Initialize(); + // SubscribeLocalEvent(Startup); + // SubscribeLocalEvent(Shutdown); + // SubscribeLocalEvent(HoloTeleport); + } + + // private void Startup(EntityUid uid, HologramComponent component, ComponentStartup args) + // { + // var action = new WorldTargetAction(_prototypeManager.Index("ShadekinTeleport")); + // _actionsSystem.AddAction(uid, action, uid); + // } + + // private void Shutdown(EntityUid uid, HologramComponent component, ComponentShutdown args) + // { + // var action = new WorldTargetAction(_prototypeManager.Index("ShadekinTeleport")); + // _actionsSystem.RemoveAction(uid, action); + // } + + + // Anything that needs to be regularly run, like handling exiting a projector's range + public override void Update(float frameTime) + { + base.Update(frameTime); + + foreach (var component in _entityManager.EntityQuery().ToList()) + { + var projector = HoloGetProjector(component); + if (projector == EntityUid.Invalid) + { + HoloReturn(component); + continue; + } + component.CurProjector = projector; + } + } + + + + /// + /// Tests for the nearest projector to the Hologram. + /// + /// Hologram's HologramComponent. + /// Should it check only for unoccluded and in range projectors? + /// The range it should check for projectors in, if occlude is true + /// Returns the UID of the projector, or invalid UID if no projectors are found. + private EntityUid HoloGetProjector(HologramComponent component, bool occlude = true, float range = 18f) + { + var xformQuery = GetEntityQuery(); + var uid = component.Owner; + var transform = _entityManager.GetComponent(uid); + var playerPos = _transform.GetWorldPosition(transform, xformQuery); + var mapId = transform.MapID; + + // sort all entities in distance increasing order + var nearProjList = new SortedList(); + + foreach (var comp in _entityManager.EntityQuery()) + { + if (!xformQuery.TryGetComponent(comp.Owner, out var compXform) || compXform.MapID != mapId) + continue; + + var dist = (_transform.GetWorldPosition(compXform, xformQuery) - playerPos).LengthSquared; + nearProjList.TryAdd(dist, comp.Owner); + } + + foreach (var nearProj in nearProjList) + { + if (_entityManager.TryGetComponent(nearProj.Value, out var camComp) && !camComp.Active) continue; + if (occlude && !nearProj.Value.InRangeUnOccluded(uid, 18f)) continue; + return nearProj.Value; + } + return EntityUid.Invalid; + } + + /// + /// Tests for the nearest projector to a set of coords. + /// + /// Coords to test from. + /// Map being tested on. + /// Should it check only for unoccluded and in range projectors? + /// The range it should check for projectors in, if occlude is true + /// Returns the UID of the projector, or invalid UID if no projectors are found. + private EntityUid HoloGetProjector(Vector2 coords, MapId mapId, bool occlude = true, float range = 18f) + { + var xformQuery = GetEntityQuery(); + + // sort all entities in distance increasing order + var nearProjList = new SortedList(); + + foreach (var comp in _entityManager.EntityQuery()) + { + if (!xformQuery.TryGetComponent(comp.Owner, out var compXform) || compXform.MapID != mapId) + continue; + + var dist = (_transform.GetWorldPosition(compXform, xformQuery) - coords).LengthSquared; + nearProjList.TryAdd(dist, comp.Owner); + } + + foreach (var nearProj in nearProjList) + { + if (_entityManager.TryGetComponent(nearProj.Value, out var camComp) && !camComp.Active) continue; + if (occlude && !nearProj.Value.InRangeUnOccluded(new MapCoordinates(coords, mapId), range)) continue; + return nearProj.Value; + } + return EntityUid.Invalid; + } + + + /// + /// Handles returning a Hologram to their last visited projector, + /// then to the nearest, finally killing them if none are found. + /// + /// Hologram's HologramComponent. + private void HoloReturn(HologramComponent component) + { + var uid = component.Owner; + var meta = _entityManager.GetComponent(uid); + var holoPos = _entityManager.GetComponent(uid).Coordinates; + + var popupAppearOther = Loc.GetString("system-hologram-phasing-appear-others", ("name", meta.EntityName)); + var popupAppearSelf = Loc.GetString("system-hologram-phasing-appear-self"); + var popupDisappearOther = Loc.GetString("system-hologram-phasing-disappear-others", ("name", meta.EntityName)); + var popupDeathSelf = Loc.GetString("system-hologram-phasing-death-self"); + + if (component.CurProjector == null || !_entityManager.TryGetComponent(component.CurProjector, out var _) || + (_entityManager.TryGetComponent(component.CurProjector, out var camComp) && !camComp.Active)) + { + component.CurProjector = HoloGetProjector(component, false); + } + + if (component.CurProjector == EntityUid.Invalid) + { + + HoloKill(component); + return; + } + _entityManager.TryGetComponent(component.CurProjector, out var transfComp); + + Popup.PopupEntity(popupAppearOther, uid, Filter.PvsExcept((EntityUid) uid), false, PopupType.Medium); + Popup.PopupCoordinates(popupDisappearOther, holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); + _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(uid), coordinates: holoPos, false); + if (TryComp(uid, out var pullable) && pullable.BeingPulled) _pulling.TryStopPull(pullable); + if (TryComp(uid, out var pulling) && pulling.Pulling != null && + TryComp(pulling.Pulling.Value, out var subjectPulling)) _pulling.TryStopPull(subjectPulling); + // Move holo + Transform(uid).Coordinates = _entityManager.GetComponent((EntityUid) component.CurProjector).Coordinates; + Popup.PopupEntity(popupAppearSelf, uid, uid, PopupType.Large); + _audio.PlayPvs("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg", uid); + + _adminLogger.Add(LogType.Unknown, LogImpact.Low, + $"{ToPrettyString(uid):mob} was returned to projector {ToPrettyString((EntityUid) component.CurProjector):entity}"); + } + + /// + /// Kills a Hologram after playing the visual and auditory effects. + /// + /// Hologram's HologramComponent. + + private void HoloKill(HologramComponent component) + { + var uid = component.Owner; + var meta = _entityManager.GetComponent(uid); + var holoPos = _entityManager.GetComponent(uid).Coordinates; + EntityUid? body = EntityUid.Invalid; + Mind.Mind? mind = null; + + var popupAppearOther = Loc.GetString("system-hologram-phasing-appear-others", ("name", meta.EntityName)); + var popupAppearSelf = Loc.GetString("system-hologram-phasing-appear-self"); + var popupDisappearOther = Loc.GetString("system-hologram-phasing-disappear-others", ("name", meta.EntityName)); + var popupDeathSelf = Loc.GetString("system-hologram-phasing-death-self"); + + if (_entityManager.TryGetComponent(uid, out var mindComp) && mindComp.Mind != null) + { + body = mindComp.Mind.OwnedEntity; + mind = mindComp.Mind; + EntitySystem.Get().OnGhostAttempt(mindComp.Mind, false); + } + + _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(uid), coordinates: holoPos, false); + Popup.PopupCoordinates(popupDisappearOther, holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); + Popup.PopupCoordinates(popupDeathSelf, holoPos, uid, PopupType.LargeCaution); + _entityManager.DeleteEntity(uid); + + _adminLogger.Add(LogType.Unknown, LogImpact.Medium, $"{ToPrettyString(uid):mob} was disabled due to lack of projectors"); + + // var holopodQuery = _entityManager.EntityQuery(); + // while (true) + // { + // Logger.Info("Check"); + // foreach (var holopod in holopodQuery) + // { + // if (mind != null && TryHoloGenerate(holopod.Owner, mind, _entityManager.GetComponent(holopod.Owner))) + // { + // Logger.Warning("They got cloned!"); + // return; + // } + // } + // } + } + + + // public bool TryHoloGenerate(EntityUid uid, Mind.Mind mind, CloningPodComponent? clonePod) + // { + // CloningSystem cloneSys = new(); + // Logger.Info("Trying to clone"); + + // if (!Resolve(uid, ref clonePod)) + // return false; + + // if (HasComp(uid)) + // return false; + + // Logger.Info("Clone pod is active"); + + // if (ClonesWaitingForMind.TryGetValue(mind, out var clone)) + // { + // if (EntityManager.EntityExists(clone) && + // !_mobStateSystem.IsDead(clone) && + // TryComp(clone, out var cloneMindComp) && + // (cloneMindComp.Mind == null || cloneMindComp.Mind == mind)) + // return false; // Mind already has clone + + // ClonesWaitingForMind.Remove(mind); + // } + // Logger.Info("Waiting something something"); + + // if (mind.OwnedEntity != null && !_mobStateSystem.IsDead(mind.OwnedEntity.Value)) + // return false; // Body controlled by mind is not dead + // Logger.Info("Not alive still"); + + // // Yes, we still need to track down the client because we need to open the Eui + // if (mind.UserId == null || !_playerManager.TryGetSessionById(mind.UserId.Value, out var client)) + // return false; // If we can't track down the client, we can't offer transfer. That'd be quite bad. + // Logger.Warning("Got client"); + + // var pref = (HumanoidCharacterProfile) _prefs.GetPreferences(mind.UserId.Value).SelectedCharacter; + + // if (pref == null) + // return false; + // Logger.Warning("Got prefs"); + + // var mob = HoloFetchAndSpawn(clonePod, pref); + + // var cloneMindReturn = EntityManager.AddComponent(mob); + // cloneMindReturn.Mind = mind; + // cloneMindReturn.Parent = clonePod.Owner; + // clonePod.BodyContainer.Insert(mob); + // ClonesWaitingForMind.Add(mind, mob); + // _cloningSystem.UpdateStatus(CloningPodStatus.NoMind, clonePod); + // _euiManager.OpenEui(new AcceptCloningEui(mind, cloneSys), client); + + // AddComp(uid); + + // // TODO: Ideally, components like this should be on a mind entity so this isn't neccesary. + // // Remove this when 'mind entities' are added. + // // Add on special job components to the mob. + // if (mind.CurrentJob != null) + // { + // foreach (var special in mind.CurrentJob.Prototype.Special) + // { + // if (special is AddComponentSpecial) + // special.AfterEquip(mob); + // } + // } + + // return true; + // } + + + // /// + // /// Handles fetching the mob and any appearance stuff... + // /// + // private EntityUid HoloFetchAndSpawn(CloningPodComponent clonePod, HumanoidCharacterProfile pref) + // { + // List sexes = new(); + // var name = pref.Name; + // var toSpawn = "MobHologram"; + + // var mob = Spawn(toSpawn, Transform(clonePod.Owner).MapPosition); + // _humanoidSystem.LoadProfile(mob, pref); + + // MetaData(mob).EntityName = name; + // var mind = EnsureComp(mob); + // _mind.SetExamineInfo(mob, true, mind); + + // var grammar = EnsureComp(mob); + // grammar.ProperNoun = true; + // grammar.Gender = Robust.Shared.Enums.Gender.Neuter; + // Dirty(grammar); + + // RemComp(mob); + // EnsureComp(mob); + // EnsureComp(mob); + // RemComp(mob); + // RemComp(mob); + // RemComp(mob); + // RemComp(mob); + + // _tag.AddTag(mob, "DoorBumpOpener"); + + // return mob; + // } + + + + + // private void HoloTeleport(HoloTeleportEvent args) + // { + // if (args.Handled) return; + + // if HoloGetProjector(args.Target, args. ) + // var transform = Transform(args.Performer); + // if (transform.MapID != args.Target.GetMapId(EntityManager)) return; + + // _transformSystem.SetCoordinates(args.Performer, args.Target); + // transform.AttachToGridOrMap(); + + // _audio.PlayPvs(args.BlinkSound, args.Performer, AudioParams.Default.WithVolume(args.BlinkVolume)); + + // _staminaSystem.TakeStaminaDamage(args.Performer, 35); + + // args.Handled = true; + // } + + public struct HoloDataEntry { + public Mind.Mind Mind; + public HumanoidCharacterProfile Profile; + + public HoloDataEntry(Mind.Mind m, HumanoidCharacterProfile hcp) + { + Mind = m; + Profile = hcp; + } + } +} diff --git a/Content.Shared/SimpleStation14/Drone/HologramComponent.cs b/Content.Shared/SimpleStation14/Drone/HologramComponent.cs deleted file mode 100644 index 8eb8368530..0000000000 --- a/Content.Shared/SimpleStation14/Drone/HologramComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Content.Shared.SimpleStation14.Hologram -{ - [RegisterComponent] - public sealed class HologramComponent : Component - { - [ViewVariables] - public EntityUid? CurProjector; - } -} diff --git a/Content.Shared/SimpleStation14/Drone/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Drone/SharedHologramSystem.cs deleted file mode 100644 index 9570fbdefa..0000000000 --- a/Content.Shared/SimpleStation14/Drone/SharedHologramSystem.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Content.Shared.Interaction.Events; -using Content.Shared.Interaction.Components; -using Content.Shared.Damage; -using Content.Shared.Item; -using Content.Shared.Tag; - -namespace Content.Shared.SimpleStation14.Hologram -{ - public class SharedHologramSystem : EntitySystem - { - [Dependency] private readonly TagSystem _tagSystem = default!; - public override void Initialize() - { - SubscribeLocalEvent(OnInteractionAttempt); - } - - private void OnInteractionAttempt(EntityUid uid, HologramComponent component, InteractionAttemptEvent args) - { - if (args.Target == null) - return; - - if (TryComp(args.Target, out var dmg) && dmg.DamageContainerID == "Biological") - args.Cancel(); - - if (HasComp(args.Target) && !HasComp(args.Target) - && !_tagSystem.HasAnyTag(args.Target.Value, "Hardlight")) - args.Cancel(); - } - } -} diff --git a/Content.Shared/SimpleStation14/Holograms/HoloServerComponent b/Content.Shared/SimpleStation14/Holograms/HoloServerComponent new file mode 100644 index 0000000000..c8849b8cec --- /dev/null +++ b/Content.Shared/SimpleStation14/Holograms/HoloServerComponent @@ -0,0 +1,6 @@ +namespace Content.Server.SimpleStation14.Hologram; + +[RegisterComponent] +public sealed class HologramServerComponent : Component +{ +} diff --git a/Content.Shared/SimpleStation14/Holograms/HologramComponent.cs b/Content.Shared/SimpleStation14/Holograms/HologramComponent.cs new file mode 100644 index 0000000000..cf5977531a --- /dev/null +++ b/Content.Shared/SimpleStation14/Holograms/HologramComponent.cs @@ -0,0 +1,12 @@ +namespace Content.Shared.SimpleStation14.Hologram; + +[RegisterComponent] +public sealed class HologramComponent : Component +{ + [ViewVariables] + public EntityUid? CurProjector; + + // Counter + [DataField("accumulator")] + public float Accumulator = 2f; +} diff --git a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs new file mode 100644 index 0000000000..015bc71fd5 --- /dev/null +++ b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs @@ -0,0 +1,27 @@ +// namespace Content.Shared.SimpleStation14.Hologram; + +// /// +// /// Raised when a hologram is being returned to its last visited projector. +// /// +// public sealed class HologramReturnEvent : EntityEventArgs +// { +// public HologramComponent Component; + +// public HologramReturnEvent(HologramComponent component) +// { +// Component = component; +// } +// } + +// /// +// /// Raised when a hologram is being killed and removed from the game world. +// /// +// public sealed class HologramKillEvent : EntityEventArgs +// { +// public HologramComponent Component; + +// public HologramKillEvent(HologramComponent component) +// { +// Component = component; +// } +// } diff --git a/Content.Shared/SimpleStation14/Holograms/HologramProjectorComponent.cs b/Content.Shared/SimpleStation14/Holograms/HologramProjectorComponent.cs new file mode 100644 index 0000000000..0bdcf59ba8 --- /dev/null +++ b/Content.Shared/SimpleStation14/Holograms/HologramProjectorComponent.cs @@ -0,0 +1,6 @@ +namespace Content.Shared.SimpleStation14.Hologram; + +[RegisterComponent] +public sealed class HologramProjectorComponent : Component +{ +} diff --git a/Content.Shared/SimpleStation14/Holograms/HolopodComponent.cs b/Content.Shared/SimpleStation14/Holograms/HolopodComponent.cs new file mode 100644 index 0000000000..21640ae990 --- /dev/null +++ b/Content.Shared/SimpleStation14/Holograms/HolopodComponent.cs @@ -0,0 +1,6 @@ +namespace Content.Server.SimpleStation14.Hologram; + +[RegisterComponent] +public sealed class HologramPodComponent : Component +{ +} diff --git a/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs new file mode 100644 index 0000000000..e7e1bb8223 --- /dev/null +++ b/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs @@ -0,0 +1,67 @@ +using Content.Shared.Interaction.Events; +using Content.Shared.Interaction.Components; +using Content.Shared.Damage; +using Content.Shared.Item; +using Content.Shared.Tag; +using Content.Shared.Interaction.Helpers; +using Content.Shared.Popups; +using Robust.Shared.Player; +using Robust.Shared.Timing; +using Robust.Shared.Serialization; + +namespace Content.Shared.SimpleStation14.Hologram; + +public class SharedHologramSystem : EntitySystem +{ + [Dependency] private readonly TagSystem _tagSystem = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] protected readonly SharedPopupSystem Popup = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnEntInserted); + } + + // Stops the Hologram from interacting with anything they shouldn't. + private void OnInteractionAttempt(EntityUid uid, HologramComponent component, InteractionAttemptEvent args) + { + if (args.Target == null) + return; + + if (TryComp(args.Target, out var dmg) && dmg.DamageContainerID == "Biological") + args.Cancel(); + + if (HasComp(args.Target) && !HasComp(args.Target) + && !_tagSystem.HasAnyTag(args.Target.Value, "Hardlight")) + args.Cancel(); + } + + /// + /// Handle adding keys to the ignition, give stuff the InVehicleComponent so it can't be picked + /// up by people not in the vehicle. + /// + private void OnEntInserted(EntityUid uid, HologramServerComponent component, EntInsertedIntoContainerMessage args) + { + if (args.Container.ID != DiskSlot || + !_entityManager.TryGetComponent(args.Entity, out var disk)) return; + + TryHoloGenerate(component.Owner, disk.HoloData!, _entityManager.GetComponent(component.Owner)); + } +} + + +// [Serializable, NetSerializable] +// public sealed class HoloTeleportEvent : EntityEventArgs +// { +// public readonly EntityUid Uid; +// public readonly List Lights; + +// public ShadekinDarkenEvent(EntityUid uid, List lights) +// { +// Uid = uid; +// Lights = lights; +// } +// } diff --git a/Resources/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg b/Resources/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg new file mode 100644 index 0000000000000000000000000000000000000000..d764f43bb70207f4a780580ffaad1a3a05a48309 GIT binary patch literal 8815 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%0DA5iNaUWE$2`yfFit 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 PS|M2fW#Q8sLFj(~Gh>a% literal 0 HcmV?d00001 diff --git a/Resources/Locale/en-US/SimpleStation14/holograms.ftl b/Resources/Locale/en-US/SimpleStation14/holograms.ftl new file mode 100644 index 0000000000..bfc06b6ded --- /dev/null +++ b/Resources/Locale/en-US/SimpleStation14/holograms.ftl @@ -0,0 +1,4 @@ +system-hologram-phasing-appear-self = You materialize into being! +system-hologram-phasing-appear-others = {$name} materializes into being! +system-hologram-phasing-disappear-others = {$name} dematerializes in a fizz! +system-hologram-phasing-death-self = You faze out of being! diff --git a/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml b/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml index 9512ee2df4..2b64b1d687 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml @@ -4,6 +4,7 @@ name: cloning pod description: A Cloning Pod. 50% reliable. components: + - type: Holopod - type: CloningPod - type: DeviceList - type: DeviceNetwork diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml index 554aa3937a..5bdc2494ab 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml @@ -4,6 +4,7 @@ name: camera description: A surveillance camera. It's watching you. Kinda. components: + - type: HologramProjector - type: Clickable - type: InteractionOutline - type: Construction diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml index 003b582af8..45ae3d0999 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml @@ -45,3 +45,76 @@ attributes: proper: true gender: male + +- type: entity + name: holo corgi + description: "A hologramatic projection of a corgi, computed by the AI and rendered by the station's cameras." + id: MobCorgiHolo22 + suffix: AI + components: + - type: LagCompensation + - type: Tag + tags: + - DoorBumpOpener + - type: InputMover + - type: MobMover + - type: HTN + rootTask: SimpleHostileCompound + - type: Input + context: "human" + - type: Faction + factions: + - Pet + - type: MovementSpeedModifier + baseWalkSpeed : 4.5 + baseSprintSpeed : 3 + - type: Sprite + noRot: true + drawdepth: Mobs + sprite: SimpleStation14/Mobs/Pets/corgi.rsi + layers: + - map: ["enum.DamageStateVisualLayers.Base"] + state: holo_corgi + netsync: false + - type: Clickable + - type: InteractionOutline + - type: Physics + bodyType: KinematicController # Same for all inheritors + - type: Fixtures + fixtures: + - shape: + # Circles, cuz rotation of rectangles looks very bad + !type:PhysShapeCircle + radius: 0.35 + density: 50 + mask: + - MobMask + layer: + - MobLayer + - type: MobState + - type: Body + prototype: Animal + - type: Examiner + - type: Appearance + - type: RotationVisuals + - type: Actions + - type: DoAfter + - type: Polymorphable + - type: StandingState + - type: Alerts + - type: FloatingVisuals + - type: NoSlip + - type: TypingIndicator + proto: holo + - type: ReplacementAccent + accent: dog + - type: InteractionPopup + interactSuccessString: hugging-success-hologram-others + interactSuccessSound: + path: /Audio/SimpleStation14/Effects/Hologram/holo_on.ogg + - type: Grammar + attributes: + gender: epicene + - type: DogVision + - type: RandomBark + - type: Hologram diff --git a/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml b/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml new file mode 100644 index 0000000000..3af21266fd --- /dev/null +++ b/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml @@ -0,0 +1,135 @@ +# - type: entity +# id: HoloChamber +# parent: BaseMachinePowered +# name: holo pod +# description: A Cloning Pod. 50% reliable. +# components: +# - type: CloningPod +# - type: DeviceList +# - type: DeviceNetwork +# deviceNetId: Wired +# - type: Sprite +# netsync: false +# sprite: Structures/Machines/cloning.rsi +# snapCardinals: true +# layers: +# - state: pod_0 +# - type: Physics +# bodyType: Static +# - type: Fixtures +# fixtures: +# - shape: +# !type:PhysShapeAabb +# bounds: "-0.25,-0.5,0.25,0.5" +# density: 190 +# mask: +# - MachineMask +# layer: +# - MachineLayer +# - type: Construction +# graph: Machine +# node: machine +# containers: +# - machine_board +# - machine_parts +# - clonepod-bodyContainer +# - type: SignalReceiver +# inputs: +# CloningPodReceiver: [] +# - type: EmptyOnMachineDeconstruct +# containers: +# - clonepod-bodyContainer +# - type: Destructible +# thresholds: +# - trigger: +# !type:DamageTrigger +# damage: 100 +# behaviors: +# - !type:ChangeConstructionNodeBehavior +# node: machineFrame +# - !type:DoActsBehavior +# acts: ["Destruction"] +# - type: Machine +# board: CloningPodMachineCircuitboard +# - type: MaterialStorage +# materialWhiteList: +# - Biomass +# - type: Wires +# BoardName: "CloningPod" +# LayoutId: CloningPod +# - type: ApcPowerReceiver +# powerLoad: 200 #Receives most of its power from the console +# - type: Appearance +# visuals: +# - type: GenericEnumVisualizer +# key: enum.CloningPodVisuals.Status +# layer: 0 +# states: +# enum.CloningPodStatus.Cloning: pod_1 +# enum.CloningPodStatus.NoMind: pod_e +# enum.CloningPodStatus.Gore: pod_g +# enum.CloningPodStatus.Idle: pod_0 +# - type: Climbable +# - type: DynamicPrice +# price: 1000 +# - type: ContainerContainer +# containers: +# machine_board: !type:Container +# machine_parts: !type:Container +# clonepod-bodyContainer: !type:ContainerSlot + +- type: entity + id: HologramServer + parent: BaseMachinePowered + name: hologram server + description: Contains the collective knowledge of holo + components: + - type: Sprite + sprite: Structures/Machines/server.rsi + state: server + - type: ApcPowerReceiver + powerLoad: 200 + priority: Low + - type: ExtensionCableReceiver + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 300 + behaviors: + - !type:DoActsBehavior + acts: ["Destruction"] + - !type:PlaySoundBehavior + sound: + path: /Audio/Effects/metalbreak.ogg + - !type:SpawnEntitiesBehavior + spawn: + SheetSteel1: + min: 1 + max: 2 + - type: AmbientSound + volume: -9 + range: 5 + sound: + path: /Audio/Ambience/Objects/server_fans.ogg + - type: HologramServer + - type: ItemSlots + slots: + holo_disk: #this slot name is important + name: Disk + whitelist: + requireAll: true + components: + - HoloDisk + - type: CloningPod + +- type: entity + parent: BaseItem + id: HologramDisk + name: holo disk + description: A disk for the holo + components: + - type: Sprite + sprite: Objects/Specific/Research/researchdisk.rsi + state: icon + - tpye: HologramDisk diff --git a/Resources/Textures/SimpleStation14/Mobs/Pets/corgi.rsi/holo_corgi.png b/Resources/Textures/SimpleStation14/Mobs/Pets/corgi.rsi/holo_corgi.png new file mode 100644 index 0000000000000000000000000000000000000000..a85cc5e0a5c9ab2fd7d7d57d725f11de7006aaf6 GIT binary patch literal 12178 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 UoK{jqTL1t607*qoM6N<$g2|) Date: Fri, 24 Feb 2023 22:51:45 -0500 Subject: [PATCH 05/25] Committing more --- .../Holograms/Systems/HologramServerSystem.cs | 22 ++++++++++++------- .../Holograms/HoloServerComponent | 2 +- .../Holograms/HologramEvents.cs | 21 +++++++++++++++++- .../Holograms/SharedHologramSystem.cs | 6 +++-- .../Machines/hologram_constructor.yml | 3 +++ Resources/Prototypes/SimpleStation14/tags.yml | 3 +++ 6 files changed, 45 insertions(+), 12 deletions(-) diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs index c51dc0f9f3..e57586dec5 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -68,18 +68,24 @@ public override void Initialize() base.Initialize(); // SubscribeLocalEvent(OnEntInserted); SubscribeLocalEvent(OnAfterInteract); + SubscribeNetworkEvent(TryHoloGenerate); } - public bool TryHoloGenerate(EntityUid uid, Mind.Mind mind, CloningPodComponent? clonePod) + public void TryHoloGenerate(HologramDiskInsertedEvent args) { + var uid = args.ServerComponent.Owner; + var clonePod = _entityManager.GetComponent(uid); + var disk = _entityManager.GetComponent(args.Uid); + var mind = disk.HoloData!; + CloningSystem cloneSys = new(); Logger.Info("Trying to clone"); if (!Resolve(uid, ref clonePod)) - return false; + return; if (HasComp(uid)) - return false; + return; Logger.Info("Clone pod is active"); @@ -89,25 +95,25 @@ public bool TryHoloGenerate(EntityUid uid, Mind.Mind mind, CloningPodComponent? !_mobStateSystem.IsDead(clone) && TryComp(clone, out var cloneMindComp) && (cloneMindComp.Mind == null || cloneMindComp.Mind == mind)) - return false; // Mind already has clone + return; // Mind already has clone ClonesWaitingForMind.Remove(mind); } Logger.Info("Waiting something something"); if (mind.OwnedEntity != null && !_mobStateSystem.IsDead(mind.OwnedEntity.Value)) - return false; // Body controlled by mind is not dead + return; // Body controlled by mind is not dead Logger.Info("Not alive still"); // Yes, we still need to track down the client because we need to open the Eui if (mind.UserId == null || !_playerManager.TryGetSessionById(mind.UserId.Value, out var client)) - return false; // If we can't track down the client, we can't offer transfer. That'd be quite bad. + return; // If we can't track down the client, we can't offer transfer. That'd be quite bad. Logger.Info("Got client"); var pref = (HumanoidCharacterProfile) _prefs.GetPreferences(mind.UserId.Value).SelectedCharacter; if (pref == null) - return false; + return; Logger.Info("Got prefs"); var mob = HoloFetchAndSpawn(clonePod, pref); @@ -136,7 +142,7 @@ public bool TryHoloGenerate(EntityUid uid, Mind.Mind mind, CloningPodComponent? } } - return true; + return; } public void UpdateStatus(CloningPodStatus status, CloningPodComponent cloningPod) diff --git a/Content.Shared/SimpleStation14/Holograms/HoloServerComponent b/Content.Shared/SimpleStation14/Holograms/HoloServerComponent index c8849b8cec..e3c856b4ad 100644 --- a/Content.Shared/SimpleStation14/Holograms/HoloServerComponent +++ b/Content.Shared/SimpleStation14/Holograms/HoloServerComponent @@ -1,4 +1,4 @@ -namespace Content.Server.SimpleStation14.Hologram; +namespace Content.Shared.SimpleStation14.Hologram; [RegisterComponent] public sealed class HologramServerComponent : Component diff --git a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs index 015bc71fd5..79e6be8cf3 100644 --- a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs +++ b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs @@ -1,4 +1,7 @@ -// namespace Content.Shared.SimpleStation14.Hologram; +using Content.Shared.SimpleStation14.Hologram; +using Robust.Shared.Serialization; + +namespace Content.Shared.SimpleStation14.Hologram; // /// // /// Raised when a hologram is being returned to its last visited projector. @@ -25,3 +28,19 @@ // Component = component; // } // } + +/// +/// Raised when a hologram is being killed and removed from the game world. +/// +[Serializable, NetSerializable] +public sealed class HologramDiskInsertedEvent : EntityEventArgs +{ + public EntityUid Uid; + public HologramServerComponent ServerComponent; + + public HologramDiskInsertedEvent(EntityUid uid, HologramServerComponent serverComponent) + { + Uid = uid; + ServerComponent = serverComponent; + } +} diff --git a/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs index e7e1bb8223..1ccb4f19d1 100644 --- a/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs @@ -8,6 +8,7 @@ using Robust.Shared.Player; using Robust.Shared.Timing; using Robust.Shared.Serialization; +using Robust.Shared.Containers; namespace Content.Shared.SimpleStation14.Hologram; @@ -19,6 +20,7 @@ public class SharedHologramSystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] protected readonly SharedPopupSystem Popup = default!; [Dependency] private readonly IGameTiming _timing = default!; + private const string DiskSlot = "holo_disk"; public override void Initialize() { @@ -46,9 +48,9 @@ private void OnInteractionAttempt(EntityUid uid, HologramComponent component, In private void OnEntInserted(EntityUid uid, HologramServerComponent component, EntInsertedIntoContainerMessage args) { if (args.Container.ID != DiskSlot || - !_entityManager.TryGetComponent(args.Entity, out var disk)) return; + !_tagSystem.HasTag(args.Entity, "HoloDisk")) return; - TryHoloGenerate(component.Owner, disk.HoloData!, _entityManager.GetComponent(component.Owner)); + RaiseNetworkEvent(new HologramDiskInsertedEvent(uid, component)); } } diff --git a/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml b/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml index 3af21266fd..2913f6dce7 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml @@ -133,3 +133,6 @@ sprite: Objects/Specific/Research/researchdisk.rsi state: icon - tpye: HologramDisk + - type: Tag + tags: + - HoloDisk diff --git a/Resources/Prototypes/SimpleStation14/tags.yml b/Resources/Prototypes/SimpleStation14/tags.yml index 2a653b5340..08cbc20b5e 100644 --- a/Resources/Prototypes/SimpleStation14/tags.yml +++ b/Resources/Prototypes/SimpleStation14/tags.yml @@ -4,6 +4,9 @@ - type: Tag id: Hardlight +- type: Tag + id: HoloDisk + - type: Tag id: Plushie From c0c4f96517e7fbe70f89711a2072d286e18833b5 Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Sun, 26 Feb 2023 14:00:50 -0500 Subject: [PATCH 06/25] More work on Holograms. Moved most things over to events, bug where hologram is deleted upon spawning and crashes as no hologram component is found? --- .../Holograms/HologramSystem.cs | 35 +++ .../Holograms/Components/HoloDiskComponent.cs | 2 +- .../Holograms/Systems/HologramServerSystem.cs | 244 +++++++++++------ .../Holograms/Systems/HologramSystem.cs | 245 +++++------------- ...ServerComponent => HoloServerComponent.cs} | 2 + .../Holograms/HologramComponent.cs | 3 + .../Holograms/HologramEvents.cs | 80 +++--- .../Holograms/SharedHologramSystem.cs | 80 +++++- .../Machines/Computers/computers.yml | 4 + .../Structures/Machines/cloning_machine.yml | 1 - .../Machines/wireless_surveillance_camera.yml | 1 + .../Entities/Mobs/Player/hologram.yml | 18 +- .../Machines/hologram_constructor.yml | 89 ++++--- 13 files changed, 448 insertions(+), 356 deletions(-) create mode 100644 Content.Client/SimpleStation14/Holograms/HologramSystem.cs rename Content.Shared/SimpleStation14/Holograms/{HoloServerComponent => HoloServerComponent.cs} (69%) diff --git a/Content.Client/SimpleStation14/Holograms/HologramSystem.cs b/Content.Client/SimpleStation14/Holograms/HologramSystem.cs new file mode 100644 index 0000000000..ff175a12ce --- /dev/null +++ b/Content.Client/SimpleStation14/Holograms/HologramSystem.cs @@ -0,0 +1,35 @@ +// using Content.Client.Gravity; +// using Content.Shared.Anomaly; +// using Content.Shared.Anomaly.Components; +// using Robust.Client.GameObjects; +// using Robust.Shared.Timing; +// using Content.Shared.SimpleStation14.Hologram; + +// namespace Content.Client.SimpleStation14.Hologram; + +// public sealed class HologramSystem : SharedHologramSystem +// { +// [Dependency] private readonly IGameTiming _timing = default!; +// [Dependency] private readonly FloatingVisualizerSystem _floating = default!; + +// /// +// public override void Initialize() +// { +// base.Initialize(); + +// SubscribeLocalEvent(OnStartup); +// SubscribeLocalEvent(OnAnimationComplete); +// } + +// private void OnStartup(EntityUid uid, HologramComponent component, ref ComponentStartup args) +// { +// _floating.FloatAnimation(uid, new Vector2(0f, 0.07f), "holofloat", 3); +// } + +// private void OnAnimationComplete(EntityUid uid, HologramComponent component, AnimationCompletedEvent args) +// { +// if (args.Key != "holofloat") +// return; +// _floating.FloatAnimation(uid, new Vector2(0, 0.15f), "holofloat", 3.5f); +// } +// } diff --git a/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs b/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs index b54d977719..d9ea85a6e8 100644 --- a/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs +++ b/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs @@ -1,4 +1,4 @@ -using static Content.Server.SimpleStation14.Hologram.HologramSystem; +// using static Content.Server.SimpleStation14.Hologram.HologramSystem; namespace Content.Server.SimpleStation14.Hologram; diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs index e57586dec5..cb5329b3f1 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -1,28 +1,7 @@ -using Content.Server.SurveillanceCamera; -using Content.Server.GameTicking; +using System.Linq; using Content.Server.Mind.Components; -using Content.Shared.Tag; -using Content.Shared.Popups; -using Content.Shared.Interaction.Helpers; -using Content.Shared.SimpleStation14.Hologram; -using Content.Shared.Actions; -using Content.Shared.Actions.ActionTypes; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; -using Content.Shared.Administration.Logs; -using Content.Shared.Database; -using Robust.Server.Player; -using Robust.Shared.Player; -using Robust.Shared.Timing; -using Robust.Shared.Map; -using Robust.Shared.Prototypes; using Content.Server.Cloning; using Content.Server.Cloning.Components; - -using Content.Shared.Cloning; -using Content.Shared.Speech; -using Content.Shared.Preferences; -using Content.Shared.Emoting; using Content.Server.Psionics; using Content.Server.Speech.Components; using Content.Server.StationEvents.Components; @@ -32,12 +11,28 @@ using Content.Server.Jobs; using Content.Server.Mind; using Content.Server.Preferences.Managers; +using Content.Server.Power.Components; +using Content.Server.Administration.Commands; +using Content.Shared.Tag; +using Content.Shared.Popups; +using Content.Shared.SimpleStation14.Hologram; +using Content.Shared.Pulling; +using Content.Shared.Administration.Logs; +using Content.Shared.Database; +using Content.Shared.Speech; +using Content.Shared.Preferences; +using Content.Shared.Emoting; using Content.Shared.Humanoid; using Content.Shared.Mobs.Systems; -using Robust.Shared.GameObjects.Components.Localization; -using System.Linq; -using Robust.Shared.Containers; using Content.Shared.Interaction; +using Content.Shared.Inventory; +using Content.Shared.Interaction.Components; +using Content.Shared.Access.Components; +using Content.Shared.Clothing.Components; +using Robust.Server.Player; +using Robust.Shared.Player; +using Robust.Shared.Containers; +using Robust.Shared.GameObjects.Components.Localization; namespace Content.Server.SimpleStation14.Hologram; @@ -59,6 +54,7 @@ public class HologramServerSystem : EntitySystem [Dependency] private readonly IServerPreferencesManager _prefs = default!; [Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly InventorySystem _inventory = default!; private const string DiskSlot = "holo_disk"; public readonly Dictionary ClonesWaitingForMind = new(); @@ -66,28 +62,91 @@ public class HologramServerSystem : EntitySystem public override void Initialize() { base.Initialize(); - // SubscribeLocalEvent(OnEntInserted); + SubscribeLocalEvent(OnEntInserted); + SubscribeLocalEvent(OnEntRemoved); SubscribeLocalEvent(OnAfterInteract); - SubscribeNetworkEvent(TryHoloGenerate); + SubscribeLocalEvent(OnPowerChanged); } - public void TryHoloGenerate(HologramDiskInsertedEvent args) + /// + /// Handles generating a hologram from an inserted disk + /// + private void OnEntInserted(EntityUid uid, HologramServerComponent component, EntInsertedIntoContainerMessage args) { - var uid = args.ServerComponent.Owner; - var clonePod = _entityManager.GetComponent(uid); - var disk = _entityManager.GetComponent(args.Uid); - var mind = disk.HoloData!; + if (args.Container.ID != DiskSlot || !_tagSystem.HasTag(args.Entity, "HoloDisk") || + (_entityManager.TryGetComponent(args.Entity, out var diskComp) && diskComp.HoloData == null)) return; - CloningSystem cloneSys = new(); - Logger.Info("Trying to clone"); + if (component.LinkedHologram != EntityUid.Invalid && _entityManager.EntityExists(component.LinkedHologram)) + { + RaiseLocalEvent(new HologramKillEvent(component.LinkedHologram.Value)); + } - if (!Resolve(uid, ref clonePod)) - return; + if (TryHoloGenerate(component.Owner, _entityManager.GetComponent(args.Entity).HoloData!, component, out var holo)) + { + var holoComp = _entityManager.GetComponent(holo); + component.LinkedHologram = holo; + holoComp.LinkedServer = component.Owner; + } + } - if (HasComp(uid)) - return; + /// + /// Handles killing a hologram when a disk is removed + /// + private void OnEntRemoved(EntityUid uid, HologramServerComponent component, EntRemovedFromContainerMessage args) + { + if (args.Container.ID != DiskSlot || !_tagSystem.HasTag(args.Entity, "HoloDisk") || + (_entityManager.TryGetComponent(args.Entity, out var diskComp) && diskComp.HoloData == null)) return; + + if (component.LinkedHologram != EntityUid.Invalid && _entityManager.EntityExists(component.LinkedHologram)) + { + RaiseLocalEvent(new HologramKillEvent(component.LinkedHologram.Value)); + } + } + + /// + /// Called when the server's power state changes + /// + /// The entity uid of the server + /// The HologramServerComponent + /// The PowerChangedEvent + private void OnPowerChanged(EntityUid uid, HologramServerComponent component, ref PowerChangedEvent args) + { + // If the server is no longer powered + if (!args.Powered && component.LinkedHologram != null && component.LinkedHologram != EntityUid.Invalid) + { + // If the hologram exists + if (component != null && _entityManager.EntityExists(component.LinkedHologram)) + { + // Kill the Holgram + RaiseLocalEvent(new HologramKillEvent(component.LinkedHologram.Value)); + } + } + // If the server is powered + else if (args.Powered && component.LinkedHologram == EntityUid.Invalid) + { + var serverContainer = _entityManager.GetComponent(component.Owner); + if (serverContainer.GetContainer(DiskSlot).ContainedEntities.Count <= 0) + { + return; // No disk in the server + } + var disk = serverContainer.GetContainer(DiskSlot).ContainedEntities.First(); + var diskData = _entityManager.GetComponent(disk).HoloData; - Logger.Info("Clone pod is active"); + // If the hologram is generated successfully + if (diskData != null && TryHoloGenerate(component.Owner, diskData, component, out var holo)) + { + // Set the linked hologram to the generated hologram + var holoComp = _entityManager.GetComponent(holo); + component.LinkedHologram = holo; + holoComp.LinkedServer = component.Owner; + } + } + } + + public bool TryHoloGenerate(EntityUid uid, Mind.Mind mind, HologramServerComponent? holoServer, out EntityUid holo) + { + CloningSystem cloneSys = new(); + holo = EntityUid.Invalid; if (ClonesWaitingForMind.TryGetValue(mind, out var clone)) { @@ -95,44 +154,30 @@ public void TryHoloGenerate(HologramDiskInsertedEvent args) !_mobStateSystem.IsDead(clone) && TryComp(clone, out var cloneMindComp) && (cloneMindComp.Mind == null || cloneMindComp.Mind == mind)) - return; // Mind already has clone + return false; // Mind already has clone ClonesWaitingForMind.Remove(mind); } - Logger.Info("Waiting something something"); - if (mind.OwnedEntity != null && !_mobStateSystem.IsDead(mind.OwnedEntity.Value)) - return; // Body controlled by mind is not dead - Logger.Info("Not alive still"); + if (mind.OwnedEntity != null && (_mobStateSystem.IsAlive(mind.OwnedEntity.Value) || _mobStateSystem.IsCritical(mind.OwnedEntity.Value))) + return false; // Body controlled by mind is not dead // Yes, we still need to track down the client because we need to open the Eui if (mind.UserId == null || !_playerManager.TryGetSessionById(mind.UserId.Value, out var client)) - return; // If we can't track down the client, we can't offer transfer. That'd be quite bad. - Logger.Info("Got client"); + return false; // If we can't track down the client, we can't offer transfer. That'd be quite bad. var pref = (HumanoidCharacterProfile) _prefs.GetPreferences(mind.UserId.Value).SelectedCharacter; if (pref == null) - return; - Logger.Info("Got prefs"); + return false; - var mob = HoloFetchAndSpawn(clonePod, pref); + var mob = HoloFetchAndSpawn(holoServer!, pref); var cloneMindReturn = EntityManager.AddComponent(mob); cloneMindReturn.Mind = mind; - cloneMindReturn.Parent = clonePod.Owner; - // clonePod.BodyContainer.Insert(mob); ClonesWaitingForMind.Add(mind, mob); - UpdateStatus(CloningPodStatus.NoMind, clonePod); - _euiManager.OpenEui(new AcceptCloningEui(mind, cloneSys), client); - - Logger.Warning("Cloned"); + TransferMindToClone(mind); - AddComp(uid); - - // TODO: Ideally, components like this should be on a mind entity so this isn't neccesary. - // Remove this when 'mind entities' are added. - // Add on special job components to the mob. if (mind.CurrentJob != null) { foreach (var special in mind.CurrentJob.Prototype.Special) @@ -140,26 +185,69 @@ public void TryHoloGenerate(HologramDiskInsertedEvent args) if (special is AddComponentSpecial) special.AfterEquip(mob); } + + // Get each access from the job prototype and add it to the mob + foreach (var access in mind.CurrentJob.Prototype.Access) + { + var accessComp = EntityManager.EnsureComponent(mob); + accessComp.Tags.Add(access); + } + + // Get the loadout from the job prototype and add it to the Hologram + // making each item unremovable and hardlight. + if (mind.CurrentJob.Prototype.StartingGear != null) + { + SetOutfitCommand.SetOutfit(mob, mind.CurrentJob.Prototype.StartingGear, _entityManager, (_, item) => + { + if (_entityManager.TryGetComponent(item, out var clothing)) + { + if (clothing.InSlot == "back" || clothing.InSlot == "pocket1" || clothing.InSlot == "pocket2" || + clothing.InSlot == "belt" || clothing.InSlot == "suitstorage" || clothing.InSlot == "id") + { + _entityManager.DeleteEntity(item); + return; + } + } + _tagSystem.AddTag(item, "Hardlight"); + _entityManager.EnsureComponent(item); + }); + } + } - return; + _adminLogger.Add(LogType.Unknown, LogImpact.Medium, + $"{ToPrettyString(mob):mob} was generated at {ToPrettyString((EntityUid) uid):entity}"); + + holo = mob; + return true; } - public void UpdateStatus(CloningPodStatus status, CloningPodComponent cloningPod) + internal void TransferMindToClone(Mind.Mind mind) { - cloningPod.Status = status; + if (!ClonesWaitingForMind.TryGetValue(mind, out var entity) || + !EntityManager.EntityExists(entity) || + !TryComp(entity, out var mindComp) || + mindComp.Mind != null) + return; + + mind.TransferTo(entity, ghostCheckOverride: true); + mind.UnVisit(); + ClonesWaitingForMind.Remove(mind); } /// /// Handles fetching the mob and any appearance stuff... /// - private EntityUid HoloFetchAndSpawn(CloningPodComponent clonePod, HumanoidCharacterProfile pref) + private EntityUid HoloFetchAndSpawn(HologramServerComponent holoServer, HumanoidCharacterProfile pref) { + List sexes = new(); var name = pref.Name; var toSpawn = "MobHologram"; - var mob = Spawn(toSpawn, Transform(clonePod.Owner).MapPosition); + var mob = Spawn(toSpawn, Transform(holoServer.Owner).MapPosition); + _entityManager.GetComponent(mob).AttachToGridOrMap(); + _humanoidSystem.LoadProfile(mob, pref); MetaData(mob).EntityName = name; @@ -171,27 +259,35 @@ private EntityUid HoloFetchAndSpawn(CloningPodComponent clonePod, HumanoidCharac grammar.Gender = Robust.Shared.Enums.Gender.Neuter; Dirty(grammar); - RemComp(mob); + var meta = _entityManager.GetComponent(mob); + var popupAppearOther = Loc.GetString("system-hologram-phasing-appear-others", ("name", meta.EntityName)); + var popupAppearSelf = Loc.GetString("system-hologram-phasing-appear-self"); + + Popup.PopupEntity(popupAppearOther, mob, Filter.PvsExcept((EntityUid) mob), false, PopupType.Medium); + Popup.PopupEntity(popupAppearSelf, mob, mob, PopupType.Large); + _audio.PlayPvs("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg", mob); + EnsureComp(mob); EnsureComp(mob); - RemComp(mob); - RemComp(mob); - RemComp(mob); - RemComp(mob); + EnsureComp(mob); + RemComp(mob); _tag.AddTag(mob, "DoorBumpOpener"); return mob; } - private void OnAfterInteract(EntityUid uid, HologramDiskComponent component, AfterInteractEvent args) { - if (args.Target == null || !TryComp(args.Target, out var targetMind) || targetMind.Mind == null) + if (args.Target == null || !TryComp(args.Target, out var targetMind)) + return; + if (targetMind.Mind == null) + { + Popup.PopupEntity(Loc.GetString("system-hologram-disk-mind-none"), args.Target.Value, args.User); return; + } component.HoloData = targetMind.Mind; - Popup.PopupEntity(Loc.GetString("Data saved, boi"), args.Target.Value, args.User); + Popup.PopupEntity(Loc.GetString("system-hologram-disk-mind-saved"), args.Target.Value, args.User); } - } diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs index 4fd0b09e3d..9365401a60 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs @@ -36,6 +36,7 @@ using Content.Shared.Mobs.Systems; using Robust.Shared.GameObjects.Components.Localization; using System.Linq; +using Robust.Shared.Utility; namespace Content.Server.SimpleStation14.Hologram; @@ -61,6 +62,8 @@ public class HologramSystem : EntitySystem public override void Initialize() { base.Initialize(); + SubscribeAllEvent(HoloKill); + SubscribeAllEvent(HoloGetProjector); // SubscribeLocalEvent(Startup); // SubscribeLocalEvent(Shutdown); // SubscribeLocalEvent(HoloTeleport); @@ -86,17 +89,56 @@ public override void Update(float frameTime) foreach (var component in _entityManager.EntityQuery().ToList()) { - var projector = HoloGetProjector(component); - if (projector == EntityUid.Invalid) + var projectorEvent = new HologramGetProjectorEvent(component.Owner); + RaiseLocalEvent(component.Owner, projectorEvent); + Logger.DebugS("holo", "Hologram {0} has projector {1}", component.Owner, projectorEvent.Projector); + if (projectorEvent.Projector == EntityUid.Invalid || !projectorEvent.Projector.IsValid()) { - HoloReturn(component); + RaiseNetworkEvent(new HologramReturnEvent(component.Owner)); + Logger.Debug("wawawah"); continue; } - component.CurProjector = projector; + component.CurProjector = projectorEvent.Projector; } } + /// + /// Tests for the nearest projector to the Hologram. + /// + /// Event arguments. + public void HoloGetProjector(HologramGetProjectorEvent args) + { + var uid = args.Hologram; + var component = _entityManager.GetComponent(uid); + var occlude = args.Occlude; + var range = args.Range; + + var xformQuery = GetEntityQuery(); + var transform = _entityManager.GetComponent(uid); + var playerPos = _transform.GetWorldPosition(transform, xformQuery); + var mapId = transform.MapID; + + // sort all entities in distance increasing order + var nearProjList = new SortedList(); + + foreach (var comp in _entityManager.EntityQuery()) + { + if (!xformQuery.TryGetComponent(comp.Owner, out var compXform) || compXform.MapID != mapId) + continue; + + var dist = (_transform.GetWorldPosition(compXform, xformQuery) - playerPos).LengthSquared; + nearProjList.TryAdd(dist, comp.Owner); + } + foreach (var nearProj in nearProjList) + { + if (_entityManager.TryGetComponent(nearProj.Value, out var camComp) && !camComp.Active) continue; + if (occlude && !nearProj.Value.InRangeUnOccluded(uid, 18f)) continue; + args.Projector = nearProj.Value; + return; + } + return; + } /// /// Tests for the nearest projector to the Hologram. @@ -105,7 +147,7 @@ public override void Update(float frameTime) /// Should it check only for unoccluded and in range projectors? /// The range it should check for projectors in, if occlude is true /// Returns the UID of the projector, or invalid UID if no projectors are found. - private EntityUid HoloGetProjector(HologramComponent component, bool occlude = true, float range = 18f) + public EntityUid HoloGetProjector(HologramComponent component, bool occlude = true, float range = 18f) { var xformQuery = GetEntityQuery(); var uid = component.Owner; @@ -142,7 +184,7 @@ private EntityUid HoloGetProjector(HologramComponent component, bool occlude = t /// Should it check only for unoccluded and in range projectors? /// The range it should check for projectors in, if occlude is true /// Returns the UID of the projector, or invalid UID if no projectors are found. - private EntityUid HoloGetProjector(Vector2 coords, MapId mapId, bool occlude = true, float range = 18f) + public EntityUid HoloGetProjector(Vector2 coords, MapId mapId, bool occlude = true, float range = 18f) { var xformQuery = GetEntityQuery(); @@ -167,60 +209,14 @@ private EntityUid HoloGetProjector(Vector2 coords, MapId mapId, bool occlude = t return EntityUid.Invalid; } - - /// - /// Handles returning a Hologram to their last visited projector, - /// then to the nearest, finally killing them if none are found. - /// - /// Hologram's HologramComponent. - private void HoloReturn(HologramComponent component) - { - var uid = component.Owner; - var meta = _entityManager.GetComponent(uid); - var holoPos = _entityManager.GetComponent(uid).Coordinates; - - var popupAppearOther = Loc.GetString("system-hologram-phasing-appear-others", ("name", meta.EntityName)); - var popupAppearSelf = Loc.GetString("system-hologram-phasing-appear-self"); - var popupDisappearOther = Loc.GetString("system-hologram-phasing-disappear-others", ("name", meta.EntityName)); - var popupDeathSelf = Loc.GetString("system-hologram-phasing-death-self"); - - if (component.CurProjector == null || !_entityManager.TryGetComponent(component.CurProjector, out var _) || - (_entityManager.TryGetComponent(component.CurProjector, out var camComp) && !camComp.Active)) - { - component.CurProjector = HoloGetProjector(component, false); - } - - if (component.CurProjector == EntityUid.Invalid) - { - - HoloKill(component); - return; - } - _entityManager.TryGetComponent(component.CurProjector, out var transfComp); - - Popup.PopupEntity(popupAppearOther, uid, Filter.PvsExcept((EntityUid) uid), false, PopupType.Medium); - Popup.PopupCoordinates(popupDisappearOther, holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); - _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(uid), coordinates: holoPos, false); - if (TryComp(uid, out var pullable) && pullable.BeingPulled) _pulling.TryStopPull(pullable); - if (TryComp(uid, out var pulling) && pulling.Pulling != null && - TryComp(pulling.Pulling.Value, out var subjectPulling)) _pulling.TryStopPull(subjectPulling); - // Move holo - Transform(uid).Coordinates = _entityManager.GetComponent((EntityUid) component.CurProjector).Coordinates; - Popup.PopupEntity(popupAppearSelf, uid, uid, PopupType.Large); - _audio.PlayPvs("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg", uid); - - _adminLogger.Add(LogType.Unknown, LogImpact.Low, - $"{ToPrettyString(uid):mob} was returned to projector {ToPrettyString((EntityUid) component.CurProjector):entity}"); - } - /// /// Kills a Hologram after playing the visual and auditory effects. /// /// Hologram's HologramComponent. - - private void HoloKill(HologramComponent component) + public void HoloKill(HologramKillEvent args) { - var uid = component.Owner; + var uid = args.Uid; + var component = _entityManager.GetComponent(uid); var meta = _entityManager.GetComponent(uid); var holoPos = _entityManager.GetComponent(uid).Coordinates; EntityUid? body = EntityUid.Invalid; @@ -241,131 +237,18 @@ private void HoloKill(HologramComponent component) _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(uid), coordinates: holoPos, false); Popup.PopupCoordinates(popupDisappearOther, holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); Popup.PopupCoordinates(popupDeathSelf, holoPos, uid, PopupType.LargeCaution); + if (component.LinkedServer != EntityUid.Invalid) + { + if (_entityManager.TryGetComponent(component.LinkedServer!.Value, out var serverComp)) + serverComp.LinkedHologram = EntityUid.Invalid; + component.LinkedServer = EntityUid.Invalid; + } + _entityManager.DeleteEntity(uid); _adminLogger.Add(LogType.Unknown, LogImpact.Medium, $"{ToPrettyString(uid):mob} was disabled due to lack of projectors"); - - // var holopodQuery = _entityManager.EntityQuery(); - // while (true) - // { - // Logger.Info("Check"); - // foreach (var holopod in holopodQuery) - // { - // if (mind != null && TryHoloGenerate(holopod.Owner, mind, _entityManager.GetComponent(holopod.Owner))) - // { - // Logger.Warning("They got cloned!"); - // return; - // } - // } - // } } - - // public bool TryHoloGenerate(EntityUid uid, Mind.Mind mind, CloningPodComponent? clonePod) - // { - // CloningSystem cloneSys = new(); - // Logger.Info("Trying to clone"); - - // if (!Resolve(uid, ref clonePod)) - // return false; - - // if (HasComp(uid)) - // return false; - - // Logger.Info("Clone pod is active"); - - // if (ClonesWaitingForMind.TryGetValue(mind, out var clone)) - // { - // if (EntityManager.EntityExists(clone) && - // !_mobStateSystem.IsDead(clone) && - // TryComp(clone, out var cloneMindComp) && - // (cloneMindComp.Mind == null || cloneMindComp.Mind == mind)) - // return false; // Mind already has clone - - // ClonesWaitingForMind.Remove(mind); - // } - // Logger.Info("Waiting something something"); - - // if (mind.OwnedEntity != null && !_mobStateSystem.IsDead(mind.OwnedEntity.Value)) - // return false; // Body controlled by mind is not dead - // Logger.Info("Not alive still"); - - // // Yes, we still need to track down the client because we need to open the Eui - // if (mind.UserId == null || !_playerManager.TryGetSessionById(mind.UserId.Value, out var client)) - // return false; // If we can't track down the client, we can't offer transfer. That'd be quite bad. - // Logger.Warning("Got client"); - - // var pref = (HumanoidCharacterProfile) _prefs.GetPreferences(mind.UserId.Value).SelectedCharacter; - - // if (pref == null) - // return false; - // Logger.Warning("Got prefs"); - - // var mob = HoloFetchAndSpawn(clonePod, pref); - - // var cloneMindReturn = EntityManager.AddComponent(mob); - // cloneMindReturn.Mind = mind; - // cloneMindReturn.Parent = clonePod.Owner; - // clonePod.BodyContainer.Insert(mob); - // ClonesWaitingForMind.Add(mind, mob); - // _cloningSystem.UpdateStatus(CloningPodStatus.NoMind, clonePod); - // _euiManager.OpenEui(new AcceptCloningEui(mind, cloneSys), client); - - // AddComp(uid); - - // // TODO: Ideally, components like this should be on a mind entity so this isn't neccesary. - // // Remove this when 'mind entities' are added. - // // Add on special job components to the mob. - // if (mind.CurrentJob != null) - // { - // foreach (var special in mind.CurrentJob.Prototype.Special) - // { - // if (special is AddComponentSpecial) - // special.AfterEquip(mob); - // } - // } - - // return true; - // } - - - // /// - // /// Handles fetching the mob and any appearance stuff... - // /// - // private EntityUid HoloFetchAndSpawn(CloningPodComponent clonePod, HumanoidCharacterProfile pref) - // { - // List sexes = new(); - // var name = pref.Name; - // var toSpawn = "MobHologram"; - - // var mob = Spawn(toSpawn, Transform(clonePod.Owner).MapPosition); - // _humanoidSystem.LoadProfile(mob, pref); - - // MetaData(mob).EntityName = name; - // var mind = EnsureComp(mob); - // _mind.SetExamineInfo(mob, true, mind); - - // var grammar = EnsureComp(mob); - // grammar.ProperNoun = true; - // grammar.Gender = Robust.Shared.Enums.Gender.Neuter; - // Dirty(grammar); - - // RemComp(mob); - // EnsureComp(mob); - // EnsureComp(mob); - // RemComp(mob); - // RemComp(mob); - // RemComp(mob); - // RemComp(mob); - - // _tag.AddTag(mob, "DoorBumpOpener"); - - // return mob; - // } - - - - // private void HoloTeleport(HoloTeleportEvent args) // { // if (args.Handled) return; @@ -383,15 +266,5 @@ private void HoloKill(HologramComponent component) // args.Handled = true; // } - - public struct HoloDataEntry { - public Mind.Mind Mind; - public HumanoidCharacterProfile Profile; - - public HoloDataEntry(Mind.Mind m, HumanoidCharacterProfile hcp) - { - Mind = m; - Profile = hcp; - } - } + // } } diff --git a/Content.Shared/SimpleStation14/Holograms/HoloServerComponent b/Content.Shared/SimpleStation14/Holograms/HoloServerComponent.cs similarity index 69% rename from Content.Shared/SimpleStation14/Holograms/HoloServerComponent rename to Content.Shared/SimpleStation14/Holograms/HoloServerComponent.cs index e3c856b4ad..14684df47b 100644 --- a/Content.Shared/SimpleStation14/Holograms/HoloServerComponent +++ b/Content.Shared/SimpleStation14/Holograms/HoloServerComponent.cs @@ -3,4 +3,6 @@ namespace Content.Shared.SimpleStation14.Hologram; [RegisterComponent] public sealed class HologramServerComponent : Component { + [ViewVariables] + public EntityUid? LinkedHologram; } diff --git a/Content.Shared/SimpleStation14/Holograms/HologramComponent.cs b/Content.Shared/SimpleStation14/Holograms/HologramComponent.cs index cf5977531a..a1c90baa63 100644 --- a/Content.Shared/SimpleStation14/Holograms/HologramComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/HologramComponent.cs @@ -3,6 +3,9 @@ namespace Content.Shared.SimpleStation14.Hologram; [RegisterComponent] public sealed class HologramComponent : Component { + [ViewVariables] + public EntityUid? LinkedServer; + [ViewVariables] public EntityUid? CurProjector; diff --git a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs index 79e6be8cf3..8d58c49254 100644 --- a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs +++ b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs @@ -3,44 +3,66 @@ namespace Content.Shared.SimpleStation14.Hologram; -// /// -// /// Raised when a hologram is being returned to its last visited projector. -// /// -// public sealed class HologramReturnEvent : EntityEventArgs -// { -// public HologramComponent Component; - -// public HologramReturnEvent(HologramComponent component) -// { -// Component = component; -// } -// } - -// /// -// /// Raised when a hologram is being killed and removed from the game world. -// /// -// public sealed class HologramKillEvent : EntityEventArgs -// { -// public HologramComponent Component; - -// public HologramKillEvent(HologramComponent component) -// { -// Component = component; -// } -// } +/// +/// Raised when a hologram is being returned to its last visited projector. +/// +[Serializable, NetSerializable] +public sealed class HologramReturnEvent : EntityEventArgs +{ + public EntityUid Uid; + + public HologramReturnEvent(EntityUid uid) + { + Uid = uid; + } +} /// /// Raised when a hologram is being killed and removed from the game world. /// [Serializable, NetSerializable] -public sealed class HologramDiskInsertedEvent : EntityEventArgs +public sealed class HologramKillEvent : EntityEventArgs { public EntityUid Uid; - public HologramServerComponent ServerComponent; - public HologramDiskInsertedEvent(EntityUid uid, HologramServerComponent serverComponent) + public HologramKillEvent(EntityUid uid) { Uid = uid; - ServerComponent = serverComponent; + } +} + +/// +/// Raised to return a bool if a given projector is valid for a given hologram. +/// +[Serializable, NetSerializable] +public sealed class HologramProjectorValidEvent : EntityEventArgs +{ + public EntityUid Hologram; + public EntityUid Projector; + public bool Valid = false; + + public HologramProjectorValidEvent(EntityUid hologram, EntityUid projector) + { + Hologram = hologram; + Projector = projector; + } +} + +/// +/// Raised to return the nearest projector to a given hologram. +/// +[Serializable, NetSerializable] +public sealed class HologramGetProjectorEvent : EntityEventArgs +{ + public EntityUid Hologram; + public bool Occlude; + public float Range; + public EntityUid Projector; + + public HologramGetProjectorEvent(EntityUid hologram, bool occlude = true, float range = 18f) + { + Hologram = hologram; + Occlude = occlude; + Range = range; } } diff --git a/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs index 1ccb4f19d1..375654032d 100644 --- a/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs @@ -9,6 +9,11 @@ using Robust.Shared.Timing; using Robust.Shared.Serialization; using Robust.Shared.Containers; +using Content.Shared.Computer; +using Content.Shared.Pulling.Components; +using Content.Shared.Administration.Logs; +using Content.Shared.Database; +using Content.Shared.Pulling; namespace Content.Shared.SimpleStation14.Hologram; @@ -20,11 +25,14 @@ public class SharedHologramSystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] protected readonly SharedPopupSystem Popup = default!; [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly SharedPullingSystem _pulling = default!; private const string DiskSlot = "holo_disk"; public override void Initialize() { - SubscribeLocalEvent(OnEntInserted); + SubscribeLocalEvent(OnInteractionAttempt); + SubscribeNetworkEvent(HoloReturn); } // Stops the Hologram from interacting with anything they shouldn't. @@ -33,24 +41,70 @@ private void OnInteractionAttempt(EntityUid uid, HologramComponent component, In if (args.Target == null) return; - if (TryComp(args.Target, out var dmg) && dmg.DamageContainerID == "Biological") - args.Cancel(); - - if (HasComp(args.Target) && !HasComp(args.Target) - && !_tagSystem.HasAnyTag(args.Target.Value, "Hardlight")) - args.Cancel(); + if (HasComp(args.Target) && !HasComp(args.Target) + && !_tagSystem.HasAnyTag(args.Target.Value, "Hardlight")) args.Cancel(); } /// - /// Handle adding keys to the ignition, give stuff the InVehicleComponent so it can't be picked - /// up by people not in the vehicle. + /// Handles returning a Hologram to their last visited projector, + /// then to the nearest, finally killing them if none are found. /// - private void OnEntInserted(EntityUid uid, HologramServerComponent component, EntInsertedIntoContainerMessage args) + /// Hologram's HologramComponent. + public void HoloReturn(HologramReturnEvent args) { - if (args.Container.ID != DiskSlot || - !_tagSystem.HasTag(args.Entity, "HoloDisk")) return; + var uid = args.Uid; + var component = _entityManager.GetComponent(uid); + var meta = _entityManager.GetComponent(uid); + var holoPos = _entityManager.GetComponent(uid).Coordinates; + + var popupAppearOther = Loc.GetString("system-hologram-phasing-appear-others", ("name", meta.EntityName)); + var popupAppearSelf = Loc.GetString("system-hologram-phasing-appear-self"); + var popupDisappearOther = Loc.GetString("system-hologram-phasing-disappear-others", ("name", meta.EntityName)); + var popupDeathSelf = Loc.GetString("system-hologram-phasing-death-self"); + + // If the Hologram's last projector isn't valid, try to find a new one. + if (component.CurProjector != null && _entityManager.TryGetComponent(component.CurProjector, out var _)) + { + var curProjEvent = new HologramProjectorValidEvent(uid, component.CurProjector.Value); + RaiseNetworkEvent(curProjEvent); + if (!curProjEvent.Valid) + { + var getProj = new HologramGetProjectorEvent(uid, false); + component.CurProjector = getProj.Projector; + } + } + else + { + var getProj = new HologramGetProjectorEvent(uid, false); + component.CurProjector = getProj.Projector; + } + + // If the Hologram's last projector is still invalid, kill them. + if (component.CurProjector == EntityUid.Invalid) + { + + RaiseNetworkEvent(new HologramKillEvent(uid)); + return; + } + + _entityManager.TryGetComponent(component.CurProjector, out var transfComp); + Popup.PopupCoordinates(popupDisappearOther, holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); + _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(uid), coordinates: holoPos, false); + + // Preapre to move holo + if (TryComp(uid, out var pullable) && pullable.BeingPulled) _pulling.TryStopPull(pullable); + if (TryComp(uid, out var pulling) && pulling.Pulling != null && + TryComp(pulling.Pulling.Value, out var subjectPulling)) _pulling.TryStopPull(subjectPulling); + + // Move holo + Transform(uid).Coordinates = _entityManager.GetComponent((EntityUid) component.CurProjector).Coordinates; + + Popup.PopupEntity(popupAppearOther, uid, Filter.PvsExcept((EntityUid) uid), false, PopupType.Medium); + Popup.PopupEntity(popupAppearSelf, uid, uid, PopupType.Large); + _audio.PlayPvs("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg", uid); - RaiseNetworkEvent(new HologramDiskInsertedEvent(uid, component)); + _adminLogger.Add(LogType.Unknown, LogImpact.Low, + $"{ToPrettyString(uid):mob} was returned to projector {ToPrettyString((EntityUid) component.CurProjector):entity}"); } } diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml index 27ad39fafb..35ada2f993 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml @@ -16,6 +16,10 @@ state: alert-2 - map: ["computerLayerKeys"] state: atmos_key + - type: Tag + tags: + - Hardlight + - type: entity parent: BaseComputer diff --git a/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml b/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml index 2b64b1d687..9512ee2df4 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml @@ -4,7 +4,6 @@ name: cloning pod description: A Cloning Pod. 50% reliable. components: - - type: Holopod - type: CloningPod - type: DeviceList - type: DeviceNetwork diff --git a/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml b/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml index d69eb96f62..25a4e21e02 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml @@ -5,6 +5,7 @@ name: wireless camera description: A camera. It's watching you. Kinda. components: + - type: HologramProjector - type: InteractionOutline - type: Eye - type: WirelessNetworkConnection diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml index 71b74aed3e..4950c84616 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml @@ -92,18 +92,19 @@ - type: Physics bodyType: KinematicController - type: Fixtures - fixtures: # TODO: This needs a second fixture just for mob collisions. + fixtures: - shape: !type:PhysShapeCircle radius: 0.35 - density: 50 + density: 25 mask: - - MobMask + - FlyingMobMask layer: - - MobLayer + - FlyingMobLayer - type: MovementSpeedModifier baseWalkSpeed : 5 baseSprintSpeed : 3.5 + - type: MovementIgnoreGravity - type: Hands showInHands: false - type: Body @@ -123,8 +124,7 @@ - type: TypingIndicator proto: holo - type: RotationVisuals - - type: FloatingVisuals - force: true + # - type: FloatingVisuals - type: Speech speechSounds: Tenor - type: Vocal @@ -148,6 +148,8 @@ components: # - type: CombatMode # disarm: null + - type: Stealth + lastVisibility: 0.83 - type: InteractionPopup successChance: 1 interactSuccessString: hugging-success-hologram @@ -193,5 +195,7 @@ - Service - Binary - type: PointLight - radius: 3.5 + radius: 1.3 softness: 1 + color: "#00FFFF" + energy: 3 diff --git a/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml b/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml index 2913f6dce7..4b28140d4d 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml @@ -84,44 +84,43 @@ name: hologram server description: Contains the collective knowledge of holo components: - - type: Sprite - sprite: Structures/Machines/server.rsi - state: server - - type: ApcPowerReceiver - powerLoad: 200 - priority: Low - - type: ExtensionCableReceiver - - type: Destructible - thresholds: - - trigger: - !type:DamageTrigger - damage: 300 - behaviors: - - !type:DoActsBehavior - acts: ["Destruction"] - - !type:PlaySoundBehavior - sound: - path: /Audio/Effects/metalbreak.ogg - - !type:SpawnEntitiesBehavior - spawn: - SheetSteel1: - min: 1 - max: 2 - - type: AmbientSound - volume: -9 - range: 5 - sound: - path: /Audio/Ambience/Objects/server_fans.ogg - - type: HologramServer - - type: ItemSlots - slots: - holo_disk: #this slot name is important - name: Disk - whitelist: - requireAll: true - components: - - HoloDisk - - type: CloningPod + - type: Sprite + sprite: Structures/Machines/server.rsi + state: server + - type: ApcPowerReceiver + powerLoad: 200 + priority: Low + - type: ExtensionCableReceiver + - type: Destructible + thresholds: + - trigger: !type:DamageTrigger + damage: 300 + behaviors: + - !type:DoActsBehavior + acts: ["Destruction"] + - !type:PlaySoundBehavior + sound: + path: /Audio/Effects/metalbreak.ogg + - !type:SpawnEntitiesBehavior + spawn: + SheetSteel1: + min: 1 + max: 2 + - type: AmbientSound + volume: -9 + range: 5 + sound: + path: /Audio/Ambience/Objects/server_fans.ogg + # - type: CloningPod + - type: HologramServer + - type: ItemSlots + slots: + holo_disk: #this slot name is important + name: Disk + whitelist: + requireAll: true + tags: + - HoloDisk - type: entity parent: BaseItem @@ -129,10 +128,10 @@ name: holo disk description: A disk for the holo components: - - type: Sprite - sprite: Objects/Specific/Research/researchdisk.rsi - state: icon - - tpye: HologramDisk - - type: Tag - tags: - - HoloDisk + - type: Sprite + sprite: Objects/Specific/Research/researchdisk.rsi + state: icon + - type: HologramDisk + - type: Tag + tags: + - HoloDisk From b1cefe2aa6c1d16b5ba89557c422997b8735cf6e Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Mon, 27 Feb 2023 13:17:20 -0500 Subject: [PATCH 07/25] Fixed holocorgi ID --- .../Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml index 45ae3d0999..5521eed937 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml @@ -49,7 +49,7 @@ - type: entity name: holo corgi description: "A hologramatic projection of a corgi, computed by the AI and rendered by the station's cameras." - id: MobCorgiHolo22 + id: MobCorgiHolo suffix: AI components: - type: LagCompensation From 4f45ffd3a7e0012c0f140e81041446451b924535 Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Tue, 28 Feb 2023 06:58:40 -0500 Subject: [PATCH 08/25] Fuckin working again. Stuff is networked now, though not to any real benefit. There's a grace period upon leaving a projector of one 24th of a second before you get returned. --- .../Holograms/Systems/HologramSystem.cs | 30 ++++++++++++++----- .../Holograms/HologramEvents.cs | 6 ++-- .../Holograms/SharedHologramSystem.cs | 21 +++++++------ .../Computers/base_structurecomputers.yml | 5 ++++ .../Machines/Computers/computers.yml | 3 -- 5 files changed, 41 insertions(+), 24 deletions(-) diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs index 9365401a60..a1c4647ecc 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs @@ -64,6 +64,7 @@ public override void Initialize() base.Initialize(); SubscribeAllEvent(HoloKill); SubscribeAllEvent(HoloGetProjector); + SubscribeAllEvent(HoloProjectorTest); // SubscribeLocalEvent(Startup); // SubscribeLocalEvent(Shutdown); // SubscribeLocalEvent(HoloTeleport); @@ -89,19 +90,34 @@ public override void Update(float frameTime) foreach (var component in _entityManager.EntityQuery().ToList()) { - var projectorEvent = new HologramGetProjectorEvent(component.Owner); - RaiseLocalEvent(component.Owner, projectorEvent); - Logger.DebugS("holo", "Hologram {0} has projector {1}", component.Owner, projectorEvent.Projector); - if (projectorEvent.Projector == EntityUid.Invalid || !projectorEvent.Projector.IsValid()) + var nearProj = HoloGetProjector(component); + if (!nearProj.IsValid()) { - RaiseNetworkEvent(new HologramReturnEvent(component.Owner)); - Logger.Debug("wawawah"); + if (component.Accumulator > 0) + { + component.Accumulator -= frameTime; + continue; + } + RaiseLocalEvent(new HologramReturnEvent(component.Owner)); continue; } - component.CurProjector = projectorEvent.Projector; + component.Accumulator = 0.24f; + component.CurProjector = nearProj; } } + /// + /// Tests if the given projector is valid. + /// + /// Event arguments. + public void HoloProjectorTest(HologramProjectorTestEvent args) + { + var curProjector = args.Projector; + if (curProjector == EntityUid.Invalid || !_entityManager.TryGetComponent(curProjector, out var _)) return; + if (_entityManager.TryGetComponent(curProjector, out var camComp) && !camComp.Active) return; + args.CanProject = true; + } + /// /// Tests for the nearest projector to the Hologram. /// diff --git a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs index 8d58c49254..c4c083dc3b 100644 --- a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs +++ b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs @@ -35,13 +35,13 @@ public HologramKillEvent(EntityUid uid) /// Raised to return a bool if a given projector is valid for a given hologram. /// [Serializable, NetSerializable] -public sealed class HologramProjectorValidEvent : EntityEventArgs +public sealed class HologramProjectorTestEvent : EntityEventArgs { public EntityUid Hologram; public EntityUid Projector; - public bool Valid = false; + public bool CanProject = false; - public HologramProjectorValidEvent(EntityUid hologram, EntityUid projector) + public HologramProjectorTestEvent(EntityUid hologram, EntityUid projector) { Hologram = hologram; Projector = projector; diff --git a/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs index 375654032d..b16b405963 100644 --- a/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs @@ -32,7 +32,7 @@ public class SharedHologramSystem : EntitySystem public override void Initialize() { SubscribeLocalEvent(OnInteractionAttempt); - SubscribeNetworkEvent(HoloReturn); + SubscribeAllEvent(HoloReturn); } // Stops the Hologram from interacting with anything they shouldn't. @@ -63,27 +63,26 @@ public void HoloReturn(HologramReturnEvent args) var popupDeathSelf = Loc.GetString("system-hologram-phasing-death-self"); // If the Hologram's last projector isn't valid, try to find a new one. - if (component.CurProjector != null && _entityManager.TryGetComponent(component.CurProjector, out var _)) + if (component.CurProjector == null) { - var curProjEvent = new HologramProjectorValidEvent(uid, component.CurProjector.Value); - RaiseNetworkEvent(curProjEvent); - if (!curProjEvent.Valid) - { - var getProj = new HologramGetProjectorEvent(uid, false); - component.CurProjector = getProj.Projector; - } + return; } - else + + var curProjCheck = new HologramProjectorTestEvent(uid, component.CurProjector.Value); + RaiseLocalEvent(curProjCheck); + if (!curProjCheck.CanProject) { var getProj = new HologramGetProjectorEvent(uid, false); + RaiseLocalEvent(getProj); component.CurProjector = getProj.Projector; } // If the Hologram's last projector is still invalid, kill them. if (component.CurProjector == EntityUid.Invalid) { + // if (_timing.InPrediction) return; - RaiseNetworkEvent(new HologramKillEvent(uid)); + RaiseLocalEvent(new HologramKillEvent(uid)); return; } diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml index d2c87deaa6..083f09726b 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml @@ -57,3 +57,8 @@ containers: board: !type:Container ents: [] + - type: DynamicPrice + price: 400 + - type: Tag + tags: + - Hardlight diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml index 35ada2f993..fdbe1a3dc3 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml @@ -16,9 +16,6 @@ state: alert-2 - map: ["computerLayerKeys"] state: atmos_key - - type: Tag - tags: - - Hardlight - type: entity From 6e1458c2de90c19db403429cdc32556cf009bda7 Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Tue, 28 Feb 2023 20:23:44 -0500 Subject: [PATCH 09/25] Prepared for projected, lightbee, and hardlight holos by separating the protos, make a temp new tag Light, deleted unused files, renamed HoloData to HoloMind, and made HoloData struct to hold info on the Holo like type and whether it's hardlight. Needs implementing in YAML. --- .../Holograms/Components/HoloDiskComponent.cs | 8 +- .../Holograms/Systems/HologramServerSystem.cs | 12 +- .../Holograms/Systems/HologramSystem.cs | 44 +++--- .../Holograms/HologramComponent.cs | 14 +- .../Holograms/HologramProjectorComponent.cs | 1 + .../Holograms/HolopodComponent.cs | 6 - .../Holograms/SharedHologramSystem.cs | 48 ++++++- .../Entities/Mobs/Player/hologram.yml | 125 ++++++++++++------ Resources/Prototypes/SimpleStation14/tags.yml | 2 + 9 files changed, 173 insertions(+), 87 deletions(-) delete mode 100644 Content.Shared/SimpleStation14/Holograms/HolopodComponent.cs diff --git a/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs b/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs index d9ea85a6e8..7adbedebf1 100644 --- a/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs +++ b/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs @@ -5,14 +5,8 @@ namespace Content.Server.SimpleStation14.Hologram; [RegisterComponent] public sealed class HologramDiskComponent : Component { - // [ViewVariables] - // public HoloDataEntry? HoloData = null; - - // [DataField("active"), ViewVariables(VVAccess.ReadWrite)] - // public bool Active = true; - [ViewVariables] - public Mind.Mind? HoloData = null; + public Mind.Mind? HoloMind = null; [DataField("active"), ViewVariables(VVAccess.ReadWrite)] public bool Active = true; diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs index cb5329b3f1..3fa935d77f 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -74,14 +74,14 @@ public override void Initialize() private void OnEntInserted(EntityUid uid, HologramServerComponent component, EntInsertedIntoContainerMessage args) { if (args.Container.ID != DiskSlot || !_tagSystem.HasTag(args.Entity, "HoloDisk") || - (_entityManager.TryGetComponent(args.Entity, out var diskComp) && diskComp.HoloData == null)) return; + (_entityManager.TryGetComponent(args.Entity, out var diskComp) && diskComp.HoloMind == null)) return; if (component.LinkedHologram != EntityUid.Invalid && _entityManager.EntityExists(component.LinkedHologram)) { RaiseLocalEvent(new HologramKillEvent(component.LinkedHologram.Value)); } - if (TryHoloGenerate(component.Owner, _entityManager.GetComponent(args.Entity).HoloData!, component, out var holo)) + if (TryHoloGenerate(component.Owner, _entityManager.GetComponent(args.Entity).HoloMind!, component, out var holo)) { var holoComp = _entityManager.GetComponent(holo); component.LinkedHologram = holo; @@ -95,7 +95,7 @@ private void OnEntInserted(EntityUid uid, HologramServerComponent component, Ent private void OnEntRemoved(EntityUid uid, HologramServerComponent component, EntRemovedFromContainerMessage args) { if (args.Container.ID != DiskSlot || !_tagSystem.HasTag(args.Entity, "HoloDisk") || - (_entityManager.TryGetComponent(args.Entity, out var diskComp) && diskComp.HoloData == null)) return; + (_entityManager.TryGetComponent(args.Entity, out var diskComp) && diskComp.HoloMind == null)) return; if (component.LinkedHologram != EntityUid.Invalid && _entityManager.EntityExists(component.LinkedHologram)) { @@ -130,7 +130,7 @@ private void OnPowerChanged(EntityUid uid, HologramServerComponent component, re return; // No disk in the server } var disk = serverContainer.GetContainer(DiskSlot).ContainedEntities.First(); - var diskData = _entityManager.GetComponent(disk).HoloData; + var diskData = _entityManager.GetComponent(disk).HoloMind; // If the hologram is generated successfully if (diskData != null && TryHoloGenerate(component.Owner, diskData, component, out var holo)) @@ -243,7 +243,7 @@ private EntityUid HoloFetchAndSpawn(HologramServerComponent holoServer, Humanoid List sexes = new(); var name = pref.Name; - var toSpawn = "MobHologram"; + var toSpawn = "MobHologramProjected"; var mob = Spawn(toSpawn, Transform(holoServer.Owner).MapPosition); _entityManager.GetComponent(mob).AttachToGridOrMap(); @@ -287,7 +287,7 @@ private void OnAfterInteract(EntityUid uid, HologramDiskComponent component, Aft return; } - component.HoloData = targetMind.Mind; + component.HoloMind = targetMind.Mind; Popup.PopupEntity(Loc.GetString("system-hologram-disk-mind-saved"), args.Target.Value, args.User); } } diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs index a1c4647ecc..7339f0f358 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs @@ -83,28 +83,28 @@ public override void Initialize() // } - // Anything that needs to be regularly run, like handling exiting a projector's range - public override void Update(float frameTime) - { - base.Update(frameTime); - - foreach (var component in _entityManager.EntityQuery().ToList()) - { - var nearProj = HoloGetProjector(component); - if (!nearProj.IsValid()) - { - if (component.Accumulator > 0) - { - component.Accumulator -= frameTime; - continue; - } - RaiseLocalEvent(new HologramReturnEvent(component.Owner)); - continue; - } - component.Accumulator = 0.24f; - component.CurProjector = nearProj; - } - } + // // Anything that needs to be regularly run, like handling exiting a projector's range + // public override void Update(float frameTime) + // { + // base.Update(frameTime); + + // foreach (var component in _entityManager.EntityQuery().ToList()) + // { + // var nearProj = HoloGetProjector(component); + // if (!nearProj.IsValid()) + // { + // if (component.Accumulator > 0) + // { + // component.Accumulator -= frameTime; + // continue; + // } + // RaiseLocalEvent(new HologramReturnEvent(component.Owner)); + // continue; + // } + // component.Accumulator = 0.24f; + // component.CurProjector = nearProj; + // } + // } /// /// Tests if the given projector is valid. diff --git a/Content.Shared/SimpleStation14/Holograms/HologramComponent.cs b/Content.Shared/SimpleStation14/Holograms/HologramComponent.cs index a1c90baa63..7c176c7c58 100644 --- a/Content.Shared/SimpleStation14/Holograms/HologramComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/HologramComponent.cs @@ -3,13 +3,23 @@ namespace Content.Shared.SimpleStation14.Hologram; [RegisterComponent] public sealed class HologramComponent : Component { + // // Custom struct that specifies the type of hologram. + // // First variable is the HoloType enum, second is whether or not it's hardlight. + // // Defaults to False. + // [DataField("holoData"), ViewVariables] + // public HoloData HoloData = new HoloData(HoloType.Projected, false); + + // Current server the Hologram is generated by. + // Will be the Lightbee if it's a Lightbee Hologram. [ViewVariables] public EntityUid? LinkedServer; + // The current projector the Hologram is connected to. + // Will be the Lightbee if it's a Lightbee Hologram. [ViewVariables] public EntityUid? CurProjector; - // Counter + // Counter before returning the Holo, so you can get through doors. [DataField("accumulator")] - public float Accumulator = 2f; + public float Accumulator = 0.5f; } diff --git a/Content.Shared/SimpleStation14/Holograms/HologramProjectorComponent.cs b/Content.Shared/SimpleStation14/Holograms/HologramProjectorComponent.cs index 0bdcf59ba8..b63e4a634f 100644 --- a/Content.Shared/SimpleStation14/Holograms/HologramProjectorComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/HologramProjectorComponent.cs @@ -3,4 +3,5 @@ namespace Content.Shared.SimpleStation14.Hologram; [RegisterComponent] public sealed class HologramProjectorComponent : Component { + } diff --git a/Content.Shared/SimpleStation14/Holograms/HolopodComponent.cs b/Content.Shared/SimpleStation14/Holograms/HolopodComponent.cs deleted file mode 100644 index 21640ae990..0000000000 --- a/Content.Shared/SimpleStation14/Holograms/HolopodComponent.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Content.Server.SimpleStation14.Hologram; - -[RegisterComponent] -public sealed class HologramPodComponent : Component -{ -} diff --git a/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs index b16b405963..b993023e41 100644 --- a/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs @@ -14,6 +14,7 @@ using Content.Shared.Administration.Logs; using Content.Shared.Database; using Content.Shared.Pulling; +using System.Linq; namespace Content.Shared.SimpleStation14.Hologram; @@ -27,7 +28,6 @@ public class SharedHologramSystem : EntitySystem [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedPullingSystem _pulling = default!; - private const string DiskSlot = "holo_disk"; public override void Initialize() { @@ -35,6 +35,31 @@ public override void Initialize() SubscribeAllEvent(HoloReturn); } + // Anything that needs to be regularly run, like handling exiting a projector's range + public override void Update(float frameTime) + { + base.Update(frameTime); + + foreach (var component in _entityManager.EntityQuery().ToList()) + { + var getProj = new HologramGetProjectorEvent(component.Owner); + RaiseLocalEvent(getProj); + var nearProj = getProj.Projector; + if (!nearProj.IsValid()) + { + if (component.Accumulator > 0) + { + component.Accumulator -= frameTime; + continue; + } + RaiseLocalEvent(new HologramReturnEvent(component.Owner)); + continue; + } + component.Accumulator = 0.24f; + component.CurProjector = nearProj; + } + } + // Stops the Hologram from interacting with anything they shouldn't. private void OnInteractionAttempt(EntityUid uid, HologramComponent component, InteractionAttemptEvent args) { @@ -42,7 +67,7 @@ private void OnInteractionAttempt(EntityUid uid, HologramComponent component, In return; if (HasComp(args.Target) && !HasComp(args.Target) - && !_tagSystem.HasAnyTag(args.Target.Value, "Hardlight")) args.Cancel(); + && !_tagSystem.HasAnyTag(args.Target.Value, "Hardlight", "Light")) args.Cancel(); } /// @@ -107,6 +132,25 @@ public void HoloReturn(HologramReturnEvent args) } } +public enum HoloType +{ + Projected, + Lightbee +} + +public struct HoloData +{ + public HoloType Type { get; set; } + public bool IsHardlight { get; set; } + + public HoloData(HoloType type, bool isHardlight = false) + { + Type = type; + IsHardlight = isHardlight; + } +} + + // [Serializable, NetSerializable] // public sealed class HoloTeleportEvent : EntityEventArgs diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml index 4950c84616..9820f65514 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml @@ -139,63 +139,104 @@ attributes: proper: true - type: Hologram + - type: AnimationPlayer + - type: Mind + showExamineInfo: true + - type: Inventory + - type: Actions + - type: Eye - type: entity save: false name: Urist McLight + suffix: Projected parent: PlayerHologramBase - id: MobHologram + id: MobHologramProjected components: - # - type: CombatMode - # disarm: null + - type: Hologram + # holoData: + # Type: HoloType.Projected + # IsHardLight: false - type: Stealth - lastVisibility: 0.83 + lastVisibility: 0.80 - type: InteractionPopup successChance: 1 interactSuccessString: hugging-success-hologram # interactSuccessSound: /Audio/Effects/thudswoosh.ogg messagePerceivedByOthers: hugging-success-hologram-others - - type: Mind - showExamineInfo: true - - type: Input - context: "human" - - type: MobMover - - type: InputMover - - type: Inventory - - type: Alerts - - type: Actions - - type: Eye - # - type: CameraRecoil - - type: Examiner - type: Faction factions: - NanoTrasen - - type: IntrinsicRadioReceiver - channels: - - Common - - Engineering - - Medical - - Science - - Service - - Binary - - type: IntrinsicRadioTransmitter - channels: - - Common - - Engineering - - Medical - - Science - - Service - - Binary - - type: ActiveRadio - channels: - - Common - - Engineering - - Medical - - Science - - Service - - Binary - type: PointLight - radius: 1.3 - softness: 1 + radius: 1.0 + softness: 1.4 color: "#00FFFF" energy: 3 + +- type: entity + save: false + name: Urist McLight + suffix: Lightbee + parent: PlayerHologramBase + id: MobHologramLightbee + components: + - type: Hologram + # holoData: !HoloData + # Type: Lightbee + # IsHardLight: false + - type: Stealth + lastVisibility: 0.85 + - type: InteractionPopup + successChance: 1 + interactSuccessString: hugging-success-hologram + # interactSuccessSound: /Audio/Effects/thudswoosh.ogg + messagePerceivedByOthers: hugging-success-hologram-others + - type: CameraRecoil + - type: Faction + factions: + - NanoTrasen + - type: PointLight + radius: 1.5 + softness: 0.8 + color: "#00FFFF" + energy: 4 + +- type: entity + save: false + name: Urist McLight + suffix: Hardlight + parent: PlayerHologramBase + id: MobHologramHardlight + components: + - type: Hologram + # holoData: + # Type: HoloType.Lightbee + # IsHardLight: true + - type: DamageOnHighSpeedImpact + damage: + types: + Blunt: 5 + soundHit: + path: /Audio/Effects/hit_kick.ogg + - type: Damageable + damageContainer: Inorganic + - type: Pullable + - type: Puller + - type: CombatMode + disarm: null + - type: Stealth + lastVisibility: 0.90 + - type: InteractionPopup + successChance: 1 + interactSuccessString: hugging-success-hologram + # interactSuccessSound: /Audio/Effects/thudswoosh.ogg + messagePerceivedByOthers: hugging-success-hologram-others + - type: CameraRecoil + - type: Faction + factions: + - NanoTrasen + - type: PointLight + radius: 0.8 + softness: 0.4 + color: "#00FFFF" + energy: 5 diff --git a/Resources/Prototypes/SimpleStation14/tags.yml b/Resources/Prototypes/SimpleStation14/tags.yml index 08cbc20b5e..eabed7860e 100644 --- a/Resources/Prototypes/SimpleStation14/tags.yml +++ b/Resources/Prototypes/SimpleStation14/tags.yml @@ -4,6 +4,8 @@ - type: Tag id: Hardlight +- type: Tag + id: Light - type: Tag id: HoloDisk From 3688ea1162a8f4b5c836d991b944f23bfd6742e4 Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Thu, 2 Mar 2023 17:35:12 -0500 Subject: [PATCH 10/25] Removed some unneeded things, cleaned some files, made it Holograms can interact with light things, and non-Holograms can't. --- .../Holograms/Systems/HologramServerSystem.cs | 48 ++++++++++++++++++- .../Gravity/FloatingVisualsComponent.cs | 4 -- .../Gravity/SharedFloatingVisualizerSystem.cs | 7 +-- .../{ => Components}/HoloServerComponent.cs | 0 .../{ => Components}/HologramComponent.cs | 0 .../HologramProjectorComponent.cs | 0 .../{ => Systems}/SharedHologramSystem.cs | 42 +++++++++++----- .../Machines/Computers/computers.yml | 1 - .../Entities/Mobs/Player/hologram.yml | 2 + Resources/Prototypes/SimpleStation14/tags.yml | 2 +- 10 files changed, 82 insertions(+), 24 deletions(-) rename Content.Shared/SimpleStation14/Holograms/{ => Components}/HoloServerComponent.cs (100%) rename Content.Shared/SimpleStation14/Holograms/{ => Components}/HologramComponent.cs (100%) rename Content.Shared/SimpleStation14/Holograms/{ => Components}/HologramProjectorComponent.cs (100%) rename Content.Shared/SimpleStation14/Holograms/{ => Systems}/SharedHologramSystem.cs (83%) diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs index 3fa935d77f..d72b42f57f 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -29,6 +29,7 @@ using Content.Shared.Interaction.Components; using Content.Shared.Access.Components; using Content.Shared.Clothing.Components; +using Content.Shared.Roles; using Robust.Server.Player; using Robust.Shared.Player; using Robust.Shared.Containers; @@ -208,11 +209,11 @@ public bool TryHoloGenerate(EntityUid uid, Mind.Mind mind, HologramServerCompone return; } } - _tagSystem.AddTag(item, "Hardlight"); + _tagSystem.AddTag(item, "Softlight"); _entityManager.EnsureComponent(item); }); + // HoloEquip(mob, mind.CurrentJob.Prototype); } - } _adminLogger.Add(LogType.Unknown, LogImpact.Medium, @@ -277,6 +278,40 @@ private EntityUid HoloFetchAndSpawn(HologramServerComponent holoServer, Humanoid return mob; } + + /// + /// WiP for equipping unique items based on job. + /// +// private void HoloEquip(EntityUid mob, JobPrototype job) +// { +// // Check what job they are against a list, and output a hardcoded item for each. + + + + +// var mobTransform = EntityManager.GetComponent(mob); +// var mobPos = mobTransform.WorldPosition; + +// if (!_entityManager.TryGetComponent(mob, out var mobInv)) +// return; +// var mobHands = EntityManager.EnsureComponent(mob); + +// foreach (var item in job.StartingGear.Items) +// { +// var itemEnt = Spawn(item.Prototype, mobPos); +// _entityManager.GetComponent(itemEnt).AttachToGridOrMap(); + +// if (item.Slot == null) +// { +// mobInv.TryPutInHandOrAny(itemEnt, out var _); +// } +// else +// { +// mobInv.TryPutInSlot(itemEnt, item.Slot); +// } +// } +// } + private void OnAfterInteract(EntityUid uid, HologramDiskComponent component, AfterInteractEvent args) { if (args.Target == null || !TryComp(args.Target, out var targetMind)) @@ -290,4 +325,13 @@ private void OnAfterInteract(EntityUid uid, HologramDiskComponent component, Aft component.HoloMind = targetMind.Mind; Popup.PopupEntity(Loc.GetString("system-hologram-disk-mind-saved"), args.Target.Value, args.User); } + + +// // List of jobs with hardcoded items for Holograms, like a Clown's horn. +// static readonly Dictionary HoloJobItems = new Dictionary +// { +// { "Clown", "BikeHorn" }, +// { "value2", "output2" }, +// { "value3", "output3" } +// }; } diff --git a/Content.Shared/Gravity/FloatingVisualsComponent.cs b/Content.Shared/Gravity/FloatingVisualsComponent.cs index 7e80a41e18..53b28aef90 100644 --- a/Content.Shared/Gravity/FloatingVisualsComponent.cs +++ b/Content.Shared/Gravity/FloatingVisualsComponent.cs @@ -24,10 +24,6 @@ public sealed class FloatingVisualsComponent : Component [ViewVariables(VVAccess.ReadWrite)] public bool CanFloat = false; - - [ViewVariables(VVAccess.ReadWrite)] - [DataField("force")] - public bool Force = false; public readonly string AnimationKey = "gravity"; } diff --git a/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs b/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs index 068e755abe..204f397801 100644 --- a/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs +++ b/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs @@ -29,9 +29,6 @@ public virtual void FloatAnimation(EntityUid uid, Vector2 offset, string animati protected bool CanFloat(EntityUid uid, FloatingVisualsComponent component, TransformComponent? transform = null) { - if (component.Force == true) - return true; - if (!Resolve(uid, ref transform)) return false; @@ -63,7 +60,7 @@ private void OnGravityChanged(ref GravityChangedEvent args) Dirty(floating); var uid = floating.Owner; - if (!args.HasGravity || floating.Force == true) + if (!args.HasGravity) FloatAnimation(uid, floating.Offset, floating.AnimationKey, floating.AnimationTime); } } @@ -71,7 +68,7 @@ private void OnGravityChanged(ref GravityChangedEvent args) private void OnEntParentChanged(EntityUid uid, FloatingVisualsComponent component, ref EntParentChangedMessage args) { var transform = args.Transform; - if (CanFloat(uid, component, transform) || component.Force == true) + if (CanFloat(uid, component, transform)) FloatAnimation(uid, component.Offset, component.AnimationKey, component.AnimationTime); } diff --git a/Content.Shared/SimpleStation14/Holograms/HoloServerComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HoloServerComponent.cs similarity index 100% rename from Content.Shared/SimpleStation14/Holograms/HoloServerComponent.cs rename to Content.Shared/SimpleStation14/Holograms/Components/HoloServerComponent.cs diff --git a/Content.Shared/SimpleStation14/Holograms/HologramComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs similarity index 100% rename from Content.Shared/SimpleStation14/Holograms/HologramComponent.cs rename to Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs diff --git a/Content.Shared/SimpleStation14/Holograms/HologramProjectorComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectorComponent.cs similarity index 100% rename from Content.Shared/SimpleStation14/Holograms/HologramProjectorComponent.cs rename to Content.Shared/SimpleStation14/Holograms/Components/HologramProjectorComponent.cs diff --git a/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs similarity index 83% rename from Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs rename to Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs index b993023e41..375ad5d1e5 100644 --- a/Content.Shared/SimpleStation14/Holograms/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs @@ -31,10 +31,40 @@ public class SharedHologramSystem : EntitySystem public override void Initialize() { - SubscribeLocalEvent(OnInteractionAttempt); + SubscribeLocalEvent(OnHoloInteractionAttempt); + SubscribeLocalEvent(OnInteractionAttempt); SubscribeAllEvent(HoloReturn); } + // Stops the Hologram from interacting with anything they shouldn't. + private void OnHoloInteractionAttempt(EntityUid uid, HologramComponent component, InteractionAttemptEvent args) + { + if (args.Target == null) + return; + + if (HasComp(args.Target) && !HasComp(args.Target) + && !_tagSystem.HasAnyTag(args.Target.Value, "Hardlight", "Softlight")) args.Cancel(); + } + + // Stops everyone else from interacting with the Holograms. + private void OnInteractionAttempt(InteractionAttemptEvent args) + { + if (args.Target == null || _tagSystem.HasAnyTag(args.Uid, "Hardlight", "Softlight") || + _entityManager.TryGetComponent(args.Uid, out var _)) + return; + + if (_tagSystem.HasAnyTag(args.Target.Value, "Softlight") && !_tagSystem.HasAnyTag(args.Target.Value, "Hardlight")){ + args.Cancel(); + + // Send a popup to the player about the interaction, and play a sound. + var meta = _entityManager.GetComponent(args.Target.Value); + var popup = Loc.GetString("system-hologram-light-interaction-fail", ("item", meta.EntityName)); + var sound = "/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg"; + Popup.PopupEntity(popup, args.Target.Value, Filter.Entities(args.Uid), false); + _audio.Play(sound, Filter.Entities(args.Uid), args.Uid, false); + } + } + // Anything that needs to be regularly run, like handling exiting a projector's range public override void Update(float frameTime) { @@ -60,16 +90,6 @@ public override void Update(float frameTime) } } - // Stops the Hologram from interacting with anything they shouldn't. - private void OnInteractionAttempt(EntityUid uid, HologramComponent component, InteractionAttemptEvent args) - { - if (args.Target == null) - return; - - if (HasComp(args.Target) && !HasComp(args.Target) - && !_tagSystem.HasAnyTag(args.Target.Value, "Hardlight", "Light")) args.Cancel(); - } - /// /// Handles returning a Hologram to their last visited projector, /// then to the nearest, finally killing them if none are found. diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml index fdbe1a3dc3..27ad39fafb 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml @@ -17,7 +17,6 @@ - map: ["computerLayerKeys"] state: atmos_key - - type: entity parent: BaseComputer id: ComputerEmergencyShuttle diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml index 9820f65514..1618d37248 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml @@ -119,6 +119,7 @@ - type: Alerts - type: Tag tags: + - DoorBumpOpener - ShoesRequiredStepTriggerImmune - type: NoSlip - type: TypingIndicator @@ -145,6 +146,7 @@ - type: Inventory - type: Actions - type: Eye + - type: Access - type: entity save: false diff --git a/Resources/Prototypes/SimpleStation14/tags.yml b/Resources/Prototypes/SimpleStation14/tags.yml index eabed7860e..92909f0730 100644 --- a/Resources/Prototypes/SimpleStation14/tags.yml +++ b/Resources/Prototypes/SimpleStation14/tags.yml @@ -5,7 +5,7 @@ id: Hardlight - type: Tag - id: Light + id: Softlight - type: Tag id: HoloDisk From 731832e736e5ac8343202ca0adf78a9e300bb156 Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Sat, 18 Mar 2023 06:47:10 -0400 Subject: [PATCH 11/25] Added damage sets for Holograms, kinda fixed rotation on spawn, begun work on hologram data in the component (no structs ;-;), and refined the variations of Holograms. --- .../Holograms/Systems/HologramServerSystem.cs | 12 +++++++ .../Holograms/Components/HologramComponent.cs | 6 ++++ .../Holograms/Systems/SharedHologramSystem.cs | 22 ++++++------ .../SimpleStation14/Damage/modifier_sets.yml | 10 ++++++ .../Entities/Mobs/Player/hologram.yml | 35 +++++++++++++++---- 5 files changed, 69 insertions(+), 16 deletions(-) diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs index d72b42f57f..7b1d058665 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -34,6 +34,8 @@ using Robust.Shared.Player; using Robust.Shared.Containers; using Robust.Shared.GameObjects.Components.Localization; +using Content.Shared.Movement.Systems; +using System.Threading.Tasks; namespace Content.Server.SimpleStation14.Hologram; @@ -56,6 +58,7 @@ public class HologramServerSystem : EntitySystem [Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly SharedMoverController _mover = default!; private const string DiskSlot = "holo_disk"; public readonly Dictionary ClonesWaitingForMind = new(); @@ -249,6 +252,8 @@ private EntityUid HoloFetchAndSpawn(HologramServerComponent holoServer, Humanoid var mob = Spawn(toSpawn, Transform(holoServer.Owner).MapPosition); _entityManager.GetComponent(mob).AttachToGridOrMap(); + ResetCamera(mob); + _humanoidSystem.LoadProfile(mob, pref); MetaData(mob).EntityName = name; @@ -278,6 +283,13 @@ private EntityUid HoloFetchAndSpawn(HologramServerComponent holoServer, Humanoid return mob; } + private async void ResetCamera(EntityUid mob) + { + await Task.Delay(500); + + _mover.ResetCamera(mob); + } + /// /// WiP for equipping unique items based on job. diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs index 7c176c7c58..d5dcd5a320 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs @@ -9,6 +9,12 @@ public sealed class HologramComponent : Component // [DataField("holoData"), ViewVariables] // public HoloData HoloData = new HoloData(HoloType.Projected, false); + [DataField("holoType")] + public HoloType HoloType = HoloType.Projected; + + [DataField("isHardlight")] + public bool IsHardlight = false; + // Current server the Hologram is generated by. // Will be the Lightbee if it's a Lightbee Hologram. [ViewVariables] diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs index 375ad5d1e5..c4eaf071e9 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs @@ -158,18 +158,20 @@ public enum HoloType Lightbee } -public struct HoloData -{ - public HoloType Type { get; set; } - public bool IsHardlight { get; set; } +// public struct HoloData +// { +// [DataField("type")] +// public HoloType Type { get; set; } - public HoloData(HoloType type, bool isHardlight = false) - { - Type = type; - IsHardlight = isHardlight; - } -} +// [DataField("isHardlight")] +// public bool IsHardlight { get; set; } +// public HoloData(HoloType type, bool isHardlight = false) +// { +// Type = type; +// IsHardlight = isHardlight; +// } +// } // [Serializable, NetSerializable] diff --git a/Resources/Prototypes/SimpleStation14/Damage/modifier_sets.yml b/Resources/Prototypes/SimpleStation14/Damage/modifier_sets.yml index 4df72522d3..7f55da871a 100644 --- a/Resources/Prototypes/SimpleStation14/Damage/modifier_sets.yml +++ b/Resources/Prototypes/SimpleStation14/Damage/modifier_sets.yml @@ -31,3 +31,13 @@ Shock: 1.25 Radiation: 1.3 +- type: damageModifierSet + id: Hardlight + coefficients: + Blunt: 1.6 + Slash: 1.0 + Piercing: 0.7 + Shock: 1.2 + Heat: 1.35 + flatReductions: + Blunt: 5 diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml index 1618d37248..6c6c4044c0 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml @@ -156,9 +156,8 @@ id: MobHologramProjected components: - type: Hologram - # holoData: - # Type: HoloType.Projected - # IsHardLight: false + holoType: HoloType.Projected + isHardLight: false - type: Stealth lastVisibility: 0.80 - type: InteractionPopup @@ -186,6 +185,19 @@ # holoData: !HoloData # Type: Lightbee # IsHardLight: false + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.05 + density: 25 + mask: + - MobMask + layer: + - MobLayer + - type: Damageable + damageContainer: Inorganic + damageModifierSet: FlimsyMetallic - type: Stealth lastVisibility: 0.85 - type: InteractionPopup @@ -214,14 +226,25 @@ # holoData: # Type: HoloType.Lightbee # IsHardLight: true + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.35 + density: 25 + mask: + - MobMask + layer: + - MobLayer + - type: Damageable + damageContainer: Inorganic + damageModifierSet: Hardlight - type: DamageOnHighSpeedImpact damage: types: - Blunt: 5 + Blunt: 6 # To get past the 5 damage threshold soundHit: path: /Audio/Effects/hit_kick.ogg - - type: Damageable - damageContainer: Inorganic - type: Pullable - type: Puller - type: CombatMode From f8c39b3c690750e43daa37d8b6a6b366ebfc8959 Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Tue, 21 Mar 2023 07:16:19 -0400 Subject: [PATCH 12/25] Removed unneeded files --- .../Silicon/Charge/SiliconChargeSystem.cs | 24 ------------------- .../Components/SiliconChargeComponent.cs | 20 ---------------- 2 files changed, 44 deletions(-) delete mode 100644 Content.Server/SimpleStation14/Silicon/Charge/SiliconChargeSystem.cs delete mode 100644 Content.Shared/SimpleStation14/Silicon/Charge/Components/SiliconChargeComponent.cs diff --git a/Content.Server/SimpleStation14/Silicon/Charge/SiliconChargeSystem.cs b/Content.Server/SimpleStation14/Silicon/Charge/SiliconChargeSystem.cs deleted file mode 100644 index ea5d58dcd8..0000000000 --- a/Content.Server/SimpleStation14/Silicon/Charge/SiliconChargeSystem.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Robust.Shared.Random; -using Content.Shared.Silicon.Charge; - -namespace Content.Server.Silicon.Charge; - -public sealed class SiliconChargeSystem : EntitySystem -{ - [Dependency] private readonly IRobustRandom _random = default!; - public override void Initialize() - { - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - foreach (var silicon in EntityQuery()) - { - if (silicon.CurrentCharge > 0) - { - silicon.CurrentCharge -= (frameTime * silicon.ChargeDrainMult * 2) * _random.NextFloat(1.1f, 0.9f); - } - } - } -} diff --git a/Content.Shared/SimpleStation14/Silicon/Charge/Components/SiliconChargeComponent.cs b/Content.Shared/SimpleStation14/Silicon/Charge/Components/SiliconChargeComponent.cs deleted file mode 100644 index a9a25672cf..0000000000 --- a/Content.Shared/SimpleStation14/Silicon/Charge/Components/SiliconChargeComponent.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Content.Shared.Silicon.Charge; - -/// -/// -/// -[RegisterComponent] -public sealed class SiliconChargeComponent : Component -{ - [DataField("currentCharge"), ViewVariables(VVAccess.ReadWrite)] - public float CurrentCharge = 100; - - [DataField("maxCharge"), ViewVariables(VVAccess.ReadWrite)] - public float MaxCharge = 2000; - - [DataField("chargeDrainMult"), ViewVariables(VVAccess.ReadWrite)] - public float ChargeDrainMult = 1; - - [DataField("freezeOnEmpty")] - public bool FreezeOnEmpty = false; -} From aa7ec26cb75901d5d98ec8f00b3adefd39049e0f Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Thu, 30 Mar 2023 23:58:24 -0400 Subject: [PATCH 13/25] Removed unused component From 232b0c66c7922420a9cd0827778a57f6a1b54f4b Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Thu, 20 Apr 2023 01:26:25 -0400 Subject: [PATCH 14/25] Death's tweaks, filtered :) --- .../Holograms/Components/HoloDiskComponent.cs | 2 +- .../Holograms/Systems/HologramServerSystem.cs | 32 ++++++++----------- .../Holograms/Systems/HologramSystem.cs | 13 ++++---- .../Components/HoloServerComponent.cs | 2 +- .../Holograms/Components/HologramComponent.cs | 2 +- .../Components/HologramProjectorComponent.cs | 2 +- .../Holograms/Systems/SharedHologramSystem.cs | 23 ++++++------- 7 files changed, 35 insertions(+), 41 deletions(-) diff --git a/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs b/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs index 7adbedebf1..55a6f896f2 100644 --- a/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs +++ b/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs @@ -1,6 +1,6 @@ // using static Content.Server.SimpleStation14.Hologram.HologramSystem; -namespace Content.Server.SimpleStation14.Hologram; +namespace Content.Server.SimpleStation14.Holograms; [RegisterComponent] public sealed class HologramDiskComponent : Component diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs index 7b1d058665..985edbf859 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -37,14 +37,14 @@ using Content.Shared.Movement.Systems; using System.Threading.Tasks; -namespace Content.Server.SimpleStation14.Hologram; +namespace Content.Server.SimpleStation14.Holograms; -public class HologramServerSystem : EntitySystem +public sealed class HologramServerSystem : EntitySystem { [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] protected readonly SharedPopupSystem Popup = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedPullingSystem _pulling = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly IPlayerManager _playerManager = null!; @@ -101,7 +101,7 @@ private void OnEntRemoved(EntityUid uid, HologramServerComponent component, EntR if (args.Container.ID != DiskSlot || !_tagSystem.HasTag(args.Entity, "HoloDisk") || (_entityManager.TryGetComponent(args.Entity, out var diskComp) && diskComp.HoloMind == null)) return; - if (component.LinkedHologram != EntityUid.Invalid && _entityManager.EntityExists(component.LinkedHologram)) + if (_entityManager.EntityExists(component.LinkedHologram)) { RaiseLocalEvent(new HologramKillEvent(component.LinkedHologram.Value)); } @@ -119,9 +119,9 @@ private void OnPowerChanged(EntityUid uid, HologramServerComponent component, re if (!args.Powered && component.LinkedHologram != null && component.LinkedHologram != EntityUid.Invalid) { // If the hologram exists - if (component != null && _entityManager.EntityExists(component.LinkedHologram)) + if (_entityManager.EntityExists(component.LinkedHologram)) { - // Kill the Holgram + // Kill the Hologram RaiseLocalEvent(new HologramKillEvent(component.LinkedHologram.Value)); } } @@ -172,9 +172,6 @@ public bool TryHoloGenerate(EntityUid uid, Mind.Mind mind, HologramServerCompone var pref = (HumanoidCharacterProfile) _prefs.GetPreferences(mind.UserId.Value).SelectedCharacter; - if (pref == null) - return false; - var mob = HoloFetchAndSpawn(holoServer!, pref); var cloneMindReturn = EntityManager.AddComponent(mob); @@ -205,8 +202,7 @@ public bool TryHoloGenerate(EntityUid uid, Mind.Mind mind, HologramServerCompone { if (_entityManager.TryGetComponent(item, out var clothing)) { - if (clothing.InSlot == "back" || clothing.InSlot == "pocket1" || clothing.InSlot == "pocket2" || - clothing.InSlot == "belt" || clothing.InSlot == "suitstorage" || clothing.InSlot == "id") + if (clothing.InSlot is "back" or "pocket1" or "pocket2" or "belt" or "suitstorage" or "id") { _entityManager.DeleteEntity(item); return; @@ -244,13 +240,12 @@ internal void TransferMindToClone(Mind.Mind mind) /// private EntityUid HoloFetchAndSpawn(HologramServerComponent holoServer, HumanoidCharacterProfile pref) { - List sexes = new(); var name = pref.Name; var toSpawn = "MobHologramProjected"; var mob = Spawn(toSpawn, Transform(holoServer.Owner).MapPosition); - _entityManager.GetComponent(mob).AttachToGridOrMap(); + Transform(mob).AttachToGridOrMap(); ResetCamera(mob); @@ -265,12 +260,11 @@ private EntityUid HoloFetchAndSpawn(HologramServerComponent holoServer, Humanoid grammar.Gender = Robust.Shared.Enums.Gender.Neuter; Dirty(grammar); - var meta = _entityManager.GetComponent(mob); - var popupAppearOther = Loc.GetString("system-hologram-phasing-appear-others", ("name", meta.EntityName)); + var popupAppearOther = Loc.GetString("system-hologram-phasing-appear-others", ("name", MetaData(mob).EntityName)); var popupAppearSelf = Loc.GetString("system-hologram-phasing-appear-self"); - Popup.PopupEntity(popupAppearOther, mob, Filter.PvsExcept((EntityUid) mob), false, PopupType.Medium); - Popup.PopupEntity(popupAppearSelf, mob, mob, PopupType.Large); + _popup.PopupEntity(popupAppearOther, mob, Filter.PvsExcept((EntityUid) mob), false, PopupType.Medium); + _popup.PopupEntity(popupAppearSelf, mob, mob, PopupType.Large); _audio.PlayPvs("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg", mob); EnsureComp(mob); @@ -330,12 +324,12 @@ private void OnAfterInteract(EntityUid uid, HologramDiskComponent component, Aft return; if (targetMind.Mind == null) { - Popup.PopupEntity(Loc.GetString("system-hologram-disk-mind-none"), args.Target.Value, args.User); + _popup.PopupEntity(Loc.GetString("system-hologram-disk-mind-none"), args.Target.Value, args.User); return; } component.HoloMind = targetMind.Mind; - Popup.PopupEntity(Loc.GetString("system-hologram-disk-mind-saved"), args.Target.Value, args.User); + _popup.PopupEntity(Loc.GetString("system-hologram-disk-mind-saved"), args.Target.Value, args.User); } diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs index 7339f0f358..a0bf8d4fae 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs @@ -38,14 +38,14 @@ using System.Linq; using Robust.Shared.Utility; -namespace Content.Server.SimpleStation14.Hologram; +namespace Content.Server.SimpleStation14.Holograms; -public class HologramSystem : EntitySystem +public sealed class HologramSystem : EntitySystem { [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] protected readonly SharedPopupSystem Popup = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedPullingSystem _pulling = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly IPlayerManager _playerManager = null!; @@ -153,7 +153,6 @@ public void HoloGetProjector(HologramGetProjectorEvent args) args.Projector = nearProj.Value; return; } - return; } /// @@ -251,8 +250,8 @@ public void HoloKill(HologramKillEvent args) } _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(uid), coordinates: holoPos, false); - Popup.PopupCoordinates(popupDisappearOther, holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); - Popup.PopupCoordinates(popupDeathSelf, holoPos, uid, PopupType.LargeCaution); + _popup.PopupCoordinates(popupDisappearOther, holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); + _popup.PopupCoordinates(popupDeathSelf, holoPos, uid, PopupType.LargeCaution); if (component.LinkedServer != EntityUid.Invalid) { if (_entityManager.TryGetComponent(component.LinkedServer!.Value, out var serverComp)) @@ -260,7 +259,7 @@ public void HoloKill(HologramKillEvent args) component.LinkedServer = EntityUid.Invalid; } - _entityManager.DeleteEntity(uid); + _entityManager.QueueDeleteEntity(uid); _adminLogger.Add(LogType.Unknown, LogImpact.Medium, $"{ToPrettyString(uid):mob} was disabled due to lack of projectors"); } diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HoloServerComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HoloServerComponent.cs index 14684df47b..2447b54f24 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HoloServerComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HoloServerComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.SimpleStation14.Hologram; +namespace Content.Shared.SimpleStation14.Holograms; [RegisterComponent] public sealed class HologramServerComponent : Component diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs index d5dcd5a320..99a1cfa956 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.SimpleStation14.Hologram; +namespace Content.Shared.SimpleStation14.Holograms; [RegisterComponent] public sealed class HologramComponent : Component diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectorComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectorComponent.cs index b63e4a634f..eb4708891c 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectorComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectorComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.SimpleStation14.Hologram; +namespace Content.Shared.SimpleStation14.Holograms; [RegisterComponent] public sealed class HologramProjectorComponent : Component diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs index c4eaf071e9..b01aa92771 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs @@ -18,13 +18,13 @@ namespace Content.Shared.SimpleStation14.Hologram; -public class SharedHologramSystem : EntitySystem +public sealed class SharedHologramSystem : EntitySystem { [Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] protected readonly SharedPopupSystem Popup = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedPullingSystem _pulling = default!; @@ -53,14 +53,15 @@ private void OnInteractionAttempt(InteractionAttemptEvent args) _entityManager.TryGetComponent(args.Uid, out var _)) return; - if (_tagSystem.HasAnyTag(args.Target.Value, "Softlight") && !_tagSystem.HasAnyTag(args.Target.Value, "Hardlight")){ + if (_tagSystem.HasAnyTag(args.Target.Value, "Softlight") && !_tagSystem.HasAnyTag(args.Target.Value, "Hardlight")) + { args.Cancel(); // Send a popup to the player about the interaction, and play a sound. var meta = _entityManager.GetComponent(args.Target.Value); var popup = Loc.GetString("system-hologram-light-interaction-fail", ("item", meta.EntityName)); var sound = "/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg"; - Popup.PopupEntity(popup, args.Target.Value, Filter.Entities(args.Uid), false); + _popup.PopupEntity(popup, args.Target.Value, Filter.Entities(args.Uid), false); _audio.Play(sound, Filter.Entities(args.Uid), args.Uid, false); } } @@ -99,8 +100,8 @@ public void HoloReturn(HologramReturnEvent args) { var uid = args.Uid; var component = _entityManager.GetComponent(uid); - var meta = _entityManager.GetComponent(uid); - var holoPos = _entityManager.GetComponent(uid).Coordinates; + var meta = MetaData(uid); + var holoPos = Transform(uid).Coordinates; var popupAppearOther = Loc.GetString("system-hologram-phasing-appear-others", ("name", meta.EntityName)); var popupAppearSelf = Loc.GetString("system-hologram-phasing-appear-self"); @@ -132,19 +133,19 @@ public void HoloReturn(HologramReturnEvent args) } _entityManager.TryGetComponent(component.CurProjector, out var transfComp); - Popup.PopupCoordinates(popupDisappearOther, holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); + _popup.PopupCoordinates(popupDisappearOther, holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(uid), coordinates: holoPos, false); - // Preapre to move holo + // Prepare to move holo if (TryComp(uid, out var pullable) && pullable.BeingPulled) _pulling.TryStopPull(pullable); if (TryComp(uid, out var pulling) && pulling.Pulling != null && TryComp(pulling.Pulling.Value, out var subjectPulling)) _pulling.TryStopPull(subjectPulling); // Move holo - Transform(uid).Coordinates = _entityManager.GetComponent((EntityUid) component.CurProjector).Coordinates; + Transform(uid).Coordinates = Transform((EntityUid) component.CurProjector).Coordinates; - Popup.PopupEntity(popupAppearOther, uid, Filter.PvsExcept((EntityUid) uid), false, PopupType.Medium); - Popup.PopupEntity(popupAppearSelf, uid, uid, PopupType.Large); + _popup.PopupEntity(popupAppearOther, uid, Filter.PvsExcept((EntityUid) uid), false, PopupType.Medium); + _popup.PopupEntity(popupAppearSelf, uid, uid, PopupType.Large); _audio.PlayPvs("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg", uid); _adminLogger.Add(LogType.Unknown, LogImpact.Low, From 10e158ea744007e3eef0c4cc775c0084ef1de745 Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Sun, 23 Apr 2023 20:54:22 -0400 Subject: [PATCH 15/25] Made Enum worked, cleaned up a bit, and fixed all namespaces --- .../SimpleStation14/Holograms/HologramSystem.cs | 4 ++-- .../Holograms/Systems/HologramServerSystem.cs | 2 +- .../Holograms/Systems/HologramSystem.cs | 2 +- .../Holograms/Components/HologramComponent.cs | 10 ++++++---- .../SimpleStation14/Holograms/HologramEvents.cs | 4 ++-- .../Holograms/Systems/SharedHologramSystem.cs | 4 ++-- .../Entities/Mobs/Player/hologram.yml | 12 +++++------- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Content.Client/SimpleStation14/Holograms/HologramSystem.cs b/Content.Client/SimpleStation14/Holograms/HologramSystem.cs index ff175a12ce..2f60ddb805 100644 --- a/Content.Client/SimpleStation14/Holograms/HologramSystem.cs +++ b/Content.Client/SimpleStation14/Holograms/HologramSystem.cs @@ -3,9 +3,9 @@ // using Content.Shared.Anomaly.Components; // using Robust.Client.GameObjects; // using Robust.Shared.Timing; -// using Content.Shared.SimpleStation14.Hologram; +// using Content.Shared.SimpleStation14.Holograms; -// namespace Content.Client.SimpleStation14.Hologram; +// namespace Content.Client.SimpleStation14.Holograms; // public sealed class HologramSystem : SharedHologramSystem // { diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs index 985edbf859..47d9515319 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -15,7 +15,7 @@ using Content.Server.Administration.Commands; using Content.Shared.Tag; using Content.Shared.Popups; -using Content.Shared.SimpleStation14.Hologram; +using Content.Shared.SimpleStation14.Holograms; using Content.Shared.Pulling; using Content.Shared.Administration.Logs; using Content.Shared.Database; diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs index a0bf8d4fae..8cfbc5284d 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs @@ -4,7 +4,7 @@ using Content.Shared.Tag; using Content.Shared.Popups; using Content.Shared.Interaction.Helpers; -using Content.Shared.SimpleStation14.Hologram; +using Content.Shared.SimpleStation14.Holograms; using Content.Shared.Actions; using Content.Shared.Actions.ActionTypes; using Content.Shared.Pulling; diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs index 99a1cfa956..a0f0732af6 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs @@ -1,3 +1,5 @@ +using Robust.Shared.Serialization.TypeSerializers.Implementations; + namespace Content.Shared.SimpleStation14.Holograms; [RegisterComponent] @@ -9,20 +11,20 @@ public sealed class HologramComponent : Component // [DataField("holoData"), ViewVariables] // public HoloData HoloData = new HoloData(HoloType.Projected, false); - [DataField("holoType")] - public HoloType HoloType = HoloType.Projected; + [DataField("holoType", customTypeSerializer: typeof(EnumSerializer))] + public Enum HoloType = HoloTypeEnum.Projected; [DataField("isHardlight")] public bool IsHardlight = false; // Current server the Hologram is generated by. // Will be the Lightbee if it's a Lightbee Hologram. - [ViewVariables] + [ViewVariables(VVAccess.ReadOnly)] public EntityUid? LinkedServer; // The current projector the Hologram is connected to. // Will be the Lightbee if it's a Lightbee Hologram. - [ViewVariables] + [ViewVariables(VVAccess.ReadOnly)] public EntityUid? CurProjector; // Counter before returning the Holo, so you can get through doors. diff --git a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs index c4c083dc3b..3c5f2e2d70 100644 --- a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs +++ b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs @@ -1,7 +1,7 @@ -using Content.Shared.SimpleStation14.Hologram; +using Content.Shared.SimpleStation14.Holograms; using Robust.Shared.Serialization; -namespace Content.Shared.SimpleStation14.Hologram; +namespace Content.Shared.SimpleStation14.Holograms; /// /// Raised when a hologram is being returned to its last visited projector. diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs index b01aa92771..6edc58d33b 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs @@ -16,7 +16,7 @@ using Content.Shared.Pulling; using System.Linq; -namespace Content.Shared.SimpleStation14.Hologram; +namespace Content.Shared.SimpleStation14.Holograms; public sealed class SharedHologramSystem : EntitySystem { @@ -153,7 +153,7 @@ public void HoloReturn(HologramReturnEvent args) } } -public enum HoloType +public enum HoloTypeEnum { Projected, Lightbee diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml index 6c6c4044c0..1b65500642 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml @@ -156,7 +156,7 @@ id: MobHologramProjected components: - type: Hologram - holoType: HoloType.Projected + holoType: enum.HoloTypeEnum.Projected isHardLight: false - type: Stealth lastVisibility: 0.80 @@ -182,9 +182,8 @@ id: MobHologramLightbee components: - type: Hologram - # holoData: !HoloData - # Type: Lightbee - # IsHardLight: false + holoData: enum.HoloTypeEnum.Lightbee + IsHardLight: false - type: Fixtures fixtures: - shape: @@ -223,9 +222,8 @@ id: MobHologramHardlight components: - type: Hologram - # holoData: - # Type: HoloType.Lightbee - # IsHardLight: true + holoData: enum.HoloTypeEnum.Lightbee + IsHardLight: true - type: Fixtures fixtures: - shape: From 7986db5f0fcb06b35b0b79cd52f04872ecd4bbaf Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Wed, 11 Oct 2023 18:22:16 -0400 Subject: [PATCH 16/25] Substantial cleanup to the code post rebase Man I was really smashing rocks together before :P Also I removed the stinky Nyano Holo stuff --- .../Holograms/HologramSystem.cs | 58 ++--- .../Holograms/HologramComponent.cs | 5 - .../Nyanotrasen/Holograms/HologramSystem.cs | 22 -- .../Holograms/Components/HoloDiskComponent.cs | 6 +- .../Holograms/Systems/HologramServerSystem.cs | 39 ++-- .../Holograms/Systems/HologramSystem.cs | 221 ++---------------- .../Holograms/Components/HologramComponent.cs | 37 +-- .../Holograms/HologramEvents.cs | 65 ------ .../Holograms/Systems/SharedHologramSystem.cs | 155 +++++++----- .../Computers/base_structurecomputers.yml | 2 - .../Entities/Mobs/Player/robots.yml | 1 - .../Entities/Mobs/NPCs/pets.yml | 27 +-- .../Entities/Mobs/Player/hologram.yml | 29 +-- .../Entities/Mobs/Player/silicon.yml | 17 +- .../Machines/hologram_constructor.yml | 1 - Resources/Prototypes/SimpleStation14/tags.yml | 5 +- 16 files changed, 240 insertions(+), 450 deletions(-) delete mode 100644 Content.Server/Nyanotrasen/Holograms/HologramComponent.cs delete mode 100644 Content.Server/Nyanotrasen/Holograms/HologramSystem.cs diff --git a/Content.Client/SimpleStation14/Holograms/HologramSystem.cs b/Content.Client/SimpleStation14/Holograms/HologramSystem.cs index 2f60ddb805..7a14414dd5 100644 --- a/Content.Client/SimpleStation14/Holograms/HologramSystem.cs +++ b/Content.Client/SimpleStation14/Holograms/HologramSystem.cs @@ -1,35 +1,35 @@ -// using Content.Client.Gravity; -// using Content.Shared.Anomaly; -// using Content.Shared.Anomaly.Components; -// using Robust.Client.GameObjects; -// using Robust.Shared.Timing; -// using Content.Shared.SimpleStation14.Holograms; +using Content.Client.Gravity; +using Content.Shared.Anomaly; +using Content.Shared.Anomaly.Components; +using Robust.Client.GameObjects; +using Robust.Shared.Timing; +using Content.Shared.SimpleStation14.Holograms; -// namespace Content.Client.SimpleStation14.Holograms; +namespace Content.Client.SimpleStation14.Holograms; -// public sealed class HologramSystem : SharedHologramSystem -// { -// [Dependency] private readonly IGameTiming _timing = default!; -// [Dependency] private readonly FloatingVisualizerSystem _floating = default!; +public sealed class HologramSystem : SharedHologramSystem +{ + // [Dependency] private readonly IGameTiming _timing = default!; + // [Dependency] private readonly FloatingVisualizerSystem _floating = default!; -// /// -// public override void Initialize() -// { -// base.Initialize(); + // /// + // public override void Initialize() + // { + // base.Initialize(); -// SubscribeLocalEvent(OnStartup); -// SubscribeLocalEvent(OnAnimationComplete); -// } + // SubscribeLocalEvent(OnStartup); + // SubscribeLocalEvent(OnAnimationComplete); + // } -// private void OnStartup(EntityUid uid, HologramComponent component, ref ComponentStartup args) -// { -// _floating.FloatAnimation(uid, new Vector2(0f, 0.07f), "holofloat", 3); -// } + // private void OnStartup(EntityUid uid, HologramComponent component, ref ComponentStartup args) + // { + // _floating.FloatAnimation(uid, new Vector2(0f, 0.07f), "holofloat", 3); + // } -// private void OnAnimationComplete(EntityUid uid, HologramComponent component, AnimationCompletedEvent args) -// { -// if (args.Key != "holofloat") -// return; -// _floating.FloatAnimation(uid, new Vector2(0, 0.15f), "holofloat", 3.5f); -// } -// } + // private void OnAnimationComplete(EntityUid uid, HologramComponent component, AnimationCompletedEvent args) + // { + // if (args.Key != "holofloat") + // return; + // _floating.FloatAnimation(uid, new Vector2(0, 0.15f), "holofloat", 3.5f); + // } +} diff --git a/Content.Server/Nyanotrasen/Holograms/HologramComponent.cs b/Content.Server/Nyanotrasen/Holograms/HologramComponent.cs deleted file mode 100644 index 69afa7cfe0..0000000000 --- a/Content.Server/Nyanotrasen/Holograms/HologramComponent.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Content.Server.Holograms -{ - [RegisterComponent] - public sealed class HologramComponent : Component { } -} diff --git a/Content.Server/Nyanotrasen/Holograms/HologramSystem.cs b/Content.Server/Nyanotrasen/Holograms/HologramSystem.cs deleted file mode 100644 index 4f95e3b14d..0000000000 --- a/Content.Server/Nyanotrasen/Holograms/HologramSystem.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Content.Shared.Storage.Components; - -namespace Content.Server.Holograms -{ - public sealed class HologramSystem : EntitySystem - { - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnStoreInContainerAttempt); - } - - private void OnStoreInContainerAttempt(EntityUid uid, HologramComponent component, ref StoreMobInItemContainerAttemptEvent args) - { - // TODO: It should be okay to move this to Shared. - // Forbid holograms from going inside anything. - args.Cancelled = true; - args.Handled = true; - } - } -} diff --git a/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs b/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs index 55a6f896f2..709260b942 100644 --- a/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs +++ b/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs @@ -5,9 +5,9 @@ namespace Content.Server.SimpleStation14.Holograms; [RegisterComponent] public sealed class HologramDiskComponent : Component { + /// + /// The mind stored in this Holodisk. + /// [ViewVariables] public Mind.Mind? HoloMind = null; - - [DataField("active"), ViewVariables(VVAccess.ReadWrite)] - public bool Active = true; } diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs index 47d9515319..c045b065b1 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -1,13 +1,9 @@ using System.Linq; -using Content.Server.Mind.Components; using Content.Server.Cloning; using Content.Server.Cloning.Components; using Content.Server.Psionics; -using Content.Server.Speech.Components; -using Content.Server.StationEvents.Components; using Content.Server.EUI; using Content.Server.Humanoid; -using Content.Server.Ghost.Roles.Components; using Content.Server.Jobs; using Content.Server.Mind; using Content.Server.Preferences.Managers; @@ -29,13 +25,13 @@ using Content.Shared.Interaction.Components; using Content.Shared.Access.Components; using Content.Shared.Clothing.Components; -using Content.Shared.Roles; using Robust.Server.Player; using Robust.Shared.Player; using Robust.Shared.Containers; using Robust.Shared.GameObjects.Components.Localization; using Content.Shared.Movement.Systems; using System.Threading.Tasks; +using Content.Server.Mind.Components; namespace Content.Server.SimpleStation14.Holograms; @@ -59,6 +55,7 @@ public sealed class HologramServerSystem : EntitySystem [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly SharedMoverController _mover = default!; + [Dependency] private readonly HologramSystem _hologram = default!; private const string DiskSlot = "holo_disk"; public readonly Dictionary ClonesWaitingForMind = new(); @@ -78,18 +75,18 @@ public override void Initialize() private void OnEntInserted(EntityUid uid, HologramServerComponent component, EntInsertedIntoContainerMessage args) { if (args.Container.ID != DiskSlot || !_tagSystem.HasTag(args.Entity, "HoloDisk") || - (_entityManager.TryGetComponent(args.Entity, out var diskComp) && diskComp.HoloMind == null)) return; + _entityManager.TryGetComponent(args.Entity, out var diskComp) && diskComp.HoloMind == null) return; if (component.LinkedHologram != EntityUid.Invalid && _entityManager.EntityExists(component.LinkedHologram)) { - RaiseLocalEvent(new HologramKillEvent(component.LinkedHologram.Value)); + _hologram.DoKillHologram(component.LinkedHologram.Value); } - if (TryHoloGenerate(component.Owner, _entityManager.GetComponent(args.Entity).HoloMind!, component, out var holo)) + if (TryHoloGenerate(uid, _entityManager.GetComponent(args.Entity).HoloMind!, component, out var holo)) { var holoComp = _entityManager.GetComponent(holo); component.LinkedHologram = holo; - holoComp.LinkedServer = component.Owner; + holoComp.LinkedServer = uid; } } @@ -103,7 +100,7 @@ private void OnEntRemoved(EntityUid uid, HologramServerComponent component, EntR if (_entityManager.EntityExists(component.LinkedHologram)) { - RaiseLocalEvent(new HologramKillEvent(component.LinkedHologram.Value)); + _hologram.DoKillHologram(component.LinkedHologram.Value); } } @@ -122,7 +119,7 @@ private void OnPowerChanged(EntityUid uid, HologramServerComponent component, re if (_entityManager.EntityExists(component.LinkedHologram)) { // Kill the Hologram - RaiseLocalEvent(new HologramKillEvent(component.LinkedHologram.Value)); + _hologram.DoKillHologram(component.LinkedHologram.Value); } } // If the server is powered @@ -156,7 +153,7 @@ public bool TryHoloGenerate(EntityUid uid, Mind.Mind mind, HologramServerCompone { if (EntityManager.EntityExists(clone) && !_mobStateSystem.IsDead(clone) && - TryComp(clone, out var cloneMindComp) && + TryComp(clone, out var cloneMindComp) && (cloneMindComp.Mind == null || cloneMindComp.Mind == mind)) return false; // Mind already has clone @@ -226,12 +223,13 @@ internal void TransferMindToClone(Mind.Mind mind) { if (!ClonesWaitingForMind.TryGetValue(mind, out var entity) || !EntityManager.EntityExists(entity) || - !TryComp(entity, out var mindComp) || + !TryComp(entity, out var mindComp) || mindComp.Mind != null) return; - mind.TransferTo(entity, ghostCheckOverride: true); - mind.UnVisit(); + _mind.TransferTo(mind, entity, true); + _mind.UnVisit(mind); + ClonesWaitingForMind.Remove(mind); } @@ -252,7 +250,7 @@ private EntityUid HoloFetchAndSpawn(HologramServerComponent holoServer, Humanoid _humanoidSystem.LoadProfile(mob, pref); MetaData(mob).EntityName = name; - var mind = EnsureComp(mob); + var mind = EnsureComp(mob); _mind.SetExamineInfo(mob, true, mind); var grammar = EnsureComp(mob); @@ -263,7 +261,7 @@ private EntityUid HoloFetchAndSpawn(HologramServerComponent holoServer, Humanoid var popupAppearOther = Loc.GetString("system-hologram-phasing-appear-others", ("name", MetaData(mob).EntityName)); var popupAppearSelf = Loc.GetString("system-hologram-phasing-appear-self"); - _popup.PopupEntity(popupAppearOther, mob, Filter.PvsExcept((EntityUid) mob), false, PopupType.Medium); + _popup.PopupEntity(popupAppearOther, mob, Filter.PvsExcept(mob), false, PopupType.Medium); _popup.PopupEntity(popupAppearSelf, mob, mob, PopupType.Large); _audio.PlayPvs("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg", mob); @@ -320,16 +318,21 @@ private async void ResetCamera(EntityUid mob) private void OnAfterInteract(EntityUid uid, HologramDiskComponent component, AfterInteractEvent args) { - if (args.Target == null || !TryComp(args.Target, out var targetMind)) + if (args.Target == null || !TryComp(args.Target, out var targetMind)) return; + if (targetMind.Mind == null) { _popup.PopupEntity(Loc.GetString("system-hologram-disk-mind-none"), args.Target.Value, args.User); + args.Handled = true; + return; } component.HoloMind = targetMind.Mind; _popup.PopupEntity(Loc.GetString("system-hologram-disk-mind-saved"), args.Target.Value, args.User); + + args.Handled = true; } diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs index 8cfbc5284d..9dc88f4c83 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs @@ -1,46 +1,17 @@ -using Content.Server.SurveillanceCamera; using Content.Server.GameTicking; using Content.Server.Mind.Components; -using Content.Shared.Tag; using Content.Shared.Popups; -using Content.Shared.Interaction.Helpers; using Content.Shared.SimpleStation14.Holograms; -using Content.Shared.Actions; -using Content.Shared.Actions.ActionTypes; using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; using Content.Shared.Administration.Logs; using Content.Shared.Database; -using Robust.Server.Player; using Robust.Shared.Player; -using Robust.Shared.Timing; -using Robust.Shared.Map; -using Robust.Shared.Prototypes; -using Content.Server.Cloning; -using Content.Server.Cloning.Components; - -using Content.Shared.Cloning; -using Content.Shared.Speech; -using Content.Shared.Preferences; -using Content.Shared.Emoting; -using Content.Server.Psionics; -using Content.Server.Speech.Components; -using Content.Server.StationEvents.Components; -using Content.Server.EUI; -using Content.Server.Humanoid; -using Content.Server.Ghost.Roles.Components; -using Content.Server.Jobs; -using Content.Server.Mind; -using Content.Server.Preferences.Managers; -using Content.Shared.Humanoid; -using Content.Shared.Mobs.Systems; -using Robust.Shared.GameObjects.Components.Localization; -using System.Linq; -using Robust.Shared.Utility; +using Content.Shared.Pulling.Components; +using Linguini.Syntax.Ast; namespace Content.Server.SimpleStation14.Holograms; -public sealed class HologramSystem : EntitySystem +public sealed class HologramSystem : SharedHologramSystem { [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; @@ -48,23 +19,13 @@ public sealed class HologramSystem : EntitySystem [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedPullingSystem _pulling = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; - [Dependency] private readonly IPlayerManager _playerManager = null!; - [Dependency] private readonly CloningSystem _cloningSystem = default!; - [Dependency] private readonly EuiManager _euiManager = null!; - [Dependency] private readonly HumanoidAppearanceSystem _humanoidSystem = default!; - [Dependency] private readonly MobStateSystem _mobStateSystem = default!; - [Dependency] private readonly MindSystem _mind = default!; - [Dependency] private readonly TagSystem _tag = default!; - [Dependency] private readonly IServerPreferencesManager _prefs = default!; + [Dependency] private readonly GameTicker _gameTicker = default!; public readonly Dictionary ClonesWaitingForMind = new(); public override void Initialize() { base.Initialize(); - SubscribeAllEvent(HoloKill); - SubscribeAllEvent(HoloGetProjector); - SubscribeAllEvent(HoloProjectorTest); // SubscribeLocalEvent(Startup); // SubscribeLocalEvent(Shutdown); // SubscribeLocalEvent(HoloTeleport); @@ -82,186 +43,42 @@ public override void Initialize() // _actionsSystem.RemoveAction(uid, action); // } - - // // Anything that needs to be regularly run, like handling exiting a projector's range - // public override void Update(float frameTime) - // { - // base.Update(frameTime); - - // foreach (var component in _entityManager.EntityQuery().ToList()) - // { - // var nearProj = HoloGetProjector(component); - // if (!nearProj.IsValid()) - // { - // if (component.Accumulator > 0) - // { - // component.Accumulator -= frameTime; - // continue; - // } - // RaiseLocalEvent(new HologramReturnEvent(component.Owner)); - // continue; - // } - // component.Accumulator = 0.24f; - // component.CurProjector = nearProj; - // } - // } - - /// - /// Tests if the given projector is valid. - /// - /// Event arguments. - public void HoloProjectorTest(HologramProjectorTestEvent args) - { - var curProjector = args.Projector; - if (curProjector == EntityUid.Invalid || !_entityManager.TryGetComponent(curProjector, out var _)) return; - if (_entityManager.TryGetComponent(curProjector, out var camComp) && !camComp.Active) return; - args.CanProject = true; - } - - /// - /// Tests for the nearest projector to the Hologram. - /// - /// Event arguments. - public void HoloGetProjector(HologramGetProjectorEvent args) - { - var uid = args.Hologram; - var component = _entityManager.GetComponent(uid); - var occlude = args.Occlude; - var range = args.Range; - - var xformQuery = GetEntityQuery(); - var transform = _entityManager.GetComponent(uid); - var playerPos = _transform.GetWorldPosition(transform, xformQuery); - var mapId = transform.MapID; - - // sort all entities in distance increasing order - var nearProjList = new SortedList(); - - foreach (var comp in _entityManager.EntityQuery()) - { - if (!xformQuery.TryGetComponent(comp.Owner, out var compXform) || compXform.MapID != mapId) - continue; - - var dist = (_transform.GetWorldPosition(compXform, xformQuery) - playerPos).LengthSquared; - nearProjList.TryAdd(dist, comp.Owner); - } - - foreach (var nearProj in nearProjList) - { - if (_entityManager.TryGetComponent(nearProj.Value, out var camComp) && !camComp.Active) continue; - if (occlude && !nearProj.Value.InRangeUnOccluded(uid, 18f)) continue; - args.Projector = nearProj.Value; - return; - } - } - - /// - /// Tests for the nearest projector to the Hologram. - /// - /// Hologram's HologramComponent. - /// Should it check only for unoccluded and in range projectors? - /// The range it should check for projectors in, if occlude is true - /// Returns the UID of the projector, or invalid UID if no projectors are found. - public EntityUid HoloGetProjector(HologramComponent component, bool occlude = true, float range = 18f) - { - var xformQuery = GetEntityQuery(); - var uid = component.Owner; - var transform = _entityManager.GetComponent(uid); - var playerPos = _transform.GetWorldPosition(transform, xformQuery); - var mapId = transform.MapID; - - // sort all entities in distance increasing order - var nearProjList = new SortedList(); - - foreach (var comp in _entityManager.EntityQuery()) - { - if (!xformQuery.TryGetComponent(comp.Owner, out var compXform) || compXform.MapID != mapId) - continue; - - var dist = (_transform.GetWorldPosition(compXform, xformQuery) - playerPos).LengthSquared; - nearProjList.TryAdd(dist, comp.Owner); - } - - foreach (var nearProj in nearProjList) - { - if (_entityManager.TryGetComponent(nearProj.Value, out var camComp) && !camComp.Active) continue; - if (occlude && !nearProj.Value.InRangeUnOccluded(uid, 18f)) continue; - return nearProj.Value; - } - return EntityUid.Invalid; - } - /// - /// Tests for the nearest projector to a set of coords. + /// Mind stuff is all server side, so this exists to actually kill the Hologram in reaction to . /// - /// Coords to test from. - /// Map being tested on. - /// Should it check only for unoccluded and in range projectors? - /// The range it should check for projectors in, if occlude is true - /// Returns the UID of the projector, or invalid UID if no projectors are found. - public EntityUid HoloGetProjector(Vector2 coords, MapId mapId, bool occlude = true, float range = 18f) + public override void DoReturnHologram(EntityUid uid, out bool holoKilled) { - var xformQuery = GetEntityQuery(); - - // sort all entities in distance increasing order - var nearProjList = new SortedList(); - - foreach (var comp in _entityManager.EntityQuery()) - { - if (!xformQuery.TryGetComponent(comp.Owner, out var compXform) || compXform.MapID != mapId) - continue; - - var dist = (_transform.GetWorldPosition(compXform, xformQuery) - coords).LengthSquared; - nearProjList.TryAdd(dist, comp.Owner); - } - - foreach (var nearProj in nearProjList) - { - if (_entityManager.TryGetComponent(nearProj.Value, out var camComp) && !camComp.Active) continue; - if (occlude && !nearProj.Value.InRangeUnOccluded(new MapCoordinates(coords, mapId), range)) continue; - return nearProj.Value; - } - return EntityUid.Invalid; + base.DoReturnHologram(uid, out holoKilled); + if (holoKilled) + DoKillHologram(uid); } /// /// Kills a Hologram after playing the visual and auditory effects. /// /// Hologram's HologramComponent. - public void HoloKill(HologramKillEvent args) + public void DoKillHologram(EntityUid uid) { - var uid = args.Uid; - var component = _entityManager.GetComponent(uid); - var meta = _entityManager.GetComponent(uid); - var holoPos = _entityManager.GetComponent(uid).Coordinates; - EntityUid? body = EntityUid.Invalid; - Mind.Mind? mind = null; + var component = Comp(uid); + var meta = MetaData(uid); + var holoPos = Transform(uid).Coordinates; - var popupAppearOther = Loc.GetString("system-hologram-phasing-appear-others", ("name", meta.EntityName)); - var popupAppearSelf = Loc.GetString("system-hologram-phasing-appear-self"); - var popupDisappearOther = Loc.GetString("system-hologram-phasing-disappear-others", ("name", meta.EntityName)); - var popupDeathSelf = Loc.GetString("system-hologram-phasing-death-self"); - - if (_entityManager.TryGetComponent(uid, out var mindComp) && mindComp.Mind != null) - { - body = mindComp.Mind.OwnedEntity; - mind = mindComp.Mind; - EntitySystem.Get().OnGhostAttempt(mindComp.Mind, false); - } + if (TryComp(uid, out var mindComp) && mindComp.Mind != null) + _gameTicker.OnGhostAttempt(mindComp.Mind, false); _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(uid), coordinates: holoPos, false); - _popup.PopupCoordinates(popupDisappearOther, holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); - _popup.PopupCoordinates(popupDeathSelf, holoPos, uid, PopupType.LargeCaution); + _popup.PopupCoordinates(Loc.GetString(PopupDisappearOther, ("name", meta.EntityName)), holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); + _popup.PopupCoordinates(Loc.GetString(PopupDeathSelf), holoPos, uid, PopupType.LargeCaution); if (component.LinkedServer != EntityUid.Invalid) { - if (_entityManager.TryGetComponent(component.LinkedServer!.Value, out var serverComp)) + if (TryComp(component.LinkedServer!.Value, out var serverComp)) serverComp.LinkedHologram = EntityUid.Invalid; component.LinkedServer = EntityUid.Invalid; } _entityManager.QueueDeleteEntity(uid); - _adminLogger.Add(LogType.Unknown, LogImpact.Medium, $"{ToPrettyString(uid):mob} was disabled due to lack of projectors"); + _adminLogger.Add(LogType.Mind, LogImpact.Medium, $"{ToPrettyString(uid):mob} was disabled due to lack of projectors"); } // private void HoloTeleport(HoloTeleportEvent args) diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs index a0f0732af6..efa5040b08 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs @@ -5,29 +5,40 @@ namespace Content.Shared.SimpleStation14.Holograms; [RegisterComponent] public sealed class HologramComponent : Component { - // // Custom struct that specifies the type of hologram. - // // First variable is the HoloType enum, second is whether or not it's hardlight. - // // Defaults to False. - // [DataField("holoData"), ViewVariables] - // public HoloData HoloData = new HoloData(HoloType.Projected, false); - + /// + /// The type of hologram this is. + /// + /// + /// See for possible values. [DataField("holoType", customTypeSerializer: typeof(EnumSerializer))] public Enum HoloType = HoloTypeEnum.Projected; + /// + /// Is this a hardlight Hologram. + /// [DataField("isHardlight")] public bool IsHardlight = false; - // Current server the Hologram is generated by. - // Will be the Lightbee if it's a Lightbee Hologram. + /// + /// The server that this hologram is generated by. + /// + /// + /// This will be the lightbee if it's a lightbee hologram. + /// [ViewVariables(VVAccess.ReadOnly)] public EntityUid? LinkedServer; - // The current projector the Hologram is connected to. - // Will be the Lightbee if it's a Lightbee Hologram. + /// + /// The current projector the hologram is connected to. + /// + /// + /// This will be the lightbee if it's a lightbee hologram. + /// [ViewVariables(VVAccess.ReadOnly)] public EntityUid? CurProjector; - // Counter before returning the Holo, so you can get through doors. - [DataField("accumulator")] - public float Accumulator = 0.5f; + /// + /// A timer for a grace period before the Holo is returned, to allow for moving through doors. + /// + public float GracePeriod = 0.5f; } diff --git a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs index 3c5f2e2d70..603e535677 100644 --- a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs +++ b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs @@ -1,68 +1,3 @@ -using Content.Shared.SimpleStation14.Holograms; using Robust.Shared.Serialization; namespace Content.Shared.SimpleStation14.Holograms; - -/// -/// Raised when a hologram is being returned to its last visited projector. -/// -[Serializable, NetSerializable] -public sealed class HologramReturnEvent : EntityEventArgs -{ - public EntityUid Uid; - - public HologramReturnEvent(EntityUid uid) - { - Uid = uid; - } -} - -/// -/// Raised when a hologram is being killed and removed from the game world. -/// -[Serializable, NetSerializable] -public sealed class HologramKillEvent : EntityEventArgs -{ - public EntityUid Uid; - - public HologramKillEvent(EntityUid uid) - { - Uid = uid; - } -} - -/// -/// Raised to return a bool if a given projector is valid for a given hologram. -/// -[Serializable, NetSerializable] -public sealed class HologramProjectorTestEvent : EntityEventArgs -{ - public EntityUid Hologram; - public EntityUid Projector; - public bool CanProject = false; - - public HologramProjectorTestEvent(EntityUid hologram, EntityUid projector) - { - Hologram = hologram; - Projector = projector; - } -} - -/// -/// Raised to return the nearest projector to a given hologram. -/// -[Serializable, NetSerializable] -public sealed class HologramGetProjectorEvent : EntityEventArgs -{ - public EntityUid Hologram; - public bool Occlude; - public float Range; - public EntityUid Projector; - - public HologramGetProjectorEvent(EntityUid hologram, bool occlude = true, float range = 18f) - { - Hologram = hologram; - Occlude = occlude; - Range = range; - } -} diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs index 6edc58d33b..db5e074c82 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs @@ -1,39 +1,41 @@ using Content.Shared.Interaction.Events; using Content.Shared.Interaction.Components; -using Content.Shared.Damage; -using Content.Shared.Item; using Content.Shared.Tag; -using Content.Shared.Interaction.Helpers; using Content.Shared.Popups; using Robust.Shared.Player; -using Robust.Shared.Timing; -using Robust.Shared.Serialization; -using Robust.Shared.Containers; -using Content.Shared.Computer; +using Content.Shared.Interaction.Helpers; +using Robust.Shared.Map; +using System.Numerics; +using System.Diagnostics.CodeAnalysis; +using Content.Shared.Storage.Components; using Content.Shared.Pulling.Components; -using Content.Shared.Administration.Logs; using Content.Shared.Database; +using Content.Shared.Administration.Logs; using Content.Shared.Pulling; -using System.Linq; namespace Content.Shared.SimpleStation14.Holograms; -public sealed class SharedHologramSystem : EntitySystem +public abstract class SharedHologramSystem : EntitySystem { [Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedPullingSystem _pulling = default!; + protected const string PopupAppearOther = "system-hologram-phasing-appear-others"; + protected const string PopupAppearSelf = "system-hologram-phasing-appear-self"; + protected const string PopupDisappearOther = "system-hologram-phasing-disappear-others"; + protected const string PopupDeathSelf = "system-hologram-phasing-death-self"; + protected const string PopupInteractionFail = "system-hologram-light-interaction-fail"; + public override void Initialize() { SubscribeLocalEvent(OnHoloInteractionAttempt); SubscribeLocalEvent(OnInteractionAttempt); - SubscribeAllEvent(HoloReturn); + SubscribeLocalEvent(OnStoreInContainerAttempt); } // Stops the Hologram from interacting with anything they shouldn't. @@ -59,35 +61,42 @@ private void OnInteractionAttempt(InteractionAttemptEvent args) // Send a popup to the player about the interaction, and play a sound. var meta = _entityManager.GetComponent(args.Target.Value); - var popup = Loc.GetString("system-hologram-light-interaction-fail", ("item", meta.EntityName)); + var popup = Loc.GetString(PopupInteractionFail, ("item", meta.EntityName)); var sound = "/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg"; _popup.PopupEntity(popup, args.Target.Value, Filter.Entities(args.Uid), false); _audio.Play(sound, Filter.Entities(args.Uid), args.Uid, false); } } - // Anything that needs to be regularly run, like handling exiting a projector's range + // Forbid holograms from going inside anything. Osmosised from Nyano :) + private void OnStoreInContainerAttempt(EntityUid uid, HologramComponent component, ref StoreMobInItemContainerAttemptEvent args) + { + args.Cancelled = true; + args.Handled = true; + } + public override void Update(float frameTime) { base.Update(frameTime); - foreach (var component in _entityManager.EntityQuery().ToList()) + var query = _entityManager.EntityQueryEnumerator(); + while (query.MoveNext(out var hologram, out var hologramComp)) { - var getProj = new HologramGetProjectorEvent(component.Owner); - RaiseLocalEvent(getProj); - var nearProj = getProj.Projector; - if (!nearProj.IsValid()) + TryGetHoloProjector(hologram, out var nearProj); + + if (nearProj == null) { - if (component.Accumulator > 0) + if (hologramComp.GracePeriod == 0) { - component.Accumulator -= frameTime; + hologramComp.GracePeriod -= frameTime; continue; } - RaiseLocalEvent(new HologramReturnEvent(component.Owner)); + DoReturnHologram(hologram, out _); continue; } - component.Accumulator = 0.24f; - component.CurProjector = nearProj; + + hologramComp.GracePeriod = 0.24f; + hologramComp.CurProjector = nearProj; } } @@ -95,45 +104,28 @@ public override void Update(float frameTime) /// Handles returning a Hologram to their last visited projector, /// then to the nearest, finally killing them if none are found. /// - /// Hologram's HologramComponent. - public void HoloReturn(HologramReturnEvent args) + public virtual void DoReturnHologram(EntityUid uid, out bool holoKilled) { - var uid = args.Uid; var component = _entityManager.GetComponent(uid); var meta = MetaData(uid); var holoPos = Transform(uid).Coordinates; - var popupAppearOther = Loc.GetString("system-hologram-phasing-appear-others", ("name", meta.EntityName)); - var popupAppearSelf = Loc.GetString("system-hologram-phasing-appear-self"); - var popupDisappearOther = Loc.GetString("system-hologram-phasing-disappear-others", ("name", meta.EntityName)); - var popupDeathSelf = Loc.GetString("system-hologram-phasing-death-self"); + holoKilled = false; - // If the Hologram's last projector isn't valid, try to find a new one. - if (component.CurProjector == null) + if (component.CurProjector == null) // TODO:HOLO Check if the projector works. { - return; + TryGetHoloProjector(uid, out component.CurProjector); } - var curProjCheck = new HologramProjectorTestEvent(uid, component.CurProjector.Value); - RaiseLocalEvent(curProjCheck); - if (!curProjCheck.CanProject) + if (component.CurProjector == null) // If the Hologram still doesn't have a working projector, kill it. // TODO:HOLO Check if the projector works. { - var getProj = new HologramGetProjectorEvent(uid, false); - RaiseLocalEvent(getProj); - component.CurProjector = getProj.Projector; - } - - // If the Hologram's last projector is still invalid, kill them. - if (component.CurProjector == EntityUid.Invalid) - { - // if (_timing.InPrediction) return; - - RaiseLocalEvent(new HologramKillEvent(uid)); + holoKilled = true; return; } + // TODO:HOLO Make this all part of a SetHoloProjector function. _entityManager.TryGetComponent(component.CurProjector, out var transfComp); - _popup.PopupCoordinates(popupDisappearOther, holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); + _popup.PopupCoordinates(Loc.GetString(PopupDisappearOther, ("name", meta.EntityName)), holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(uid), coordinates: holoPos, false); // Prepare to move holo @@ -142,21 +134,78 @@ public void HoloReturn(HologramReturnEvent args) TryComp(pulling.Pulling.Value, out var subjectPulling)) _pulling.TryStopPull(subjectPulling); // Move holo - Transform(uid).Coordinates = Transform((EntityUid) component.CurProjector).Coordinates; + _transform.SetCoordinates(uid, Transform(component.CurProjector.Value).Coordinates); - _popup.PopupEntity(popupAppearOther, uid, Filter.PvsExcept((EntityUid) uid), false, PopupType.Medium); - _popup.PopupEntity(popupAppearSelf, uid, uid, PopupType.Large); + _popup.PopupEntity(Loc.GetString(PopupAppearOther, ("name", meta.EntityName)), uid, Filter.PvsExcept(uid), false, PopupType.Medium); + _popup.PopupEntity(Loc.GetString(PopupAppearSelf, ("name", meta.EntityName)), uid, uid, PopupType.Large); _audio.PlayPvs("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg", uid); _adminLogger.Add(LogType.Unknown, LogImpact.Low, $"{ToPrettyString(uid):mob} was returned to projector {ToPrettyString((EntityUid) component.CurProjector):entity}"); } + + /// + /// Tests for the nearest projector to a set of coords. + /// + /// Coords to test from. + /// Map being tested on. + /// The UID of the projector, or null if no projectors are found. + /// Should it check only for unoccluded and in range projectors? + /// The range it should check for projectors in, if occlude is true + /// Returns true if a projector is found, false if not. + public bool TryGetHoloProjector(Vector2 coords, MapId mapId, [NotNullWhen(true)] out EntityUid? result, bool occlude = true, float range = 18f) + { + result = null; + + var xformQuery = GetEntityQuery(); + + // sort all entities in distance increasing order + var nearProjList = new SortedList(); + + var query = _entityManager.EntityQueryEnumerator(); + while (query.MoveNext(out var projector, out var projComp)) + { + if (!xformQuery.TryGetComponent(projector, out var compXform) || compXform.MapID != mapId) + continue; + + var dist = (_transform.GetWorldPosition(compXform!, xformQuery) - coords).LengthSquared(); + nearProjList.TryAdd(dist, projector); + } + + foreach (var nearProj in nearProjList) + { + if (occlude && !nearProj.Value.InRangeUnOccluded(new MapCoordinates(coords, mapId), range)) continue; + result = nearProj.Value; + return true; + } + return false; + } + + /// + public bool TryGetHoloProjector(EntityUid uid, [NotNullWhen(true)] out EntityUid? result, bool occlude = true, float range = 18f) + { + var xformQuery = GetEntityQuery(); + var transform = _entityManager.GetComponent(uid); + var playerPos = _transform.GetWorldPosition(transform, xformQuery); + + return TryGetHoloProjector(playerPos, transform.MapID, out result, occlude, range); + } } public enum HoloTypeEnum { + /// + /// A hologram projected from a projector. + /// Projected, - Lightbee + /// + /// A hologram tied to the internal storage of a lightbee. + /// + Lightbee, + /// + /// A hologram that + /// + Standalone, } // public struct HoloData diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml index 083f09726b..2d1be7b45b 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml @@ -57,8 +57,6 @@ containers: board: !type:Container ents: [] - - type: DynamicPrice - price: 400 - type: Tag tags: - Hardlight diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/robots.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/robots.yml index 0eedde7f29..459fa209dd 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/robots.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/robots.yml @@ -206,7 +206,6 @@ id: PlayerRobotStandard name: standard robot components: - - type: SiliconCharge - type: InnateTool tools: - id: WelderIndustrial diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml index 5521eed937..2e45c5b391 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml @@ -48,7 +48,7 @@ - type: entity name: holo corgi - description: "A hologramatic projection of a corgi, computed by the AI and rendered by the station's cameras." + description: "A hologramatic projection of a corgi, computed by the SAI and rendered by the station's cameras." id: MobCorgiHolo suffix: AI components: @@ -62,9 +62,9 @@ rootTask: SimpleHostileCompound - type: Input context: "human" - - type: Faction - factions: - - Pet + # - type: Faction + # factions: + # - Pet - type: MovementSpeedModifier baseWalkSpeed : 4.5 baseSprintSpeed : 3 @@ -82,15 +82,16 @@ bodyType: KinematicController # Same for all inheritors - type: Fixtures fixtures: - - shape: - # Circles, cuz rotation of rectangles looks very bad - !type:PhysShapeCircle - radius: 0.35 - density: 50 - mask: - - MobMask - layer: - - MobLayer + fix1: + shape: + # Circles, cuz rotation of rectangles looks very bad + !type:PhysShapeCircle + radius: 0.35 + density: 50 + mask: + - MobMask + layer: + - MobLayer - type: MobState - type: Body prototype: Animal diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml index 1b65500642..b57e06f704 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml @@ -93,7 +93,8 @@ bodyType: KinematicController - type: Fixtures fixtures: - - shape: + fix1: + shape: !type:PhysShapeCircle radius: 0.35 density: 25 @@ -141,7 +142,7 @@ proper: true - type: Hologram - type: AnimationPlayer - - type: Mind + - type: MindContainer showExamineInfo: true - type: Inventory - type: Actions @@ -165,9 +166,9 @@ interactSuccessString: hugging-success-hologram # interactSuccessSound: /Audio/Effects/thudswoosh.ogg messagePerceivedByOthers: hugging-success-hologram-others - - type: Faction - factions: - - NanoTrasen + # - type: Faction + # factions: + # - NanoTrasen - type: PointLight radius: 1.0 softness: 1.4 @@ -186,7 +187,8 @@ IsHardLight: false - type: Fixtures fixtures: - - shape: + fix1: + shape: !type:PhysShapeCircle radius: 0.05 density: 25 @@ -205,9 +207,9 @@ # interactSuccessSound: /Audio/Effects/thudswoosh.ogg messagePerceivedByOthers: hugging-success-hologram-others - type: CameraRecoil - - type: Faction - factions: - - NanoTrasen + # - type: Faction + # factions: + # - NanoTrasen - type: PointLight radius: 1.5 softness: 0.8 @@ -226,7 +228,8 @@ IsHardLight: true - type: Fixtures fixtures: - - shape: + fix1: + shape: !type:PhysShapeCircle radius: 0.35 density: 25 @@ -255,9 +258,9 @@ # interactSuccessSound: /Audio/Effects/thudswoosh.ogg messagePerceivedByOthers: hugging-success-hologram-others - type: CameraRecoil - - type: Faction - factions: - - NanoTrasen + # - type: Faction + # factions: + # - NanoTrasen - type: PointLight radius: 0.8 softness: 0.4 diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon.yml index 1f5a0e47f3..e5497b43c9 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon.yml @@ -69,14 +69,15 @@ sprite: SimpleStation14/Mobs/Silicon/scutter.rsi - type: Fixtures fixtures: - - shape: - !type:PhysShapeCircle - radius: 0.25 - density: 50 - mask: - - SmallMobMask - layer: - - SmallMobLayer + fix1: + shape: + !type:PhysShapeCircle + radius: 0.25 + density: 50 + mask: + - SmallMobMask + layer: + - SmallMobLayer # - type: Appearance # visuals: # - type: GenericEnumVisualizer diff --git a/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml b/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml index 4b28140d4d..24dc0f04a3 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml @@ -111,7 +111,6 @@ range: 5 sound: path: /Audio/Ambience/Objects/server_fans.ogg - # - type: CloningPod - type: HologramServer - type: ItemSlots slots: diff --git a/Resources/Prototypes/SimpleStation14/tags.yml b/Resources/Prototypes/SimpleStation14/tags.yml index 92909f0730..518897da79 100644 --- a/Resources/Prototypes/SimpleStation14/tags.yml +++ b/Resources/Prototypes/SimpleStation14/tags.yml @@ -4,11 +4,12 @@ - type: Tag id: Hardlight -- type: Tag - id: Softlight - type: Tag id: HoloDisk +- type: Tag + id: Softlight + - type: Tag id: Plushie From 45a55d59079a54c5f32ba83981a9c1c9000b2a78 Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Thu, 12 Oct 2023 04:55:49 -0400 Subject: [PATCH 17/25] Fixes double-playing audio --- .../Holograms/Systems/SharedHologramSystem.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs index db5e074c82..1030c11874 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs @@ -12,6 +12,7 @@ using Content.Shared.Database; using Content.Shared.Administration.Logs; using Content.Shared.Pulling; +using Robust.Shared.Timing; namespace Content.Shared.SimpleStation14.Holograms; @@ -24,6 +25,7 @@ public abstract class SharedHologramSystem : EntitySystem [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedPullingSystem _pulling = default!; + [Dependency] private readonly GameTiming _timing = default!; protected const string PopupAppearOther = "system-hologram-phasing-appear-others"; protected const string PopupAppearSelf = "system-hologram-phasing-appear-self"; @@ -125,8 +127,11 @@ public virtual void DoReturnHologram(EntityUid uid, out bool holoKilled) // TODO:HOLO Make this all part of a SetHoloProjector function. _entityManager.TryGetComponent(component.CurProjector, out var transfComp); - _popup.PopupCoordinates(Loc.GetString(PopupDisappearOther, ("name", meta.EntityName)), holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); - _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(uid), coordinates: holoPos, false); + if (_timing.IsFirstTimePredicted) + { + _popup.PopupCoordinates(Loc.GetString(PopupDisappearOther, ("name", meta.EntityName)), holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); + _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(uid), coordinates: holoPos, false); + } // Prepare to move holo if (TryComp(uid, out var pullable) && pullable.BeingPulled) _pulling.TryStopPull(pullable); @@ -136,9 +141,12 @@ public virtual void DoReturnHologram(EntityUid uid, out bool holoKilled) // Move holo _transform.SetCoordinates(uid, Transform(component.CurProjector.Value).Coordinates); - _popup.PopupEntity(Loc.GetString(PopupAppearOther, ("name", meta.EntityName)), uid, Filter.PvsExcept(uid), false, PopupType.Medium); - _popup.PopupEntity(Loc.GetString(PopupAppearSelf, ("name", meta.EntityName)), uid, uid, PopupType.Large); - _audio.PlayPvs("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg", uid); + if (_timing.IsFirstTimePredicted) + { + _popup.PopupEntity(Loc.GetString(PopupAppearOther, ("name", meta.EntityName)), uid, Filter.PvsExcept(uid), false, PopupType.Medium); + _popup.PopupEntity(Loc.GetString(PopupAppearSelf, ("name", meta.EntityName)), uid, uid, PopupType.Large); + _audio.PlayPvs("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg", uid); + } _adminLogger.Add(LogType.Unknown, LogImpact.Low, $"{ToPrettyString(uid):mob} was returned to projector {ToPrettyString((EntityUid) component.CurProjector):entity}"); From 5279c738d058eabee55d30c5165cc516b6b59ac5 Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Sun, 15 Oct 2023 05:23:15 -0400 Subject: [PATCH 18/25] Completely overhauled large portions. The HologramComponent has now been broken up into three Components, soon to be more. All the functions of the HologramSystem are chunked up and completely reconsidered. Prediction is cool. --- .../Holograms/HologramSystem.cs | 38 +-- .../Holograms/Systems/HologramServerSystem.cs | 40 ++-- .../Holograms/Systems/HologramSystem.cs | 22 +- .../Holograms/Components/HologramComponent.cs | 36 +-- .../Components/HologramProjectedComponent.cs | 29 +++ .../HologramServerLinkedComponent.cs | 25 ++ .../Systems/SharedHologramSystem.Projected.cs | 222 ++++++++++++++++++ .../Holograms/Systems/SharedHologramSystem.cs | 158 +------------ .../Entities/Mobs/Player/hologram.yml | 5 +- 9 files changed, 330 insertions(+), 245 deletions(-) create mode 100644 Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs create mode 100644 Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs create mode 100644 Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs diff --git a/Content.Client/SimpleStation14/Holograms/HologramSystem.cs b/Content.Client/SimpleStation14/Holograms/HologramSystem.cs index 7a14414dd5..fc3573d780 100644 --- a/Content.Client/SimpleStation14/Holograms/HologramSystem.cs +++ b/Content.Client/SimpleStation14/Holograms/HologramSystem.cs @@ -1,35 +1,17 @@ -using Content.Client.Gravity; -using Content.Shared.Anomaly; -using Content.Shared.Anomaly.Components; -using Robust.Client.GameObjects; -using Robust.Shared.Timing; -using Content.Shared.SimpleStation14.Holograms; +using Content.Shared.SimpleStation14.Holograms; +using Content.Shared.SimpleStation14.Holograms.Components; +using Robust.Client.Player; namespace Content.Client.SimpleStation14.Holograms; public sealed class HologramSystem : SharedHologramSystem { - // [Dependency] private readonly IGameTiming _timing = default!; - // [Dependency] private readonly FloatingVisualizerSystem _floating = default!; + [Dependency] private readonly IPlayerManager _player = default!; - // /// - // public override void Initialize() - // { - // base.Initialize(); - - // SubscribeLocalEvent(OnStartup); - // SubscribeLocalEvent(OnAnimationComplete); - // } - - // private void OnStartup(EntityUid uid, HologramComponent component, ref ComponentStartup args) - // { - // _floating.FloatAnimation(uid, new Vector2(0f, 0.07f), "holofloat", 3); - // } - - // private void OnAnimationComplete(EntityUid uid, HologramComponent component, AnimationCompletedEvent args) - // { - // if (args.Key != "holofloat") - // return; - // _floating.FloatAnimation(uid, new Vector2(0, 0.15f), "holofloat", 3.5f); - // } + public override void Update(float frameTime) + { + var player = _player.LocalPlayer?.ControlledEntity; + if (TryComp(player, out var holoProjComp)) + ProjectedUpdate(player.Value, holoProjComp, frameTime); + } } diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs index c045b065b1..eb29e3d200 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -32,6 +32,7 @@ using Content.Shared.Movement.Systems; using System.Threading.Tasks; using Content.Server.Mind.Components; +using Content.Shared.SimpleStation14.Holograms.Components; namespace Content.Server.SimpleStation14.Holograms; @@ -75,18 +76,19 @@ public override void Initialize() private void OnEntInserted(EntityUid uid, HologramServerComponent component, EntInsertedIntoContainerMessage args) { if (args.Container.ID != DiskSlot || !_tagSystem.HasTag(args.Entity, "HoloDisk") || - _entityManager.TryGetComponent(args.Entity, out var diskComp) && diskComp.HoloMind == null) return; + !_entityManager.TryGetComponent(args.Entity, out var diskComp) || diskComp.HoloMind == null) + return; - if (component.LinkedHologram != EntityUid.Invalid && _entityManager.EntityExists(component.LinkedHologram)) + if (component.LinkedHologram != null && _entityManager.EntityExists(component.LinkedHologram)) { _hologram.DoKillHologram(component.LinkedHologram.Value); } - if (TryHoloGenerate(uid, _entityManager.GetComponent(args.Entity).HoloMind!, component, out var holo)) + if (TryHoloGenerate(uid, diskComp.HoloMind!, component, out var holo)) { - var holoComp = _entityManager.GetComponent(holo); + var holoLinkComp = _entityManager.EnsureComponent(holo); component.LinkedHologram = holo; - holoComp.LinkedServer = uid; + holoLinkComp.LinkedServer = uid; } } @@ -96,7 +98,7 @@ private void OnEntInserted(EntityUid uid, HologramServerComponent component, Ent private void OnEntRemoved(EntityUid uid, HologramServerComponent component, EntRemovedFromContainerMessage args) { if (args.Container.ID != DiskSlot || !_tagSystem.HasTag(args.Entity, "HoloDisk") || - (_entityManager.TryGetComponent(args.Entity, out var diskComp) && diskComp.HoloMind == null)) return; + !_entityManager.TryGetComponent(args.Entity, out var diskComp) || diskComp.HoloMind == null) return; if (_entityManager.EntityExists(component.LinkedHologram)) { @@ -112,34 +114,32 @@ private void OnEntRemoved(EntityUid uid, HologramServerComponent component, EntR /// The PowerChangedEvent private void OnPowerChanged(EntityUid uid, HologramServerComponent component, ref PowerChangedEvent args) { - // If the server is no longer powered - if (!args.Powered && component.LinkedHologram != null && component.LinkedHologram != EntityUid.Invalid) + // If the server is no longer powered and the hologram exists + if (!args.Powered && _entityManager.EntityExists(component.LinkedHologram)) { - // If the hologram exists - if (_entityManager.EntityExists(component.LinkedHologram)) - { - // Kill the Hologram - _hologram.DoKillHologram(component.LinkedHologram.Value); - } + // Kill the Hologram + _hologram.DoKillHologram(component.LinkedHologram.Value); + component.LinkedHologram = null; } + // If the server is powered - else if (args.Powered && component.LinkedHologram == EntityUid.Invalid) + else if (args.Powered) { - var serverContainer = _entityManager.GetComponent(component.Owner); + var serverContainer = _entityManager.GetComponent(uid); if (serverContainer.GetContainer(DiskSlot).ContainedEntities.Count <= 0) { return; // No disk in the server } - var disk = serverContainer.GetContainer(DiskSlot).ContainedEntities.First(); + var disk = serverContainer.GetContainer(DiskSlot).ContainedEntities[0]; var diskData = _entityManager.GetComponent(disk).HoloMind; // If the hologram is generated successfully - if (diskData != null && TryHoloGenerate(component.Owner, diskData, component, out var holo)) + if (diskData != null && TryHoloGenerate(uid, diskData, component, out var holo)) { // Set the linked hologram to the generated hologram - var holoComp = _entityManager.GetComponent(holo); + var holoLinkComp = _entityManager.EnsureComponent(holo); component.LinkedHologram = holo; - holoComp.LinkedServer = component.Owner; + holoLinkComp.LinkedServer = uid; } } } diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs index 9dc88f4c83..5eb9c1ea30 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs @@ -8,6 +8,9 @@ using Robust.Shared.Player; using Content.Shared.Pulling.Components; using Linguini.Syntax.Ast; +using Robust.Shared.Timing; +using JetBrains.Annotations; +using Content.Shared.SimpleStation14.Holograms.Components; namespace Content.Server.SimpleStation14.Holograms; @@ -46,9 +49,9 @@ public override void Initialize() /// /// Mind stuff is all server side, so this exists to actually kill the Hologram in reaction to . /// - public override void DoReturnHologram(EntityUid uid, out bool holoKilled) + public override void DoReturnHologram(EntityUid uid, out bool holoKilled, HologramProjectedComponent? component = null) { - base.DoReturnHologram(uid, out holoKilled); + base.DoReturnHologram(uid, out holoKilled, component); if (holoKilled) DoKillHologram(uid); } @@ -56,10 +59,11 @@ public override void DoReturnHologram(EntityUid uid, out bool holoKilled) /// /// Kills a Hologram after playing the visual and auditory effects. /// - /// Hologram's HologramComponent. - public void DoKillHologram(EntityUid uid) + public void DoKillHologram(EntityUid uid, HologramComponent? holoComp = null) { - var component = Comp(uid); + if (!Resolve(uid, ref holoComp)) + return; + var meta = MetaData(uid); var holoPos = Transform(uid).Coordinates; @@ -69,11 +73,11 @@ public void DoKillHologram(EntityUid uid) _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(uid), coordinates: holoPos, false); _popup.PopupCoordinates(Loc.GetString(PopupDisappearOther, ("name", meta.EntityName)), holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); _popup.PopupCoordinates(Loc.GetString(PopupDeathSelf), holoPos, uid, PopupType.LargeCaution); - if (component.LinkedServer != EntityUid.Invalid) + if (TryComp(uid, out var holoLinkComp) && holoLinkComp.LinkedServer != null) { - if (TryComp(component.LinkedServer!.Value, out var serverComp)) - serverComp.LinkedHologram = EntityUid.Invalid; - component.LinkedServer = EntityUid.Invalid; + if (TryComp(holoLinkComp.LinkedServer.Value, out var serverComp)) + serverComp.LinkedHologram = null; + holoLinkComp.LinkedServer = null; } _entityManager.QueueDeleteEntity(uid); diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs index efa5040b08..e100508378 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs @@ -2,43 +2,17 @@ namespace Content.Shared.SimpleStation14.Holograms; +/// +/// Marks the entity as a being made of light. +/// Details determined by sister components. +/// [RegisterComponent] public sealed class HologramComponent : Component { - /// - /// The type of hologram this is. - /// - /// - /// See for possible values. - [DataField("holoType", customTypeSerializer: typeof(EnumSerializer))] - public Enum HoloType = HoloTypeEnum.Projected; - /// /// Is this a hardlight Hologram. /// + [ViewVariables(VVAccess.ReadWrite)] [DataField("isHardlight")] public bool IsHardlight = false; - - /// - /// The server that this hologram is generated by. - /// - /// - /// This will be the lightbee if it's a lightbee hologram. - /// - [ViewVariables(VVAccess.ReadOnly)] - public EntityUid? LinkedServer; - - /// - /// The current projector the hologram is connected to. - /// - /// - /// This will be the lightbee if it's a lightbee hologram. - /// - [ViewVariables(VVAccess.ReadOnly)] - public EntityUid? CurProjector; - - /// - /// A timer for a grace period before the Holo is returned, to allow for moving through doors. - /// - public float GracePeriod = 0.5f; } diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs new file mode 100644 index 0000000000..98ddd7595b --- /dev/null +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs @@ -0,0 +1,29 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.SimpleStation14.Holograms.Components; + +/// +/// Marks that this Hologram requires a server to generate it. +/// +[RegisterComponent] +[NetworkedComponent] +public sealed class HologramProjectedComponent : Component +{ + /// + /// A timer for a grace period before the Holo is returned, to allow for moving through doors. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("gracePeriod")] + public float GracePeriod = 0.5f; + + /// + /// The current projector the hologram is connected to. + /// + [ViewVariables(VVAccess.ReadOnly)] + public EntityUid? CurProjector; + + /// + /// A timer for a grace period before the Holo is returned, to allow for moving through doors. + /// + public float GraceTimer = 0.5f; +} diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs new file mode 100644 index 0000000000..5833be940e --- /dev/null +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs @@ -0,0 +1,25 @@ +namespace Content.Shared.SimpleStation14.Holograms.Components; + +/// +/// Marks that this Hologram requires a server of some kind to generate it. +/// +[RegisterComponent] +public sealed class HologramServerLinkedComponent : Component +{ + /// + /// Whether this Hologram is bound to the same grid as its server. + /// If false, it will be returned if it leaves the grid. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("gridBound")] + public bool GridBound = true; + + /// + /// The server that this hologram is generated by. + /// + /// + /// This will be the lightbee if it's a lightbee hologram. + /// + [ViewVariables(VVAccess.ReadOnly)] + public EntityUid? LinkedServer; +} diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs new file mode 100644 index 0000000000..79b4f5128a --- /dev/null +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs @@ -0,0 +1,222 @@ +using Content.Shared.Popups; +using Robust.Shared.Player; +using Content.Shared.Interaction.Helpers; +using Robust.Shared.Map; +using System.Diagnostics.CodeAnalysis; +using Content.Shared.Storage.Components; +using Content.Shared.Pulling.Components; +using Content.Shared.Database; +using Content.Shared.SimpleStation14.Holograms.Components; + +namespace Content.Shared.SimpleStation14.Holograms; + +public abstract partial class SharedHologramSystem +{ + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = _entityManager.EntityQueryEnumerator(); + while (query.MoveNext(out var hologram, out var hologramProjectedComp)) + { + ProjectedUpdate(hologram, hologramProjectedComp, frameTime); + } + } + + /// + /// Returns a hologram to its last visited projector, or kills it if the projector is invalid. + /// + /// The hologram to return. + /// True if the hologram was killed, false if it was returned. + /// The hologram's projected component. + public virtual void DoReturnHologram(EntityUid hologram, out bool holoKilled, HologramProjectedComponent? holoProjectedComp = null) + { + holoKilled = false; + + if (!Resolve(hologram, ref holoProjectedComp)) + return; + + if (!IsHoloProjectorValid(hologram, holoProjectedComp.CurProjector, 0, false)) // If their last visited Projector is invalid... + { + if (!TryGetHoloProjector(hologram, out holoProjectedComp.CurProjector, 0, false)) // Check for a new one, ignoring occlusion... + { + holoKilled = true; // And if none is found, kill the hologram. + return; + } + } + + MoveHologramToProjector(hologram, holoProjectedComp.CurProjector!.Value); + + _adminLogger.Add(LogType.Mind, LogImpact.Low, + $"{ToPrettyString(hologram):mob} was returned to projector {ToPrettyString(holoProjectedComp.CurProjector.Value):entity}"); + } + + /// + /// Tests for the nearest projector to a set of coords. + /// + /// The coords to perform the check from. + /// The UID of the projector, or null if no projectors are found. + /// The range it should check for projectors in, if occlude is true + /// Should it check only for unoccluded and in range projectors? + /// Returns true if a projector is found, false if not. + public bool TryGetHoloProjector(MapCoordinates coords, [NotNullWhen(true)] out EntityUid? result, float range = 18f, bool occlude = true) + { + result = null; + + // Sort all projectors in distance increasing order. + var nearProjList = new SortedList(); + + var query = _entityManager.EntityQueryEnumerator(); + while (query.MoveNext(out var projector, out _)) + { + var dist = (_transform.GetWorldPosition(projector) - coords.Position).LengthSquared(); + nearProjList.TryAdd(dist, projector); + } + + // Find the nearest, valid projector. + foreach (var nearProj in nearProjList) + { + if (!IsHoloProjectorValid(coords, nearProj.Value, range, occlude)) continue; + result = nearProj.Value; + return true; + } + return false; + } + + /// + public bool TryGetHoloProjector(EntityUid uid, out EntityUid? result, float range = 18f, bool occlude = true) + { + return TryGetHoloProjector(Transform(uid).MapPosition, out result, range, occlude); + } + + /// + /// Returns the best projector for a hologram to use. + /// + /// + /// Defaults to the hologram's current projector, if it has one. + /// + /// The hologram to find a projector for. + /// The UID of the projector, or null if no projectors are found. + /// The hologram's projected component. + public bool TryGetWorkingProjector(EntityUid hologram, [NotNullWhen(true)] out EntityUid? projector, HologramProjectedComponent? holoProjectedComp = null) + { + projector = null; + + if (!Resolve(hologram, ref holoProjectedComp)) + return false; + + if (IsHoloProjectorValid(hologram, holoProjectedComp.CurProjector)) + { + projector = holoProjectedComp.CurProjector!; + return true; + } + + return TryGetHoloProjector(hologram, out projector); + } + + /// + /// Tests if a projector is valid for a given hologram. + /// + /// The hologram to check for, or its position. + /// The projector to compare on, or its position. + /// The max range to allow. Ignored if occlude is false. + /// Should it check only for unoccluded and in range projectors? + /// True if the projector is within range, and unoccluded to the hologram. Otherwise, false. + public bool IsHoloProjectorValid(EntityUid hologram, EntityUid? projector, float range = 18f, bool occlude = true) + { + return _entityManager.EntityExists(projector) && (!occlude || projector.Value.InRangeUnOccluded(hologram, range)); + } + + /// + public bool IsHoloProjectorValid(EntityUid hologram, MapCoordinates projector, float range = 18f, bool occlude = true) + { + return !occlude || projector.InRangeUnOccluded(hologram, range); + } + + /// + public bool IsHoloProjectorValid(MapCoordinates hologram, EntityUid? projector, float range = 18f, bool occlude = true) + { + return _entityManager.EntityExists(projector) && (!occlude || projector.Value.InRangeUnOccluded(hologram, range)); + } + + /// + public bool IsHoloProjectorValid(MapCoordinates hologram, MapCoordinates projector, float range = 18f, bool occlude = true) + { + return !occlude || projector.InRangeUnOccluded(hologram, range); + } + + /// + /// Moves a hologram to a projector. + /// + /// The hologram to move. + /// The projector to move it to. + public void MoveHologram(EntityUid hologram, EntityCoordinates projector) + { + // Stops any pulling goin on. + if (TryComp(hologram, out var pullable) && pullable.BeingPulled) + _pulling.TryStopPull(pullable); + + if (TryComp(hologram, out var pulling) && pulling.Pulling != null && + TryComp(pulling.Pulling.Value, out var subjectPulling)) + _pulling.TryStopPull(subjectPulling); + + // Plays the vanishing effects. + var meta = MetaData(hologram); + + if (!_timing.InPrediction) + { + var holoPos = Transform(hologram).Coordinates; + _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(hologram), coordinates: holoPos, false); + _popup.PopupCoordinates(Loc.GetString(PopupDisappearOther, ("name", meta.EntityName)), holoPos, Filter.PvsExcept(hologram), false, PopupType.MediumCaution); + } + + // Does the do. + _transform.SetCoordinates(hologram, projector); + + // Plays the appearing effects. + if (!_timing.InPrediction) + { + _audio.PlayPvs("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg", hologram); + _popup.PopupEntity(Loc.GetString(PopupAppearOther, ("name", meta.EntityName)), hologram, Filter.PvsExcept(hologram), false, PopupType.Medium); + _popup.PopupEntity(Loc.GetString(PopupAppearSelf, ("name", meta.EntityName)), hologram, hologram, PopupType.Large); + } + } + + /// + public void MoveHologramToProjector(EntityUid hologram, EntityUid projector) + { + MoveHologram(hologram, Transform(projector).Coordinates); + } + + protected bool ProjectedUpdate(EntityUid hologram, HologramProjectedComponent hologramProjectedComp, float frameTime) + { + if (TryGetWorkingProjector(hologram, out var nearProj, hologramProjectedComp)) + { + hologramProjectedComp.GraceTimer = hologramProjectedComp.GracePeriod; + hologramProjectedComp.CurProjector = nearProj; + return true; + } + + // If none is found, starts counting... + if (hologramProjectedComp.GraceTimer > 0) + { + hologramProjectedComp.GraceTimer -= frameTime; + return true; + } + + // Attempts to return the hologram if their time is up. + DoReturnHologram(hologram, out _); + return false; + } + + // Forbid holograms from going inside anything. Osmosised from Nyano :) + private void OnStoreInContainerAttempt(EntityUid uid, HologramComponent component, ref StoreMobInItemContainerAttemptEvent args) + { + if (HasComp(uid)) + { + DoReturnHologram(uid, out _); + args.Cancelled = true; + args.Handled = true; + } + } +} diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs index 1030c11874..b73bae4881 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs @@ -3,20 +3,15 @@ using Content.Shared.Tag; using Content.Shared.Popups; using Robust.Shared.Player; -using Content.Shared.Interaction.Helpers; -using Robust.Shared.Map; -using System.Numerics; -using System.Diagnostics.CodeAnalysis; using Content.Shared.Storage.Components; -using Content.Shared.Pulling.Components; -using Content.Shared.Database; using Content.Shared.Administration.Logs; using Content.Shared.Pulling; using Robust.Shared.Timing; +using Robust.Shared.Network; namespace Content.Shared.SimpleStation14.Holograms; -public abstract class SharedHologramSystem : EntitySystem +public abstract partial class SharedHologramSystem : EntitySystem { [Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly IEntityManager _entityManager = default!; @@ -25,7 +20,8 @@ public abstract class SharedHologramSystem : EntitySystem [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedPullingSystem _pulling = default!; - [Dependency] private readonly GameTiming _timing = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly INetManager _net = default!; protected const string PopupAppearOther = "system-hologram-phasing-appear-others"; protected const string PopupAppearSelf = "system-hologram-phasing-appear-self"; @@ -69,153 +65,7 @@ private void OnInteractionAttempt(InteractionAttemptEvent args) _audio.Play(sound, Filter.Entities(args.Uid), args.Uid, false); } } - - // Forbid holograms from going inside anything. Osmosised from Nyano :) - private void OnStoreInContainerAttempt(EntityUid uid, HologramComponent component, ref StoreMobInItemContainerAttemptEvent args) - { - args.Cancelled = true; - args.Handled = true; - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - var query = _entityManager.EntityQueryEnumerator(); - while (query.MoveNext(out var hologram, out var hologramComp)) - { - TryGetHoloProjector(hologram, out var nearProj); - - if (nearProj == null) - { - if (hologramComp.GracePeriod == 0) - { - hologramComp.GracePeriod -= frameTime; - continue; - } - DoReturnHologram(hologram, out _); - continue; - } - - hologramComp.GracePeriod = 0.24f; - hologramComp.CurProjector = nearProj; - } - } - - /// - /// Handles returning a Hologram to their last visited projector, - /// then to the nearest, finally killing them if none are found. - /// - public virtual void DoReturnHologram(EntityUid uid, out bool holoKilled) - { - var component = _entityManager.GetComponent(uid); - var meta = MetaData(uid); - var holoPos = Transform(uid).Coordinates; - - holoKilled = false; - - if (component.CurProjector == null) // TODO:HOLO Check if the projector works. - { - TryGetHoloProjector(uid, out component.CurProjector); - } - - if (component.CurProjector == null) // If the Hologram still doesn't have a working projector, kill it. // TODO:HOLO Check if the projector works. - { - holoKilled = true; - return; - } - - // TODO:HOLO Make this all part of a SetHoloProjector function. - _entityManager.TryGetComponent(component.CurProjector, out var transfComp); - if (_timing.IsFirstTimePredicted) - { - _popup.PopupCoordinates(Loc.GetString(PopupDisappearOther, ("name", meta.EntityName)), holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); - _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(uid), coordinates: holoPos, false); - } - - // Prepare to move holo - if (TryComp(uid, out var pullable) && pullable.BeingPulled) _pulling.TryStopPull(pullable); - if (TryComp(uid, out var pulling) && pulling.Pulling != null && - TryComp(pulling.Pulling.Value, out var subjectPulling)) _pulling.TryStopPull(subjectPulling); - - // Move holo - _transform.SetCoordinates(uid, Transform(component.CurProjector.Value).Coordinates); - - if (_timing.IsFirstTimePredicted) - { - _popup.PopupEntity(Loc.GetString(PopupAppearOther, ("name", meta.EntityName)), uid, Filter.PvsExcept(uid), false, PopupType.Medium); - _popup.PopupEntity(Loc.GetString(PopupAppearSelf, ("name", meta.EntityName)), uid, uid, PopupType.Large); - _audio.PlayPvs("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg", uid); - } - - _adminLogger.Add(LogType.Unknown, LogImpact.Low, - $"{ToPrettyString(uid):mob} was returned to projector {ToPrettyString((EntityUid) component.CurProjector):entity}"); - } - - /// - /// Tests for the nearest projector to a set of coords. - /// - /// Coords to test from. - /// Map being tested on. - /// The UID of the projector, or null if no projectors are found. - /// Should it check only for unoccluded and in range projectors? - /// The range it should check for projectors in, if occlude is true - /// Returns true if a projector is found, false if not. - public bool TryGetHoloProjector(Vector2 coords, MapId mapId, [NotNullWhen(true)] out EntityUid? result, bool occlude = true, float range = 18f) - { - result = null; - - var xformQuery = GetEntityQuery(); - - // sort all entities in distance increasing order - var nearProjList = new SortedList(); - - var query = _entityManager.EntityQueryEnumerator(); - while (query.MoveNext(out var projector, out var projComp)) - { - if (!xformQuery.TryGetComponent(projector, out var compXform) || compXform.MapID != mapId) - continue; - - var dist = (_transform.GetWorldPosition(compXform!, xformQuery) - coords).LengthSquared(); - nearProjList.TryAdd(dist, projector); - } - - foreach (var nearProj in nearProjList) - { - if (occlude && !nearProj.Value.InRangeUnOccluded(new MapCoordinates(coords, mapId), range)) continue; - result = nearProj.Value; - return true; - } - return false; - } - - /// - public bool TryGetHoloProjector(EntityUid uid, [NotNullWhen(true)] out EntityUid? result, bool occlude = true, float range = 18f) - { - var xformQuery = GetEntityQuery(); - var transform = _entityManager.GetComponent(uid); - var playerPos = _transform.GetWorldPosition(transform, xformQuery); - - return TryGetHoloProjector(playerPos, transform.MapID, out result, occlude, range); - } -} - -public enum HoloTypeEnum -{ - /// - /// A hologram projected from a projector. - /// - Projected, - /// - /// A hologram tied to the internal storage of a lightbee. - /// - Lightbee, - /// - /// A hologram that - /// - Standalone, } - // public struct HoloData // { // [DataField("type")] diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml index b57e06f704..7248e66678 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml @@ -157,8 +157,9 @@ id: MobHologramProjected components: - type: Hologram - holoType: enum.HoloTypeEnum.Projected isHardLight: false + - type: HologramProjected + gracePeriod: 0.08 - type: Stealth lastVisibility: 0.80 - type: InteractionPopup @@ -183,7 +184,6 @@ id: MobHologramLightbee components: - type: Hologram - holoData: enum.HoloTypeEnum.Lightbee IsHardLight: false - type: Fixtures fixtures: @@ -224,7 +224,6 @@ id: MobHologramHardlight components: - type: Hologram - holoData: enum.HoloTypeEnum.Lightbee IsHardLight: true - type: Fixtures fixtures: From 15995ca9cbaff25fc0d1cf7fbb85d61e166c53c4 Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Mon, 23 Oct 2023 12:44:06 -0400 Subject: [PATCH 19/25] Bulk of work done towards the HologramProjectedComponent's functionality. Need to decide how the projector selection is done, and how to filter collisions. --- .../Holograms/HologramSystem.cs | 88 +++++++++++- .../Holograms/Systems/HologramServerSystem.cs | 4 +- .../Holograms/Components/HologramComponent.cs | 27 +++- .../Components/HologramProjectedComponent.cs | 73 ++++++++-- .../Holograms/HologramEvents.cs | 44 +++++- .../Systems/SharedHologramSystem.Projected.cs | 135 +++++++++++------- .../Holograms/Systems/SharedHologramSystem.cs | 68 ++++++--- .../Entities/Mobs/Player/observer.yml | 1 + .../Entities/Objects/Power/lights.yml | 1 + .../Entities/Objects/Tools/glowstick.yml | 3 + .../Doors/Airlocks/base_structureairlocks.yml | 3 + .../Machines/wireless_surveillance_camera.yml | 5 +- .../Wallmounts/surveillance_camera.yml | 5 +- .../Entities/Effects/hologram_effects.yml | 23 +++ .../Entities/Mobs/Player/hologram.yml | 38 ++--- .../Entities/Mobs/Player/silicon.yml | 1 + .../Machines/hologram_constructor.yml | 4 + Resources/Prototypes/SimpleStation14/tags.yml | 11 +- .../hologram_projection_beam.rsi/beam.png | Bin 0 -> 24802 bytes .../hologram_projection_beam.rsi/meta.json | 24 ++++ 20 files changed, 438 insertions(+), 120 deletions(-) create mode 100644 Resources/Prototypes/SimpleStation14/Entities/Effects/hologram_effects.yml create mode 100644 Resources/Textures/SimpleStation14/Effects/hologram_projection_beam.rsi/beam.png create mode 100644 Resources/Textures/SimpleStation14/Effects/hologram_projection_beam.rsi/meta.json diff --git a/Content.Client/SimpleStation14/Holograms/HologramSystem.cs b/Content.Client/SimpleStation14/Holograms/HologramSystem.cs index fc3573d780..0a92b1fdc1 100644 --- a/Content.Client/SimpleStation14/Holograms/HologramSystem.cs +++ b/Content.Client/SimpleStation14/Holograms/HologramSystem.cs @@ -1,17 +1,101 @@ -using Content.Shared.SimpleStation14.Holograms; +using System.Numerics; +using Content.Shared.SimpleStation14.Holograms; using Content.Shared.SimpleStation14.Holograms.Components; +using Robust.Client.GameObjects; using Robust.Client.Player; +using Robust.Shared.Map; namespace Content.Client.SimpleStation14.Holograms; public sealed class HologramSystem : SharedHologramSystem { [Dependency] private readonly IPlayerManager _player = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnHoloProjectedShutdown); + } public override void Update(float frameTime) { - var player = _player.LocalPlayer?.ControlledEntity; + var player = _player.LocalPlayer?.ControlledEntity; // This makes it so only the currently controlled entity is predicted, assuming they're a hologram. if (TryComp(player, out var holoProjComp)) ProjectedUpdate(player.Value, holoProjComp, frameTime); + + HandleProjectedEffects(EntityQueryEnumerator()); + } + + private void HandleProjectedEffects(EntityQueryEnumerator query) + { + while (query.MoveNext(out var hologram, out var holoProjectedComp)) + { + if (!holoProjectedComp.DoProjectionEffect) + { + DeleteEffect(holoProjectedComp); + continue; + } + + if (!holoProjectedComp.CurrentlyInProjector || holoProjectedComp.CurProjector == null || !Exists(holoProjectedComp.CurProjector.Value)) + { + DeleteEffect(holoProjectedComp); + continue; + } + + var projector = holoProjectedComp.CurProjector.Value; + + var holoXformComp = Transform(hologram); + var holoCoords = _transform.GetMoverCoordinates(hologram, holoXformComp); + + var projXformComp = Transform(projector); + var projCoords = _transform.GetMoverCoordinates(projector, projXformComp); + + if (holoCoords.EntityId != projCoords.EntityId) // ¯\_(ツ)_/¯ + { + DeleteEffect(holoProjectedComp); + continue; + } + + // Determine a middle point between the hologram and the projector. + var effectPos = (holoCoords.Position + projCoords.Position) / 2; + // Offset the position a quarter tile towards the projector. + effectPos += (projCoords.Position - holoCoords.Position).Normalized() * 0.25f; + // Determine a rotation that points from the projector to the hologram. + var effectRot = (holoCoords.Position - projCoords.Position).ToAngle() + -MathHelper.PiOver2; + + var effectCoords = new EntityCoordinates(holoCoords.EntityId, effectPos); + if (!effectCoords.IsValid(EntityManager)) + { + DeleteEffect(holoProjectedComp); + continue; + } + + // Set or spawn the effect. + if (holoProjectedComp.EffectEntity == null || !Exists(holoProjectedComp.EffectEntity.Value)) + holoProjectedComp.EffectEntity = Spawn(holoProjectedComp.EffectPrototype, effectCoords); + else + _transform.SetLocalPosition(holoProjectedComp.EffectEntity.Value, effectPos); + + _transform.SetLocalRotation(holoProjectedComp.EffectEntity.Value, effectRot); + + // Determine the scaling factor to make it fit between the hologram and the projector. + var effectScale = new Vector2(1, (holoCoords.Position - projCoords.Position).Length()); + Comp(holoProjectedComp.EffectEntity.Value).Scale = effectScale.Y > 0.1f ? effectScale : Vector2.One; + } + } + + private void OnHoloProjectedShutdown(EntityUid uid, HologramProjectedComponent component, ComponentShutdown args) + { + DeleteEffect(component); + } + + private void DeleteEffect(HologramProjectedComponent component) + { + if (component.EffectEntity != null && Exists(component.EffectEntity.Value)) + QueueDel(component.EffectEntity.Value); + + component.EffectEntity = null; } } diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs index eb29e3d200..da1e6c5b87 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -192,7 +192,7 @@ public bool TryHoloGenerate(EntityUid uid, Mind.Mind mind, HologramServerCompone } // Get the loadout from the job prototype and add it to the Hologram - // making each item unremovable and hardlight. + // making each item unremovable. if (mind.CurrentJob.Prototype.StartingGear != null) { SetOutfitCommand.SetOutfit(mob, mind.CurrentJob.Prototype.StartingGear, _entityManager, (_, item) => @@ -205,7 +205,7 @@ public bool TryHoloGenerate(EntityUid uid, Mind.Mind mind, HologramServerCompone return; } } - _tagSystem.AddTag(item, "Softlight"); + EnsureComp(item); _entityManager.EnsureComponent(item); }); // HoloEquip(mob, mind.CurrentJob.Prototype); diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs index e100508378..1460e6b1c3 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs @@ -1,4 +1,8 @@ +using Content.Shared.Tag; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; using Robust.Shared.Serialization.TypeSerializers.Implementations; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Shared.SimpleStation14.Holograms; @@ -7,12 +11,27 @@ namespace Content.Shared.SimpleStation14.Holograms; /// Details determined by sister components. /// [RegisterComponent] +[NetworkedComponent] public sealed class HologramComponent : Component { /// - /// Is this a hardlight Hologram. + /// The sound to play when the Hologram is turned on. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("isHardlight")] - public bool IsHardlight = false; + [DataField("onSound"), ViewVariables(VVAccess.ReadWrite)] + public SoundSpecifier OnSound = new SoundPathSpecifier("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg"); + + /// + /// The sound to play when the Hologram is turned off. + /// + [DataField("offSound"), ViewVariables(VVAccess.ReadWrite)] + public SoundSpecifier OffSound = new SoundPathSpecifier("/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg"); + + /// + /// A list of tags for the Hologram to collide with, assuming they're not hardlight. + /// + /// + /// This should generally include the 'Wall' tag. + /// + [DataField("collideTags", customTypeSerializer: typeof(PrototypeIdListSerializer)), ViewVariables(VVAccess.ReadWrite)] + public List CollideTags = new() { "Wall", "Airlock" }; } diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs index 98ddd7595b..84492bdbf5 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs @@ -1,29 +1,84 @@ +using Content.Shared.Tag; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Shared.SimpleStation14.Holograms.Components; /// -/// Marks that this Hologram requires a server to generate it. +/// Marks that this Hologram is projected from cameras, or some other hologram projector source. /// [RegisterComponent] -[NetworkedComponent] -public sealed class HologramProjectedComponent : Component +[NetworkedComponent, AutoGenerateComponentState] +public sealed partial class HologramProjectedComponent : Component { + /// + /// A list of tags to check for on projectors, to determine if they're valid. + /// + [DataField("validProjectorTags", customTypeSerializer: typeof(PrototypeIdListSerializer)), ViewVariables(VVAccess.ReadWrite)] + public List ValidProjectorTags = new(); + /// /// A timer for a grace period before the Holo is returned, to allow for moving through doors. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("gracePeriod")] - public float GracePeriod = 0.5f; + [DataField("gracePeriod"), ViewVariables(VVAccess.ReadWrite)] + public TimeSpan GracePeriod = TimeSpan.FromSeconds(0.1f); + + /// + /// The maximum range from a projector a Hologram can be before they're returned. + /// + [DataField("projectorRange"), ViewVariables(VVAccess.ReadWrite)] + public float ProjectorRange = 18f; + + /// + /// The prototype of the effect to spawn for the Hologram's projection, assuming is true. + /// + [DataField("effectPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string EffectPrototype = "EffectHologramProjectionBeam"; + + /// + /// Whether or not the Hologram should have a visual projection effect. + /// + [DataField("doProjectionEffect"), ViewVariables(VVAccess.ReadWrite)] + public bool DoProjectionEffect = true; /// - /// The current projector the hologram is connected to. + /// The current projector the hologram is connected to. /// + /// + /// Note that this may not be a valid projector, as it is left set to the last projector the Hologram was in range of during the grace period. + /// [ViewVariables(VVAccess.ReadOnly)] + [AutoNetworkedField] public EntityUid? CurProjector; /// - /// A timer for a grace period before the Holo is returned, to allow for moving through doors. + /// If set, the Hologram will only be able to be projected from this projector, simply ignoring all others. + /// + [ViewVariables(VVAccess.ReadOnly)] + public EntityUid? ProjectorOverride; + + /// + /// Whether or not the Hologram is currently in the range of a projector. + /// + [ViewVariables(VVAccess.ReadOnly)] + [AutoNetworkedField] // TODO: Probably remove this and just sync the projector then determine this client side? + public bool CurrentlyInProjector = false; + + /// + /// The point at which a Hologram will be sent back to their last projector or killed, based on when they were last in the range of one. + /// + /// + /// Note that THIS WILL NOT BE SET TO NULL. If a hologram enters a projector, this value will be left alone and simply be innacurate. + /// Do not rely on it. + /// + // [AutoNetworkedField] + public TimeSpan VanishTime = TimeSpan.Zero; + + /// + /// The UID of the entity for the Hologram's visual projection effect. + /// Client side only. /// - public float GraceTimer = 0.5f; + public EntityUid? EffectEntity = null; } diff --git a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs index 603e535677..fcf32d6c99 100644 --- a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs +++ b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs @@ -1,3 +1,43 @@ -using Robust.Shared.Serialization; - namespace Content.Shared.SimpleStation14.Holograms; + +/// +/// Sent directed at a Hologram about to be returned to be handled by other systems. +/// +/// +/// Note that if this event is cancelled, there should be a plan to deal with it, since it'll just happen again next frame. +/// +[ByRefEvent] +public record struct HologramReturnAttemptEvent(bool Cancelled = false); + +/// +/// Sent directed at a Hologram before they are returned, often due to not being near a projector. +/// +/// The projector the Hologram is being returned to. +public readonly record struct HologramReturnedEvent(EntityUid Projector); + +/// +/// Sent directed at a Hologram about to be killed to be handled by other systems. +/// +/// +/// Note that if this event is cancelled, there should be a plan to deal with it, since it'll just happen again next frame. +/// +[ByRefEvent] +public record struct HologramKillAttemptEvent(bool Cancelled = false); + +/// +/// Sent directed at a Hologram being killed, often due to not having any valid projectors. +/// +public readonly record struct HologramKilledEvent(); + +/// +/// Sent directed at a Hologram when searching for any valid Projectors. +/// Allows for manually setting the projector to use. +/// Note that this Projector will not be validated in *any* way. +/// +/// +/// Setting override to 'True' will use whatever's in ProjectorOverride- including a null value, which allows cancelling the projector search. +/// A Component-set override will override this ovaerride. +/// +[ByRefEvent] +public record struct HologramGetProjectorEvent(EntityUid? ProjectorOverride = null, bool Override = false); + diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs index 79b4f5128a..1a3e3f653a 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs @@ -18,13 +18,11 @@ public override void Update(float frameTime) var query = _entityManager.EntityQueryEnumerator(); while (query.MoveNext(out var hologram, out var hologramProjectedComp)) - { ProjectedUpdate(hologram, hologramProjectedComp, frameTime); - } } /// - /// Returns a hologram to its last visited projector, or kills it if the projector is invalid. + /// Returns a hologram to its last visited projector, or kills it if the projector is invalid. /// /// The hologram to return. /// True if the hologram was killed, false if it was returned. @@ -36,15 +34,30 @@ public virtual void DoReturnHologram(EntityUid hologram, out bool holoKilled, Ho if (!Resolve(hologram, ref holoProjectedComp)) return; - if (!IsHoloProjectorValid(hologram, holoProjectedComp.CurProjector, 0, false)) // If their last visited Projector is invalid... + if (!IsHoloProjectorValid(hologram, holoProjectedComp.CurProjector, 0, false)) // If their last visited Projector is invalid ignoring occlusion... { - if (!TryGetHoloProjector(hologram, out holoProjectedComp.CurProjector, 0, false)) // Check for a new one, ignoring occlusion... + if (!TryGetHoloProjector(hologram, holoProjectedComp.ProjectorRange, out holoProjectedComp.CurProjector, holoProjectedComp)) { - holoKilled = true; // And if none is found, kill the hologram. - return; + var killedEvent = new HologramKillAttemptEvent(); + RaiseLocalEvent(hologram, ref killedEvent); + if (killedEvent.Cancelled) + return; + + RaiseLocalEvent(hologram, new HologramKilledEvent()); + holoKilled = true; // And if none is found and it doesn't get cancelled, kill the hologram. + return; // The killing is dealt with server-side, due to mind component. } } + // The two if statements above set the current projector, and return if it's null, so we know it's not null moving forward. + + var returnedEvent = new HologramReturnAttemptEvent(); + RaiseLocalEvent(hologram, ref returnedEvent); + if (returnedEvent.Cancelled) + return; + + RaiseLocalEvent(hologram, new HologramReturnedEvent(holoProjectedComp.CurProjector!.Value)); + MoveHologramToProjector(hologram, holoProjectedComp.CurProjector!.Value); _adminLogger.Add(LogType.Mind, LogImpact.Low, @@ -52,14 +65,15 @@ public virtual void DoReturnHologram(EntityUid hologram, out bool holoKilled, Ho } /// - /// Tests for the nearest projector to a set of coords. + /// Tests for the nearest projector to a set of coords. /// /// The coords to perform the check from. /// The UID of the projector, or null if no projectors are found. + /// A list of tags to check for on projectors, to determine if they're valid. /// The range it should check for projectors in, if occlude is true /// Should it check only for unoccluded and in range projectors? /// Returns true if a projector is found, false if not. - public bool TryGetHoloProjector(MapCoordinates coords, [NotNullWhen(true)] out EntityUid? result, float range = 18f, bool occlude = true) + public bool TryGetHoloProjector(MapCoordinates coords, float range, [NotNullWhen(true)] out EntityUid? result, List? allowedTags = null, bool occlude = true) { result = null; @@ -76,42 +90,45 @@ public bool TryGetHoloProjector(MapCoordinates coords, [NotNullWhen(true)] out E // Find the nearest, valid projector. foreach (var nearProj in nearProjList) { - if (!IsHoloProjectorValid(coords, nearProj.Value, range, occlude)) continue; + if (!IsHoloProjectorValid(coords, nearProj.Value, range, occlude)) + continue; result = nearProj.Value; return true; } return false; } - /// - public bool TryGetHoloProjector(EntityUid uid, out EntityUid? result, float range = 18f, bool occlude = true) - { - return TryGetHoloProjector(Transform(uid).MapPosition, out result, range, occlude); - } - - /// - /// Returns the best projector for a hologram to use. - /// /// - /// Defaults to the hologram's current projector, if it has one. + /// This takes into consideration any ProjectorOverride the hologram may have. /// - /// The hologram to find a projector for. - /// The UID of the projector, or null if no projectors are found. - /// The hologram's projected component. - public bool TryGetWorkingProjector(EntityUid hologram, [NotNullWhen(true)] out EntityUid? projector, HologramProjectedComponent? holoProjectedComp = null) + /// + public bool TryGetHoloProjector(EntityUid uid, float range, [NotNullWhen(true)] out EntityUid? result, HologramProjectedComponent? projectedComp = null, bool occlude = true) { - projector = null; + result = null; - if (!Resolve(hologram, ref holoProjectedComp)) + if (!Resolve(uid, ref projectedComp)) return false; - if (IsHoloProjectorValid(hologram, holoProjectedComp.CurProjector)) + if (projectedComp.ProjectorOverride != null) // Check for Component-set overrides. { - projector = holoProjectedComp.CurProjector!; - return true; + if (IsHoloProjectorValid(uid, projectedComp.ProjectorOverride, range, occlude)) + { + result = projectedComp.ProjectorOverride; + return true; + } + return false; } - return TryGetHoloProjector(hologram, out projector); + var projectorEvent = new HologramGetProjectorEvent(); // Check for Event-set overrides. + RaiseLocalEvent(uid, ref projectorEvent); + if (projectorEvent.Override) + { + result = projectorEvent.ProjectorOverride; + return projectorEvent.ProjectorOverride != null; + } + + // Otherwise, we simply check for the nearest projector, considering any tags it requires. + return TryGetHoloProjector(Transform(uid).MapPosition, range, out result, projectedComp.ValidProjectorTags, occlude); } /// @@ -122,34 +139,37 @@ public bool TryGetWorkingProjector(EntityUid hologram, [NotNullWhen(true)] out E /// The max range to allow. Ignored if occlude is false. /// Should it check only for unoccluded and in range projectors? /// True if the projector is within range, and unoccluded to the hologram. Otherwise, false. - public bool IsHoloProjectorValid(EntityUid hologram, EntityUid? projector, float range = 18f, bool occlude = true) + public bool IsHoloProjectorValid(EntityUid hologram, EntityUid? projector, float range = 18f, bool occlude = true, HologramProjectedComponent? projectedComp = null) { - return _entityManager.EntityExists(projector) && (!occlude || projector.Value.InRangeUnOccluded(hologram, range)); + if (!Resolve(hologram, ref projectedComp)) + return false; + return IsHoloProjectorValid(Transform(hologram).MapPosition, projector, range, occlude, projectedComp.ValidProjectorTags); } - /// - public bool IsHoloProjectorValid(EntityUid hologram, MapCoordinates projector, float range = 18f, bool occlude = true) + /// + /// A list of tags to check for on projectors, to determine if they're valid. Usually found on the Holo's . + public bool IsHoloProjectorValid(MapCoordinates hologram, EntityUid? projector, float range = 18f, bool occlude = true, List? allowedTags = null) { - return !occlude || projector.InRangeUnOccluded(hologram, range); - } + if (projector == null || !Exists(projector.Value)) + return false; - /// - public bool IsHoloProjectorValid(MapCoordinates hologram, EntityUid? projector, float range = 18f, bool occlude = true) - { - return _entityManager.EntityExists(projector) && (!occlude || projector.Value.InRangeUnOccluded(hologram, range)); - } + if (allowedTags != null && !_tags.HasAnyTag(projector.Value, allowedTags)) + return false; - /// - public bool IsHoloProjectorValid(MapCoordinates hologram, MapCoordinates projector, float range = 18f, bool occlude = true) - { - return !occlude || projector.InRangeUnOccluded(hologram, range); + if (occlude && !projector.Value.InRangeUnOccluded(hologram, range)) + return false; + + return true; } /// - /// Moves a hologram to a projector. + /// Moves a hologram to a new location. /// + /// + /// Does no validation for any projectors before moving. + /// /// The hologram to move. - /// The projector to move it to. + /// The projector to move it to, or the projector's position. public void MoveHologram(EntityUid hologram, EntityCoordinates projector) { // Stops any pulling goin on. @@ -172,6 +192,7 @@ public void MoveHologram(EntityUid hologram, EntityCoordinates projector) // Does the do. _transform.SetCoordinates(hologram, projector); + _transform.AttachToGridOrMap(hologram); // Plays the appearing effects. if (!_timing.InPrediction) @@ -182,7 +203,7 @@ public void MoveHologram(EntityUid hologram, EntityCoordinates projector) } } - /// + /// public void MoveHologramToProjector(EntityUid hologram, EntityUid projector) { MoveHologram(hologram, Transform(projector).Coordinates); @@ -190,22 +211,30 @@ public void MoveHologramToProjector(EntityUid hologram, EntityUid projector) protected bool ProjectedUpdate(EntityUid hologram, HologramProjectedComponent hologramProjectedComp, float frameTime) { - if (TryGetWorkingProjector(hologram, out var nearProj, hologramProjectedComp)) + if (TryGetHoloProjector(hologram, hologramProjectedComp.ProjectorRange, out var nearProj, hologramProjectedComp)) // Checks for a projector in range. { - hologramProjectedComp.GraceTimer = hologramProjectedComp.GracePeriod; hologramProjectedComp.CurProjector = nearProj; + hologramProjectedComp.CurrentlyInProjector = true; + Dirty(hologramProjectedComp); return true; } - // If none is found, starts counting... - if (hologramProjectedComp.GraceTimer > 0) + // If none is found, and they were in the range of a projector during the last check, we set the time they'll be disappeared at. + if (hologramProjectedComp.CurrentlyInProjector) + { + hologramProjectedComp.CurrentlyInProjector = false; + hologramProjectedComp.VanishTime = _timing.CurTime + hologramProjectedComp.GracePeriod; + } + + if (hologramProjectedComp.VanishTime > _timing.CurTime) { - hologramProjectedComp.GraceTimer -= frameTime; + Dirty(hologramProjectedComp); return true; } // Attempts to return the hologram if their time is up. DoReturnHologram(hologram, out _); + Dirty(hologramProjectedComp); return false; } diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs index b73bae4881..855279fc9f 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs @@ -7,13 +7,13 @@ using Content.Shared.Administration.Logs; using Content.Shared.Pulling; using Robust.Shared.Timing; -using Robust.Shared.Network; +using Robust.Shared.Physics.Events; namespace Content.Shared.SimpleStation14.Holograms; public abstract partial class SharedHologramSystem : EntitySystem { - [Dependency] private readonly TagSystem _tagSystem = default!; + [Dependency] private readonly TagSystem _tags = default!; [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; @@ -21,49 +21,73 @@ public abstract partial class SharedHologramSystem : EntitySystem [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedPullingSystem _pulling = default!; [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly INetManager _net = default!; protected const string PopupAppearOther = "system-hologram-phasing-appear-others"; protected const string PopupAppearSelf = "system-hologram-phasing-appear-self"; protected const string PopupDisappearOther = "system-hologram-phasing-disappear-others"; protected const string PopupDeathSelf = "system-hologram-phasing-death-self"; - protected const string PopupInteractionFail = "system-hologram-light-interaction-fail"; + protected const string PopupHoloInteractionFail = "system-hologram-interaction-with-others-fail"; + protected const string PopupInteractionWithHoloFail = "system-hologram-interaction-with-holo-fail"; + + public const string TagHardLight = "Hardlight"; + public const string TagHoloMapped = "HoloMapped"; public override void Initialize() { SubscribeLocalEvent(OnHoloInteractionAttempt); - SubscribeLocalEvent(OnInteractionAttempt); + SubscribeLocalEvent(OnInteractionWithHoloAttempt); SubscribeLocalEvent(OnStoreInContainerAttempt); + SubscribeLocalEvent(OnHoloCollide); } // Stops the Hologram from interacting with anything they shouldn't. private void OnHoloInteractionAttempt(EntityUid uid, HologramComponent component, InteractionAttemptEvent args) { - if (args.Target == null) + if (HoloInteractionAllowed(args.Uid, args.Target) || args.Target == null) return; - if (HasComp(args.Target) && !HasComp(args.Target) - && !_tagSystem.HasAnyTag(args.Target.Value, "Hardlight", "Softlight")) args.Cancel(); + args.Cancel(); + + // Send a popup to the player about the interaction, and play a sound. + // var popup = Loc.GetString(PopupHoloInteractionFail, ("target-name", MetaData(args.Target.Value).EntityName)); + // _popup.PopupEntity(popup, args.Target.Value, args.Uid); + // _audio.Play(component.OnSound, Filter.Entities(args.Uid), args.Target.Value, false); } // Stops everyone else from interacting with the Holograms. - private void OnInteractionAttempt(InteractionAttemptEvent args) + private void OnInteractionWithHoloAttempt(EntityUid uid, HologramComponent component, GettingInteractedWithAttemptEvent args) { - if (args.Target == null || _tagSystem.HasAnyTag(args.Uid, "Hardlight", "Softlight") || - _entityManager.TryGetComponent(args.Uid, out var _)) + // Allow the interaction if either of them are hardlight, or if the interactor is a Hologram. + if (HoloInteractionAllowed(uid, args.Uid) || args.Target == null) return; - if (_tagSystem.HasAnyTag(args.Target.Value, "Softlight") && !_tagSystem.HasAnyTag(args.Target.Value, "Hardlight")) - { - args.Cancel(); - - // Send a popup to the player about the interaction, and play a sound. - var meta = _entityManager.GetComponent(args.Target.Value); - var popup = Loc.GetString(PopupInteractionFail, ("item", meta.EntityName)); - var sound = "/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg"; - _popup.PopupEntity(popup, args.Target.Value, Filter.Entities(args.Uid), false); - _audio.Play(sound, Filter.Entities(args.Uid), args.Uid, false); - } + args.Cancel(); + + // Send a popup to the player about the interaction, and play a sound. + // var popup = Loc.GetString(PopupInteractionWithHoloFail, ("target-name", MetaData(uid).EntityName)); + // _popup.PopupEntity(popup, uid, args.Target.Value); + // _audio.Play(component.OnSound, Filter.Entities(args.Target.Value), uid, false); + } + + private void OnHoloCollide(EntityUid uid, HologramComponent component, ref PreventCollideEvent args) + { + if (_tags.HasAnyTag(args.OtherEntity, component.CollideTags) || HoloInteractionAllowed(args.OurEntity, args.OtherEntity, component)) + return; + + args.Cancelled = true; + } + + /// + /// Validates an interaction between two possibly-hologramatic entities. + /// + /// This should be the hologramatic entity, if one is known. + /// This entity can be anything, a null value will return true. + /// True if both entities are holograms, or if either is hardlight. A null entity will return true. + public bool HoloInteractionAllowed(EntityUid hologram, EntityUid? potential, HologramComponent? holoComp = null) + { + if (potential == null) + return true; + return _tags.HasTag(hologram, TagHardLight) || _tags.HasTag(potential.Value, TagHardLight) || Resolve(hologram, ref holoComp) == HasComp(potential); } } // public struct HoloData diff --git a/Resources/Prototypes/Entities/Mobs/Player/observer.yml b/Resources/Prototypes/Entities/Mobs/Player/observer.yml index 19a2276514..855c5a2504 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/observer.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/observer.yml @@ -74,3 +74,4 @@ - type: Tag tags: - BypassInteractionRangeChecks + - Hardlight diff --git a/Resources/Prototypes/Entities/Objects/Power/lights.yml b/Resources/Prototypes/Entities/Objects/Power/lights.yml index a6d1ed80ca..842f09e1bb 100644 --- a/Resources/Prototypes/Entities/Objects/Power/lights.yml +++ b/Resources/Prototypes/Entities/Objects/Power/lights.yml @@ -58,6 +58,7 @@ - type: Appearance - type: Tag tags: + - Hardlight # it is a hard light - Trash - type: PhysicalComposition materialComposition: diff --git a/Resources/Prototypes/Entities/Objects/Tools/glowstick.yml b/Resources/Prototypes/Entities/Objects/Tools/glowstick.yml index bddcb06e86..941466585f 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/glowstick.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/glowstick.yml @@ -61,6 +61,9 @@ startValue: 5.0 endValue: 1.5 property: Radius + - type: Tag + tags: + - Hardlight # it is a hard light - type: entity name: red glowstick diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml index 6e22fdb4dc..4ee5cb58ca 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml @@ -131,5 +131,8 @@ - type: DynamicPrice price: 150 - type: AccessReader + - type: Tag + tags: + - Airlock placement: mode: SnapgridCenter diff --git a/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml b/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml index 25a4e21e02..5f59c5d29c 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml @@ -5,7 +5,6 @@ name: wireless camera description: A camera. It's watching you. Kinda. components: - - type: HologramProjector - type: InteractionOutline - type: Eye - type: WirelessNetworkConnection @@ -36,6 +35,10 @@ interfaces: - key: enum.SurveillanceCameraSetupUiKey.Camera type: SurveillanceCameraSetupBoundUi + - type: HologramProjector + - type: Tag + tags: + - HoloProjectorCamera placement: mode: SnapgridCenter diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml index 5bdc2494ab..0d8d17d2b9 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml @@ -4,7 +4,6 @@ name: camera description: A surveillance camera. It's watching you. Kinda. components: - - type: HologramProjector - type: Clickable - type: InteractionOutline - type: Construction @@ -66,6 +65,10 @@ - !type:PlaySoundBehavior sound: path: /Audio/Effects/metalbreak.ogg + - type: HologramProjector + - type: Tag + tags: + - HoloProjectorCamera placement: mode: SnapgridCenter snap: diff --git a/Resources/Prototypes/SimpleStation14/Entities/Effects/hologram_effects.yml b/Resources/Prototypes/SimpleStation14/Entities/Effects/hologram_effects.yml new file mode 100644 index 0000000000..c461bace43 --- /dev/null +++ b/Resources/Prototypes/SimpleStation14/Entities/Effects/hologram_effects.yml @@ -0,0 +1,23 @@ +- type: entity + id: EffectHologramProjectionBeam + noSpawn: true + components: + # - type: PointLight + # radius: 10.5 + # energy: 15 + # color: "#18abf5" + # - type: TimedDespawn + # lifetime: 1 + - type: Sprite + drawdepth: Effects + layers: + - shader: unshaded + map: ["enum.EffectLayers.Unshaded"] + sprite: SimpleStation14/Effects/hologram_projection_beam.rsi + state: beam + color: "#c0f9ff" + - type: Tag + tags: + - HideContextMenu + - type: Stealth + lastVisibility: 0.2 diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml index 7248e66678..0ec047a5ea 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml @@ -19,16 +19,6 @@ - type: Clickable # - type: Damageable # damageContainer: Inorganic - # - type: Bloodstream - # bloodReagent: MotorOil - # bloodlossDamage: - # types: - # Bloodloss: - # 1 - # bloodlossHealDamage: - # types: - # Bloodloss: - # -0.25 - type: InteractionOutline - type: Sprite netsync: false @@ -86,9 +76,6 @@ - map: ["enum.HumanoidVisualLayers.Wings"] - type: HumanoidAppearance species: Human - # - type: Body - # prototype: Human - # requiredLegs: 2 - type: Physics bodyType: KinematicController - type: Fixtures @@ -99,9 +86,9 @@ radius: 0.35 density: 25 mask: - - FlyingMobMask + - MobMask layer: - - FlyingMobLayer + - BulletImpassable # MobLayer just makes them opaque as well, so this is ideal. - type: MovementSpeedModifier baseWalkSpeed : 5 baseSprintSpeed : 3.5 @@ -111,9 +98,9 @@ - type: Body prototype: Hologram - type: DoAfter - # - type: Pullable + - type: Pullable - type: Examiner - # - type: Puller + - type: Puller # - type: Recyclable # safe: false - type: StandingState @@ -121,8 +108,8 @@ - type: Tag tags: - DoorBumpOpener - - ShoesRequiredStepTriggerImmune - - type: NoSlip + # - ShoesRequiredStepTriggerImmune + # - type: NoSlip - type: TypingIndicator proto: holo - type: RotationVisuals @@ -145,6 +132,7 @@ - type: MindContainer showExamineInfo: true - type: Inventory + - type: InventorySlots - type: Actions - type: Eye - type: Access @@ -158,8 +146,14 @@ components: - type: Hologram isHardLight: false + collideTags: + - Wall + - Airlock - type: HologramProjected gracePeriod: 0.08 + validProjectorTags: + - HoloProjectorServer + - HoloProjectorCamera - type: Stealth lastVisibility: 0.80 - type: InteractionPopup @@ -193,9 +187,9 @@ radius: 0.05 density: 25 mask: - - MobMask + - FlyingMobMask layer: - - MobLayer + - FlyingMobLayer - type: Damageable damageContainer: Inorganic damageModifierSet: FlimsyMetallic @@ -245,8 +239,6 @@ Blunt: 6 # To get past the 5 damage threshold soundHit: path: /Audio/Effects/hit_kick.ogg - - type: Pullable - - type: Puller - type: CombatMode disarm: null - type: Stealth diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon.yml index e5497b43c9..8c2fc8219d 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon.yml @@ -9,6 +9,7 @@ prototype: Scutter - type: Inventory templateId: scutter + - type: InventorySlots - type: Strippable - type: UserInterface interfaces: diff --git a/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml b/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml index 24dc0f04a3..21e502ca9c 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml @@ -111,6 +111,10 @@ range: 5 sound: path: /Audio/Ambience/Objects/server_fans.ogg + - type: HologramProjector + - type: Tag + tags: + - HoloProjectorServer - type: HologramServer - type: ItemSlots slots: diff --git a/Resources/Prototypes/SimpleStation14/tags.yml b/Resources/Prototypes/SimpleStation14/tags.yml index 518897da79..e6c88dd642 100644 --- a/Resources/Prototypes/SimpleStation14/tags.yml +++ b/Resources/Prototypes/SimpleStation14/tags.yml @@ -1,3 +1,6 @@ +- type: Tag + id: Airlock + - type: Tag id: GlassesNearsight @@ -8,7 +11,13 @@ id: HoloDisk - type: Tag - id: Softlight + id: HoloProjectorCamera + +- type: Tag + id: HoloProjectorServer + +- type: Tag # For entities that are 'mapped' in to a Hologram's processing, like walls on a station. + id: HoloMapped - type: Tag id: Plushie diff --git a/Resources/Textures/SimpleStation14/Effects/hologram_projection_beam.rsi/beam.png b/Resources/Textures/SimpleStation14/Effects/hologram_projection_beam.rsi/beam.png new file mode 100644 index 0000000000000000000000000000000000000000..8c362d325d261fd2c2a3720e49881fe0d38e27b2 GIT binary patch literal 24802 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 E0a;t#o&W#< literal 0 HcmV?d00001 diff --git a/Resources/Textures/SimpleStation14/Effects/hologram_projection_beam.rsi/meta.json b/Resources/Textures/SimpleStation14/Effects/hologram_projection_beam.rsi/meta.json new file mode 100644 index 0000000000..874d2b6962 --- /dev/null +++ b/Resources/Textures/SimpleStation14/Effects/hologram_projection_beam.rsi/meta.json @@ -0,0 +1,24 @@ +{ + "version": 1, + "license": "", + "copyright": "", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "beam", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + } + ] +} From 4718be2674cd3917f1f065527234b2429c9b2b98 Mon Sep 17 00:00:00 2001 From: Pspritechologist Date: Tue, 6 Feb 2024 16:53:12 -0500 Subject: [PATCH 20/25] Ton of work refactoring Holograms, generally cleaning it up, and adding new functionality. The AIEye can now function as a camera-bound Hologram (commented out), work still needs to be done on making Hologram disks and servers cool to use, and I need to decide how to determine what a Hologram collides with. --- .../Holograms/AcceptHologramEui.cs | 44 +++ .../Holograms/AcceptHologramWindow.cs | 60 ++++ .../Holograms/HologramSystem.cs | 60 +++- .../Holograms/AcceptHologramEui.cs | 32 ++ ...kComponent.cs => HologramDiskComponent.cs} | 5 +- .../Components/HologramDiskDummyComponent.cs | 18 ++ .../Systems/HologramProjectorSystem.cs | 34 +++ .../Holograms/Systems/HologramServerSystem.cs | 273 +++--------------- .../Holograms/Systems/HologramSystem.cs | 214 +++++++++----- .../StationAI/Systems/AIEyeSystem.cs | 6 + .../Systems/SurveillanceCameraSystem.cs | 7 +- .../Holograms/AcceptHologramEuiMessage.cs | 22 ++ .../Components/HoloServerComponent.cs | 8 - .../Components/HologramProjectedComponent.cs | 26 +- .../HologramProjectorActiveComponent.cs | 10 + .../Components/HologramProjectorComponent.cs | 11 +- .../Components/HologramServerComponent.cs | 14 + .../HologramServerLinkedComponent.cs | 5 +- .../Systems/SharedHologramSystem.Projected.cs | 76 +++-- .../SharedHologramSystem.ServerLinked.cs | 17 ++ .../Holograms/Systems/SharedHologramSystem.cs | 68 ++--- .../Entities/Mobs/Player/admin_ghost.yml | 1 + .../Wallmounts/surveillance_camera.yml | 5 + .../Entities/Mobs/Player/hologram.yml | 4 +- .../Entities/Mobs/Player/stationai.yml | 19 +- .../Machines/hologram_constructor.yml | 1 + 26 files changed, 628 insertions(+), 412 deletions(-) create mode 100644 Content.Client/SimpleStation14/Holograms/AcceptHologramEui.cs create mode 100644 Content.Client/SimpleStation14/Holograms/AcceptHologramWindow.cs create mode 100644 Content.Server/SimpleStation14/Holograms/AcceptHologramEui.cs rename Content.Server/SimpleStation14/Holograms/Components/{HoloDiskComponent.cs => HologramDiskComponent.cs} (65%) create mode 100644 Content.Server/SimpleStation14/Holograms/Components/HologramDiskDummyComponent.cs create mode 100644 Content.Server/SimpleStation14/Holograms/Systems/HologramProjectorSystem.cs create mode 100644 Content.Shared/SimpleStation14/Holograms/AcceptHologramEuiMessage.cs delete mode 100644 Content.Shared/SimpleStation14/Holograms/Components/HoloServerComponent.cs create mode 100644 Content.Shared/SimpleStation14/Holograms/Components/HologramProjectorActiveComponent.cs create mode 100644 Content.Shared/SimpleStation14/Holograms/Components/HologramServerComponent.cs create mode 100644 Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.ServerLinked.cs diff --git a/Content.Client/SimpleStation14/Holograms/AcceptHologramEui.cs b/Content.Client/SimpleStation14/Holograms/AcceptHologramEui.cs new file mode 100644 index 0000000000..232efc37cc --- /dev/null +++ b/Content.Client/SimpleStation14/Holograms/AcceptHologramEui.cs @@ -0,0 +1,44 @@ +using Content.Client.Eui; +using Content.Client.Holograms; +using Content.Shared.SimpleStation14.Holograms; +using JetBrains.Annotations; +using Robust.Client.Graphics; + +namespace Content.Client.SimpleStation14.Holograms; + +[UsedImplicitly] +public sealed class AcceptHologramEui : BaseEui +{ + private readonly AcceptHologramWindow _window; + + public AcceptHologramEui() + { + _window = new AcceptHologramWindow(); + + _window.DenyButton.OnPressed += _ => + { + SendMessage(new AcceptHologramChoiceMessage(AcceptHologramUiButton.Deny)); + _window.Close(); + }; + + _window.OnClose += () => SendMessage(new AcceptHologramChoiceMessage(AcceptHologramUiButton.Deny)); + + _window.AcceptButton.OnPressed += _ => + { + SendMessage(new AcceptHologramChoiceMessage(AcceptHologramUiButton.Accept)); + _window.Close(); + }; + } + + public override void Opened() + { + IoCManager.Resolve().RequestWindowAttention(); + _window.OpenCentered(); + } + + public override void Closed() + { + _window.Close(); + } + +} diff --git a/Content.Client/SimpleStation14/Holograms/AcceptHologramWindow.cs b/Content.Client/SimpleStation14/Holograms/AcceptHologramWindow.cs new file mode 100644 index 0000000000..e4da45d059 --- /dev/null +++ b/Content.Client/SimpleStation14/Holograms/AcceptHologramWindow.cs @@ -0,0 +1,60 @@ +using System.Numerics; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using static Robust.Client.UserInterface.Controls.BoxContainer; + +namespace Content.Client.Holograms; + +public sealed class AcceptHologramWindow : DefaultWindow +{ + public readonly Button DenyButton; + public readonly Button AcceptButton; + + public AcceptHologramWindow() + { + + Title = Loc.GetString("accept-hologram-window-title"); + + Contents.AddChild(new BoxContainer + { + Orientation = LayoutOrientation.Vertical, + Children = + { + new BoxContainer + { + Orientation = LayoutOrientation.Vertical, + Children = + { + new Label() + { + Text = Loc.GetString("accept-hologram-window-prompt-text-part") + }, + new BoxContainer + { + Orientation = LayoutOrientation.Horizontal, + Align = AlignMode.Center, + Children = + { + (AcceptButton = new Button + { + Text = Loc.GetString("accept-hologram-window-accept-button"), + }), + + new Control() + { + MinSize = new Vector2(20, 0) + }, + + (DenyButton = new Button + { + Text = Loc.GetString("accept-hologram-window-deny-button"), + }) + } + }, + } + }, + } + }); + } +} diff --git a/Content.Client/SimpleStation14/Holograms/HologramSystem.cs b/Content.Client/SimpleStation14/Holograms/HologramSystem.cs index 0a92b1fdc1..ff88b124dc 100644 --- a/Content.Client/SimpleStation14/Holograms/HologramSystem.cs +++ b/Content.Client/SimpleStation14/Holograms/HologramSystem.cs @@ -10,29 +10,43 @@ namespace Content.Client.SimpleStation14.Holograms; public sealed class HologramSystem : SharedHologramSystem { [Dependency] private readonly IPlayerManager _player = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly TransformSystem _transform = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnHoloProjectedShutdown); + SubscribeLocalEvent(OnProjectedShutdown); } public override void Update(float frameTime) { - var player = _player.LocalPlayer?.ControlledEntity; // This makes it so only the currently controlled entity is predicted, assuming they're a hologram. + var player = _player.LocalPlayer?.ControlledEntity; if (TryComp(player, out var holoProjComp)) - ProjectedUpdate(player.Value, holoProjComp, frameTime); + { + ProjectedUpdate(player.Value, holoProjComp, frameTime); // This makes it so only the currently controlled entity is predicted, assuming they're a hologram. + + // Check if we should be setting the eye target of the hologram. + if (holoProjComp.SetEyeTarget && TryComp(player.Value, out var eyeComp)) + eyeComp.Target = holoProjComp.CurProjector; + } HandleProjectedEffects(EntityQueryEnumerator()); } + private void OnProjectedShutdown(EntityUid hologram, HologramProjectedComponent component, ComponentShutdown args) + { + DeleteEffect(component); + + if (component.SetEyeTarget && TryComp(hologram, out var eyeComp)) + eyeComp.Target = null; // This should be fine? I guess if you're a hologram riding a vehicle when this happens it'd be a bit weird. + } + private void HandleProjectedEffects(EntityQueryEnumerator query) { while (query.MoveNext(out var hologram, out var holoProjectedComp)) { - if (!holoProjectedComp.DoProjectionEffect) + if (holoProjectedComp.EffectPrototype == null) { DeleteEffect(holoProjectedComp); continue; @@ -58,12 +72,30 @@ private void HandleProjectedEffects(EntityQueryEnumerator(projector, out var projComp)) + { + var direction = projXformComp.LocalRotation.GetCardinalDir(); + + var offset = direction switch + { + Direction.North => projComp.EffectOffsets[Direction.South], + Direction.South => projComp.EffectOffsets[Direction.North], + Direction.East => projComp.EffectOffsets[Direction.West], + Direction.West => projComp.EffectOffsets[Direction.East], + _ => Vector2.Zero + }; + + originPos += offset; + } + // Determine a middle point between the hologram and the projector. - var effectPos = (holoCoords.Position + projCoords.Position) / 2; - // Offset the position a quarter tile towards the projector. - effectPos += (projCoords.Position - holoCoords.Position).Normalized() * 0.25f; + var effectPos = (holoCoords.Position + originPos) / 2; + // Determine a rotation that points from the projector to the hologram. - var effectRot = (holoCoords.Position - projCoords.Position).ToAngle() + -MathHelper.PiOver2; + var effectRot = (holoCoords.Position - originPos).ToAngle() - MathHelper.PiOver2; var effectCoords = new EntityCoordinates(holoCoords.EntityId, effectPos); if (!effectCoords.IsValid(EntityManager)) @@ -81,16 +113,12 @@ private void HandleProjectedEffects(EntityQueryEnumerator(holoProjectedComp.EffectEntity.Value).Scale = effectScale.Y > 0.1f ? effectScale : Vector2.One; + var yScale = (holoCoords.Position - originPos).Length(); + var effectScale = new Vector2(1, Math.Max(0.1f, yScale)); // No smaller than 0.1. + Comp(holoProjectedComp.EffectEntity.Value).Scale = effectScale; } } - private void OnHoloProjectedShutdown(EntityUid uid, HologramProjectedComponent component, ComponentShutdown args) - { - DeleteEffect(component); - } - private void DeleteEffect(HologramProjectedComponent component) { if (component.EffectEntity != null && Exists(component.EffectEntity.Value)) diff --git a/Content.Server/SimpleStation14/Holograms/AcceptHologramEui.cs b/Content.Server/SimpleStation14/Holograms/AcceptHologramEui.cs new file mode 100644 index 0000000000..ca0f8d9691 --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/AcceptHologramEui.cs @@ -0,0 +1,32 @@ +using Content.Server.EUI; +using Content.Shared.Eui; +using Content.Shared.SimpleStation14.Holograms; + +namespace Content.Server.SimpleStation14.Holograms; + +public sealed class AcceptHologramEui : BaseEui +{ + private readonly HologramSystem _hologramSystem; + private readonly Mind.Mind _mind; + + public AcceptHologramEui(Mind.Mind mind, HologramSystem hologramSys) + { + _mind = mind; + _hologramSystem = hologramSys; + } + + public override void HandleMessage(EuiMessageBase msg) + { + base.HandleMessage(msg); + + if (msg is not AcceptHologramChoiceMessage choice || + choice.Button == AcceptHologramUiButton.Deny) + { + Close(); + return; + } + + _hologramSystem.TransferMindToHologram(_mind); + Close(); + } +} diff --git a/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs b/Content.Server/SimpleStation14/Holograms/Components/HologramDiskComponent.cs similarity index 65% rename from Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs rename to Content.Server/SimpleStation14/Holograms/Components/HologramDiskComponent.cs index 709260b942..d2b0b9b589 100644 --- a/Content.Server/SimpleStation14/Holograms/Components/HoloDiskComponent.cs +++ b/Content.Server/SimpleStation14/Holograms/Components/HologramDiskComponent.cs @@ -1,7 +1,8 @@ -// using static Content.Server.SimpleStation14.Hologram.HologramSystem; - namespace Content.Server.SimpleStation14.Holograms; +/// +/// Marks this entity as storing a hologram's data in it, for use in a . +/// [RegisterComponent] public sealed class HologramDiskComponent : Component { diff --git a/Content.Server/SimpleStation14/Holograms/Components/HologramDiskDummyComponent.cs b/Content.Server/SimpleStation14/Holograms/Components/HologramDiskDummyComponent.cs new file mode 100644 index 0000000000..0bf910a951 --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/Components/HologramDiskDummyComponent.cs @@ -0,0 +1,18 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.SimpleStation14.Holograms.Components; + +/// +/// For any items that should generate a 'dummy' hologram when inserted as a holo disk. +/// Mostly intended for jokes and gaffs, but could be used for useful AI entities as well. +/// +[RegisterComponent] +public sealed class HologramDiskDummyComponent : Component +{ + /// + /// The prototype to spawn when this disk is inserted into a server. + /// + [DataField("prototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)] + public string HoloPrototype = default!; +} diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramProjectorSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramProjectorSystem.cs new file mode 100644 index 0000000000..ab853e359f --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramProjectorSystem.cs @@ -0,0 +1,34 @@ +using Content.Server.Power.Components; +using Content.Server.Power.EntitySystems; +using Content.Server.SurveillanceCamera; +using Content.Shared.SimpleStation14.Holograms; +using Content.Shared.SimpleStation14.Holograms.Components; + +namespace Content.Server.SimpleStation14.Holograms; + +public sealed class HologramProjectorSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent((EntityUid ent, HologramProjectorComponent comp, ref PowerChangedEvent _) => CheckState(ent, comp)); + SubscribeLocalEvent((ent, comp, args) => CheckState(ent, comp)); + SubscribeLocalEvent((ent, comp, args) => CheckState(ent, comp)); + } + + public void CheckState(EntityUid projector, HologramProjectorComponent? projComp = null) + { + if (!Resolve(projector, ref projComp)) + return; + + if (TryComp(projector, out var powerComp) && !powerComp.Powered || + TryComp(projector, out var cameraComp) && !cameraComp.Active) + { + RemComp(projector); + return; + } + + EnsureComp(projector); + } +} diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs index da1e6c5b87..05ae57b91f 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -1,65 +1,32 @@ -using System.Linq; -using Content.Server.Cloning; -using Content.Server.Cloning.Components; -using Content.Server.Psionics; -using Content.Server.EUI; using Content.Server.Humanoid; -using Content.Server.Jobs; using Content.Server.Mind; using Content.Server.Preferences.Managers; using Content.Server.Power.Components; -using Content.Server.Administration.Commands; using Content.Shared.Tag; using Content.Shared.Popups; using Content.Shared.SimpleStation14.Holograms; -using Content.Shared.Pulling; using Content.Shared.Administration.Logs; -using Content.Shared.Database; -using Content.Shared.Speech; -using Content.Shared.Preferences; -using Content.Shared.Emoting; -using Content.Shared.Humanoid; using Content.Shared.Mobs.Systems; using Content.Shared.Interaction; -using Content.Shared.Inventory; -using Content.Shared.Interaction.Components; -using Content.Shared.Access.Components; -using Content.Shared.Clothing.Components; using Robust.Server.Player; -using Robust.Shared.Player; using Robust.Shared.Containers; -using Robust.Shared.GameObjects.Components.Localization; using Content.Shared.Movement.Systems; -using System.Threading.Tasks; using Content.Server.Mind.Components; using Content.Shared.SimpleStation14.Holograms.Components; +using System.Diagnostics.CodeAnalysis; +using Content.Server.EUI; +using Robust.Server.GameObjects; namespace Content.Server.SimpleStation14.Holograms; public sealed class HologramServerSystem : EntitySystem { - [Dependency] private readonly IEntityManager _entityManager = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly SharedPullingSystem _pulling = default!; - [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; - [Dependency] private readonly IPlayerManager _playerManager = null!; - [Dependency] private readonly CloningSystem _cloningSystem = default!; - [Dependency] private readonly EuiManager _euiManager = null!; - [Dependency] private readonly HumanoidAppearanceSystem _humanoidSystem = default!; - [Dependency] private readonly MobStateSystem _mobStateSystem = default!; - [Dependency] private readonly MindSystem _mind = default!; - [Dependency] private readonly TagSystem _tag = default!; - [Dependency] private readonly IServerPreferencesManager _prefs = default!; - [Dependency] private readonly TagSystem _tagSystem = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly InventorySystem _inventory = default!; - [Dependency] private readonly SharedMoverController _mover = default!; + [Dependency] private readonly TagSystem _tags = default!; [Dependency] private readonly HologramSystem _hologram = default!; + [Dependency] private readonly TransformSystem _transform = default!; - private const string DiskSlot = "holo_disk"; - public readonly Dictionary ClonesWaitingForMind = new(); + public const string TagHoloDisk = "HoloDisk"; public override void Initialize() { @@ -71,43 +38,38 @@ public override void Initialize() } /// - /// Handles generating a hologram from an inserted disk + /// Handles generating a hologram from an inserted disk /// private void OnEntInserted(EntityUid uid, HologramServerComponent component, EntInsertedIntoContainerMessage args) { - if (args.Container.ID != DiskSlot || !_tagSystem.HasTag(args.Entity, "HoloDisk") || - !_entityManager.TryGetComponent(args.Entity, out var diskComp) || diskComp.HoloMind == null) + if (args.Container.ID != component.DiskSlot || !_tags.HasTag(args.Entity, TagHoloDisk)) return; - if (component.LinkedHologram != null && _entityManager.EntityExists(component.LinkedHologram)) - { - _hologram.DoKillHologram(component.LinkedHologram.Value); - } + if (Exists(component.LinkedHologram)) + if (!_hologram.TryKillHologram(component.LinkedHologram.Value)) + return; // This is a werid situation to encounter, so we'll just stop doin stuff. - if (TryHoloGenerate(uid, diskComp.HoloMind!, component, out var holo)) + if (TryGenerateHologram(uid, args.Entity, out var holo, component)) { - var holoLinkComp = _entityManager.EnsureComponent(holo); component.LinkedHologram = holo; - holoLinkComp.LinkedServer = uid; + EnsureComp(holo.Value).LinkedServer = uid; } } /// - /// Handles killing a hologram when a disk is removed + /// Handles killing a hologram when a disk is removed /// private void OnEntRemoved(EntityUid uid, HologramServerComponent component, EntRemovedFromContainerMessage args) { - if (args.Container.ID != DiskSlot || !_tagSystem.HasTag(args.Entity, "HoloDisk") || - !_entityManager.TryGetComponent(args.Entity, out var diskComp) || diskComp.HoloMind == null) return; + if (args.Container.ID != component.DiskSlot || !_tags.HasTag(args.Entity, "HoloDisk")) + return; - if (_entityManager.EntityExists(component.LinkedHologram)) - { + if (Exists(component.LinkedHologram)) _hologram.DoKillHologram(component.LinkedHologram.Value); - } } /// - /// Called when the server's power state changes + /// Called when the server's power state changes /// /// The entity uid of the server /// The HologramServerComponent @@ -115,7 +77,7 @@ private void OnEntRemoved(EntityUid uid, HologramServerComponent component, EntR private void OnPowerChanged(EntityUid uid, HologramServerComponent component, ref PowerChangedEvent args) { // If the server is no longer powered and the hologram exists - if (!args.Powered && _entityManager.EntityExists(component.LinkedHologram)) + if (!args.Powered && Exists(component.LinkedHologram)) { // Kill the Hologram _hologram.DoKillHologram(component.LinkedHologram.Value); @@ -125,197 +87,37 @@ private void OnPowerChanged(EntityUid uid, HologramServerComponent component, re // If the server is powered else if (args.Powered) { - var serverContainer = _entityManager.GetComponent(uid); - if (serverContainer.GetContainer(DiskSlot).ContainedEntities.Count <= 0) - { + if (component.DiskSlot == null) + return; // No disk slot + + var container = Comp(uid).Containers[component.DiskSlot]; + + if (container.ContainedEntities.Count <= 0) return; // No disk in the server - } - var disk = serverContainer.GetContainer(DiskSlot).ContainedEntities[0]; - var diskData = _entityManager.GetComponent(disk).HoloMind; // If the hologram is generated successfully - if (diskData != null && TryHoloGenerate(uid, diskData, component, out var holo)) + if (TryGenerateHologram(uid, container.ContainedEntities[0], out var holo, component)) { // Set the linked hologram to the generated hologram - var holoLinkComp = _entityManager.EnsureComponent(holo); + var holoLinkComp = EnsureComp(holo.Value); component.LinkedHologram = holo; holoLinkComp.LinkedServer = uid; } } } - public bool TryHoloGenerate(EntityUid uid, Mind.Mind mind, HologramServerComponent? holoServer, out EntityUid holo) + public bool TryGenerateHologram(EntityUid server, EntityUid disk, [NotNullWhen(true)] out EntityUid? hologram, HologramServerComponent? holoServerComp = null) { - CloningSystem cloneSys = new(); - holo = EntityUid.Invalid; - - if (ClonesWaitingForMind.TryGetValue(mind, out var clone)) - { - if (EntityManager.EntityExists(clone) && - !_mobStateSystem.IsDead(clone) && - TryComp(clone, out var cloneMindComp) && - (cloneMindComp.Mind == null || cloneMindComp.Mind == mind)) - return false; // Mind already has clone - - ClonesWaitingForMind.Remove(mind); - } - - if (mind.OwnedEntity != null && (_mobStateSystem.IsAlive(mind.OwnedEntity.Value) || _mobStateSystem.IsCritical(mind.OwnedEntity.Value))) - return false; // Body controlled by mind is not dead - - // Yes, we still need to track down the client because we need to open the Eui - if (mind.UserId == null || !_playerManager.TryGetSessionById(mind.UserId.Value, out var client)) - return false; // If we can't track down the client, we can't offer transfer. That'd be quite bad. + hologram = null; - var pref = (HumanoidCharacterProfile) _prefs.GetPreferences(mind.UserId.Value).SelectedCharacter; + // if (TryComp(disk, out var diskDummyComp)) //TODO - var mob = HoloFetchAndSpawn(holoServer!, pref); + if (!TryComp(disk, out var diskComp) || diskComp.HoloMind == null) + return false; - var cloneMindReturn = EntityManager.AddComponent(mob); - cloneMindReturn.Mind = mind; - ClonesWaitingForMind.Add(mind, mob); - TransferMindToClone(mind); - - if (mind.CurrentJob != null) - { - foreach (var special in mind.CurrentJob.Prototype.Special) - { - if (special is AddComponentSpecial) - special.AfterEquip(mob); - } - - // Get each access from the job prototype and add it to the mob - foreach (var access in mind.CurrentJob.Prototype.Access) - { - var accessComp = EntityManager.EnsureComponent(mob); - accessComp.Tags.Add(access); - } - - // Get the loadout from the job prototype and add it to the Hologram - // making each item unremovable. - if (mind.CurrentJob.Prototype.StartingGear != null) - { - SetOutfitCommand.SetOutfit(mob, mind.CurrentJob.Prototype.StartingGear, _entityManager, (_, item) => - { - if (_entityManager.TryGetComponent(item, out var clothing)) - { - if (clothing.InSlot is "back" or "pocket1" or "pocket2" or "belt" or "suitstorage" or "id") - { - _entityManager.DeleteEntity(item); - return; - } - } - EnsureComp(item); - _entityManager.EnsureComponent(item); - }); - // HoloEquip(mob, mind.CurrentJob.Prototype); - } - } - - _adminLogger.Add(LogType.Unknown, LogImpact.Medium, - $"{ToPrettyString(mob):mob} was generated at {ToPrettyString((EntityUid) uid):entity}"); - - holo = mob; - return true; + return _hologram.TryGenerateHologram(diskComp.HoloMind, _transform.GetMoverCoordinates(server), out hologram); } - internal void TransferMindToClone(Mind.Mind mind) - { - if (!ClonesWaitingForMind.TryGetValue(mind, out var entity) || - !EntityManager.EntityExists(entity) || - !TryComp(entity, out var mindComp) || - mindComp.Mind != null) - return; - - _mind.TransferTo(mind, entity, true); - _mind.UnVisit(mind); - - ClonesWaitingForMind.Remove(mind); - } - - /// - /// Handles fetching the mob and any appearance stuff... - /// - private EntityUid HoloFetchAndSpawn(HologramServerComponent holoServer, HumanoidCharacterProfile pref) - { - List sexes = new(); - var name = pref.Name; - var toSpawn = "MobHologramProjected"; - - var mob = Spawn(toSpawn, Transform(holoServer.Owner).MapPosition); - Transform(mob).AttachToGridOrMap(); - - ResetCamera(mob); - - _humanoidSystem.LoadProfile(mob, pref); - - MetaData(mob).EntityName = name; - var mind = EnsureComp(mob); - _mind.SetExamineInfo(mob, true, mind); - - var grammar = EnsureComp(mob); - grammar.ProperNoun = true; - grammar.Gender = Robust.Shared.Enums.Gender.Neuter; - Dirty(grammar); - - var popupAppearOther = Loc.GetString("system-hologram-phasing-appear-others", ("name", MetaData(mob).EntityName)); - var popupAppearSelf = Loc.GetString("system-hologram-phasing-appear-self"); - - _popup.PopupEntity(popupAppearOther, mob, Filter.PvsExcept(mob), false, PopupType.Medium); - _popup.PopupEntity(popupAppearSelf, mob, mob, PopupType.Large); - _audio.PlayPvs("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg", mob); - - EnsureComp(mob); - EnsureComp(mob); - EnsureComp(mob); - RemComp(mob); - - _tag.AddTag(mob, "DoorBumpOpener"); - - return mob; - } - - private async void ResetCamera(EntityUid mob) - { - await Task.Delay(500); - - _mover.ResetCamera(mob); - } - - - /// - /// WiP for equipping unique items based on job. - /// -// private void HoloEquip(EntityUid mob, JobPrototype job) -// { -// // Check what job they are against a list, and output a hardcoded item for each. - - - - -// var mobTransform = EntityManager.GetComponent(mob); -// var mobPos = mobTransform.WorldPosition; - -// if (!_entityManager.TryGetComponent(mob, out var mobInv)) -// return; -// var mobHands = EntityManager.EnsureComponent(mob); - -// foreach (var item in job.StartingGear.Items) -// { -// var itemEnt = Spawn(item.Prototype, mobPos); -// _entityManager.GetComponent(itemEnt).AttachToGridOrMap(); - -// if (item.Slot == null) -// { -// mobInv.TryPutInHandOrAny(itemEnt, out var _); -// } -// else -// { -// mobInv.TryPutInSlot(itemEnt, item.Slot); -// } -// } -// } - private void OnAfterInteract(EntityUid uid, HologramDiskComponent component, AfterInteractEvent args) { if (args.Target == null || !TryComp(args.Target, out var targetMind)) @@ -334,13 +136,4 @@ private void OnAfterInteract(EntityUid uid, HologramDiskComponent component, Aft args.Handled = true; } - - -// // List of jobs with hardcoded items for Holograms, like a Clown's horn. -// static readonly Dictionary HoloJobItems = new Dictionary -// { -// { "Clown", "BikeHorn" }, -// { "value2", "output2" }, -// { "value3", "output3" } -// }; } diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs index 5eb9c1ea30..33359f4b82 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs @@ -2,105 +2,189 @@ using Content.Server.Mind.Components; using Content.Shared.Popups; using Content.Shared.SimpleStation14.Holograms; -using Content.Shared.Pulling; using Content.Shared.Administration.Logs; using Content.Shared.Database; using Robust.Shared.Player; -using Content.Shared.Pulling.Components; -using Linguini.Syntax.Ast; -using Robust.Shared.Timing; -using JetBrains.Annotations; +using Content.Server.Cloning.Components; +using Content.Server.Psionics; +using Content.Server.Humanoid; +using Content.Server.Jobs; +using Content.Server.Mind; +using Content.Server.Preferences.Managers; +using Content.Server.Power.Components; +using Content.Server.Administration.Commands; +using Content.Shared.Tag; +using Content.Shared.Speech; +using Content.Shared.Preferences; +using Content.Shared.Emoting; +using Content.Shared.Humanoid; +using Content.Shared.Mobs.Systems; +using Content.Shared.Interaction; +using Content.Shared.Interaction.Components; +using Content.Shared.Access.Components; +using Content.Shared.Clothing.Components; +using Robust.Server.Player; +using Robust.Shared.Containers; +using Robust.Shared.GameObjects.Components.Localization; +using Content.Shared.Movement.Systems; +using System.Threading.Tasks; using Content.Shared.SimpleStation14.Holograms.Components; +using Content.Server.SimpleStation14.Holograms.Components; +using System.Diagnostics.CodeAnalysis; +using Content.Server.EUI; +using Robust.Server.GameObjects; +using Robust.Shared.Enums; +using Robust.Shared.Map; +using Content.Server.Access.Systems; +using Content.Server.Station.Systems; +using Content.Server.Station.Components; namespace Content.Server.SimpleStation14.Holograms; public sealed class HologramSystem : SharedHologramSystem { [Dependency] private readonly IEntityManager _entityManager = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly SharedPullingSystem _pulling = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly GameTicker _gameTicker = default!; + [Dependency] private readonly IPlayerManager _playerManager = null!; + [Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!; + [Dependency] private readonly MobStateSystem _mobState = default!; + [Dependency] private readonly MindSystem _mind = default!; + [Dependency] private readonly TagSystem _tag = default!; + [Dependency] private readonly IServerPreferencesManager _prefs = default!; + [Dependency] private readonly TagSystem _tags = default!; + [Dependency] private readonly SharedMoverController _mover = default!; + [Dependency] private readonly EuiManager _eui = default!; + [Dependency] private readonly TransformSystem _transform = default!; + [Dependency] private readonly MetaDataSystem _meta = default!; + [Dependency] private readonly AccessSystem _access = default!; + [Dependency] private readonly StationSystem _station = default!; + + public readonly Dictionary HologramsWaitingForMind = new(); - public readonly Dictionary ClonesWaitingForMind = new(); - - public override void Initialize() + /// + /// Handles killing a Hologram, with no checks in place. + /// + /// + /// You should generally use instead. + /// + public override void DoKillHologram(EntityUid hologram, HologramComponent? holoComp = null) // TODOPark: HOLO Move this to Shared once Upstream merge. { - base.Initialize(); - // SubscribeLocalEvent(Startup); - // SubscribeLocalEvent(Shutdown); - // SubscribeLocalEvent(HoloTeleport); - } + var meta = MetaData(hologram); + var holoPos = Transform(hologram).Coordinates; - // private void Startup(EntityUid uid, HologramComponent component, ComponentStartup args) - // { - // var action = new WorldTargetAction(_prototypeManager.Index("ShadekinTeleport")); - // _actionsSystem.AddAction(uid, action, uid); - // } + if (TryComp(hologram, out var mindComp) && mindComp.Mind != null) + _gameTicker.OnGhostAttempt(mindComp.Mind, false); - // private void Shutdown(EntityUid uid, HologramComponent component, ComponentShutdown args) - // { - // var action = new WorldTargetAction(_prototypeManager.Index("ShadekinTeleport")); - // _actionsSystem.RemoveAction(uid, action); - // } + _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(hologram), coordinates: holoPos, false); + _popup.PopupCoordinates(Loc.GetString(PopupDisappearOther, ("name", meta.EntityName)), holoPos, Filter.PvsExcept(hologram), false, PopupType.MediumCaution); + _popup.PopupCoordinates(Loc.GetString(PopupDeathSelf), holoPos, hologram, PopupType.LargeCaution); - /// - /// Mind stuff is all server side, so this exists to actually kill the Hologram in reaction to . - /// - public override void DoReturnHologram(EntityUid uid, out bool holoKilled, HologramProjectedComponent? component = null) - { - base.DoReturnHologram(uid, out holoKilled, component); - if (holoKilled) - DoKillHologram(uid); + _entityManager.QueueDeleteEntity(hologram); + + _adminLogger.Add(LogType.Mind, LogImpact.Medium, $"{ToPrettyString(hologram):mob} was killed!"); } - /// - /// Kills a Hologram after playing the visual and auditory effects. - /// - public void DoKillHologram(EntityUid uid, HologramComponent? holoComp = null) + public bool TryGenerateHologram(Mind.Mind mind, EntityCoordinates coords, [NotNullWhen(true)] out EntityUid? holo) { - if (!Resolve(uid, ref holoComp)) - return; + holo = null; - var meta = MetaData(uid); - var holoPos = Transform(uid).Coordinates; + if (HologramsWaitingForMind.TryGetValue(mind, out var clone)) + { + if (EntityManager.EntityExists(clone) && + !_mobState.IsDead(clone) && + TryComp(clone, out var cloneMindComp) && + (cloneMindComp.Mind == null || cloneMindComp.Mind == mind)) + return false; // Mind already has clone - if (TryComp(uid, out var mindComp) && mindComp.Mind != null) - _gameTicker.OnGhostAttempt(mindComp.Mind, false); + HologramsWaitingForMind.Remove(mind); + } - _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(uid), coordinates: holoPos, false); - _popup.PopupCoordinates(Loc.GetString(PopupDisappearOther, ("name", meta.EntityName)), holoPos, Filter.PvsExcept(uid), false, PopupType.MediumCaution); - _popup.PopupCoordinates(Loc.GetString(PopupDeathSelf), holoPos, uid, PopupType.LargeCaution); - if (TryComp(uid, out var holoLinkComp) && holoLinkComp.LinkedServer != null) + if (mind.OwnedEntity != null && (_mobState.IsAlive(mind.OwnedEntity.Value) || _mobState.IsCritical(mind.OwnedEntity.Value))) + return false; // Body controlled by mind is not dead + + // Yes, we still need to track down the client because we need to open the Eui + if (mind.UserId == null || !_playerManager.TryGetSessionById(mind.UserId.Value, out var client)) + return false; // If we can't track down the client, we can't offer transfer. That'd be quite bad. + + var pref = (HumanoidCharacterProfile) _prefs.GetPreferences(mind.UserId.Value).SelectedCharacter; + + var mob = HoloFetchAndSpawn(pref, coords, "MobHologramProjected"); + + HologramsWaitingForMind.Add(mind, mob); + _eui.OpenEui(new AcceptHologramEui(mind, this), client); + + if (mind.CurrentJob != null) { - if (TryComp(holoLinkComp.LinkedServer.Value, out var serverComp)) - serverComp.LinkedHologram = null; - holoLinkComp.LinkedServer = null; + foreach (var special in mind.CurrentJob.Prototype.Special) + if (special is AddComponentSpecial) + special.AfterEquip(mob); + + // Get each access from the job prototype and add it to the mob + var extended = _station.GetOwningStation(mob) is { } station && TryComp(station, out var jobComp) && jobComp.ExtendedAccess; + _access.SetAccessToJob(mob, mind.CurrentJob.Prototype, extended, EnsureComp(mob)); + + // Get the loadout from the job prototype and add it to the Hologram making each item unremovable. + if (mind.CurrentJob.Prototype.StartingGear != null) + { + SetOutfitCommand.SetOutfit(mob, mind.CurrentJob.Prototype.StartingGear, EntityManager, (_, item) => + { + if (TryComp(item, out var clothing)) + { + if (clothing.InSlot is "back" or "pocket1" or "pocket2" or "belt" or "suitstorage" or "id") + { + QueueDel(item); + return; + } + } + EnsureComp(item); + EnsureComp(item); + }); + } } - _entityManager.QueueDeleteEntity(uid); + _adminLogger.Add(LogType.Mind, LogImpact.Medium, + $"Hologram {ToPrettyString(mob):mob} was generated at {coords}"); - _adminLogger.Add(LogType.Mind, LogImpact.Medium, $"{ToPrettyString(uid):mob} was disabled due to lack of projectors"); + holo = mob; + return true; } - // private void HoloTeleport(HoloTeleportEvent args) - // { - // if (args.Handled) return; + internal void TransferMindToHologram(Mind.Mind mind) + { + if (!HologramsWaitingForMind.TryGetValue(mind, out var entity) || + !EntityManager.EntityExists(entity) || + !TryComp(entity, out var mindComp) || + mindComp.Mind != null) + return; + + _mind.TransferTo(mind, entity, true); + _mind.UnVisit(mind); - // if HoloGetProjector(args.Target, args. ) - // var transform = Transform(args.Performer); - // if (transform.MapID != args.Target.GetMapId(EntityManager)) return; + HologramsWaitingForMind.Remove(mind); + } - // _transformSystem.SetCoordinates(args.Performer, args.Target); - // transform.AttachToGridOrMap(); + /// + /// Handles fetching the mob and any appearance stuff... + /// + private EntityUid HoloFetchAndSpawn(HumanoidCharacterProfile pref, EntityCoordinates coords, string mobPrototype) + { + var mob = Spawn(mobPrototype, coords); + _transform.AttachToGridOrMap(mob); + + _humanoid.LoadProfile(mob, pref); + _meta.SetEntityName(mob, pref.Name); - // _audio.PlayPvs(args.BlinkSound, args.Performer, AudioParams.Default.WithVolume(args.BlinkVolume)); + var mind = EnsureComp(mob); + _mind.SetExamineInfo(mob, true, mind); - // _staminaSystem.TakeStaminaDamage(args.Performer, 35); + var grammar = EnsureComp(mob); + grammar.ProperNoun = true; + grammar.Gender = Gender.Neuter; + Dirty(grammar); - // args.Handled = true; - // } - // } + return mob; + } } diff --git a/Content.Server/SimpleStation14/StationAI/Systems/AIEyeSystem.cs b/Content.Server/SimpleStation14/StationAI/Systems/AIEyeSystem.cs index a98d47d7f5..80897240f4 100644 --- a/Content.Server/SimpleStation14/StationAI/Systems/AIEyeSystem.cs +++ b/Content.Server/SimpleStation14/StationAI/Systems/AIEyeSystem.cs @@ -12,6 +12,8 @@ using Content.Server.Borgs; using Robust.Server.GameObjects; using Content.Server.Visible; +using Content.Shared.SimpleStation14.Holograms.Components; +using Content.Shared.SimpleStation14.Holograms; namespace Content.Server.SimpleStation14.StationAI { @@ -70,6 +72,10 @@ private void OnPowerUsed(EntityUid uid, AIEyePowerComponent component, AIEyePowe Transform(projection).AttachToGridOrMap(); _mindSwap.Swap(uid, projection); + // Hologram stuff. + if (TryComp(projection, out var serverLinkedComp)) + serverLinkedComp.LinkedServer = uid; + // Consistent name _entityManager.GetComponent(projection).EntityName = core.EntityName != "" diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs index f159ec52d9..180a29eedf 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs @@ -58,7 +58,7 @@ public override void Initialize() SubscribeLocalEvent(OnSetName); SubscribeLocalEvent(OnSetNetwork); SubscribeLocalEvent>(AddVerbs); - + SubscribeLocalEvent(OnEmpPulse); SubscribeLocalEvent(OnEmpDisabledRemoved); } @@ -262,6 +262,8 @@ private void Deactivate(EntityUid camera, SurveillanceCameraComponent? component // Send a local event that's broadcasted everywhere afterwards. RaiseLocalEvent(ev); + RaiseLocalEvent(camera, new SurveillanceCameraChangeStateEvent(false)); // Parkstation-Holograms + UpdateVisuals(camera, component); } @@ -279,6 +281,7 @@ public void SetActive(EntityUid camera, bool setting, SurveillanceCameraComponen if (attemptEv.Cancelled) return; component.Active = setting; + RaiseLocalEvent(camera, new SurveillanceCameraChangeStateEvent(setting)); // Parkstation-Holograms } else { @@ -439,3 +442,5 @@ public SurveillanceCameraDeactivateEvent(EntityUid camera) [ByRefEvent] public record struct SurveillanceCameraSetActiveAttemptEvent(bool Cancelled); + +public readonly record struct SurveillanceCameraChangeStateEvent(bool Active); // Parkstation-Holograms diff --git a/Content.Shared/SimpleStation14/Holograms/AcceptHologramEuiMessage.cs b/Content.Shared/SimpleStation14/Holograms/AcceptHologramEuiMessage.cs new file mode 100644 index 0000000000..1b66002a9f --- /dev/null +++ b/Content.Shared/SimpleStation14/Holograms/AcceptHologramEuiMessage.cs @@ -0,0 +1,22 @@ +using Content.Shared.Eui; +using Robust.Shared.Serialization; + +namespace Content.Shared.SimpleStation14.Holograms; + +[Serializable, NetSerializable] +public enum AcceptHologramUiButton +{ + Deny, + Accept, +} + +[Serializable, NetSerializable] +public sealed class AcceptHologramChoiceMessage : EuiMessageBase +{ + public readonly AcceptHologramUiButton Button; + + public AcceptHologramChoiceMessage(AcceptHologramUiButton button) + { + Button = button; + } +} diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HoloServerComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HoloServerComponent.cs deleted file mode 100644 index 2447b54f24..0000000000 --- a/Content.Shared/SimpleStation14/Holograms/Components/HoloServerComponent.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Content.Shared.SimpleStation14.Holograms; - -[RegisterComponent] -public sealed class HologramServerComponent : Component -{ - [ViewVariables] - public EntityUid? LinkedHologram; -} diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs index 84492bdbf5..039fe38f84 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs @@ -1,4 +1,5 @@ using Content.Shared.Tag; +using Content.Shared.Whitelist; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -14,10 +15,10 @@ namespace Content.Shared.SimpleStation14.Holograms.Components; public sealed partial class HologramProjectedComponent : Component { /// - /// A list of tags to check for on projectors, to determine if they're valid. + /// A whitelist to check for on projectors, to determine if they're valid. /// - [DataField("validProjectorTags", customTypeSerializer: typeof(PrototypeIdListSerializer)), ViewVariables(VVAccess.ReadWrite)] - public List ValidProjectorTags = new(); + [DataField("validProjectorWhitelist"), ViewVariables(VVAccess.ReadWrite)] + public EntityWhitelist ValidProjectorWhitelist = new(); /// /// A timer for a grace period before the Holo is returned, to allow for moving through doors. @@ -28,20 +29,27 @@ public sealed partial class HologramProjectedComponent : Component /// /// The maximum range from a projector a Hologram can be before they're returned. /// + /// + /// Note that making this number larger than PVS is highly inadvisable, as the client will be stuck predicting the Hologram returning while the server confirms that they do not. + /// [DataField("projectorRange"), ViewVariables(VVAccess.ReadWrite)] - public float ProjectorRange = 18f; + public float ProjectorRange = 14f; /// - /// The prototype of the effect to spawn for the Hologram's projection, assuming is true. + /// The prototype of the effect to spawn for the Hologram's projection. Leave null to disable the visual projection effect. /// [DataField("effectPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string EffectPrototype = "EffectHologramProjectionBeam"; + public string? EffectPrototype; /// - /// Whether or not the Hologram should have a visual projection effect. + /// Whether or not the Hologram's vision should snap to the projector they're projected from. /// - [DataField("doProjectionEffect"), ViewVariables(VVAccess.ReadWrite)] - public bool DoProjectionEffect = true; + /// + /// This provides a super cool effect of the Hologram only getting the visual information they technically should, but it's also a bit of a pain from a player perspective. + /// Primarily used for the station AI. + /// + [DataField("setEyeTarget"), ViewVariables(VVAccess.ReadWrite)] + public bool SetEyeTarget = false; /// /// The current projector the hologram is connected to. diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectorActiveComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectorActiveComponent.cs new file mode 100644 index 0000000000..aaf726b518 --- /dev/null +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectorActiveComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.SimpleStation14.Holograms.Components; + +/// +/// Marks a hologram projector as active and working. +/// +[RegisterComponent, NetworkedComponent] +public sealed class HologramProjectorActiveComponent : Component +{ } diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectorComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectorComponent.cs index eb4708891c..a60e9dddb8 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectorComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectorComponent.cs @@ -1,7 +1,14 @@ +using System.Numerics; +using Robust.Shared.GameStates; + namespace Content.Shared.SimpleStation14.Holograms; -[RegisterComponent] +[RegisterComponent, NetworkedComponent] public sealed class HologramProjectorComponent : Component { - + /// + /// The tile offset of the projector effect for this projector for each direction. + /// + [DataField("effectOffsets")] + public Dictionary EffectOffsets { get; } = new() { { Direction.North, Vector2.Zero }, { Direction.East, Vector2.Zero }, { Direction.South, Vector2.Zero }, { Direction.West, Vector2.Zero } }; } diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramServerComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramServerComponent.cs new file mode 100644 index 0000000000..c2f83e6299 --- /dev/null +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramServerComponent.cs @@ -0,0 +1,14 @@ +namespace Content.Shared.SimpleStation14.Holograms; + +/// +/// Marks an entity as being capable of generating a hologram by inserting a into it. +/// +[RegisterComponent] +public sealed class HologramServerComponent : Component +{ + [DataField("diskSlot")] + public string? DiskSlot; + + [ViewVariables(VVAccess.ReadOnly)] + public EntityUid? LinkedHologram; +} diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs index 5833be940e..2587d2f610 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs @@ -3,12 +3,15 @@ namespace Content.Shared.SimpleStation14.Holograms.Components; /// /// Marks that this Hologram requires a server of some kind to generate it. /// +/// +/// This could be anything from a literal server, to an AICore, to the person a HoloParasite lives in. +/// [RegisterComponent] public sealed class HologramServerLinkedComponent : Component { /// /// Whether this Hologram is bound to the same grid as its server. - /// If false, it will be returned if it leaves the grid. + /// If true, it will be returned if it leaves the grid. /// [ViewVariables(VVAccess.ReadWrite)] [DataField("gridBound")] diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs index 1a3e3f653a..54a219c0aa 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs @@ -7,11 +7,21 @@ using Content.Shared.Pulling.Components; using Content.Shared.Database; using Content.Shared.SimpleStation14.Holograms.Components; +using Robust.Shared.Configuration; +using Robust.Shared; +using Content.Shared.Whitelist; namespace Content.Shared.SimpleStation14.Holograms; -public abstract partial class SharedHologramSystem +public partial class SharedHologramSystem { + [Dependency] private readonly IConfigurationManager _config = default!; + + private void InitializeProjected() + { + SubscribeLocalEvent(OnProjectedInit); + } + public override void Update(float frameTime) { base.Update(frameTime); @@ -27,38 +37,30 @@ public override void Update(float frameTime) /// The hologram to return. /// True if the hologram was killed, false if it was returned. /// The hologram's projected component. - public virtual void DoReturnHologram(EntityUid hologram, out bool holoKilled, HologramProjectedComponent? holoProjectedComp = null) + public virtual void DoReturnHologram(EntityUid hologram, HologramProjectedComponent? holoProjectedComp = null) { - holoKilled = false; - if (!Resolve(hologram, ref holoProjectedComp)) return; if (!IsHoloProjectorValid(hologram, holoProjectedComp.CurProjector, 0, false)) // If their last visited Projector is invalid ignoring occlusion... { - if (!TryGetHoloProjector(hologram, holoProjectedComp.ProjectorRange, out holoProjectedComp.CurProjector, holoProjectedComp)) + if (!TryGetHoloProjector(hologram, holoProjectedComp.ProjectorRange, out holoProjectedComp.CurProjector, holoProjectedComp, false)) { - var killedEvent = new HologramKillAttemptEvent(); - RaiseLocalEvent(hologram, ref killedEvent); - if (killedEvent.Cancelled) - return; - - RaiseLocalEvent(hologram, new HologramKilledEvent()); - holoKilled = true; // And if none is found and it doesn't get cancelled, kill the hologram. - return; // The killing is dealt with server-side, due to mind component. + TryKillHologram(hologram); // And if none is found, kill the hologram. + return; } } - // The two if statements above set the current projector, and return if it's null, so we know it's not null moving forward. + // The two if statements above set the current projector, and kill if it's null, so we know it's not null moving forward. var returnedEvent = new HologramReturnAttemptEvent(); RaiseLocalEvent(hologram, ref returnedEvent); if (returnedEvent.Cancelled) return; - RaiseLocalEvent(hologram, new HologramReturnedEvent(holoProjectedComp.CurProjector!.Value)); + RaiseLocalEvent(hologram, new HologramReturnedEvent(holoProjectedComp.CurProjector.Value)); - MoveHologramToProjector(hologram, holoProjectedComp.CurProjector!.Value); + MoveHologramToProjector(hologram, holoProjectedComp.CurProjector.Value); _adminLogger.Add(LogType.Mind, LogImpact.Low, $"{ToPrettyString(hologram):mob} was returned to projector {ToPrettyString(holoProjectedComp.CurProjector.Value):entity}"); @@ -69,18 +71,18 @@ public virtual void DoReturnHologram(EntityUid hologram, out bool holoKilled, Ho /// /// The coords to perform the check from. /// The UID of the projector, or null if no projectors are found. - /// A list of tags to check for on projectors, to determine if they're valid. + /// A list of tags to check for on projectors, to determine if they're valid. /// The range it should check for projectors in, if occlude is true /// Should it check only for unoccluded and in range projectors? /// Returns true if a projector is found, false if not. - public bool TryGetHoloProjector(MapCoordinates coords, float range, [NotNullWhen(true)] out EntityUid? result, List? allowedTags = null, bool occlude = true) + public bool TryGetHoloProjector(MapCoordinates coords, float range, [NotNullWhen(true)] out EntityUid? result, EntityWhitelist? whiteList = null, bool occlude = true) { result = null; // Sort all projectors in distance increasing order. var nearProjList = new SortedList(); - var query = _entityManager.EntityQueryEnumerator(); + var query = _entityManager.EntityQueryEnumerator(); while (query.MoveNext(out var projector, out _)) { var dist = (_transform.GetWorldPosition(projector) - coords.Position).LengthSquared(); @@ -90,7 +92,7 @@ public bool TryGetHoloProjector(MapCoordinates coords, float range, [NotNullWhen // Find the nearest, valid projector. foreach (var nearProj in nearProjList) { - if (!IsHoloProjectorValid(coords, nearProj.Value, range, occlude)) + if (!IsHoloProjectorValid(coords, nearProj.Value, range, occlude, whiteList)) continue; result = nearProj.Value; return true; @@ -101,7 +103,7 @@ public bool TryGetHoloProjector(MapCoordinates coords, float range, [NotNullWhen /// /// This takes into consideration any ProjectorOverride the hologram may have. /// - /// + /// public bool TryGetHoloProjector(EntityUid uid, float range, [NotNullWhen(true)] out EntityUid? result, HologramProjectedComponent? projectedComp = null, bool occlude = true) { result = null; @@ -128,7 +130,7 @@ public bool TryGetHoloProjector(EntityUid uid, float range, [NotNullWhen(true)] } // Otherwise, we simply check for the nearest projector, considering any tags it requires. - return TryGetHoloProjector(Transform(uid).MapPosition, range, out result, projectedComp.ValidProjectorTags, occlude); + return TryGetHoloProjector(Transform(uid).MapPosition, range, out result, projectedComp.ValidProjectorWhitelist, occlude); } /// @@ -138,22 +140,26 @@ public bool TryGetHoloProjector(EntityUid uid, float range, [NotNullWhen(true)] /// The projector to compare on, or its position. /// The max range to allow. Ignored if occlude is false. /// Should it check only for unoccluded and in range projectors? + /// The hologram's component. If provided, the hologram's list of allowed tags will be used. /// True if the projector is within range, and unoccluded to the hologram. Otherwise, false. - public bool IsHoloProjectorValid(EntityUid hologram, EntityUid? projector, float range = 18f, bool occlude = true, HologramProjectedComponent? projectedComp = null) + public bool IsHoloProjectorValid(EntityUid hologram, [NotNullWhen(true)] EntityUid? projector, float range = 18f, bool occlude = true, HologramProjectedComponent? projectedComp = null) { if (!Resolve(hologram, ref projectedComp)) return false; - return IsHoloProjectorValid(Transform(hologram).MapPosition, projector, range, occlude, projectedComp.ValidProjectorTags); + return IsHoloProjectorValid(Transform(hologram).MapPosition, projector, range, occlude, projectedComp.ValidProjectorWhitelist); } - /// - /// A list of tags to check for on projectors, to determine if they're valid. Usually found on the Holo's . - public bool IsHoloProjectorValid(MapCoordinates hologram, EntityUid? projector, float range = 18f, bool occlude = true, List? allowedTags = null) + /// + /// A whitelist to check for on projectors, to determine if they're valid. Usually found on the Holo's . + public bool IsHoloProjectorValid(MapCoordinates hologram, EntityUid? projector, float range = 18f, bool occlude = true, EntityWhitelist? whitelist = null) { if (projector == null || !Exists(projector.Value)) return false; - if (allowedTags != null && !_tags.HasAnyTag(projector.Value, allowedTags)) + if (!HasComp(projector.Value)) + return false; + + if (whitelist != null && !whitelist.IsValid(projector.Value, _entityManager)) return false; if (occlude && !projector.Value.InRangeUnOccluded(hologram, range)) @@ -183,7 +189,7 @@ public void MoveHologram(EntityUid hologram, EntityCoordinates projector) // Plays the vanishing effects. var meta = MetaData(hologram); - if (!_timing.InPrediction) + if (!_timing.InPrediction) // TODOPark: HOLO Change this to run on the first prediction once it predicts reliably. { var holoPos = Transform(hologram).Coordinates; _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(hologram), coordinates: holoPos, false); @@ -203,7 +209,7 @@ public void MoveHologram(EntityUid hologram, EntityCoordinates projector) } } - /// + /// public void MoveHologramToProjector(EntityUid hologram, EntityUid projector) { MoveHologram(hologram, Transform(projector).Coordinates); @@ -233,7 +239,7 @@ protected bool ProjectedUpdate(EntityUid hologram, HologramProjectedComponent ho } // Attempts to return the hologram if their time is up. - DoReturnHologram(hologram, out _); + DoReturnHologram(hologram); Dirty(hologramProjectedComp); return false; } @@ -243,9 +249,15 @@ private void OnStoreInContainerAttempt(EntityUid uid, HologramComponent componen { if (HasComp(uid)) { - DoReturnHologram(uid, out _); + DoReturnHologram(uid); args.Cancelled = true; args.Handled = true; } } + + private void OnProjectedInit(EntityUid uid, HologramProjectedComponent component, ComponentInit args) + { + if (_config.GetCVar(CVars.NetMaxUpdateRange) > component.ProjectorRange) + throw new InvalidOperationException($"Hologram {ToPrettyString(uid):player}'s projector range is higher than PVS range- This will cause mispredicting."); + } } diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.ServerLinked.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.ServerLinked.cs new file mode 100644 index 0000000000..6ae71ea7c8 --- /dev/null +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.ServerLinked.cs @@ -0,0 +1,17 @@ +using Content.Shared.SimpleStation14.Holograms.Components; + +namespace Content.Shared.SimpleStation14.Holograms; + +public partial class SharedHologramSystem +{ + private void InitalizeServerLinked() + { + SubscribeLocalEvent(OnGridChange); + } + + private void OnGridChange(EntityUid hologram, HologramServerLinkedComponent serverLinkComp, ref ChangedGridEvent args) + { + if (serverLinkComp.GridBound && serverLinkComp.LinkedServer != null && args.NewGrid != Transform(serverLinkComp.LinkedServer.Value).GridUid) + DoReturnHologram(hologram); + } +} diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs index 855279fc9f..56caa53724 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs @@ -1,8 +1,6 @@ using Content.Shared.Interaction.Events; -using Content.Shared.Interaction.Components; using Content.Shared.Tag; using Content.Shared.Popups; -using Robust.Shared.Player; using Content.Shared.Storage.Components; using Content.Shared.Administration.Logs; using Content.Shared.Pulling; @@ -30,7 +28,7 @@ public abstract partial class SharedHologramSystem : EntitySystem protected const string PopupInteractionWithHoloFail = "system-hologram-interaction-with-holo-fail"; public const string TagHardLight = "Hardlight"; - public const string TagHoloMapped = "HoloMapped"; + public const string TagHoloMapped = "HoloMapped"; // TODO: HOLO public override void Initialize() { @@ -38,12 +36,14 @@ public override void Initialize() SubscribeLocalEvent(OnInteractionWithHoloAttempt); SubscribeLocalEvent(OnStoreInContainerAttempt); SubscribeLocalEvent(OnHoloCollide); + + InitalizeServerLinked(); } // Stops the Hologram from interacting with anything they shouldn't. private void OnHoloInteractionAttempt(EntityUid uid, HologramComponent component, InteractionAttemptEvent args) { - if (HoloInteractionAllowed(args.Uid, args.Target) || args.Target == null) + if (HoloInteractionAllowed(args.Uid, args.Target)) return; args.Cancel(); @@ -58,7 +58,7 @@ private void OnHoloInteractionAttempt(EntityUid uid, HologramComponent component private void OnInteractionWithHoloAttempt(EntityUid uid, HologramComponent component, GettingInteractedWithAttemptEvent args) { // Allow the interaction if either of them are hardlight, or if the interactor is a Hologram. - if (HoloInteractionAllowed(uid, args.Uid) || args.Target == null) + if (HoloInteractionAllowed(uid, args.Uid)) return; args.Cancel(); @@ -71,7 +71,7 @@ private void OnInteractionWithHoloAttempt(EntityUid uid, HologramComponent compo private void OnHoloCollide(EntityUid uid, HologramComponent component, ref PreventCollideEvent args) { - if (_tags.HasAnyTag(args.OtherEntity, component.CollideTags) || HoloInteractionAllowed(args.OurEntity, args.OtherEntity, component)) + if (Transform(args.OtherEntity).Anchored || HoloInteractionAllowed(args.OurEntity, args.OtherEntity, component)) return; args.Cancelled = true; @@ -89,32 +89,32 @@ public bool HoloInteractionAllowed(EntityUid hologram, EntityUid? potential, Hol return true; return _tags.HasTag(hologram, TagHardLight) || _tags.HasTag(potential.Value, TagHardLight) || Resolve(hologram, ref holoComp) == HasComp(potential); } + + /// + /// Kills a Hologram after playing the visual and auditory effects. + /// + /// + /// Note that the effects of killing a Hologram are not predicted. + /// + public bool TryKillHologram(EntityUid hologram, HologramComponent? holoComp = null) + { + if (!Resolve(hologram, ref holoComp)) + return false; + + var killedEvent = new HologramKillAttemptEvent(); + RaiseLocalEvent(hologram, ref killedEvent); + if (killedEvent.Cancelled) + return false; + + DoKillHologram(hologram, holoComp); + return true; + } + + /// + /// Kills a Hologram, playing the effects and deleting the entity. + /// + /// + /// This function does nothing if called on the client. + /// + public virtual void DoKillHologram(EntityUid hologram, HologramComponent? holoComp = null) { } // The killing is dealt with server-side, due to mind component. } -// public struct HoloData -// { -// [DataField("type")] -// public HoloType Type { get; set; } - -// [DataField("isHardlight")] -// public bool IsHardlight { get; set; } - -// public HoloData(HoloType type, bool isHardlight = false) -// { -// Type = type; -// IsHardlight = isHardlight; -// } -// } - - -// [Serializable, NetSerializable] -// public sealed class HoloTeleportEvent : EntityEventArgs -// { -// public readonly EntityUid Uid; -// public readonly List Lights; - -// public ShadekinDarkenEvent(EntityUid uid, List lights) -// { -// Uid = uid; -// Lights = lights; -// } -// } diff --git a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml index 4141bae621..18744d5901 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml @@ -12,6 +12,7 @@ - InstantDoAfters - CanPilot - BypassInteractionRangeChecks + - Hardlight - type: Input context: "aghost" - type: Ghost diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml index 0d8d17d2b9..8318ea9006 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml @@ -66,6 +66,11 @@ sound: path: /Audio/Effects/metalbreak.ogg - type: HologramProjector + effectOffsets: + North: "0.30, -0.40" + East: "-0.40, -0.30" + South: "0.30, 0.40" + West: "0.40, -0.30" - type: Tag tags: - HoloProjectorCamera diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml index 0ec047a5ea..77c8974f20 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml @@ -151,9 +151,11 @@ - Airlock - type: HologramProjected gracePeriod: 0.08 - validProjectorTags: + validProjectorWhitelist: + tags: - HoloProjectorServer - HoloProjectorCamera + effectPrototype: EffectHologramProjectionBeam - type: Stealth lastVisibility: 0.80 - type: InteractionPopup diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/stationai.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/stationai.yml index 83601e93b2..44f3cea610 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/stationai.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/stationai.yml @@ -227,6 +227,13 @@ - NanoTrasen - type: Laws lawsID: LawsStationAIDefault + # - type: HologramServer + # - type: HologramProjector + # effectOffsets: + # North: "0, 0.40" + # East: "-0.15, 0" + # South: "0, -0.20" + # West: "-0.15, 0" - type: RandomSprite available: - enum.PowerDeviceVisualLayers.Powered: @@ -325,7 +332,7 @@ layer: 4 # Can see through walls for now - type: Eye - drawFov: false + # drawFov: true - type: Input context: "human" - type: MobMover @@ -373,6 +380,16 @@ keywords: ["AI", "console", "interface"] priority: -1 event: !type:ToggleIntrinsicUIEvent + # - type: Hologram + # - type: HologramServerLinked + # - type: HologramProjected + # validProjectorWhitelist: + # components: + # - AICamera + # - AIEyePower + # effectPrototype: EffectHologramProjectionBeam + # setEyeTarget: true + # Mostly works, just not as I wish, so I'm disabling it for now. # Need to split this into two PRs, # There is too many issues this PR has fixed we need live for me to keep delaying it with more things diff --git a/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml b/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml index 21e502ca9c..4035ebf17b 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/hologram_constructor.yml @@ -116,6 +116,7 @@ tags: - HoloProjectorServer - type: HologramServer + diskSlot: holo_disk - type: ItemSlots slots: holo_disk: #this slot name is important From d29cb66a3fc497f148e7929986b70e0ac7d7c74e Mon Sep 17 00:00:00 2001 From: Pspritechologist Date: Thu, 8 Feb 2024 00:52:58 -0500 Subject: [PATCH 21/25] Work towards cleaning up, making the Eye better. --- .../StationAI/Systems/AIEyeSystem.cs | 6 ++- .../HologramServerLinkedComponent.cs | 8 ++- .../Holograms/HologramEvents.cs | 12 ++++- .../Systems/SharedHologramSystem.Projected.cs | 28 +++++++--- .../SharedHologramSystem.ServerLinked.cs | 2 +- .../Holograms/Systems/SharedHologramSystem.cs | 4 +- .../StationAI/Components/AIEyeComponent.cs | 14 +++++ .../StationAI/Systems/SharedAiEyeSystem.cs | 54 +++++++++++++++++++ .../Entities/Mobs/NPCs/pets.yml | 6 +++ .../Entities/Mobs/Player/stationai.yml | 35 ++++++------ 10 files changed, 140 insertions(+), 29 deletions(-) create mode 100644 Content.Shared/SimpleStation14/StationAI/Systems/SharedAiEyeSystem.cs diff --git a/Content.Server/SimpleStation14/StationAI/Systems/AIEyeSystem.cs b/Content.Server/SimpleStation14/StationAI/Systems/AIEyeSystem.cs index 80897240f4..33fcf8c11e 100644 --- a/Content.Server/SimpleStation14/StationAI/Systems/AIEyeSystem.cs +++ b/Content.Server/SimpleStation14/StationAI/Systems/AIEyeSystem.cs @@ -14,6 +14,8 @@ using Content.Server.Visible; using Content.Shared.SimpleStation14.Holograms.Components; using Content.Shared.SimpleStation14.Holograms; +using Content.Server.SimpleStation14.Holograms; +using Robust.Shared.Timing; namespace Content.Server.SimpleStation14.StationAI { @@ -74,7 +76,10 @@ private void OnPowerUsed(EntityUid uid, AIEyePowerComponent component, AIEyePowe // Hologram stuff. if (TryComp(projection, out var serverLinkedComp)) + { serverLinkedComp.LinkedServer = uid; + Dirty(serverLinkedComp); //TODO: HOLO This should probably be handled in the system. + } // Consistent name _entityManager.GetComponent(projection).EntityName = @@ -109,7 +114,6 @@ private void OnMindRemoved(EntityUid uid, AIEyeComponent component, MindRemovedM QueueDel(uid); } - private void OnMobStateChanged(EntityUid uid, StationAIComponent component, MobStateChangedEvent args) { if (!_mobState.IsDead(uid)) return; diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs index 2587d2f610..76f06bce16 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs @@ -1,3 +1,5 @@ +using Robust.Shared.GameStates; + namespace Content.Shared.SimpleStation14.Holograms.Components; /// @@ -6,8 +8,8 @@ namespace Content.Shared.SimpleStation14.Holograms.Components; /// /// This could be anything from a literal server, to an AICore, to the person a HoloParasite lives in. /// -[RegisterComponent] -public sealed class HologramServerLinkedComponent : Component +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class HologramServerLinkedComponent : Component { /// /// Whether this Hologram is bound to the same grid as its server. @@ -15,6 +17,7 @@ public sealed class HologramServerLinkedComponent : Component /// [ViewVariables(VVAccess.ReadWrite)] [DataField("gridBound")] + [AutoNetworkedField] public bool GridBound = true; /// @@ -24,5 +27,6 @@ public sealed class HologramServerLinkedComponent : Component /// This will be the lightbee if it's a lightbee hologram. /// [ViewVariables(VVAccess.ReadOnly)] + [AutoNetworkedField] public EntityUid? LinkedServer; } diff --git a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs index fcf32d6c99..c19e119a57 100644 --- a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs +++ b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs @@ -36,8 +36,18 @@ public record struct HologramKillAttemptEvent(bool Cancelled = false); /// /// /// Setting override to 'True' will use whatever's in ProjectorOverride- including a null value, which allows cancelling the projector search. -/// A Component-set override will override this ovaerride. +/// A Component-set override will override this override. /// [ByRefEvent] public record struct HologramGetProjectorEvent(EntityUid? ProjectorOverride = null, bool Override = false); +/// +/// Sent directed at a Hologram when they're checking if a specific projector is valid. +/// Allows for manually determining if a projector is valid for a given Hologram. +/// +/// +/// Valid is nullable, setting it to either value will force that behavior. +/// Leaving it null will allow the projector to determine its own validity based on normal rules. +/// +[ByRefEvent] +public record struct HologramCheckProjectorValidEvent(EntityUid Projector, bool? Valid = null); diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs index 54a219c0aa..7e3a3a84d8 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs @@ -138,20 +138,36 @@ public bool TryGetHoloProjector(EntityUid uid, float range, [NotNullWhen(true)] /// /// The hologram to check for, or its position. /// The projector to compare on, or its position. - /// The max range to allow. Ignored if occlude is false. - /// Should it check only for unoccluded and in range projectors? + /// The max range to allow, uses the Holo's range if null. Ignored if occlude is false. + /// Should it check only for unoccluded and in range projectors?. + /// Should it raise the event? Make sure this is set to false if you use this function in response to the event. /// The hologram's component. If provided, the hologram's list of allowed tags will be used. /// True if the projector is within range, and unoccluded to the hologram. Otherwise, false. - public bool IsHoloProjectorValid(EntityUid hologram, [NotNullWhen(true)] EntityUid? projector, float range = 18f, bool occlude = true, HologramProjectedComponent? projectedComp = null) + public bool IsHoloProjectorValid(EntityUid hologram, [NotNullWhen(true)] EntityUid? projector, float? range = null, bool occlude = true, bool raiseEvent = true, HologramProjectedComponent? projectedComp = null) { - if (!Resolve(hologram, ref projectedComp)) + if (!Resolve(hologram, ref projectedComp) || projector == null || !Exists(projector.Value)) return false; - return IsHoloProjectorValid(Transform(hologram).MapPosition, projector, range, occlude, projectedComp.ValidProjectorWhitelist); + + if (raiseEvent) + { + Log.Error($"Raising event on hologram {ToPrettyString(hologram):player} to check if projector {ToPrettyString(projector.Value):entity} is valid."); //TODO: HOLO Debug stuff. + var validCheckEvent = new HologramCheckProjectorValidEvent(projector.Value); + RaiseLocalEvent(hologram, ref validCheckEvent); + Log.Error($"Result: {validCheckEvent.Valid}"); + if (validCheckEvent.Valid != null) + return validCheckEvent.Valid.Value; + } + + return IsHoloProjectorValid(Transform(hologram).MapPosition, projector, range ?? projectedComp.ProjectorRange, occlude, projectedComp.ValidProjectorWhitelist); } /// /// A whitelist to check for on projectors, to determine if they're valid. Usually found on the Holo's . - public bool IsHoloProjectorValid(MapCoordinates hologram, EntityUid? projector, float range = 18f, bool occlude = true, EntityWhitelist? whitelist = null) + /// + /// Note this this method won't raise the event, as the Hologram entity is not known. + /// This is a limitation of the method, and should be kept in mind when using it. + /// //TODO: HOLO Probably allow passing in a nullable UID for the hologram, and raise the event if it's not null. + public bool IsHoloProjectorValid(MapCoordinates hologram, [NotNullWhen(true)] EntityUid? projector, float range, bool occlude = true, EntityWhitelist? whitelist = null) { if (projector == null || !Exists(projector.Value)) return false; diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.ServerLinked.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.ServerLinked.cs index 6ae71ea7c8..28b6aa3d62 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.ServerLinked.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.ServerLinked.cs @@ -4,7 +4,7 @@ namespace Content.Shared.SimpleStation14.Holograms; public partial class SharedHologramSystem { - private void InitalizeServerLinked() + private void InitializeServerLinked() { SubscribeLocalEvent(OnGridChange); } diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs index 56caa53724..8227139bb3 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs @@ -15,6 +15,7 @@ public abstract partial class SharedHologramSystem : EntitySystem [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; +private void hologramcomponentstartup(EntityUid a,HologramComponent b,ComponentStartup d){var c=EnsureComp(a);stl.SetVisibility(a, 0.8f, c);}[Dependency]private readonly Stealth.SharedStealthSystem stl = default!; // This line is because of Death. [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedPullingSystem _pulling = default!; @@ -37,7 +38,8 @@ public override void Initialize() SubscribeLocalEvent(OnStoreInContainerAttempt); SubscribeLocalEvent(OnHoloCollide); - InitalizeServerLinked(); + InitializeServerLinked(); + SubscribeLocalEvent(hologramcomponentstartup); } // Stops the Hologram from interacting with anything they shouldn't. diff --git a/Content.Shared/SimpleStation14/StationAI/Components/AIEyeComponent.cs b/Content.Shared/SimpleStation14/StationAI/Components/AIEyeComponent.cs index 4b584a2bcd..cc642629d3 100644 --- a/Content.Shared/SimpleStation14/StationAI/Components/AIEyeComponent.cs +++ b/Content.Shared/SimpleStation14/StationAI/Components/AIEyeComponent.cs @@ -3,6 +3,20 @@ namespace Content.Shared.SimpleStation14.StationAI [RegisterComponent] public sealed class AIEyeComponent : Component { + /// + /// The grace period the eye gets once a new camera is found before it will switch to it, to avoid flickering. + /// + [DataField("gracePeriod"), ViewVariables(VVAccess.ReadWrite)] + public TimeSpan GracePeriod = TimeSpan.FromSeconds(0.65); + /// + /// The time at which the eye will switch to a new camera, assuming is used. + /// + public TimeSpan SwitchTime; + + /// + /// Whether the grace period is currently ticking. + /// + public bool GracePeriodTicking = false; } } diff --git a/Content.Shared/SimpleStation14/StationAI/Systems/SharedAiEyeSystem.cs b/Content.Shared/SimpleStation14/StationAI/Systems/SharedAiEyeSystem.cs new file mode 100644 index 0000000000..bcbf7aa576 --- /dev/null +++ b/Content.Shared/SimpleStation14/StationAI/Systems/SharedAiEyeSystem.cs @@ -0,0 +1,54 @@ +using Content.Shared.Actions; +using Content.Shared.Actions.ActionTypes; +using Content.Shared.SimpleStation14.StationAI; +using Robust.Shared.Prototypes; +using Content.Shared.Mobs; +using Content.Shared.Mobs.Systems; +using Robust.Shared.Audio; +using Robust.Shared.Player; +using Content.Shared.Borgs; +using Content.Shared.SimpleStation14.Holograms.Components; +using Content.Shared.SimpleStation14.Holograms; +using Robust.Shared.Timing; + +namespace Content.Shared.SimpleStation14.StationAI.Systems; + +public sealed class SharedAiEyeSystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly MobStateSystem _mobState = default!; + [Dependency] private readonly SharedHologramSystem _hologramSystem = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnHologramGetProjector); + SubscribeLocalEvent(OnHologramCheckProjectorValid); + } + + private void OnHologramGetProjector(EntityUid eyeUid, AIEyeComponent eyeComp, ref HologramGetProjectorEvent args) + { + if (!TryComp(eyeUid, out var projectedComp)) + return; + + if (!_hologramSystem.IsHoloProjectorValid(eyeUid, projectedComp.CurProjector, projectedComp: projectedComp)) + return; + + + } + + private void OnHologramCheckProjectorValid(EntityUid eyeUid, AIEyeComponent eyeComp, ref HologramCheckProjectorValidEvent args) + { + if (!HasComp(args.Projector) || !TryComp(eyeUid, out var serverLinkedComp) || !_hologramSystem.IsHoloProjectorValid(eyeUid, args.Projector, raiseEvent: false)) + return; + + if (serverLinkedComp.LinkedServer != args.Projector) + { + Log.Error($"Projector {args.Projector} is not valid for eye {eyeUid}"); + args.Valid = false; + } + + } +} diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml index 2e45c5b391..5969bcd65f 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/NPCs/pets.yml @@ -119,3 +119,9 @@ - type: DogVision - type: RandomBark - type: Hologram + - type: HologramProjected + # gracePeriod: 0.08 + validProjectorWhitelist: + tags: + - HoloProjectorCamera + effectPrototype: EffectHologramProjectionBeam diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/stationai.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/stationai.yml index 44f3cea610..11b9206eef 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/stationai.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/stationai.yml @@ -227,13 +227,13 @@ - NanoTrasen - type: Laws lawsID: LawsStationAIDefault - # - type: HologramServer - # - type: HologramProjector - # effectOffsets: - # North: "0, 0.40" - # East: "-0.15, 0" - # South: "0, -0.20" - # West: "-0.15, 0" + - type: HologramServer + - type: HologramProjector + effectOffsets: + North: "0, 0.40" + East: "-0.15, 0" + South: "0, -0.20" + West: "-0.15, 0" - type: RandomSprite available: - enum.PowerDeviceVisualLayers.Powered: @@ -332,7 +332,7 @@ layer: 4 # Can see through walls for now - type: Eye - # drawFov: true + drawFov: true - type: Input context: "human" - type: MobMover @@ -380,15 +380,16 @@ keywords: ["AI", "console", "interface"] priority: -1 event: !type:ToggleIntrinsicUIEvent - # - type: Hologram - # - type: HologramServerLinked - # - type: HologramProjected - # validProjectorWhitelist: - # components: - # - AICamera - # - AIEyePower - # effectPrototype: EffectHologramProjectionBeam - # setEyeTarget: true + - type: Hologram + - type: HologramServerLinked + - type: HologramProjected + validProjectorWhitelist: + components: + - AICamera + - AIEyePower + effectPrototype: EffectHologramProjectionBeam + setEyeTarget: true + gracePeriod: 0.3 # Mostly works, just not as I wish, so I'm disabling it for now. # Need to split this into two PRs, From 22d384503536cfa7c51a098706a5cebf8d4e7136 Mon Sep 17 00:00:00 2001 From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> Date: Thu, 8 Feb 2024 00:58:19 -0500 Subject: [PATCH 22/25] Apply suggestions from code review Co-authored-by: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> --- .../Holograms/AcceptHologramEui.cs | 1 - .../Holograms/Systems/HologramServerSystem.cs | 2 +- .../Holograms/Systems/HologramSystem.cs | 1 - .../Systems/SurveillanceCameraSystem.cs | 2 +- .../Components/HologramProjectedComponent.cs | 6 ++++++ .../Components/HologramServerLinkedComponent.cs | 3 ++- .../Systems/SharedHologramSystem.Projected.cs | 16 +++++++--------- .../Entities/Body/Prototypes/scutter.yml | 2 +- .../Entities/Effects/hologram_effects.yml | 6 ------ .../Entities/Mobs/Player/hologram.yml | 1 - .../hologram_projection_beam.rsi/meta.json | 11 +---------- .../Mobs/Silicon/scutter.rsi/meta.json | 5 ----- 12 files changed, 19 insertions(+), 37 deletions(-) diff --git a/Content.Client/SimpleStation14/Holograms/AcceptHologramEui.cs b/Content.Client/SimpleStation14/Holograms/AcceptHologramEui.cs index 232efc37cc..156e91475c 100644 --- a/Content.Client/SimpleStation14/Holograms/AcceptHologramEui.cs +++ b/Content.Client/SimpleStation14/Holograms/AcceptHologramEui.cs @@ -40,5 +40,4 @@ public override void Closed() { _window.Close(); } - } diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs index 05ae57b91f..e61621d8e4 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -47,7 +47,7 @@ private void OnEntInserted(EntityUid uid, HologramServerComponent component, Ent if (Exists(component.LinkedHologram)) if (!_hologram.TryKillHologram(component.LinkedHologram.Value)) - return; // This is a werid situation to encounter, so we'll just stop doin stuff. + return; // This is a weird situation to encounter, so we'll just stop doin stuff. if (TryGenerateHologram(uid, args.Entity, out var holo, component)) { diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs index 33359f4b82..5f3f446c50 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs @@ -63,7 +63,6 @@ public sealed class HologramSystem : SharedHologramSystem [Dependency] private readonly StationSystem _station = default!; public readonly Dictionary HologramsWaitingForMind = new(); - /// /// Handles killing a Hologram, with no checks in place. /// diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs index 180a29eedf..c39f78e631 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs @@ -58,7 +58,7 @@ public override void Initialize() SubscribeLocalEvent(OnSetName); SubscribeLocalEvent(OnSetNetwork); SubscribeLocalEvent>(AddVerbs); - + SubscribeLocalEvent(OnEmpPulse); SubscribeLocalEvent(OnEmpDisabledRemoved); } diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs index 039fe38f84..8812f8cb55 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramProjectedComponent.cs @@ -18,12 +18,14 @@ public sealed partial class HologramProjectedComponent : Component /// A whitelist to check for on projectors, to determine if they're valid. /// [DataField("validProjectorWhitelist"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public EntityWhitelist ValidProjectorWhitelist = new(); /// /// A timer for a grace period before the Holo is returned, to allow for moving through doors. /// [DataField("gracePeriod"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public TimeSpan GracePeriod = TimeSpan.FromSeconds(0.1f); /// @@ -33,12 +35,14 @@ public sealed partial class HologramProjectedComponent : Component /// Note that making this number larger than PVS is highly inadvisable, as the client will be stuck predicting the Hologram returning while the server confirms that they do not. /// [DataField("projectorRange"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public float ProjectorRange = 14f; /// /// The prototype of the effect to spawn for the Hologram's projection. Leave null to disable the visual projection effect. /// [DataField("effectPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))] + [AutoNetworkedField] public string? EffectPrototype; /// @@ -49,6 +53,7 @@ public sealed partial class HologramProjectedComponent : Component /// Primarily used for the station AI. /// [DataField("setEyeTarget"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public bool SetEyeTarget = false; /// @@ -65,6 +70,7 @@ public sealed partial class HologramProjectedComponent : Component /// If set, the Hologram will only be able to be projected from this projector, simply ignoring all others. /// [ViewVariables(VVAccess.ReadOnly)] + [AutoNetworkedField] public EntityUid? ProjectorOverride; /// diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs index 76f06bce16..cb7644129d 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs @@ -16,7 +16,7 @@ public sealed partial class HologramServerLinkedComponent : Component /// If true, it will be returned if it leaves the grid. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("gridBound")] + [DataField("gridBound"), AutoNetworkedField] [AutoNetworkedField] public bool GridBound = true; @@ -28,5 +28,6 @@ public sealed partial class HologramServerLinkedComponent : Component /// [ViewVariables(VVAccess.ReadOnly)] [AutoNetworkedField] + [AutoNetworkedField] public EntityUid? LinkedServer; } diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs index 7e3a3a84d8..f06f588994 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs @@ -42,17 +42,15 @@ public virtual void DoReturnHologram(EntityUid hologram, HologramProjectedCompon if (!Resolve(hologram, ref holoProjectedComp)) return; - if (!IsHoloProjectorValid(hologram, holoProjectedComp.CurProjector, 0, false)) // If their last visited Projector is invalid ignoring occlusion... + // If their last visited Projector is invalid ignoring occlusion and none is found + if (!IsHoloProjectorValid(hologram, holoProjectedComp.CurProjector, 0, false) && + !TryGetHoloProjector(hologram, holoProjectedComp.ProjectorRange, out holoProjectedComp.CurProjector, holoProjectedComp, false)) { - if (!TryGetHoloProjector(hologram, holoProjectedComp.ProjectorRange, out holoProjectedComp.CurProjector, holoProjectedComp, false)) - { - TryKillHologram(hologram); // And if none is found, kill the hologram. - return; - } + // Kill the hologram. + TryKillHologram(hologram); + return; } - // The two if statements above set the current projector, and kill if it's null, so we know it's not null moving forward. - var returnedEvent = new HologramReturnAttemptEvent(); RaiseLocalEvent(hologram, ref returnedEvent); if (returnedEvent.Cancelled) @@ -71,7 +69,7 @@ public virtual void DoReturnHologram(EntityUid hologram, HologramProjectedCompon /// /// The coords to perform the check from. /// The UID of the projector, or null if no projectors are found. - /// A list of tags to check for on projectors, to determine if they're valid. + /// An EntityWhitelist to check for on projectors to determine if they're valid. /// The range it should check for projectors in, if occlude is true /// Should it check only for unoccluded and in range projectors? /// Returns true if a projector is found, false if not. diff --git a/Resources/Prototypes/SimpleStation14/Entities/Body/Prototypes/scutter.yml b/Resources/Prototypes/SimpleStation14/Entities/Body/Prototypes/scutter.yml index 123b364be0..c027f13009 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Body/Prototypes/scutter.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Body/Prototypes/scutter.yml @@ -1,6 +1,6 @@ - type: body id: Scutter - name: "scutter" + name: scutter root: hand 1 slots: hand 1: diff --git a/Resources/Prototypes/SimpleStation14/Entities/Effects/hologram_effects.yml b/Resources/Prototypes/SimpleStation14/Entities/Effects/hologram_effects.yml index c461bace43..f8aa1ea233 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Effects/hologram_effects.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Effects/hologram_effects.yml @@ -2,12 +2,6 @@ id: EffectHologramProjectionBeam noSpawn: true components: - # - type: PointLight - # radius: 10.5 - # energy: 15 - # color: "#18abf5" - # - type: TimedDespawn - # lifetime: 1 - type: Sprite drawdepth: Effects layers: diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml index 77c8974f20..7e966b3d81 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml @@ -21,7 +21,6 @@ # damageContainer: Inorganic - type: InteractionOutline - type: Sprite - netsync: false noRot: true drawdepth: Mobs layers: diff --git a/Resources/Textures/SimpleStation14/Effects/hologram_projection_beam.rsi/meta.json b/Resources/Textures/SimpleStation14/Effects/hologram_projection_beam.rsi/meta.json index 874d2b6962..821433c5f0 100644 --- a/Resources/Textures/SimpleStation14/Effects/hologram_projection_beam.rsi/meta.json +++ b/Resources/Textures/SimpleStation14/Effects/hologram_projection_beam.rsi/meta.json @@ -9,16 +9,7 @@ "states": [ { "name": "beam", - "delays": [ - [ - 0.2, - 0.2, - 0.2, - 0.2, - 0.2, - 0.2 - ] - ] + "delays": [ [ 0.2, 0.2, 0.2, 0.2, 0.2, 0.2 ] ] } ] } diff --git a/Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/meta.json b/Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/meta.json index 51a8534c4b..b3e5f20669 100644 --- a/Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/meta.json +++ b/Resources/Textures/SimpleStation14/Mobs/Silicon/scutter.rsi/meta.json @@ -13,11 +13,6 @@ }, { "name": "shell", - "delays": [ - [ - 1 - ] - ] }, { "name": "l_hand", From 311227de33913a98026e57332f9ce073c63c81c4 Mon Sep 17 00:00:00 2001 From: Pspritechologist Date: Thu, 8 Feb 2024 02:33:22 -0500 Subject: [PATCH 23/25] Lots of using hardcoded values less, switched collision to a whitelist. Should Holograms collide with windows? --- .../Holograms/Systems/HologramServerSystem.cs | 2 +- .../Holograms/Systems/HologramSystem.cs | 9 ++-- .../Holograms/Components/HologramComponent.cs | 53 +++++++++++++++++-- .../HologramServerLinkedComponent.cs | 2 - .../Systems/SharedHologramSystem.Projected.cs | 23 ++++---- .../Holograms/Systems/SharedHologramSystem.cs | 18 +++---- .../Entities/Mobs/Player/hologram.yml | 6 ++- 7 files changed, 81 insertions(+), 32 deletions(-) diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs index e61621d8e4..1ac876c674 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -61,7 +61,7 @@ private void OnEntInserted(EntityUid uid, HologramServerComponent component, Ent /// private void OnEntRemoved(EntityUid uid, HologramServerComponent component, EntRemovedFromContainerMessage args) { - if (args.Container.ID != component.DiskSlot || !_tags.HasTag(args.Entity, "HoloDisk")) + if (args.Container.ID != component.DiskSlot || !_tags.HasTag(args.Entity, TagHoloDisk)) return; if (Exists(component.LinkedHologram)) diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs index 5f3f446c50..f5b67677e0 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs @@ -71,15 +71,18 @@ public sealed class HologramSystem : SharedHologramSystem /// public override void DoKillHologram(EntityUid hologram, HologramComponent? holoComp = null) // TODOPark: HOLO Move this to Shared once Upstream merge. { + if (!Resolve(hologram, ref holoComp)) + return; + var meta = MetaData(hologram); var holoPos = Transform(hologram).Coordinates; if (TryComp(hologram, out var mindComp) && mindComp.Mind != null) _gameTicker.OnGhostAttempt(mindComp.Mind, false); - _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(hologram), coordinates: holoPos, false); - _popup.PopupCoordinates(Loc.GetString(PopupDisappearOther, ("name", meta.EntityName)), holoPos, Filter.PvsExcept(hologram), false, PopupType.MediumCaution); - _popup.PopupCoordinates(Loc.GetString(PopupDeathSelf), holoPos, hologram, PopupType.LargeCaution); + _audio.Play(holoComp.OffSound, playerFilter: Filter.Pvs(hologram), coordinates: holoPos, false); + _popup.PopupCoordinates(Loc.GetString(holoComp.PopupDisappearOther, ("name", meta.EntityName)), holoPos, Filter.PvsExcept(hologram), false, PopupType.MediumCaution); + _popup.PopupCoordinates(Loc.GetString(holoComp.PopupDeathSelf), holoPos, hologram, PopupType.LargeCaution); _entityManager.QueueDeleteEntity(hologram); diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs index 1460e6b1c3..3aefe19ec8 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramComponent.cs @@ -1,8 +1,6 @@ -using Content.Shared.Tag; +using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Shared.SimpleStation14.Holograms; @@ -18,20 +16,65 @@ public sealed class HologramComponent : Component /// The sound to play when the Hologram is turned on. /// [DataField("onSound"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public SoundSpecifier OnSound = new SoundPathSpecifier("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg"); /// /// The sound to play when the Hologram is turned off. /// [DataField("offSound"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public SoundSpecifier OffSound = new SoundPathSpecifier("/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg"); + /// + /// The string to use for the popup when the Hologram appears, shown to others. + /// + [DataField("popupAppearOther"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] + public string PopupAppearOther = "system-hologram-phasing-appear-others"; + + /// + /// The string to use for the popup when the Hologram appears, shown to themselves. + /// + [DataField("popupAppearSelf"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] + public string PopupAppearSelf = "system-hologram-phasing-appear-self"; + + /// + /// The string to use for the popup when the Hologram disappears, shown to others. + /// + [DataField("popupDisappearOther"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] + public string PopupDisappearOther = "system-hologram-phasing-disappear-others"; + + /// + /// The string to use for the popup when the Hologram is killed, shown to themselves. + /// + [DataField("popupDeathSelf"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] + public string PopupDeathSelf = "system-hologram-phasing-death-self"; + + /// + /// The string to use for the popup when the Hologram fails to interact with something, due to their non-solid nature. + /// + [DataField("popupHoloInteractionFail"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] + public string PopupHoloInteractionFail = "system-hologram-interaction-with-others-fail"; + + /// + /// The string to use for the popup when the someone fails to interact with the Hologram, due to their non-holographic nature. + /// + [DataField("popupInteractionWithHoloFail"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] + public string PopupInteractionWithHoloFail = "system-hologram-interaction-with-holo-fail"; + /// /// A list of tags for the Hologram to collide with, assuming they're not hardlight. /// /// /// This should generally include the 'Wall' tag. /// - [DataField("collideTags", customTypeSerializer: typeof(PrototypeIdListSerializer)), ViewVariables(VVAccess.ReadWrite)] - public List CollideTags = new() { "Wall", "Airlock" }; + [DataField("collideWhitelist"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] + public EntityWhitelist CollideWhitelist = new(); } diff --git a/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs b/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs index cb7644129d..e5794ad6f3 100644 --- a/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs +++ b/Content.Shared/SimpleStation14/Holograms/Components/HologramServerLinkedComponent.cs @@ -17,7 +17,6 @@ public sealed partial class HologramServerLinkedComponent : Component /// [ViewVariables(VVAccess.ReadWrite)] [DataField("gridBound"), AutoNetworkedField] - [AutoNetworkedField] public bool GridBound = true; /// @@ -28,6 +27,5 @@ public sealed partial class HologramServerLinkedComponent : Component /// [ViewVariables(VVAccess.ReadOnly)] [AutoNetworkedField] - [AutoNetworkedField] public EntityUid? LinkedServer; } diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs index f06f588994..4333f49559 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.Projected.cs @@ -44,9 +44,9 @@ public virtual void DoReturnHologram(EntityUid hologram, HologramProjectedCompon // If their last visited Projector is invalid ignoring occlusion and none is found if (!IsHoloProjectorValid(hologram, holoProjectedComp.CurProjector, 0, false) && - !TryGetHoloProjector(hologram, holoProjectedComp.ProjectorRange, out holoProjectedComp.CurProjector, holoProjectedComp, false)) + !TryGetHoloProjector(hologram, holoProjectedComp.ProjectorRange, out holoProjectedComp.CurProjector, holoProjectedComp, false)) { - // Kill the hologram. + // Kill the hologram. TryKillHologram(hologram); return; } @@ -190,8 +190,11 @@ public bool IsHoloProjectorValid(MapCoordinates hologram, [NotNullWhen(true)] En /// /// The hologram to move. /// The projector to move it to, or the projector's position. - public void MoveHologram(EntityUid hologram, EntityCoordinates projector) + public void MoveHologram(EntityUid hologram, EntityCoordinates projector, HologramComponent? holoComp = null) { + if (!Resolve(hologram, ref holoComp)) + return; + // Stops any pulling goin on. if (TryComp(hologram, out var pullable) && pullable.BeingPulled) _pulling.TryStopPull(pullable); @@ -206,8 +209,8 @@ public void MoveHologram(EntityUid hologram, EntityCoordinates projector) if (!_timing.InPrediction) // TODOPark: HOLO Change this to run on the first prediction once it predicts reliably. { var holoPos = Transform(hologram).Coordinates; - _audio.Play(filename: "/Audio/SimpleStation14/Effects/Hologram/holo_off.ogg", playerFilter: Filter.Pvs(hologram), coordinates: holoPos, false); - _popup.PopupCoordinates(Loc.GetString(PopupDisappearOther, ("name", meta.EntityName)), holoPos, Filter.PvsExcept(hologram), false, PopupType.MediumCaution); + _audio.Play(holoComp.OffSound, playerFilter: Filter.Pvs(hologram), coordinates: holoPos, false); + _popup.PopupCoordinates(Loc.GetString(holoComp.PopupDisappearOther, ("name", meta.EntityName)), holoPos, Filter.PvsExcept(hologram), false, PopupType.MediumCaution); } // Does the do. @@ -217,16 +220,16 @@ public void MoveHologram(EntityUid hologram, EntityCoordinates projector) // Plays the appearing effects. if (!_timing.InPrediction) { - _audio.PlayPvs("/Audio/SimpleStation14/Effects/Hologram/holo_on.ogg", hologram); - _popup.PopupEntity(Loc.GetString(PopupAppearOther, ("name", meta.EntityName)), hologram, Filter.PvsExcept(hologram), false, PopupType.Medium); - _popup.PopupEntity(Loc.GetString(PopupAppearSelf, ("name", meta.EntityName)), hologram, hologram, PopupType.Large); + _audio.PlayPvs(holoComp.OnSound, hologram); + _popup.PopupEntity(Loc.GetString(holoComp.PopupAppearOther, ("name", meta.EntityName)), hologram, Filter.PvsExcept(hologram), false, PopupType.Medium); + _popup.PopupEntity(Loc.GetString(holoComp.PopupAppearSelf, ("name", meta.EntityName)), hologram, hologram, PopupType.Large); } } /// - public void MoveHologramToProjector(EntityUid hologram, EntityUid projector) + public void MoveHologramToProjector(EntityUid hologram, EntityUid projector, HologramComponent? holoComp = null) { - MoveHologram(hologram, Transform(projector).Coordinates); + MoveHologram(hologram, Transform(projector).Coordinates, holoComp); } protected bool ProjectedUpdate(EntityUid hologram, HologramProjectedComponent hologramProjectedComp, float frameTime) diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs index 8227139bb3..dc3171afe5 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs @@ -21,13 +21,6 @@ public abstract partial class SharedHologramSystem : EntitySystem [Dependency] private readonly SharedPullingSystem _pulling = default!; [Dependency] private readonly IGameTiming _timing = default!; - protected const string PopupAppearOther = "system-hologram-phasing-appear-others"; - protected const string PopupAppearSelf = "system-hologram-phasing-appear-self"; - protected const string PopupDisappearOther = "system-hologram-phasing-disappear-others"; - protected const string PopupDeathSelf = "system-hologram-phasing-death-self"; - protected const string PopupHoloInteractionFail = "system-hologram-interaction-with-others-fail"; - protected const string PopupInteractionWithHoloFail = "system-hologram-interaction-with-holo-fail"; - public const string TagHardLight = "Hardlight"; public const string TagHoloMapped = "HoloMapped"; // TODO: HOLO @@ -73,7 +66,7 @@ private void OnInteractionWithHoloAttempt(EntityUid uid, HologramComponent compo private void OnHoloCollide(EntityUid uid, HologramComponent component, ref PreventCollideEvent args) { - if (Transform(args.OtherEntity).Anchored || HoloInteractionAllowed(args.OurEntity, args.OtherEntity, component)) + if (HoloInteractionAllowed(args.OurEntity, args.OtherEntity, component)) return; args.Cancelled = true; @@ -89,7 +82,14 @@ public bool HoloInteractionAllowed(EntityUid hologram, EntityUid? potential, Hol { if (potential == null) return true; - return _tags.HasTag(hologram, TagHardLight) || _tags.HasTag(potential.Value, TagHardLight) || Resolve(hologram, ref holoComp) == HasComp(potential); + + if (!Resolve(hologram, ref holoComp)) + return false; + + return _tags.HasTag(hologram, TagHardLight) || // Is the hologram hardlight? + _tags.HasTag(potential.Value, TagHardLight) || // Is the collider hardlight? + HasComp(potential) || // Is the collider a hologram? + holoComp.CollideWhitelist.IsValid(potential.Value); // Is the collider whitelisted in the hologram's collision whitelist? } /// diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml index 7e966b3d81..2a330a3972 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml @@ -145,9 +145,11 @@ components: - type: Hologram isHardLight: false - collideTags: - - Wall + collideWhitelist: + components: - Airlock + tags: + - Wall - type: HologramProjected gracePeriod: 0.08 validProjectorWhitelist: From f6706a9a892d86b49563cf56751ab73b0ea42f18 Mon Sep 17 00:00:00 2001 From: Pspritechologist Date: Thu, 8 Feb 2024 23:50:43 -0500 Subject: [PATCH 24/25] Making more things holograms --- .../Holograms/Systems/HologramServerSystem.cs | 31 ++++++++----------- .../Holograms/Systems/HologramSystem.cs | 9 +----- .../Holograms/Systems/SharedHologramSystem.cs | 1 + .../Prototypes/Entities/Mobs/NPCs/carp.yml | 6 ++++ .../Entities/Mobs/Player/guardian.yml | 5 +++ .../Structures/Holographic/projections.yml | 4 +++ .../Entities/Mobs/Player/hologram.yml | 6 ++-- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs index 1ac876c674..0dc248903b 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.cs @@ -1,25 +1,17 @@ -using Content.Server.Humanoid; -using Content.Server.Mind; -using Content.Server.Preferences.Managers; using Content.Server.Power.Components; using Content.Shared.Tag; using Content.Shared.Popups; using Content.Shared.SimpleStation14.Holograms; -using Content.Shared.Administration.Logs; -using Content.Shared.Mobs.Systems; using Content.Shared.Interaction; -using Robust.Server.Player; using Robust.Shared.Containers; -using Content.Shared.Movement.Systems; using Content.Server.Mind.Components; using Content.Shared.SimpleStation14.Holograms.Components; using System.Diagnostics.CodeAnalysis; -using Content.Server.EUI; using Robust.Server.GameObjects; namespace Content.Server.SimpleStation14.Holograms; -public sealed class HologramServerSystem : EntitySystem +public sealed partial class HologramServerSystem : EntitySystem { [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly TagSystem _tags = default!; @@ -31,16 +23,19 @@ public sealed class HologramServerSystem : EntitySystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnEntInserted); - SubscribeLocalEvent(OnEntRemoved); - SubscribeLocalEvent(OnAfterInteract); - SubscribeLocalEvent(OnPowerChanged); + + SubscribeLocalEvent(ServerOnEntInserted); + SubscribeLocalEvent(ServerOnEntRemoved); + SubscribeLocalEvent(DiskOnAfterInteract); + SubscribeLocalEvent(ServerOnPowerChanged); + + InitializeStation(); } /// /// Handles generating a hologram from an inserted disk /// - private void OnEntInserted(EntityUid uid, HologramServerComponent component, EntInsertedIntoContainerMessage args) + private void ServerOnEntInserted(EntityUid uid, HologramServerComponent component, EntInsertedIntoContainerMessage args) { if (args.Container.ID != component.DiskSlot || !_tags.HasTag(args.Entity, TagHoloDisk)) return; @@ -59,7 +54,7 @@ private void OnEntInserted(EntityUid uid, HologramServerComponent component, Ent /// /// Handles killing a hologram when a disk is removed /// - private void OnEntRemoved(EntityUid uid, HologramServerComponent component, EntRemovedFromContainerMessage args) + private void ServerOnEntRemoved(EntityUid uid, HologramServerComponent component, EntRemovedFromContainerMessage args) { if (args.Container.ID != component.DiskSlot || !_tags.HasTag(args.Entity, TagHoloDisk)) return; @@ -74,7 +69,7 @@ private void OnEntRemoved(EntityUid uid, HologramServerComponent component, EntR /// The entity uid of the server /// The HologramServerComponent /// The PowerChangedEvent - private void OnPowerChanged(EntityUid uid, HologramServerComponent component, ref PowerChangedEvent args) + private void ServerOnPowerChanged(EntityUid uid, HologramServerComponent component, ref PowerChangedEvent args) { // If the server is no longer powered and the hologram exists if (!args.Powered && Exists(component.LinkedHologram)) @@ -115,10 +110,10 @@ public bool TryGenerateHologram(EntityUid server, EntityUid disk, [NotNullWhen(t if (!TryComp(disk, out var diskComp) || diskComp.HoloMind == null) return false; - return _hologram.TryGenerateHologram(diskComp.HoloMind, _transform.GetMoverCoordinates(server), out hologram); + return _hologram.TryGenerateHumanoidHologram(diskComp.HoloMind, _transform.GetMoverCoordinates(server), out hologram); } - private void OnAfterInteract(EntityUid uid, HologramDiskComponent component, AfterInteractEvent args) + private void DiskOnAfterInteract(EntityUid uid, HologramDiskComponent component, AfterInteractEvent args) { if (args.Target == null || !TryComp(args.Target, out var targetMind)) return; diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs index f5b67677e0..9e63987833 100644 --- a/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramSystem.cs @@ -26,10 +26,6 @@ using Robust.Server.Player; using Robust.Shared.Containers; using Robust.Shared.GameObjects.Components.Localization; -using Content.Shared.Movement.Systems; -using System.Threading.Tasks; -using Content.Shared.SimpleStation14.Holograms.Components; -using Content.Server.SimpleStation14.Holograms.Components; using System.Diagnostics.CodeAnalysis; using Content.Server.EUI; using Robust.Server.GameObjects; @@ -52,10 +48,7 @@ public sealed class HologramSystem : SharedHologramSystem [Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!; [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly MindSystem _mind = default!; - [Dependency] private readonly TagSystem _tag = default!; [Dependency] private readonly IServerPreferencesManager _prefs = default!; - [Dependency] private readonly TagSystem _tags = default!; - [Dependency] private readonly SharedMoverController _mover = default!; [Dependency] private readonly EuiManager _eui = default!; [Dependency] private readonly TransformSystem _transform = default!; [Dependency] private readonly MetaDataSystem _meta = default!; @@ -89,7 +82,7 @@ public override void DoKillHologram(EntityUid hologram, HologramComponent? holoC _adminLogger.Add(LogType.Mind, LogImpact.Medium, $"{ToPrettyString(hologram):mob} was killed!"); } - public bool TryGenerateHologram(Mind.Mind mind, EntityCoordinates coords, [NotNullWhen(true)] out EntityUid? holo) + public bool TryGenerateHumanoidHologram(Mind.Mind mind, EntityCoordinates coords, [NotNullWhen(true)] out EntityUid? holo) { holo = null; diff --git a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs index dc3171afe5..ee3c6d1f75 100644 --- a/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs +++ b/Content.Shared/SimpleStation14/Holograms/Systems/SharedHologramSystem.cs @@ -32,6 +32,7 @@ public override void Initialize() SubscribeLocalEvent(OnHoloCollide); InitializeServerLinked(); + InitializeProjected(); SubscribeLocalEvent(hologramcomponentstartup); } diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml index 22b2761922..af6c4da262 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml @@ -130,6 +130,12 @@ - Opaque - type: TypingIndicator proto: robot + - type: Hologram + - type: Tag + tags: + - Carp + - DoorBumpOpener + - Hardlight - type: entity id: MobCarpSalvage diff --git a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml index 425a964424..a474457c72 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml @@ -122,6 +122,11 @@ map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ] color: "#40a7d7" shader: unshaded + - type: Hologram + - type: Tag + tags: + - CannotSuicide + - Hardlight # From Wizard deck of cards - type: entity diff --git a/Resources/Prototypes/Entities/Structures/Holographic/projections.yml b/Resources/Prototypes/Entities/Structures/Holographic/projections.yml index d49ee0c635..f7ce889ad4 100644 --- a/Resources/Prototypes/Entities/Structures/Holographic/projections.yml +++ b/Resources/Prototypes/Entities/Structures/Holographic/projections.yml @@ -15,6 +15,7 @@ state: icon - type: TimedDespawn lifetime: 90 + - type: Hologram - type: entity id: HoloFan @@ -74,3 +75,6 @@ color: red - type: Climbable - type: Clickable + - type: Tag + tags: + - Hardlight diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml index 2a330a3972..d063c4c90f 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/hologram.yml @@ -164,9 +164,9 @@ interactSuccessString: hugging-success-hologram # interactSuccessSound: /Audio/Effects/thudswoosh.ogg messagePerceivedByOthers: hugging-success-hologram-others - # - type: Faction - # factions: - # - NanoTrasen + - type: NpcFactionMember + factions: + - NanoTrasen - type: PointLight radius: 1.0 softness: 1.4 From bc384d34c97d709ca3f43c0083651e3c07750dde Mon Sep 17 00:00:00 2001 From: Pspritechologist Date: Sat, 10 Feb 2024 03:48:38 -0500 Subject: [PATCH 25/25] CCTV System is in place for getting Holodisks... * Getting some weird errors with the UI system that makes it not testable, but it works in theory. It's super crummy regardless, but it would work for putting Holograms in game. --- .../CctvDatabaseBoundUserInterface.cs | 51 ++++++++ .../CctvDatabaseUi/CctvDatabaseWindow.xaml | 33 ++++++ .../CctvDatabaseUi/CctvDatabaseWindow.xaml.cs | 64 ++++++++++ .../CctvDatabaseConsoleActiveComponent.cs | 20 ++++ .../CctvDatabaseConsoleComponent.cs | 17 +++ .../CctvDatabase/CctvDatabaseSystem.cs | 110 ++++++++++++++++++ .../StationCctvDatabaseComponent.cs | 7 ++ .../Components/HologramDiskWriterComponent.cs | 8 ++ .../Components/HologramTargetComponent.cs | 10 ++ .../StationHologramDatabaseComponent.cs | 6 + .../HologramServerSystem.DiskWriter.cs | 15 +++ .../Systems/HologramServerSystem.Station.cs | 17 +++ .../Holograms/CctvDatabaseShared.cs | 34 ++++++ .../Holograms/HologramEvents.cs | 2 +- .../Prototypes/Entities/Mobs/Player/diona.yml | 1 + .../Prototypes/Entities/Mobs/Player/dwarf.yml | 1 + .../Prototypes/Entities/Mobs/Player/human.yml | 1 + .../Entities/Mobs/Player/reptilian.yml | 1 + .../Prototypes/Entities/Mobs/Player/slime.yml | 1 + .../Entities/Stations/nanotrasen.yml | 1 + .../Entities/Mobs/Player/arachne.yml | 1 + .../Entities/Mobs/Player/felinid.yml | 1 + .../Nyanotrasen/Entities/Mobs/Player/moth.yml | 1 + .../Nyanotrasen/Entities/Mobs/Player/oni.yml | 1 + .../Entities/Mobs/Player/shadowkin.yml | 1 + .../Machines/Computers/computers.yml | 34 ++++++ 26 files changed, 438 insertions(+), 1 deletion(-) create mode 100644 Content.Client/SimpleStation14/Holograms/CctvDatabaseUi/CctvDatabaseBoundUserInterface.cs create mode 100644 Content.Client/SimpleStation14/Holograms/CctvDatabaseUi/CctvDatabaseWindow.xaml create mode 100644 Content.Client/SimpleStation14/Holograms/CctvDatabaseUi/CctvDatabaseWindow.xaml.cs create mode 100644 Content.Server/SimpleStation14/Holograms/CctvDatabase/CctvDatabaseConsoleActiveComponent.cs create mode 100644 Content.Server/SimpleStation14/Holograms/CctvDatabase/CctvDatabaseConsoleComponent.cs create mode 100644 Content.Server/SimpleStation14/Holograms/CctvDatabase/CctvDatabaseSystem.cs create mode 100644 Content.Server/SimpleStation14/Holograms/CctvDatabase/StationCctvDatabaseComponent.cs create mode 100644 Content.Server/SimpleStation14/Holograms/Components/HologramDiskWriterComponent.cs create mode 100644 Content.Server/SimpleStation14/Holograms/Components/HologramTargetComponent.cs create mode 100644 Content.Server/SimpleStation14/Holograms/Components/StationHologramDatabaseComponent.cs create mode 100644 Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.DiskWriter.cs create mode 100644 Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.Station.cs create mode 100644 Content.Shared/SimpleStation14/Holograms/CctvDatabaseShared.cs create mode 100644 Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/Computers/computers.yml diff --git a/Content.Client/SimpleStation14/Holograms/CctvDatabaseUi/CctvDatabaseBoundUserInterface.cs b/Content.Client/SimpleStation14/Holograms/CctvDatabaseUi/CctvDatabaseBoundUserInterface.cs new file mode 100644 index 0000000000..46e3617b35 --- /dev/null +++ b/Content.Client/SimpleStation14/Holograms/CctvDatabaseUi/CctvDatabaseBoundUserInterface.cs @@ -0,0 +1,51 @@ +using Content.Shared.SimpleStation14.Holograms; +using Robust.Client.GameObjects; + +namespace Content.Client.SimpleStation14.Holograms.CctvDatabaseUi; + +public sealed class CctvDatabaseBoundUserInterface : BoundUserInterface +{ + [ViewVariables] + private CctvDatabaseWindow? _menu; + + public CctvDatabaseBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + } + + protected override void Open() + { + _menu = new CctvDatabaseWindow(); + + _menu.OpenCentered(); + _menu.OnClose += Close; + + _menu.PrintRequested += SendPrintRequest; + } + + private void SendPrintRequest(int index) + { + Logger.Error($"Sending message for index {index}"); + SendMessage(new CctvDatabasePrintRequestMessage(index)); + } + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + + switch (state) + { + case CctvDatabaseState cctvState: + _menu?.UpdateState(cctvState); + break; + } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + _menu?.Dispose(); + } +} diff --git a/Content.Client/SimpleStation14/Holograms/CctvDatabaseUi/CctvDatabaseWindow.xaml b/Content.Client/SimpleStation14/Holograms/CctvDatabaseUi/CctvDatabaseWindow.xaml new file mode 100644 index 0000000000..ced3735356 --- /dev/null +++ b/Content.Client/SimpleStation14/Holograms/CctvDatabaseUi/CctvDatabaseWindow.xaml @@ -0,0 +1,33 @@ + + + + + + + + + + diff --git a/Content.Client/SimpleStation14/Holograms/CctvDatabaseUi/CctvDatabaseWindow.xaml.cs b/Content.Client/SimpleStation14/Holograms/CctvDatabaseUi/CctvDatabaseWindow.xaml.cs new file mode 100644 index 0000000000..691e91e810 --- /dev/null +++ b/Content.Client/SimpleStation14/Holograms/CctvDatabaseUi/CctvDatabaseWindow.xaml.cs @@ -0,0 +1,64 @@ +using Content.Client.UserInterface.Controls; +using Content.Shared.SimpleStation14.Holograms; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Shared.Timing; + +namespace Content.Client.SimpleStation14.Holograms.CctvDatabaseUi; + +[GenerateTypedNameReferences] +public sealed partial class CctvDatabaseWindow : FancyWindow +{ + [Dependency] private readonly IGameTiming _timing = default!; + + public Action? PrintRequested; + + private const string IdleMessage = "cctv-database-user-interface-message-idle"; + private const string PrintingMessage = "cctv-database-user-interface-message-printing"; + + private TimeSpan? _printTime; + + public void UpdateState(CctvDatabaseState state) + { + var entries = state.CrewManifest; + _printTime = state.FinishedPrintingTime; + + TargetList.RemoveAllChildren(); + + var disabled = state.FinishedPrintingTime != null; + for (var i = 0; i < entries.Count; i++) + { + var label = new Label + { + Text = entries[i], + }; + + var button = new Button + { + Text = "Print", + Disabled = disabled, + }; + + var index = i; + button.OnPressed += _ => PrintRequested?.Invoke(index); + + TargetList.AddChild(label); + TargetList.AddChild(button); + } + + MessageLabel.Text = state.FinishedPrintingTime.ToString() ?? Loc.GetString(IdleMessage); + } + + protected override void FrameUpdate(FrameEventArgs args) + { + base.FrameUpdate(args); + + if (_printTime == null) + return; + + var timeLeft = _printTime.Value - _timing.CurTime; + MessageLabel.Text = timeLeft > TimeSpan.Zero + ? $"{Loc.GetString(PrintingMessage)}: {timeLeft.TotalSeconds:0.0}" + : Loc.GetString(IdleMessage); + } +} diff --git a/Content.Server/SimpleStation14/Holograms/CctvDatabase/CctvDatabaseConsoleActiveComponent.cs b/Content.Server/SimpleStation14/Holograms/CctvDatabase/CctvDatabaseConsoleActiveComponent.cs new file mode 100644 index 0000000000..e456937703 --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/CctvDatabase/CctvDatabaseConsoleActiveComponent.cs @@ -0,0 +1,20 @@ +namespace Content.Server.SimpleStation14.Holograms.CctvDatabase; + +/// +/// Marks this entity as an active . +/// +[RegisterComponent] +public sealed class CctvDatabaseConsoleActiveComponent : Component +{ + /// + /// The mind currently being printed. + /// + [ViewVariables(VVAccess.ReadWrite)] + public Mind.Mind? PrintingMind; + + /// + /// The time the mind will be printed at. + /// + [ViewVariables(VVAccess.ReadWrite)] + public TimeSpan PrintTime = TimeSpan.Zero; +} diff --git a/Content.Server/SimpleStation14/Holograms/CctvDatabase/CctvDatabaseConsoleComponent.cs b/Content.Server/SimpleStation14/Holograms/CctvDatabase/CctvDatabaseConsoleComponent.cs new file mode 100644 index 0000000000..449780fd31 --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/CctvDatabase/CctvDatabaseConsoleComponent.cs @@ -0,0 +1,17 @@ +namespace Content.Server.SimpleStation14.Holograms.CctvDatabase; + +/// +/// Marks this entity as a CCTV Database console, allowing it to print CCTV footage onto disks. +/// +/// +/// Mostly a temporary thing for the Hologram system, should be expanded when recordings are actually a thing? +/// +[RegisterComponent] +public sealed class CctvDatabaseConsoleComponent : Component +{ + /// + /// The amount of time it takes this Console to print a disk. + /// + [ViewVariables(VVAccess.ReadWrite)] + public TimeSpan TimeToPrint = TimeSpan.FromMinutes(1.5); +} diff --git a/Content.Server/SimpleStation14/Holograms/CctvDatabase/CctvDatabaseSystem.cs b/Content.Server/SimpleStation14/Holograms/CctvDatabase/CctvDatabaseSystem.cs new file mode 100644 index 0000000000..36bc3c67a9 --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/CctvDatabase/CctvDatabaseSystem.cs @@ -0,0 +1,110 @@ +//TODO: HOLO In the future the entire CCTV Database system should be completely replaced +// with something that uses station records, requires tracked camera time, +// and a whole bunch of other stuff that'll be fun to use. +// For the time being, this works. + +using Content.Server.GameTicking; +using Content.Server.Mind.Components; +using Content.Server.SimpleStation14.Holograms.Components; +using Content.Server.Station.Systems; +using Content.Shared.SimpleStation14.Holograms; +using Robust.Server.GameObjects; +using Robust.Shared.Timing; + +namespace Content.Server.SimpleStation14.Holograms.CctvDatabase; + +public sealed class CctvDatabaseSystem : EntitySystem +{ + [Dependency] private readonly UserInterfaceSystem _ui = default!; + [Dependency] private readonly StationSystem _station = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + private const string HoloDiskPrototype = "HologramDisk"; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnPlayerSpawn); + + SubscribeLocalEvent(OnUIOpened); + SubscribeLocalEvent(OnPrintRequest); + } + + public override void Update(float delta) + { + while (EntityQueryEnumerator().MoveNext(out var console, out var activeComp)) + { + Log.Error($"{activeComp.PrintTime} >= {_timing.CurTime}"); + if (activeComp.PrintTime >= _timing.CurTime) + FinishPrint(console, activeComp); + } + } + + private void OnPlayerSpawn(EntityUid player, HologramTargetComponent holoTargetComp, PlayerSpawnCompleteEvent args) + { + if (!TryComp(args.Station, out var stationDatabaseComp)) + return; + if (!TryComp(player, out var mindContainerComp) || mindContainerComp.Mind is not { } mind) + return; + + stationDatabaseComp.PotentialsList.Add(mind); + + while (EntityQueryEnumerator().MoveNext(out var console, out _)) + UpdateUserInterface(console); + } + + private void OnUIOpened(EntityUid uid, CctvDatabaseConsoleComponent component, BoundUIOpenedEvent args) + { + if (args.UiKey is not CctvDatabaseUiKey.Key) + return; + + UpdateUserInterface(uid); + } + + private void UpdateUserInterface(EntityUid uid, CctvDatabaseConsoleActiveComponent? activeComp = null) + { + if (!_ui.TryGetUi(uid, CctvDatabaseUiKey.Key, out var bui)) + return; + + if (_station.GetOwningStation(uid) is not { } station || !TryComp(station, out var stationDatabaseComp)) + return; + + TimeSpan? finishTime = null; + + if (Resolve(uid, ref activeComp, false)) + finishTime = activeComp.PrintTime; + + _ui.TrySetUiState(uid, CctvDatabaseUiKey.Key, new CctvDatabaseState(stationDatabaseComp.PotentialsList.ConvertAll(x => x.CharacterName ?? "Unknown"), finishTime)); + } + + private void OnPrintRequest(EntityUid console, CctvDatabaseConsoleComponent consoleComp, CctvDatabasePrintRequestMessage args) + { + if (HasComp(console)) + return; + + if (_station.GetOwningStation(console) is not { } station || !TryComp(station, out var stationDatabaseComp)) + return; + + if (stationDatabaseComp.PotentialsList.Count <= args.Index) // Should never happen. + { + Log.Error($"CCTV Database console {console} tried to print a disk with index {args.Index} but the list only has {stationDatabaseComp.PotentialsList.Count} entries."); + return; + } + + var mind = stationDatabaseComp.PotentialsList[args.Index]; + var activeComp = AddComp(console); + activeComp.PrintingMind = mind; + activeComp.PrintTime = consoleComp.TimeToPrint + _timing.CurTime; + UpdateUserInterface(console, activeComp); + } + + private void FinishPrint(EntityUid console, CctvDatabaseConsoleActiveComponent activeComp) + { + var disk = Spawn(HoloDiskPrototype, Transform(console).Coordinates); + var diskComp = EnsureComp(disk); + diskComp.HoloMind = activeComp.PrintingMind; + RemComp(console); + UpdateUserInterface(console); + } +} diff --git a/Content.Server/SimpleStation14/Holograms/CctvDatabase/StationCctvDatabaseComponent.cs b/Content.Server/SimpleStation14/Holograms/CctvDatabase/StationCctvDatabaseComponent.cs new file mode 100644 index 0000000000..3f87a512f8 --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/CctvDatabase/StationCctvDatabaseComponent.cs @@ -0,0 +1,7 @@ +namespace Content.Server.SimpleStation14.Holograms.CctvDatabase; + +[RegisterComponent] +public sealed class StationCctvDatabaseComponent : Component +{ + public List PotentialsList = new(); +} diff --git a/Content.Server/SimpleStation14/Holograms/Components/HologramDiskWriterComponent.cs b/Content.Server/SimpleStation14/Holograms/Components/HologramDiskWriterComponent.cs new file mode 100644 index 0000000000..8c72688b41 --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/Components/HologramDiskWriterComponent.cs @@ -0,0 +1,8 @@ +namespace Content.Server.SimpleStation14.Holograms.Components; + +[RegisterComponent] +public sealed class HologramDiskWriterComponent : Component +{ + [DataField("diskSlot")] + public string DiskSlot = "disk_slot"; +} diff --git a/Content.Server/SimpleStation14/Holograms/Components/HologramTargetComponent.cs b/Content.Server/SimpleStation14/Holograms/Components/HologramTargetComponent.cs new file mode 100644 index 0000000000..a2c8422031 --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/Components/HologramTargetComponent.cs @@ -0,0 +1,10 @@ +//TODO: HOLO In the future, this and the entire CCTV Database system should be completely replaced +// with something that uses station records, requires tracked camera time, +// and a whole bunch of other stuff that'll be fun to use. +// For the time being, this works. + +namespace Content.Server.SimpleStation14.Holograms.Components; + +[RegisterComponent] +public sealed class HologramTargetComponent : Component +{ } diff --git a/Content.Server/SimpleStation14/Holograms/Components/StationHologramDatabaseComponent.cs b/Content.Server/SimpleStation14/Holograms/Components/StationHologramDatabaseComponent.cs new file mode 100644 index 0000000000..eed181ca1e --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/Components/StationHologramDatabaseComponent.cs @@ -0,0 +1,6 @@ +namespace Content.Server.SimpleStation14.Holograms.Components; + +[RegisterComponent] +public sealed class StationHologramDatabaseComponent : Component +{ +} diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.DiskWriter.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.DiskWriter.cs new file mode 100644 index 0000000000..d3010c9f9b --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.DiskWriter.cs @@ -0,0 +1,15 @@ +using Content.Server.Mind.Components; +using Content.Server.Power.Components; +using Content.Shared.Interaction; +using Content.Shared.SimpleStation14.Holograms; +using Robust.Shared.Containers; + +namespace Content.Server.SimpleStation14.Holograms; + +public sealed partial class HologramServerSystem +{ + public void InitializeDiskWriter() + { + base.Initialize(); + } +} diff --git a/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.Station.cs b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.Station.cs new file mode 100644 index 0000000000..0cb7ffe3a6 --- /dev/null +++ b/Content.Server/SimpleStation14/Holograms/Systems/HologramServerSystem.Station.cs @@ -0,0 +1,17 @@ +using Content.Server.GameTicking; +using Content.Server.SimpleStation14.Holograms.Components; + +namespace Content.Server.SimpleStation14.Holograms; + +public sealed partial class HologramServerSystem +{ + private void InitializeStation() + { + SubscribeLocalEvent(OnPlayerSpawn); + } + + private void OnPlayerSpawn(EntityUid player, StationHologramDatabaseComponent component, PlayerSpawnCompleteEvent args) + { + } +} + diff --git a/Content.Shared/SimpleStation14/Holograms/CctvDatabaseShared.cs b/Content.Shared/SimpleStation14/Holograms/CctvDatabaseShared.cs new file mode 100644 index 0000000000..4fcb5a915c --- /dev/null +++ b/Content.Shared/SimpleStation14/Holograms/CctvDatabaseShared.cs @@ -0,0 +1,34 @@ +using Content.Shared.CrewManifest; +using Robust.Shared.Serialization; + +namespace Content.Shared.SimpleStation14.Holograms; + +[Serializable, NetSerializable] +public enum CctvDatabaseUiKey +{ + Key +} + +[Serializable, NetSerializable] +public sealed class CctvDatabaseState : BoundUserInterfaceState +{ + public List CrewManifest; + public TimeSpan? FinishedPrintingTime; + + public CctvDatabaseState(List crewManifest, TimeSpan? finishedPrintingTime = null) + { + CrewManifest = crewManifest; + FinishedPrintingTime = finishedPrintingTime; + } +} + +[Serializable, NetSerializable] +public sealed class CctvDatabasePrintRequestMessage : BoundUserInterfaceMessage +{ + public int Index; + + public CctvDatabasePrintRequestMessage(int index) + { + Index = index; + } +} diff --git a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs index c19e119a57..afc6ffac6a 100644 --- a/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs +++ b/Content.Shared/SimpleStation14/Holograms/HologramEvents.cs @@ -46,7 +46,7 @@ public record struct HologramGetProjectorEvent(EntityUid? ProjectorOverride = nu /// Allows for manually determining if a projector is valid for a given Hologram. /// /// -/// Valid is nullable, setting it to either value will force that behavior. +/// Setting Valid to either True or False will force that behavior. /// Leaving it null will allow the projector to determine its own validity based on normal rules. /// [ByRefEvent] diff --git a/Resources/Prototypes/Entities/Mobs/Player/diona.yml b/Resources/Prototypes/Entities/Mobs/Player/diona.yml index 63f24b68b0..7cb99149ef 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/diona.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/diona.yml @@ -35,3 +35,4 @@ - type: NpcFactionMember factions: - NanoTrasen + - type: HologramTarget diff --git a/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml b/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml index ee80ea4389..c7b5a3b9d2 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml @@ -26,3 +26,4 @@ factions: - NanoTrasen - type: PotentialPsionic + - type: HologramTarget diff --git a/Resources/Prototypes/Entities/Mobs/Player/human.yml b/Resources/Prototypes/Entities/Mobs/Player/human.yml index 980ab7a73a..465ae07568 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/human.yml @@ -33,6 +33,7 @@ factions: - NanoTrasen - type: PotentialPsionic + - type: HologramTarget #Syndie - type: entity diff --git a/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml index 21671b3428..27ff04fd63 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml @@ -32,3 +32,4 @@ damageRecovery: types: Asphyxiation: -1.0 + - type: HologramTarget diff --git a/Resources/Prototypes/Entities/Mobs/Player/slime.yml b/Resources/Prototypes/Entities/Mobs/Player/slime.yml index 4a090af959..15b03c4192 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/slime.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/slime.yml @@ -27,3 +27,4 @@ - type: PotentialPsionic - type: TypingIndicator proto: slime + - type: HologramTarget diff --git a/Resources/Prototypes/Entities/Stations/nanotrasen.yml b/Resources/Prototypes/Entities/Stations/nanotrasen.yml index 3275c08e5d..929b1af691 100644 --- a/Resources/Prototypes/Entities/Stations/nanotrasen.yml +++ b/Resources/Prototypes/Entities/Stations/nanotrasen.yml @@ -25,6 +25,7 @@ noSpawn: true components: - type: Transform + - type: StationCctvDatabase - type: entity id: NanotrasenCentralCommand diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/arachne.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/arachne.yml index bebf42f31b..ee79c3463e 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/arachne.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/arachne.yml @@ -33,3 +33,4 @@ factions: - NanoTrasen - type: PotentialPsionic + - type: HologramTarget diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml index 84e653ab1d..e904a034ce 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml @@ -33,3 +33,4 @@ factions: - NanoTrasen - type: PotentialPsionic + - type: HologramTarget diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/moth.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/moth.yml index 537ec17d58..f8b115cfc4 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/moth.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/moth.yml @@ -33,3 +33,4 @@ factions: - NanoTrasen - type: PotentialPsionic + - type: HologramTarget diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/oni.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/oni.yml index 562b9c564e..78cf83e765 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/oni.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/oni.yml @@ -33,3 +33,4 @@ factions: - NanoTrasen - type: PotentialPsionic + - type: HologramTarget diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/shadowkin.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/shadowkin.yml index e560d9eed8..83a47e7bbc 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/shadowkin.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/shadowkin.yml @@ -123,6 +123,7 @@ - type: MovementSpeedModifier baseWalkSpeed : 2.7 baseSprintSpeed : 4.5 + - type: HologramTarget - type: entity diff --git a/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/Computers/computers.yml new file mode 100644 index 0000000000..1404a2b4ca --- /dev/null +++ b/Resources/Prototypes/SimpleStation14/Entities/Structures/Machines/Computers/computers.yml @@ -0,0 +1,34 @@ +- type: entity + parent: BaseComputer + id: ComputerCctvDatabase + name: CCTV database console + description: Used to fard + components: + - type: Sprite + layers: + - map: ["computerLayerBody"] + state: computer + - map: ["computerLayerKeyboard"] + state: generic_keyboard + - map: ["computerLayerScreen"] + state: security + - map: ["computerLayerKeys"] + state: security_key + - type: PointLight + radius: 1.5 + energy: 1.6 + color: "#006400" + # - type: Computer + # board: CrewMonitoringComputerCircuitboard + - type: ActivatableUI + key: enum.CctvDatabaseUiKey.Key + - type: UserInterface + interfaces: + - key: enum.CctvDatabaseUiKey.Key + type: CctvDatabaseBoundUserInterface + - type: CctvDatabaseConsole + # - type: DeviceNetwork + # deviceNetId: Wireless + # receiveFrequencyId: CrewMonitor + # - type: WirelessNetworkConnection + # range: 1200