I wanted to show yall the current logic for the rotation, by far the most complicated one yet.

Even if you don't understand code the logic should be in place.

Let me know if something is glaringly wrong =D

ps, || means logical OR , and && means logical AND.

Code:
//this checks to see if we have a GCD to consume
            if(bs.isGCD())
            {
                //this gets the timings for the time since the last time we cast those attacks.
                lastGL = currEvent.eventTime() - bs.getLastGL();
                lastTwin = currEvent.eventTime() - bs.getLastTwin();
                lastDK = currEvent.eventTime() - myTarget.getLastDK();
                //basically sets the last time we did demo to a million years ago if we're lacking demo (for PB)
                lastDemo = (myTarget.demo()?currEvent.eventTime() - myTarget.getLastDEMO().eventTime():-100000);
                
                //this gets our current GCD (modified by GL stacks)
                currGCD = bs.getGCD();
                
                //this just does PB at the start of the fight
                if(currEvent.eventTime()==0 && !bs.pbCD())
                {
                    bs.addAction(MNKEvent.EventType.PB, myTarget);
                    continue;
                }
                
                //this tells us what we do inside a PB
                if(bs.pb())
                {
                    //setup GL and buffs, first priority during PB
                    if(bs.gl() < 3)
                    {
                        //only Demo during PB only after buffs if we're starting with pb
                        if(!myTarget.demo() && (currEvent.eventTime() > 1000 || bs.bfb() && bs.ir()))
                            bs.addAction(MNKEvent.EventType.DEMO, myTarget);
                        else    //otherwise SP
                            bs.addAction(MNKEvent.EventType.SP, myTarget);
                    }
                    else
                    {
                        //once we have GL3, setup other buffs, prioritizing DK before OPO form runs out
                        if(bs.getLastStance() == MNKSimulator.Stance.OPO && !myTarget.dk())
                            bs.addAction(MNKEvent.EventType.DK, myTarget);
                        else if(!bs.twin())
                            bs.addAction(MNKEvent.EventType.TWIN, myTarget);
                        else    //if we have all buffs, just SP for max damage.
                        {
                            bs.addAction(MNKEvent.EventType.SP, myTarget);
                        }
                    }
                }
                else
                {
                    //do different timings based on stance
                    switch(bs.getLastStance())
                    {
                        //we only have NONE stance if we just came out of PB or we had to leave target
                        case NONE:
                            //basically if we don't have DK, Twin or GL3, or demo, immediately start GL combo
                            if(!myTarget.dk() || lastDemo >= 1800 - currGCD * 2 || lastGL >= 1200 - currGCD*3 || lastTwin >= 1200 - currGCD * 2 || bs.gl() < 3)
                                bs.addAction(MNKEvent.EventType.DK, myTarget);
                            else if(!myTarget.tod())    //otherwise, we have time to ToD
                                bs.addAction(MNKEvent.EventType.TOD, myTarget);
                            else if(!myTarget.fr())     //otherwise, we have time to FR
                                bs.addAction(MNKEvent.EventType.FR, myTarget);
                            else    //otherwise ID filler
                                bs.addAction(MNKEvent.EventType.ID, myTarget);
                            break;
                        case RAPTOR:
                            if(lastTwin >= 1200 - currGCD*3)    //if twin will fall off within next combo
                                bs.addAction(MNKEvent.EventType.TWIN, myTarget);
                            //this tests timings to see whether we have time to filler
                            else if(lastGL < 1200 - currGCD*2 && lastDemo < 1800 - currGCD && lastTwin < 1200 - currGCD && lastDK < 1500 - currGCD*3)
                            {
                                //filler priority is ToD > FR > ID
                                if(!myTarget.tod())
                                    bs.addAction(MNKEvent.EventType.TOD, myTarget);
                                else if(!myTarget.fr())
                                    bs.addAction(MNKEvent.EventType.FR, myTarget);
                                else
                                    bs.addAction(MNKEvent.EventType.ID, myTarget);
                            }
                            else
                                bs.addAction(MNKEvent.EventType.TRUE, myTarget);
                            break;
                        case COEURL:
                            //more timings, demo if it will expire in less than 3 seconds (arbitrary number here)
                            if(!myTarget.demo() || (lastDemo > 1500 && currEvent.numBuffs() > myTarget.getLastDEMO().numBuffs()))
                                bs.addAction(MNKEvent.EventType.DEMO, myTarget);
                            //otherwise SP if DK, GL, or Twin will fall off
                            else if(lastGL >= 1200 - currGCD || lastDK >= 1500 - currGCD*2 || lastTwin >= 1200 - currGCD*3)
                                bs.addAction(MNKEvent.EventType.SP, myTarget);
                            else
                            {
                                //otherwise filler
                                if(!myTarget.tod())
                                    bs.addAction(MNKEvent.EventType.TOD, myTarget);
                                else if(!myTarget.fr())
                                    bs.addAction(MNKEvent.EventType.FR, myTarget);
                                else
                                    bs.addAction(MNKEvent.EventType.ID, myTarget);
                            }
                            break;
                        case OPO:
                            //dk if dk is going to fall off
                            if(!myTarget.dk() || lastDK > 1500 - currGCD*3)
                                bs.addAction(MNKEvent.EventType.DK, myTarget);
                            //if nothing's going to fall off we can filler
                            else if(lastGL < 1200 - currGCD*3 && lastDemo < 1800 - currGCD * 2 && lastTwin < 1200 - currGCD*2 && lastDK < 1500 - currGCD)
                            {
                                if(!myTarget.tod())
                                    bs.addAction(MNKEvent.EventType.TOD, myTarget);
                                else if(!myTarget.fr())
                                    bs.addAction(MNKEvent.EventType.FR, myTarget);
                                else
                                    bs.addAction(MNKEvent.EventType.ID, myTarget);
                            }
                            //if somehow we get here (usually because i've disabled ID filler, we can BS if DK won't fall off
                            else if(myTarget.dk() && lastDK < 1500 - currGCD*3 && myTarget.canBackstab())
                                bs.addAction(MNKEvent.EventType.BS, myTarget);
                            else
                                //if we run out of stuff to do might as well DK to continue rotation
                                bs.addAction(MNKEvent.EventType.DK, myTarget);
                            break;
                    }
                }
            }
            //this checks to see if there is an oGCD slot for an action
            else if(bs.isOGCD())
            {
                //do all OGCD actions here
                //PB if its up, and we are either missing GL stacks or the stance isn't COEURL (so we don't waste a coeurl)
                if(!bs.pbCD() && (bs.gl() < 3 || bs.getLastStance() != MNKSimulator.Stance.COEURL))
                {
                    bs.addAction(MNKEvent.EventType.PB, myTarget);
                }
                //do BfB > IR > HF > Peak > invig cooldowns, too lazy (and not much point) in saving to stack.
                else if(!bs.bfbCD())
                    bs.addAction(MNKEvent.EventType.BFB, myTarget);
                else if(!bs.irCD() && (!myTarget.demo() || lastDemo > 1200))
                    bs.addAction(MNKEvent.EventType.IR, myTarget);
                else if(!bs.hfCD())
                    bs.addAction(MNKEvent.EventType.HF, myTarget);
                else if(!bs.peakCD())
                    bs.addAction(MNKEvent.EventType.PEAK, myTarget);
                else if(bs.getTPBalance() < 540)
                    bs.addAction(MNKEvent.EventType.INVIG, myTarget);
            }