} //end PaintTopInGame

        public void AfterCollect()
        {
            if (!Hud.Game.IsInGame)
            {
                return;
            }

            var toRemove = Snapshots.Where(pair => !Hud.Game.Players.Any(p => p.HeroId == pair.Key)).Select(pair => pair.Key).ToList();

            foreach (var key in toRemove)
            {
                Snapshots.Remove(key);
            }

            foreach (IPlayer player in Hud.Game.Players.Where(p => p.HasValidActor && p.SnoArea == Hud.Game.Me.SnoArea && p.CoordinateKnown))
            {
                ProcRuleCalculator.CalculatePaintInfo(player);                 //check for procs

                if (ProcRuleCalculator.PaintInfoList.Count > 0)                //proc detected
                {
                    BuffPaintInfo info       = ProcRuleCalculator.PaintInfoList[0];
                    int           finishtick = Hud.Game.CurrentGameTick + (int)(info.TimeLeft * 60d);
                    int           starttick  = Hud.Game.CurrentGameTick - (int)(info.Elapsed * 60d);
                    double        duration   = info.TimeLeft + info.Elapsed;
                    bool          play       = false;

                    ProcInfo snapshot;
                    if (!Snapshots.TryGetValue(player.HeroId, out snapshot))
                    {
                        play = true;

                        snapshot = new ProcInfo()
                        {
                            PlayerName      = player.BattleTagAbovePortrait,
                            HeroId          = player.HeroId,
                            PlayerClass     = player.HeroClassDefinition.HeroClass,
                            StartTick       = starttick,
                            FinishTick      = finishtick,                        //Hud.Game.CurrentRealTimeMilliseconds + (long)(info.TimeLeft*1000), //long endtime
                            Duration        = duration,
                            Texture         = info.Texture,
                            SoundPlayedTick = Hud.Game.CurrentGameTick
                        };

                        Snapshots.Add(player.HeroId, snapshot);
                    }
                    else if (Math.Abs(finishtick - snapshot.FinishTick) > 2)                         //different end time
                    //is the old record expired?
                    //if (snapshot.FinishTick < Hud.Game.CurrentGameTick) {
                    {
                        if (starttick > snapshot.SoundPlayedTick)
                        {
                            play = true;
                            snapshot.SoundPlayedTick = Hud.Game.CurrentGameTick;
                        }

                        snapshot.StartTick  = starttick;
                        snapshot.FinishTick = finishtick;
                        snapshot.Duration   = duration;
                        snapshot.Count     += 1;
                        snapshot.Texture    = info.Texture;

                        //if (snapshot.PlayerName != player.BattleTagAbovePortrait) { //that is a desync, need to resync...would this ever happen?
                        //}

                        Snapshots[player.HeroId] = snapshot;
                    }

                    if (play && PlaySounds)
                    {
                        ThreadPool.QueueUserWorkItem(state => {
                            try {
                                if (player.IsMe)
                                {
                                    if (SoundYou != null)
                                    {
                                        SoundYou.Play();
                                    }
                                    else
                                    {
                                        Hud.Sound.Speak(SayYouHaveProcced);
                                    }
                                }
                                else
                                {
                                    Hud.Sound.Speak(player.BattleTagAbovePortrait + SayHasProcced);
                                }
                            } catch (Exception) {}
                        });
                    }
                }
                else
                {
                    //no proc detected, but double check that the proc is not supposed to still be running (there may be an issue with proc buffs in that they momentarily register as inactive)
                    ProcInfo snapshot;
                    if (Snapshots.TryGetValue(player.HeroId, out snapshot))
                    {
                        double timeLeft  = (double)(snapshot.FinishTick - Hud.Game.CurrentGameTick) / 60d;
                        IQuest riftQuest = Hud.Game.Quests.FirstOrDefault(q => q.SnoQuest.Sno == Hud.Sno.SnoQuests.GreaterNephalemRift_382695.Sno);

                        if (timeLeft < 0 ||                      //expired snapshot
                            timeLeft > snapshot.Duration ||                             //this happens when data lingers between games
                            (riftQuest != null && (snapshot.FinishTick - (int)(snapshot.Duration * 60)) < riftQuest.CreatedOn) ||                           //if the proc started before the GR was opened
                            player.IsDeadSafeCheck)                                //player.HeadStone != null
                        {
                            Snapshots[player.HeroId].FinishTick = 0;
                        }
                    }
                }
            }
        }
        public void PaintTopInGame(ClipState clipState)
        //public void PaintWorld(WorldLayer layer)
        {
            if (!ShowTracker)
            {
                return;
            }

            var h = Hud.Window.Size.Height * 0.001667f * BarHeight;          //8
            var w = Hud.Window.Size.Width * 0.00155f * BarWidth;             //55

            if (PositionX == -1 || PositionY == -1)
            {
                var objectivesPosition = Hud.Render.GetUiElement("Root.NormalLayer.eventtext_bkgrnd.eventtext_region.title").Rectangle;
                PositionX = objectivesPosition.X - ProcRuleCalculator.StandardIconSize - Gap; // Hud.Render.MinimapUiElement.Rectangle.X - Gap*2 - w - Gap - ProcRuleCalculator.StandardIconSize; //left of the minimap
                PositionY = objectivesPosition.Y;                                             //Hud.Window.Size.Height * 0.015f; //0.14f;
            }

            var x = PositionX;
            var y = PositionY;

            IEnumerable <KeyValuePair <uint, ProcInfo> > ActiveSnapshots = Snapshots.Where(kvp => kvp.Value.FinishTick > Hud.Game.CurrentGameTick);

            //draw background
            int active = ActiveSnapshots.Count();

            if (active > 0)
            {
                ShadowBrush.Opacity = 0.25f;
                ShadowBrush.DrawRectangle(x + ProcRuleCalculator.StandardIconSize, y, w + Gap * 2 + BorderBrush.StrokeWidth, active * (ProcRuleCalculator.StandardIconSize + Gap) - Gap);
            }

            //draw countdowns
            foreach (KeyValuePair <uint, ProcInfo> entry in ActiveSnapshots)
            {
                //render the proc snapshot if it is not expired
                ProcInfo snapshot = entry.Value;
                float    timeLeft = (float)(snapshot.FinishTick - Hud.Game.CurrentGameTick) / 60f;              //seconds
                float    w2       = (float)(timeLeft * w / snapshot.Duration);
                float    opacity  = (timeLeft >= 1 || (timeLeft < 1 && (Hud.Game.CurrentRealTimeMilliseconds / 200) % 2 == 0) ? 0.9f : 0.2f);

                snapshot.Texture.Draw(x, y, ProcRuleCalculator.StandardIconSize, ProcRuleCalculator.StandardIconSize, opacity);                 //draw custom icon
                BorderBrush.DrawRectangle(x + 1, y + 1, ProcRuleCalculator.StandardIconSize - 2, ProcRuleCalculator.StandardIconSize - 2);      //draw custom border

                float x2 = x + ProcRuleCalculator.StandardIconSize + Gap + BorderBrush.StrokeWidth;
                float y2 = y + ProcRuleCalculator.StandardIconSize * 0.5f - h * 0.5f;

                ShadowBrush.Opacity = 0.25f;
                ShadowBrush.DrawRectangle(x2 - 4, y2 - 4, w + 8, h + 8);

                IBrush brush;
                if (!ProcBrush.TryGetValue(snapshot.PlayerClass, out brush))
                {
                    brush = ProcBrushDefault;
                }

                brush.DrawRectangle(x2, y2, w2, h);
                BorderBrush.DrawRectangle(x2 - 2, y2 - 2, w + 4, h + 4);

                //draw countdown text
                TextLayout layout = TimeLeftFont.GetTextLayout(timeLeft.ToString(timeLeft > 1 ? "F0" : "F1"));
                TimeLeftFont.DrawText(layout, x2 + w * 0.5f - layout.Metrics.Width * 0.5f, y2 + h * 0.5f - layout.Metrics.Height * 0.5f);

                //draw player name
                layout = PlayerFont.GetTextLayout(snapshot.PlayerName);
                PlayerFont.DrawText(layout, x - layout.Metrics.Width - Gap, y + ProcRuleCalculator.StandardIconSize * 0.5f - layout.Metrics.Height * 0.5f);

                y += ProcRuleCalculator.StandardIconSize + Gap;
            }             //end foreach
        } //end PaintTopInGame