void UpdateProDrums(float time, HitWindow <DrumsNoteHitKnowledge> hitWindow, uint noteStreak, LaneInfo laneInfo)
    {
        DrumsNoteHitKnowledge nextNoteToHit = hitWindow.oldestUnhitNote;
        int tomsInputMask    = DrumsInput.GetProDrumsTomPressedInputMask(laneInfo);
        int cymbalsInputMask = DrumsInput.GetProDrumsCymbalPressedInputMask(laneInfo);

        if (nextNoteToHit != null)
        {
            // process toms
            bool tomsHitSuccess = false;
            {
                int tomsNoteMask = nextNoteToHit.note.GetMaskWithRequiredFlags(Note.Flags.None);
                DrumsNoteHitKnowledge.InputTiming tomsHitTimingTracker = nextNoteToHit.standardPadTiming;
                tomsHitSuccess = ShouldHitAndProcessMiss(laneInfo, time, tomsInputMask, tomsNoteMask, tomsHitTimingTracker);
            }

            // process cymbals
            bool cymbalsHitSuccess = false;
            {
                int cymbalsNoteMask = nextNoteToHit.note.GetMaskWithRequiredFlags(Note.Flags.ProDrums_Cymbal);
                DrumsNoteHitKnowledge.InputTiming cymbalsHitTimingTracker = nextNoteToHit.cymbalPadTiming;
                cymbalsHitSuccess = ShouldHitAndProcessMiss(laneInfo, time, cymbalsInputMask, cymbalsNoteMask, cymbalsHitTimingTracker);
            }

            if (tomsHitSuccess && cymbalsHitSuccess)
            {
                HitNote(time, nextNoteToHit);
            }
        }
        else if (tomsInputMask != 0 || cymbalsInputMask != 0)
        {
            Debug.Log("Missed due to hitting pad when there was no hit in window");
            MissNote(time, MissSubType.Overhit);
        }
    }
Пример #2
0
    protected int UpdateWindowExit <TNoteHitKnowledge>(float time, HitWindow <TNoteHitKnowledge> hitWindow) where TNoteHitKnowledge : NoteHitKnowledge
    {
        uint noteStreak = stats.noteStreak;
        int  missCount  = 0;

        {
            var notesRemoved = hitWindow.DetectExit(time);

            foreach (var noteKnowledge in notesRemoved)
            {
                // Miss, exited window
                if (!noteKnowledge.hasBeenHit)
                {
                    foreach (Note chordNote in noteKnowledge.note.chord)
                    {
                        chordNote.controller.sustainBroken = true;

                        if (noteStreak > 0)
                        {
                            chordNote.controller.DeactivateNote();
                        }
                    }

                    ++missCount;
                }
            }
        }

        return(missCount);
    }
Пример #3
0
    void UpdateNoteKnowledge(float time, HitWindow <GuitarNoteHitKnowledge> hitWindow, int inputMask, bool strummed, uint noteStreak, GuitarNoteHitKnowledge nextNoteToHit, GuitarSustainHitKnowledge sustainKnowledge)
    {
        // Check if it's valid to query the last hit note
        if (noteStreak <= 0 || lastNoteHit == null || !hitWindow.IsWithinTimeWindow(lastNoteHit.note, nextNoteToHit != null ? nextNoteToHit.note : null, time))
        {
            lastNoteHit = null;
        }

        if (nextNoteToHit != null && noteStreak > 0)    // None of this knowledge should be used for recovery
        {
            if (nextNoteToHit.strumCounter > 1)
            {
                nextNoteToHit.strumCounter = 1;     // Make this still valid to hit because it's still in the hit window for a reason
            }
            // Fill out note knowledge
            if (GameplayInputFunctions.ValidateFrets(nextNoteToHit.note, inputMask, noteStreak, sustainKnowledge.extendedSustainsMask))
            {
                nextNoteToHit.fretValidationTime = time;
            }
            else
            {
                nextNoteToHit.lastestFretInvalidationTime = time;
            }

            if (GameplayInputFunctions.ValidateStrum(nextNoteToHit.note, canTap, strummed, noteStreak))
            {
                nextNoteToHit.strumValidationTime = time;
            }
            else
            {
                nextNoteToHit.lastestStrumInvalidationTime = time;
            }

            if (strummed)
            {
                if (lastNoteHit != null && lastNoteHit.strumCounter <= 0)// lastNoteHit.note.type != Note.Note_Type.Strum)
                {
                    ++lastNoteHit.strumCounter;
                }
                else
                {
                    ++nextNoteToHit.strumCounter;
                }
            }
        }
    }
    public void Update(float time, HitWindow <DrumsNoteHitKnowledge> hitWindow, uint noteStreak, LaneInfo laneInfo)
    {
        switch (GameSettings.drumsModeOptions)
        {
        case GameSettings.DrumModeOptions.ProDrums:
        {
            UpdateProDrums(time, hitWindow, noteStreak, laneInfo);
            break;
        }

        default:
        {
            UpdateStandardDrums(time, hitWindow, noteStreak, laneInfo);
            break;
        }
        }
    }
    public void Update(float time, HitWindow <DrumsNoteHitKnowledge> hitWindow, GamepadInput drumsInput)
    {
        uint     noteStreak = stats.noteStreak;
        int      missCount  = UpdateWindowExit(time, hitWindow);
        LaneInfo laneInfo   = ChartEditor.Instance.laneInfo;

        for (int i = 0; i < missCount; ++i)
        {
            if (noteStreak > 0)
            {
                Debug.Log("Missed due to note falling out of window");
            }

            MissNote(time, DrumsNoteHitAndMissDetect.MissSubType.NoteMiss, null);
        }

        hitAndMissNoteDetect.Update(time, hitWindow, drumsInput, stats.noteStreak, laneInfo);
    }
Пример #6
0
    // Update is called once per frame
    public void Update(float time, HitWindow <GuitarNoteHitKnowledge> hitWindow)
    {
        int missCount = UpdateWindowExit(time, hitWindow);

        for (int i = 0; i < missCount; ++i)
        {
            if (stats.noteStreak > 0)
            {
                Debug.Log("Missed due to note falling out of window");
            }

            MissNote(time, GuitarNoteHitAndMissDetect.MissSubType.NoteMiss, null);
        }

        guitarSustainHitKnowledge.Update(time);
        sustainBreakDetect.Update(time, guitarSustainHitKnowledge, stats.noteStreak);
        hitAndMissNoteDetect.Update(time, hitWindow, stats.noteStreak, guitarSustainHitKnowledge);
    }
Пример #7
0
    void PreserveStreakDetect(float time, HitWindow <GuitarNoteHitKnowledge> hitWindow, bool strummed, uint noteStreak, GuitarNoteHitKnowledge nextNoteToHit, int inputMask)
    {
        if (nextNoteToHit.strumCounter > 1)
        {
            MissNote(time, MissSubType.Overstrum);
            Debug.Log("Missed note due to double strumming on a single note");
        }
        else if (nextNoteToHit.fretsValidated && nextNoteToHit.strumValidated && Mathf.Abs(nextNoteToHit.fretValidationTime - nextNoteToHit.strumValidationTime) <= GuitarTiming.slopBufferTime)
        {
            HitNote(time, nextNoteToHit);
        }
        else if (nextNoteToHit.strumValidated && Mathf.Abs(time - nextNoteToHit.strumValidationTime) > GuitarTiming.slopBufferTime && nextNoteToHit.strumCounter > 0)
        {
            MissNote(time, MissSubType.Overstrum);
            Debug.Log("Missed note due to strum expiration");

            nextNoteToHit.strumValidationTime = GuitarNoteHitKnowledge.NULL_TIME;
        }
    }
    public void Update(float time, HitWindow <GuitarNoteHitKnowledge> hitWindow, uint noteStreak, GuitarSustainHitKnowledge sustainKnowledge)
    {
        // Capture input
        bool strum     = GuitarInput.GetStrumInput();
        int  inputMask = GuitarInput.GetFretInputMask();

        if (inputMask != previousInputMask)
        {
            canTap = true;
        }

        if (strum)
        {
            WriteInputToChart(time, inputMask);
        }

        // What note is the player trying to hit next?
        GuitarNoteHitKnowledge nextNoteToHit = hitWindow.oldestUnhitNote;

        UpdateNoteKnowledge(time, hitWindow, inputMask, strum, noteStreak, nextNoteToHit, sustainKnowledge);

        if (nextNoteToHit != null)
        {
            Note nextSeperate = nextNoteToHit.note.nextSeperateNote;

            if (noteStreak > 0)
            {
                PreserveStreakDetect(time, hitWindow, strum, noteStreak, nextNoteToHit, inputMask);
            }
            else
            {
                RecoveryDetect(time, hitWindow, inputMask, strum, noteStreak);
            }
        }
        // No note in window
        else
        {
            BlankWindowDetect(time, strum);
        }

        previousInputMask = inputMask;
    }
    public void Update(float time, HitWindow <NoteHitKnowledge> hitWindow)
    {
        NoteHitKnowledge nextNoteToHit = hitWindow.oldestUnhitNote;

        if (nextNoteToHit != null)
        {
            NoteController nCon = nextNoteToHit.note.controller;
            if (nCon != null)
            {
                Vector3 notePosition       = nCon.transform.position;
                Vector3 strikelinePosition = ChartEditor.Instance.visibleStrikeline.position;

                bool belowStrikeLine = notePosition.y <= strikelinePosition.y + (Time.deltaTime * GameSettings.hyperspeed / GameSettings.gameSpeed);
                if (belowStrikeLine)
                {
                    HitNote(time, nextNoteToHit);
                }
            }
        }
    }
    public void Update(float time, HitWindow <NoteHitKnowledge> hitWindow)
    {
        NoteHitKnowledge nextNoteToHit = hitWindow.oldestUnhitNote;

        while (nextNoteToHit != null)   // The bot is allowed to hit more than 1 note per frame
        {
            NoteController nCon = nextNoteToHit.note.controller;
            if (nCon != null)
            {
                Vector3 notePosition       = nCon.transform.position;
                Vector3 strikelinePosition = ChartEditor.Instance.visibleStrikeline.position;

                float visualOffset    = Time.deltaTime / Globals.gameSettings.hyperspeed * Globals.gameSettings.gameSpeed;  // We want to hit it just before it crosses the strikeline. Looks a bit better.
                bool  belowStrikeLine = notePosition.y <= strikelinePosition.y + visualOffset;
                if (belowStrikeLine)
                {
                    HitNote(time, nextNoteToHit);
                    nextNoteToHit = hitWindow.oldestUnhitNote;
                }
                else
                {
                    nextNoteToHit = null;
                }
            }
        }

        // Note that having this logic here essentially gives the bot an infinite backend window in case of a framerate hiccup.
        int missCount = UpdateWindowExit(time, hitWindow);

        for (int i = 0; i < missCount; ++i)
        {
            if (stats.noteStreak > 0)
            {
                Debug.Log("Bot missed due to note falling out of window. There may be more notes in the window thatn the framerate can handle");
            }

            MissNote(time, GuitarNoteHitAndMissDetect.MissSubType.NoteMiss, null);
        }
    }
    void UpdateStandardDrums(float time, HitWindow <DrumsNoteHitKnowledge> hitWindow, uint noteStreak, LaneInfo laneInfo)
    {
        DrumsNoteHitKnowledge nextNoteToHit = hitWindow.oldestUnhitNote;
        int inputMask = DrumsInput.GetPadPressedInputMask(laneInfo);

        if (nextNoteToHit != null)
        {
            int noteMask = nextNoteToHit.note.mask;
            DrumsNoteHitKnowledge.InputTiming hitTimingTracker = nextNoteToHit.standardPadTiming;
            bool standardPadSuccess = ShouldHitAndProcessMiss(laneInfo, time, inputMask, noteMask, hitTimingTracker);

            if (standardPadSuccess)
            {
                HitNote(time, nextNoteToHit);
            }
        }
        else if (inputMask != 0)
        {
            Debug.Log("Missed due to hitting pad when there was no hit in window");
            MissNote(time, MissSubType.Overhit);
        }
    }
Пример #12
0
    void RecoveryDetect(float time, HitWindow <GuitarNoteHitKnowledge> hitWindow, int fretInputMask, bool strummed, uint noteStreak)
    {
        var noteKnowledgeList = hitWindow.noteKnowledgeQueue;

        // Search to see if user is hitting a note ahead
        List <GuitarNoteHitKnowledge> validatedNotes = new List <GuitarNoteHitKnowledge>();

        foreach (GuitarNoteHitKnowledge noteKnowledge in noteKnowledgeList)
        {
            // Collect all notes the user is possibly hitting
            if (
                GameplayInputFunctions.ValidateFrets(noteKnowledge.note, fretInputMask, noteStreak) &&
                GameplayInputFunctions.ValidateStrum(noteKnowledge.note, canTap, strummed, noteStreak)
                )
            {
                validatedNotes.Add(noteKnowledge);
            }
        }

        if (validatedNotes.Count > 0)
        {
            // Recovery algorithm
            // Select the note closest to the strikeline
            float aimYPos = ChartEditor.Instance.visibleStrikeline.transform.position.y + 0.25f;  // Added offset from the note controller

            GuitarNoteHitKnowledge selectedNote = validatedNotes[0];

            float dis = -1;

            foreach (GuitarNoteHitKnowledge validatedNote in validatedNotes)
            {
                if (!selectedNote.note.controller)
                {
                    return;
                }

                NoteController noteController = selectedNote.note.controller;

                float distance = Mathf.Abs(aimYPos - noteController.transform.position.y);
                if (distance < dis || dis < 0)
                {
                    selectedNote = validatedNote;
                    dis          = distance;
                }
            }

            int index = noteKnowledgeList.IndexOf(selectedNote);
            GuitarNoteHitKnowledge note = noteKnowledgeList[index];

            // Recovery missed notes
            if (index > 0)
            {
                Debug.Log("Missed notes when performing recovery. Notes skipped = " + index);
            }

            for (int missedCounter = 0; missedCounter < index; ++missedCounter)
            {
                MissNote(time, MissSubType.NoteMiss, noteKnowledgeList[missedCounter]);
            }

            HitNote(time, note);

            // We fill out our own knowledge
            note.fretValidationTime  = time;
            note.strumValidationTime = time;
            if (strummed)
            {
                ++note.strumCounter;
            }
        }
        else if (strummed)
        {
            MissNote(time, MissSubType.Overstrum);
            Debug.Log("Missed due to strumming when there were no notes to strum during recovery");
        }
    }
Пример #13
0
    public void Update(float time, HitWindow <DrumsNoteHitKnowledge> hitWindow, uint noteStreak, LaneInfo laneInfo)
    {
        DrumsNoteHitKnowledge nextNoteToHit = hitWindow.oldestUnhitNote;
        int inputMask = DrumsInput.GetPadPressedInputMask(laneInfo);

        if (nextNoteToHit != null)
        {
            int noteMask = nextNoteToHit.note.mask;
            int laneMask = laneInfo.laneMask;

            // Cull notes from the notemask by lanes that are being used
            foreach (Note.DrumPad pad in EnumX <Note.DrumPad> .Values)
            {
                if (pad == Note.DrumPad.Kick)
                {
                    continue;
                }

                int padBitInput = (int)pad;
                int padMask     = 1 << padBitInput;

                bool includeLane = (padMask & laneMask) != 0;
                if (!includeLane)
                {
                    noteMask &= ~padMask;
                }
            }

            bool badHit = false;

            if ((inputMask | noteMask) != noteMask)
            {
                badHit = true;
            }
            else
            {
                foreach (Note.DrumPad drumPad in EnumX <Note.DrumPad> .Values)
                {
                    bool hitPad = DrumsInput.GetPadPressedInput(drumPad, laneInfo);
                    if (hitPad)
                    {
                        if (nextNoteToHit.GetHitTime(drumPad) == NoteHitKnowledge.NULL_TIME)
                        {
                            nextNoteToHit.SetHitTime(drumPad, time);
                        }
                        else
                        {
                            badHit = true;
                        }
                    }
                }
            }

            if (badHit)
            {
                // Bad input
                Debug.Log("Missed due to bad input");
                MissNote(time, MissSubType.Overhit);

                foreach (Note.DrumPad drumPad in EnumX <Note.DrumPad> .Values)
                {
                    nextNoteToHit.SetHitTime(drumPad, NoteHitKnowledge.NULL_TIME);
                }
            }
            else
            {
                float min = float.MaxValue, max = float.MinValue;
                int   totalHitsMask = 0;

                foreach (Note.DrumPad drumPad in EnumX <Note.DrumPad> .Values)
                {
                    if (nextNoteToHit.GetHitTime(drumPad) != NoteHitKnowledge.NULL_TIME)
                    {
                        float hitTime = nextNoteToHit.GetHitTime(drumPad);
                        min = Mathf.Min(min, hitTime);
                        max = Mathf.Max(max, hitTime);

                        totalHitsMask |= 1 << (int)drumPad;
                    }
                }

                float totalSlop = max - min;

                if (min != float.MaxValue && time - min > DrumsTiming.slopBufferTime)
                {
                    // Technically an underhit
                    Debug.Log("Missed due to underhit");
                    MissNote(time, MissSubType.Overhit);
                }
                else if (totalHitsMask == noteMask && totalSlop < DrumsTiming.slopBufferTime)
                {
                    HitNote(time, nextNoteToHit);
                }
            }
        }
        else if (inputMask != 0)
        {
            Debug.Log("Missed due to hitting pad when there was no hit in window");
            MissNote(time, MissSubType.Overhit);
        }
    }