private void UserInteraction(IEntity player, GridCoordinates coordinates, EntityUid clickedUid)
        {
            // Get entity clicked upon from UID if valid UID, if not assume no entity clicked upon and null
            if (!EntityManager.TryGetEntity(clickedUid, out var attacked))
            {
                attacked = null;
            }

            // Verify player has a transform component
            if (!player.TryGetComponent <ITransformComponent>(out var playerTransform))
            {
                return;
            }

            // Verify player is on the same map as the entity he clicked on
            if (_mapManager.GetGrid(coordinates.GridID).ParentMapId != playerTransform.MapID)
            {
                Logger.WarningS("system.interaction",
                                $"Player named {player.Name} clicked on a map he isn't located on");
                return;
            }

            // Verify player has a hand, and find what object he is currently holding in his active hand
            if (!player.TryGetComponent <IHandsComponent>(out var hands))
            {
                return;
            }

            var item = hands.GetActiveHand?.Owner;

            if (ActionBlockerSystem.CanChangeDirection(player))
            {
                var diff = coordinates.ToMapPos(_mapManager) - playerTransform.MapPosition.Position;
                if (diff.LengthSquared > 0.01f)
                {
                    playerTransform.LocalRotation = new Angle(diff);
                }
            }

            if (!ActionBlockerSystem.CanInteract(player))
            {
                return;
            }

            // TODO: Check if client should be able to see that object to click on it in the first place

            // Clicked on empty space behavior, try using ranged attack
            if (attacked == null)
            {
                if (item != null)
                {
                    // After attack: Check if we clicked on an empty location, if so the only interaction we can do is AfterInteract
                    InteractAfter(player, item, coordinates);
                }

                return;
            }

            // Verify attacked object is on the map if we managed to click on it somehow
            if (!attacked.Transform.IsMapTransform)
            {
                Logger.WarningS("system.interaction",
                                $"Player named {player.Name} clicked on object {attacked.Name} that isn't currently on the map somehow");
                return;
            }

            // RangedInteract/AfterInteract: Check distance between user and clicked item, if too large parse it in the ranged function
            // TODO: have range based upon the item being used? or base it upon some variables of the player himself?
            var distance = (playerTransform.WorldPosition - attacked.Transform.WorldPosition).LengthSquared;

            if (distance > InteractionRangeSquared)
            {
                if (item != null)
                {
                    RangedInteraction(player, item, attacked, coordinates);
                    return;
                }

                return; // Add some form of ranged InteractHand here if you need it someday, or perhaps just ways to modify the range of InteractHand
            }

            // We are close to the nearby object and the object isn't contained in our active hand
            // InteractUsing/AfterInteract: We will either use the item on the nearby object
            if (item != null)
            {
                Interaction(player, item, attacked, coordinates);
            }
            // InteractHand/Activate: Since our hand is empty we will use InteractHand/Activate
            else
            {
                Interaction(player, attacked);
            }
        }
        public bool TryPoint(ICommonSession?session, GridCoordinates coords, EntityUid uid)
        {
            var player = session?.AttachedEntity;

            if (player == null)
            {
                return(false);
            }

            if (_pointers.TryGetValue(session !, out var lastTime) &&
                _gameTiming.CurTime < lastTime + PointDelay)
            {
                return(false);
            }

            if (!InRange(coords, player.Transform.GridPosition))
            {
                player.PopupMessage(player, Loc.GetString("You can't reach there!"));
                return(false);
            }

            if (ActionBlockerSystem.CanChangeDirection(player))
            {
                var diff = coords.ToMapPos(_mapManager) - player.Transform.MapPosition.Position;
                if (diff.LengthSquared > 0.01f)
                {
                    player.Transform.LocalRotation = new Angle(diff);
                }
            }

            var viewers = _playerManager.GetPlayersInRange(player.Transform.GridPosition, 15);

            EntityManager.SpawnEntity("pointingarrow", coords);

            string selfMessage;
            string viewerMessage;
            string?viewerPointedAtMessage = null;

            if (EntityManager.TryGetEntity(uid, out var pointed))
            {
                selfMessage = player == pointed
                    ? Loc.GetString("You point at yourself.")
                    : Loc.GetString("You point at {0:theName}.", pointed);

                viewerMessage = player == pointed
                    ? $"{player.Name} {Loc.GetString("points at {0:themself}.", player)}"
                    : $"{player.Name} {Loc.GetString("points at {0:theName}.", pointed)}";

                viewerPointedAtMessage = $"{player.Name} {Loc.GetString("points at you.")}";
            }
            else
            {
                var tileRef = _mapManager.GetGrid(coords.GridID).GetTileRef(coords);
                var tileDef = _tileDefinitionManager[tileRef.Tile.TypeId];

                selfMessage = Loc.GetString("You point at {0}.", tileDef.DisplayName);

                viewerMessage = $"{player.Name} {Loc.GetString("points at {0}.", tileDef.DisplayName)}";
            }

            _pointers[session !] = _gameTiming.CurTime;
        public bool TryPoint(ICommonSession?session, GridCoordinates coords, EntityUid uid)
        {
            var player = (session as IPlayerSession)?.ContentData()?.Mind?.CurrentEntity;

            if (player == null)
            {
                return(false);
            }

            if (_pointers.TryGetValue(session !, out var lastTime) &&
                _gameTiming.CurTime < lastTime + PointDelay)
            {
                return(false);
            }

            if (EntityManager.TryGetEntity(uid, out var entity) && entity.HasComponent <PointingArrowComponent>())
            {
                // this is a pointing arrow. no pointing here...
                return(false);
            }

            if (!InRange(coords, player.Transform.GridPosition))
            {
                player.PopupMessage(Loc.GetString("You can't reach there!"));
                return(false);
            }

            if (ActionBlockerSystem.CanChangeDirection(player))
            {
                var diff = coords.ToMapPos(_mapManager) - player.Transform.MapPosition.Position;
                if (diff.LengthSquared > 0.01f)
                {
                    player.Transform.LocalRotation = new Angle(diff);
                }
            }

            var arrow = EntityManager.SpawnEntity("pointingarrow", coords);

            var layer = (int)VisibilityFlags.Normal;

            if (player.TryGetComponent(out VisibilityComponent? playerVisibility))
            {
                var arrowVisibility = arrow.EnsureComponent <VisibilityComponent>();
                layer = arrowVisibility.Layer = playerVisibility.Layer;
            }

            // Get players that are in range and whose visibility layer matches the arrow's.
            var viewers = _playerManager.GetPlayersBy((playerSession) =>
            {
                if ((playerSession.VisibilityMask & layer) == 0)
                {
                    return(false);
                }

                var ent = playerSession.ContentData()?.Mind?.CurrentEntity;

                return(ent != null &&
                       ent.Transform.MapPosition.InRange(player.Transform.MapPosition, PointingRange));
            });

            string selfMessage;
            string viewerMessage;
            string?viewerPointedAtMessage = null;

            if (EntityManager.TryGetEntity(uid, out var pointed))
            {
                selfMessage = player == pointed
                    ? Loc.GetString("You point at yourself.")
                    : Loc.GetString("You point at {0:theName}.", pointed);

                viewerMessage = player == pointed
                    ? $"{player.Name} {Loc.GetString("points at {0:themself}.", player)}"
                    : $"{player.Name} {Loc.GetString("points at {0:theName}.", pointed)}";

                viewerPointedAtMessage = $"{player.Name} {Loc.GetString("points at you.")}";
            }
            else
            {
                var tileRef = _mapManager.GetGrid(coords.GridID).GetTileRef(coords);
                var tileDef = _tileDefinitionManager[tileRef.Tile.TypeId];

                selfMessage = Loc.GetString("You point at {0}.", tileDef.DisplayName);

                viewerMessage = $"{player.Name} {Loc.GetString("points at {0}.", tileDef.DisplayName)}";
            }

            _pointers[session !] = _gameTiming.CurTime;