]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Fix matchstick prediction issues (#31418)
authorbeck-thompson <107373427+beck-thompson@users.noreply.github.com>
Tue, 8 Apr 2025 21:00:57 +0000 (14:00 -0700)
committerGitHub <noreply@github.com>
Tue, 8 Apr 2025 21:00:57 +0000 (23:00 +0200)
* First commit

* Minor fixes please ymal error begone

* If this fixes it

* Last chance

* How

* Forgot

* First fixes

* Added correct component tags

* Minor cleanup

* Address review!

* Namespace change

* Fix yaml yelling

* Changes

* Update namespace

* Removed the unneeded files

Content.Server/Light/Components/MatchboxComponent.cs [deleted file]
Content.Server/Light/Components/MatchstickComponent.cs [deleted file]
Content.Server/Light/EntitySystems/MatchboxSystem.cs [deleted file]
Content.Server/Light/EntitySystems/MatchstickSystem.cs [deleted file]
Content.Shared/IgnitionSource/Components/MatchboxComponent.cs [new file with mode: 0644]
Content.Shared/IgnitionSource/Components/MatchstickComponent.cs [new file with mode: 0644]
Content.Shared/IgnitionSource/EntitySystems/MatchboxSystem.cs [new file with mode: 0644]
Content.Shared/IgnitionSource/EntitySystems/MatchstickSystem.cs [new file with mode: 0644]
Resources/Prototypes/Entities/Objects/Tools/matches.yml

diff --git a/Content.Server/Light/Components/MatchboxComponent.cs b/Content.Server/Light/Components/MatchboxComponent.cs
deleted file mode 100644 (file)
index 12cd4e3..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Content.Server.Light.Components
-{
-    // TODO make changes in icons when different threshold reached
-    // e.g. different icons for 10% 50% 100%
-    [RegisterComponent]
-    public sealed partial class MatchboxComponent : Component
-    {
-    }
-}
diff --git a/Content.Server/Light/Components/MatchstickComponent.cs b/Content.Server/Light/Components/MatchstickComponent.cs
deleted file mode 100644 (file)
index 3c47f4c..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-using Content.Server.Light.EntitySystems;
-using Content.Shared.Smoking;
-using Robust.Shared.Audio;
-
-namespace Content.Server.Light.Components
-{
-    [RegisterComponent]
-    [Access(typeof(MatchstickSystem))]
-    public sealed partial class MatchstickComponent : Component
-    {
-        /// <summary>
-        /// Current state to matchstick. Can be <code>Unlit</code>, <code>Lit</code> or <code>Burnt</code>.
-        /// </summary>
-        [DataField("state")]
-        public SmokableState CurrentState = SmokableState.Unlit;
-
-        /// <summary>
-        /// How long will matchstick last in seconds.
-        /// </summary>
-        [ViewVariables(VVAccess.ReadOnly)]
-        [DataField("duration")]
-        public int Duration = 10;
-
-        /// <summary>
-        /// Sound played when you ignite the matchstick.
-        /// </summary>
-        [DataField("igniteSound", required: true)] public SoundSpecifier IgniteSound = default!;
-    }
-}
diff --git a/Content.Server/Light/EntitySystems/MatchboxSystem.cs b/Content.Server/Light/EntitySystems/MatchboxSystem.cs
deleted file mode 100644 (file)
index 9a73e44..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-using Content.Server.Light.Components;
-using Content.Server.Storage.EntitySystems;
-using Content.Shared.Interaction;
-using Content.Shared.Smoking;
-
-namespace Content.Server.Light.EntitySystems
-{
-    public sealed class MatchboxSystem : EntitySystem
-    {
-        [Dependency] private readonly MatchstickSystem _stickSystem = default!;
-
-        public override void Initialize()
-        {
-            base.Initialize();
-            SubscribeLocalEvent<MatchboxComponent, InteractUsingEvent>(OnInteractUsing, before: new[] { typeof(StorageSystem) });
-        }
-
-        private void OnInteractUsing(EntityUid uid, MatchboxComponent component, InteractUsingEvent args)
-        {
-            if (!args.Handled
-                && EntityManager.TryGetComponent(args.Used, out MatchstickComponent? matchstick)
-                && matchstick.CurrentState == SmokableState.Unlit)
-            {
-                _stickSystem.Ignite((args.Used, matchstick), args.User);
-                args.Handled = true;
-            }
-        }
-    }
-}
diff --git a/Content.Server/Light/EntitySystems/MatchstickSystem.cs b/Content.Server/Light/EntitySystems/MatchstickSystem.cs
deleted file mode 100644 (file)
index 96e4695..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-using Content.Server.Atmos.EntitySystems;
-using Content.Server.Light.Components;
-using Content.Shared.Audio;
-using Content.Shared.Interaction;
-using Content.Shared.Item;
-using Content.Shared.Smoking;
-using Content.Shared.Temperature;
-using Robust.Server.GameObjects;
-using Robust.Shared.Audio;
-using Robust.Shared.Audio.Systems;
-using Robust.Shared.Player;
-
-namespace Content.Server.Light.EntitySystems
-{
-    public sealed class MatchstickSystem : EntitySystem
-    {
-        [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
-        [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
-        [Dependency] private readonly SharedAudioSystem _audio = default!;
-        [Dependency] private readonly SharedItemSystem _item = default!;
-        [Dependency] private readonly SharedPointLightSystem _lights = default!;
-        [Dependency] private readonly TransformSystem _transformSystem = default!;
-
-        private readonly HashSet<Entity<MatchstickComponent>> _litMatches = new();
-
-        public override void Initialize()
-        {
-            base.Initialize();
-            SubscribeLocalEvent<MatchstickComponent, InteractUsingEvent>(OnInteractUsing);
-            SubscribeLocalEvent<MatchstickComponent, IsHotEvent>(OnIsHotEvent);
-            SubscribeLocalEvent<MatchstickComponent, ComponentShutdown>(OnShutdown);
-        }
-
-        private void OnShutdown(Entity<MatchstickComponent> ent, ref ComponentShutdown args)
-        {
-            _litMatches.Remove(ent);
-        }
-
-        public override void Update(float frameTime)
-        {
-            base.Update(frameTime);
-
-            foreach (var match in _litMatches)
-            {
-                if (match.Comp.CurrentState != SmokableState.Lit || Paused(match) || match.Comp.Deleted)
-                    continue;
-
-                var xform = Transform(match);
-
-                if (xform.GridUid is not {} gridUid)
-                    return;
-
-                var position = _transformSystem.GetGridOrMapTilePosition(match, xform);
-
-                _atmosphereSystem.HotspotExpose(gridUid, position, 400, 50, match, true);
-            }
-        }
-
-        private void OnInteractUsing(Entity<MatchstickComponent> ent, ref InteractUsingEvent args)
-        {
-            if (args.Handled || ent.Comp.CurrentState != SmokableState.Unlit)
-                return;
-
-            var isHotEvent = new IsHotEvent();
-            RaiseLocalEvent(args.Used, isHotEvent);
-
-            if (!isHotEvent.IsHot)
-                return;
-
-            Ignite(ent, args.User);
-            args.Handled = true;
-        }
-
-        private void OnIsHotEvent(EntityUid uid, MatchstickComponent component, IsHotEvent args)
-        {
-            args.IsHot = component.CurrentState == SmokableState.Lit;
-        }
-
-        public void Ignite(Entity<MatchstickComponent> matchstick, EntityUid user)
-        {
-            var component = matchstick.Comp;
-
-            // Play Sound
-            _audio.PlayPvs(component.IgniteSound, matchstick, AudioParams.Default.WithVariation(0.125f).WithVolume(-0.125f));
-
-            // Change state
-            SetState(matchstick, component, SmokableState.Lit);
-            _litMatches.Add(matchstick);
-            matchstick.Owner.SpawnTimer(component.Duration * 1000, delegate
-            {
-                SetState(matchstick, component, SmokableState.Burnt);
-                _litMatches.Remove(matchstick);
-            });
-        }
-
-        private void SetState(EntityUid uid, MatchstickComponent component, SmokableState value)
-        {
-            component.CurrentState = value;
-
-            if (_lights.TryGetLight(uid, out var pointLightComponent))
-            {
-                _lights.SetEnabled(uid, component.CurrentState == SmokableState.Lit, pointLightComponent);
-            }
-
-            if (EntityManager.TryGetComponent(uid, out ItemComponent? item))
-            {
-                switch (component.CurrentState)
-                {
-                    case SmokableState.Lit:
-                        _item.SetHeldPrefix(uid, "lit", component: item);
-                        break;
-                    default:
-                        _item.SetHeldPrefix(uid, "unlit", component: item);
-                        break;
-                }
-            }
-
-            if (EntityManager.TryGetComponent(uid, out AppearanceComponent? appearance))
-            {
-                _appearance.SetData(uid, SmokingVisuals.Smoking, component.CurrentState, appearance);
-            }
-        }
-    }
-}
diff --git a/Content.Shared/IgnitionSource/Components/MatchboxComponent.cs b/Content.Shared/IgnitionSource/Components/MatchboxComponent.cs
new file mode 100644 (file)
index 0000000..dda0ca1
--- /dev/null
@@ -0,0 +1,10 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.IgnitionSource.Components;
+
+/// <summary>
+///     Component for entities that light matches when they interact. (E.g. striking the match on the matchbox)
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class MatchboxComponent : Component;
+
diff --git a/Content.Shared/IgnitionSource/Components/MatchstickComponent.cs b/Content.Shared/IgnitionSource/Components/MatchstickComponent.cs
new file mode 100644 (file)
index 0000000..d1bbae4
--- /dev/null
@@ -0,0 +1,34 @@
+using Content.Shared.Smoking;
+using Robust.Shared.Audio;
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+
+namespace Content.Shared.IgnitionSource.Components;
+
+[NetworkedComponent, RegisterComponent, AutoGenerateComponentState, AutoGenerateComponentPause]
+public sealed partial class MatchstickComponent : Component
+{
+    /// <summary>
+    ///     Current state to matchstick. Can be <code>Unlit</code>, <code>Lit</code> or <code>Burnt</code>.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public SmokableState State = SmokableState.Unlit;
+
+    /// <summary>
+    ///     How long the matchstick will burn for.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public TimeSpan Duration = TimeSpan.FromSeconds(10);
+
+    /// <summary>
+    ///     The time that the match will burn out. If null, that means the match is unlit.
+    /// </summary>
+    [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField, AutoPausedField]
+    public TimeSpan? TimeMatchWillBurnOut;
+
+    /// <summary>
+    ///     Sound played when you ignite the matchstick.
+    /// </summary>
+    [DataField]
+    public SoundSpecifier? IgniteSound;
+}
diff --git a/Content.Shared/IgnitionSource/EntitySystems/MatchboxSystem.cs b/Content.Shared/IgnitionSource/EntitySystems/MatchboxSystem.cs
new file mode 100644 (file)
index 0000000..806e1e9
--- /dev/null
@@ -0,0 +1,25 @@
+using Content.Shared.Storage.EntitySystems;
+using Content.Shared.Interaction;
+using Content.Shared.IgnitionSource.Components;
+
+namespace Content.Shared.IgnitionSource.EntitySystems;
+
+public sealed class MatchboxSystem : EntitySystem
+{
+    [Dependency] private readonly MatchstickSystem _match = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<MatchboxComponent, InteractUsingEvent>(OnInteractUsing, before: [ typeof(SharedStorageSystem) ]);
+    }
+
+    private void OnInteractUsing(Entity<MatchboxComponent> ent, ref InteractUsingEvent args)
+    {
+        if (args.Handled || !TryComp<MatchstickComponent>(args.Used, out var matchstick))
+            return;
+
+        args.Handled = _match.TryIgnite((args.Used, matchstick), args.User);
+    }
+}
diff --git a/Content.Shared/IgnitionSource/EntitySystems/MatchstickSystem.cs b/Content.Shared/IgnitionSource/EntitySystems/MatchstickSystem.cs
new file mode 100644 (file)
index 0000000..1267af3
--- /dev/null
@@ -0,0 +1,102 @@
+using Content.Shared.Interaction;
+using Content.Shared.Item;
+using Content.Shared.Smoking;
+using Content.Shared.Temperature;
+using Robust.Shared.Audio.Systems;
+using Content.Shared.IgnitionSource.Components;
+using Robust.Shared.Timing;
+
+namespace Content.Shared.IgnitionSource.EntitySystems;
+
+public sealed partial class MatchstickSystem : EntitySystem
+{
+    [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+    [Dependency] private readonly SharedAudioSystem _audio = default!;
+    [Dependency] private readonly SharedItemSystem _item = default!;
+    [Dependency] private readonly SharedPointLightSystem _lights = default!;
+    [Dependency] private readonly IGameTiming _timing = default!;
+    [Dependency] private readonly SharedIgnitionSourceSystem _ignition = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<MatchstickComponent, InteractUsingEvent>(OnInteractUsing);
+    }
+
+    // This is for something *else* lighting the matchstick, not the matchstick lighting something else.
+    private void OnInteractUsing(Entity<MatchstickComponent> ent, ref InteractUsingEvent args)
+    {
+        if (args.Handled)
+            return;
+
+        var isHotEvent = new IsHotEvent();
+        RaiseLocalEvent(args.Used, isHotEvent);
+
+        if (!isHotEvent.IsHot)
+            return;
+
+        args.Handled = TryIgnite(ent, args.User);
+    }
+
+    /// <summary>
+    ///     Try to light a matchstick!
+    /// </summary>
+    /// <param name="matchstick">The matchstick to light.</param>
+    /// <param name="user">The user lighting the matchstick can be null if there isn't any user.</param>
+    /// <returns>True if the matchstick was lit, false otherwise.</returns>
+    public bool TryIgnite(Entity<MatchstickComponent> matchstick, EntityUid? user)
+    {
+        if (matchstick.Comp.State != SmokableState.Unlit)
+            return false;
+
+        // Play Sound
+        _audio.PlayPredicted(matchstick.Comp.IgniteSound, matchstick, user);
+
+        // Change state
+        SetState(matchstick, SmokableState.Lit);
+        matchstick.Comp.TimeMatchWillBurnOut = _timing.CurTime + matchstick.Comp.Duration;
+
+        Dirty(matchstick);
+
+        return true;
+    }
+
+    private void SetState(Entity<MatchstickComponent> ent, SmokableState newState)
+    {
+        _lights.SetEnabled(ent, newState == SmokableState.Lit);
+
+        _appearance.SetData(ent, SmokingVisuals.Smoking, newState);
+
+        _ignition.SetIgnited(ent.Owner, newState == SmokableState.Lit);
+
+        switch (newState)
+        {
+            case SmokableState.Lit:
+                _item.SetHeldPrefix(ent, "lit");
+                break;
+            default:
+                _item.SetHeldPrefix(ent, "unlit");
+                break;
+        }
+
+        ent.Comp.State = newState;
+        Dirty(ent);
+    }
+
+    public override void Update(float frameTime)
+    {
+        base.Update(frameTime);
+
+        var query = EntityQueryEnumerator<MatchstickComponent>();
+
+        while (query.MoveNext(out var uid, out var match))
+        {
+            if (match.State != SmokableState.Lit)
+                continue;
+
+            // Check if the match has expired.
+            if (_timing.CurTime > match.TimeMatchWillBurnOut)
+                SetState((uid, match), SmokableState.Burnt);
+        }
+    }
+}
index e8601fcf355dba81f091437caf76c38384607e15..ee5100c999df6b963b05e9d1cf60552cce32bc60 100644 (file)
     duration: 10
     igniteSound:
       path: /Audio/Items/match_strike.ogg
+      params:
+        volume: -0.125
+        variation: 0.125
+  - type: IgnitionSource
+    ignited: false
+    temperature: 400.0
   - type: PointLight
     enabled: false
     radius: 1.1