<commit_before>﻿#nullable enable
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Content.Shared.GameObjects.Components;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Interfaces;
using Content.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Timers;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Timers;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;

namespace Content.Server.GameObjects.Components.Stack
{

    // TODO: Naming and presentation and such could use some improvement.
    [RegisterComponent]
    [ComponentReference(typeof(SharedStackComponent))]
    public class StackComponent : SharedStackComponent, IInteractUsing, IExamine
    {
        private bool _throwIndividually = false;

        [ViewVariables(VVAccess.ReadWrite)]
        public bool ThrowIndividually
        {
            get => _throwIndividually;
            private set
            {
                _throwIndividually = value;
                Dirty();
            }
        }

        public void Add(int amount)
        {
            Count += amount;
        }

        /// <summary>
        ///     Try to use an amount of items on this stack.
        /// </summary>
        /// <param name="amount"></param>
        /// <returns>True if there were enough items to remove, false if not in which case nothing was changed.</returns>
        public bool Use(int amount)
        {
            if (Count >= amount)
            {
                Count -= amount;
                return true;
            }
            return false;
        }

        /// <summary>
        ///     Attempts to split this stack in two.
        /// </summary>
        /// <param name="amount">amount the new stack will have</param>
        /// <param name="spawnPosition">the position the new stack will spawn at</param>
        /// <param name="stack">the new stack</param>
        /// <returns></returns>
        public bool Split(int amount, EntityCoordinates spawnPosition, [NotNullWhen(true)] out IEntity? stack)
        {
            if (Count >= amount)
            {
                Count -= amount;

                stack = Owner.EntityManager.SpawnEntity(Owner.Prototype?.ID, spawnPosition);

                if (stack.TryGetComponent(out StackComponent? stackComp))
                {
                    stackComp.Count = amount;
                }

                return true;
            }

            stack = null;
            return false;
        }

        public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
        {
            if (eventArgs.Using.TryGetComponent<StackComponent>(out var stack))
            {
                if (!stack.StackType.Equals(StackType))
                {
                    return false;
                }

                var toTransfer = Math.Min(Count, stack.AvailableSpace);
                Count -= toTransfer;
                stack.Add(toTransfer);

                var popupPos = eventArgs.ClickLocation;
                if (popupPos == EntityCoordinates.Invalid)
                {
                    popupPos = eventArgs.User.Transform.Coordinates;
                }


                if (toTransfer > 0)
                {
                    popupPos.PopupMessage(eventArgs.User, $"+{toTransfer}");

                    if (stack.AvailableSpace == 0)
                    {
                        Owner.SpawnTimer(300, () => popupPos.PopupMessage(eventArgs.User, "Stack is now full."));
                    }

                    return true;
                }
                else if (toTransfer == 0 && stack.AvailableSpace == 0)
                {
                    popupPos.PopupMessage(eventArgs.User, "Stack is already full.");
                }
            }

            return false;
        }

        void IExamine.Examine(FormattedMessage message, bool inDetailsRange)<commit_msg>Fix server exception on emptying a StackComponent.cs.<commit_after>﻿#nullable enable
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Content.Shared.GameObjects.Components;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Interfaces;
using Content.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Timers;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;

namespace Content.Server.GameObjects.Components.Stack
{

    // TODO: Naming and presentation and such could use some improvement.
    [RegisterComponent]
    [ComponentReference(typeof(SharedStackComponent))]
    public class StackComponent : SharedStackComponent, IInteractUsing, IExamine
    {
        private bool _throwIndividually = false;

        [ViewVariables(VVAccess.ReadWrite)]
        public bool ThrowIndividually
        {
            get => _throwIndividually;
            private set
            {
                _throwIndividually = value;
                Dirty();
            }
        }

        public void Add(int amount)
        {
            Count += amount;
        }

        /// <summary>
        ///     Try to use an amount of items on this stack.
        /// </summary>
        /// <param name="amount"></param>
        /// <returns>True if there were enough items to remove, false if not in which case nothing was changed.</returns>
        public bool Use(int amount)
        {
            if (Count >= amount)
            {
                Count -= amount;
                return true;
            }
            return false;
        }

        /// <summary>
        ///     Attempts to split this stack in two.
        /// </summary>
        /// <param name="amount">amount the new stack will have</param>
        /// <param name="spawnPosition">the position the new stack will spawn at</param>
        /// <param name="stack">the new stack</param>
        /// <returns></returns>
        public bool Split(int amount, EntityCoordinates spawnPosition, [NotNullWhen(true)] out IEntity? stack)
        {
            if (Count >= amount)
            {
                Count -= amount;

                stack = Owner.EntityManager.SpawnEntity(Owner.Prototype?.ID, spawnPosition);

                if (stack.TryGetComponent(out StackComponent? stackComp))
                {
                    stackComp.Count = amount;
                }

                return true;
            }

            stack = null;
            return false;
        }

        public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
        {
            if (!eventArgs.Using.TryGetComponent<StackComponent>(out var stack))
                return false;

            if (!stack.StackType.Equals(StackType))
            {
                return false;
            }

            var toTransfer = Math.Min(Count, stack.AvailableSpace);
            Count -= toTransfer;
            stack.Add(toTransfer);

            var popupPos = eventArgs.ClickLocation;
            if (popupPos == EntityCoordinates.Invalid)
            {
                popupPos = eventArgs.User.Transform.Coordinates;
            }


            if (toTransfer > 0)
            {
                popupPos.PopupMessage(eventArgs.User, $"+{toTransfer}");

                if (stack.AvailableSpace == 0)
                {
                    eventArgs.Using.SpawnTimer(300, () => popupPos.PopupMessage(eventArgs.User, "Stack is now full."));
                }
            }
            else if (toTransfer == 0 && stack.AvailableSpace == 0)
            {
                popupPos.PopupMessage(eventArgs.User, "Stack is already full.");
            }

            return true;
        }

        void IExamine.Examine(FormattedMessage message, bool inDetailsRange)
{'fraction_non_alphanumeric': 0.09373446046742914, 'fraction_numerical': 0.00174042764793635, 'mean_word_length': 1.6906354515050168, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4553736', 'n_tokens_mistral': 2057, 'n_tokens_neox': 1950, 'n_words': 483}