<commit_before>﻿// Copyright (c) 2007-2018 ppy Pty Ltd <<EMAIL>>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

using OpenTK;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Framework.Graphics.Primitives;
using osu.Game.Configuration;
using osu.Game.Rulesets.Scoring;

namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
    public class DrawableSlider : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
    {
        private readonly Slider slider;
        private readonly List<Drawable> components = new List<Drawable>();

        public readonly DrawableHitCircle HeadCircle;
        public readonly SliderBody Body;
        public readonly SliderBall Ball;

        public DrawableSlider(Slider s)
            : base(s)
        {
            slider = s;

            DrawableSliderTail tail;
            Container<DrawableSliderTick> ticks;
            Container<DrawableRepeatPoint> repeatPoints;

            Children = new Drawable[]
            {
                Body = new SliderBody(s)
                {
                    AccentColour = AccentColour,
                    Position = s.StackedPosition,
                    PathWidth = s.Scale * 64,
                },
                ticks = new Container<DrawableSliderTick>(),
                repeatPoints = new Container<DrawableRepeatPoint>(),
                Ball = new SliderBall(s)
                {
                    Scale = new Vector2(s.Scale),
                    AccentColour = AccentColour,
                    AlwaysPresent = true,
                    Alpha = 0
                },
                HeadCircle = new DrawableHitCircle(s.HeadCircle),
                tail = new DrawableSliderTail(s.TailCircle)
            };

            components.Add(Body);
            components.Add(Ball);

            AddNested(HeadCircle);

            AddNested(tail);
            components.Add(tail);

            foreach (var tick in s.NestedHitObjects.OfType<SliderTick>())
            {
                var drawableTick = new DrawableSliderTick(tick)
                {
                    Position = tick.StackedPosition
                };

                ticks.Add(drawableTick);
                components.Add(drawableTick);
                AddNested(drawableTick);
            }

            foreach (var repeatPoint in s.NestedHitObjects.OfType<RepeatPoint>())
            {
                var drawableRepeatPoint = new DrawableRepeatPoint(repeatPoint, this)
                {
                    Position = repeatPoint.StackedPosition
                };

                repeatPoints.Add(drawableRepeatPoint);
                components.Add(drawableRepeatPoint);
                AddNested(drawableRepeatPoint);
            }
        }

        [BackgroundDependencyLoader]
        private void load(OsuConfigManager config)
        {
            config.BindWith(OsuSetting.SnakingInSliders, Body.SnakingIn);
            config.BindWith(OsuSetting.SnakingOutSliders, Body.SnakingOut);
        }

        public bool Tracking;

        protected override void Update()
        {
            base.Update();

            Tracking = Ball.Tracking;

            double completionProgress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);

            //todo: we probably want to reconsider this before adding scoring, but it looks and feels nice.
            if (!HeadCircle.IsHit)
                HeadCircle.Position = slider.StackedPositionAt(completionProgress);

            foreach (var c in components.OfType<ISliderProgress>()) c.UpdateProgress(completionProgress);
            foreach (var c in components.OfType<ITrackSnaking>()) c.UpdateSnakingPosition(slider.Curve.PositionAt(Body.SnakedStart ?? 0), slider.Curve.PositionAt(Body.SnakedEnd ?? 0));
            foreach (var t in components.OfType<IRequireTracking>()) t.Tracking = Ball.Tracking;
        }

        protected override void CheckForJudgements(bool userTriggered, double timeOffset)
        {
            if (!userTriggered && Time.Current >= slider.EndTime)
            {
                var judgementsCount = NestedHitObjects.Count;
                var judgementsHit = NestedHitObjects.Count(h => h.IsHit);

                var hitFraction = (double)judgementsHit / judgementsCount;
                if (hitFraction == 1 && HeadCircle.Judgements.Any(j => j.Result == HitResult.Great))
                    AddJudgement(new OsuJudgement { Result = HitResult.Great });
                else if (hitFraction >= 0.5 && HeadCircle.Judgements.Any(j => j.Result >= HitResult.Good))
                    AddJudgement(new OsuJudgement { Result = HitResult.Good });
                else if (hitFraction > 0)
                    AddJudgement(new OsuJudgement { Result = HitResult.Meh });
                else
                    AddJudgement(new OsuJudgement { Result = HitResult.Miss });
            }
        }

        protected override void UpdateCurrentState(ArmedState state)
        {
            Ball.FadeIn();
            Ball.ScaleTo(HitObject.Scale);

            using (BeginDelayedSequence(slider.Duration, true))
            {
                const float fade_out_time = 450;

                // intentionally pile on an extra FadeOut to make it happen much faster.
                Ball.FadeOut(fade_out_time / 4, Easing.Out);

                switch (state)
                {
                    case ArmedState.Hit:
                        Ball.ScaleTo(HitObject.Scale * 1.4f, fade_out_time, Easing.Out);
                        break;
                }

                this.FadeOut(fade_out_time, Easing.OutQuint).Expire();
            }
        }

        public Drawable ProxiedLayer => HeadCircle.ApproachCircle;

        public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Body.ReceiveMouseInputAt(screenSpacePos);

        public override Vector2 SelectionPoint => ToScreenSpace(Body.Position);
        public override Quad SelectionQuad => Body.PathDrawQuad;
    }
}<commit_msg>Fix sliders never getting a correct lifetime set<commit_after>﻿// Copyright (c) 2007-2018 ppy Pty Ltd <<EMAIL>>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

using OpenTK;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Framework.Graphics.Primitives;
using osu.Game.Configuration;
using osu.Game.Rulesets.Scoring;

namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
    public class DrawableSlider : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
    {
        private readonly Slider slider;
        private readonly List<Drawable> components = new List<Drawable>();

        public readonly DrawableHitCircle HeadCircle;
        public readonly SliderBody Body;
        public readonly SliderBall Ball;

        public DrawableSlider(Slider s)
            : base(s)
        {
            slider = s;

            DrawableSliderTail tail;
            Container<DrawableSliderTick> ticks;
            Container<DrawableRepeatPoint> repeatPoints;

            Children = new Drawable[]
            {
                Body = new SliderBody(s)
                {
                    AccentColour = AccentColour,
                    Position = s.StackedPosition,
                    PathWidth = s.Scale * 64,
                },
                ticks = new Container<DrawableSliderTick>(),
                repeatPoints = new Container<DrawableRepeatPoint>(),
                Ball = new SliderBall(s)
                {
                    Scale = new Vector2(s.Scale),
                    AccentColour = AccentColour,
                    AlwaysPresent = true,
                    Alpha = 0
                },
                HeadCircle = new DrawableHitCircle(s.HeadCircle),
                tail = new DrawableSliderTail(s.TailCircle)
            };

            components.Add(Body);
            components.Add(Ball);

            AddNested(HeadCircle);

            AddNested(tail);
            components.Add(tail);

            foreach (var tick in s.NestedHitObjects.OfType<SliderTick>())
            {
                var drawableTick = new DrawableSliderTick(tick)
                {
                    Position = tick.StackedPosition
                };

                ticks.Add(drawableTick);
                components.Add(drawableTick);
                AddNested(drawableTick);
            }

            foreach (var repeatPoint in s.NestedHitObjects.OfType<RepeatPoint>())
            {
                var drawableRepeatPoint = new DrawableRepeatPoint(repeatPoint, this)
                {
                    Position = repeatPoint.StackedPosition
                };

                repeatPoints.Add(drawableRepeatPoint);
                components.Add(drawableRepeatPoint);
                AddNested(drawableRepeatPoint);
            }
        }

        [BackgroundDependencyLoader]
        private void load(OsuConfigManager config)
        {
            config.BindWith(OsuSetting.SnakingInSliders, Body.SnakingIn);
            config.BindWith(OsuSetting.SnakingOutSliders, Body.SnakingOut);
        }

        public bool Tracking;

        protected override void Update()
        {
            base.Update();

            Tracking = Ball.Tracking;

            double completionProgress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);

            //todo: we probably want to reconsider this before adding scoring, but it looks and feels nice.
            if (!HeadCircle.IsHit)
                HeadCircle.Position = slider.StackedPositionAt(completionProgress);

            foreach (var c in components.OfType<ISliderProgress>()) c.UpdateProgress(completionProgress);
            foreach (var c in components.OfType<ITrackSnaking>()) c.UpdateSnakingPosition(slider.Curve.PositionAt(Body.SnakedStart ?? 0), slider.Curve.PositionAt(Body.SnakedEnd ?? 0));
            foreach (var t in components.OfType<IRequireTracking>()) t.Tracking = Ball.Tracking;
        }

        protected override void CheckForJudgements(bool userTriggered, double timeOffset)
        {
            if (!userTriggered && Time.Current >= slider.EndTime)
            {
                var judgementsCount = NestedHitObjects.Count;
                var judgementsHit = NestedHitObjects.Count(h => h.IsHit);

                var hitFraction = (double)judgementsHit / judgementsCount;
                if (hitFraction == 1 && HeadCircle.Judgements.Any(j => j.Result == HitResult.Great))
                    AddJudgement(new OsuJudgement { Result = HitResult.Great });
                else if (hitFraction >= 0.5 && HeadCircle.Judgements.Any(j => j.Result >= HitResult.Good))
                    AddJudgement(new OsuJudgement { Result = HitResult.Good });
                else if (hitFraction > 0)
                    AddJudgement(new OsuJudgement { Result = HitResult.Meh });
                else
                    AddJudgement(new OsuJudgement { Result = HitResult.Miss });
            }
        }

        protected override void UpdateCurrentState(ArmedState state)
        {
            Ball.FadeIn();
            Ball.ScaleTo(HitObject.Scale);

            using (BeginDelayedSequence(slider.Duration, true))
            {
                const float fade_out_time = 450;

                // intentionally pile on an extra FadeOut to make it happen much faster.
                Ball.FadeOut(fade_out_time / 4, Easing.Out);

                switch (state)
                {
                    case ArmedState.Hit:
                        Ball.ScaleTo(HitObject.Scale * 1.4f, fade_out_time, Easing.Out);
                        break;
                }

                this.FadeOut(fade_out_time, Easing.OutQuint).Expire();
            }

            Expire(true);
        }

        public Drawable ProxiedLayer => HeadCircle.ApproachCircle;

        public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Body.ReceiveMouseInputAt(screenSpacePos);

        public override Vector2 SelectionPoint => ToScreenSpace(Body.Position);
        public override Quad SelectionQuad => Body.PathDrawQuad;
    }
}
{'fraction_non_alphanumeric': 0.084044908285895, 'fraction_numerical': 0.004427577482605946, 'mean_word_length': 1.8682539682539683, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 51, 'https://': 2, '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': '5828655', 'n_tokens_mistral': 3519, 'n_tokens_neox': 3238, 'n_words': 676}