void StarSystem::ExecuteUnitAI()
{
    try {
        Unit *unit = NULL;
        for (un_iter iter = getUnitList().createIterator(); (unit = *iter); ++iter) {
            unit->ExecuteAI();
            unit->ResetThreatLevel();
        }
    }
    catch (const boost::python::error_already_set) {
        if ( PyErr_Occurred() ) {
            PyErr_Print();
            PyErr_Clear();
            fflush( stderr );
            fflush( stdout );
        } throw;
    }
}
void StarSystem::UpdateUnitPhysics( bool firstframe )
{
    static bool phytoggle  = true;
    static int  batchcount = SIM_QUEUE_SIZE-1;
    double aitime = 0;
    double phytime = 0;
    double collidetime     = 0;
    double flattentime     = 0;
    double bolttime = 0;
    targetpick   = 0;
    aggfire      = 0;
    numprocessed = 0;
    stats.CheckVitals( this );
    if (phytoggle) {
        for (++batchcount; batchcount > 0; --batchcount) {
            //BELOW COMMENTS ARE NO LONGER IN SYNCH
            //NOTE: Randomization is necessary to preserve scattering - otherwise, whenever a
            //unit goes from low-priority to high-priority and back to low-priority, they
            //get synchronized and start producing peaks.
            //NOTE2: But... randomization must come only on priority changes. Otherwise, it may
            //interfere with subunit scheduling. Luckily, all units that make use of subunit
            //scheduling also require a constant base priority, since otherwise priority changes
            //will wreak havoc with subunit interpolation. Luckily again, we only need
            //randomization on priority changes, so we're fine.
            try {
                Unit *unit = NULL;
                for (un_iter iter = physics_buffer[current_sim_location].createIterator(); (unit = *iter); ++iter) {
                    int priority  = UnitUtil::getPhysicsPriority( unit );
                    //Doing spreading here and only on priority changes, so as to make AI easier
                    int predprior = unit->predicted_priority;
                    //If the priority has really changed (not an initial scattering, because prediction doesn't match)
                    if (priority != predprior) {
                        if (predprior == 0)
                            //Validate snapshot of current interpolated state (this is a reschedule)
                            unit->curr_physical_state = unit->cumulative_transformation;
                        //Save priority value as prediction for next scheduling, but don't overwrite yet.
                        predprior = priority;
                        //Scatter, so as to achieve uniform distribution
                        priority  = 1+( ( (unsigned int) vsrandom.genrand_int32() )%priority );
                    }
                    float backup = SIMULATION_ATOM;
                    theunitcounter   = theunitcounter+1;
                    SIMULATION_ATOM *= priority;
                    unit->sim_atom_multiplier = priority;
                    double aa = queryTime();
                    unit->ExecuteAI();
                    double bb = queryTime();
                    unit->ResetThreatLevel();
                    //FIXME "firstframe"-- assume no more than 2 physics updates per frame.
                    unit->UpdatePhysics( identity_transformation, identity_matrix, Vector( 0,
                                                                                           0,
                                                                                           0 ), priority
                                         == 1 ? firstframe : true, &this->gravitationalUnits(), unit );
                    double cc = queryTime();
                    aitime  += bb-aa;
                    phytime += cc-bb;
                    SIMULATION_ATOM = backup;
                    unit->predicted_priority = predprior;
                }
            }
            catch (const boost::python::error_already_set) {
                if ( PyErr_Occurred() ) {
                    PyErr_Print();
                    PyErr_Clear();
                    fflush( stderr );
                    fflush( stdout );
                } throw;
            }
            double c0  = queryTime();
            Bolt::UpdatePhysics( this );
            double cc  = queryTime();
            last_collisions.clear();
            double fl0 = queryTime();
            collidemap[Unit::UNIT_BOLT]->flatten();
            if (Unit::NUM_COLLIDE_MAPS > 1)
                collidemap[Unit::UNIT_ONLY]->flatten( *collidemap[Unit::UNIT_BOLT] );
            flattentime = queryTime()-fl0;
            Unit *unit;
            for (un_iter iter = physics_buffer[current_sim_location].createIterator(); (unit = *iter);) {
                int   priority = unit->sim_atom_multiplier;
                float backup   = SIMULATION_ATOM;
                SIMULATION_ATOM *= priority;
                unsigned int newloc = (current_sim_location+priority)%SIM_QUEUE_SIZE;
                unit->CollideAll();
                SIMULATION_ATOM = backup;
                if (newloc == current_sim_location)
                    ++iter;
                else
                    iter.moveBefore( physics_buffer[newloc] );
            }
            double dd = queryTime();
            collidetime += dd-cc;
            bolttime    += cc-c0;
            current_sim_location = (current_sim_location+1)%SIM_QUEUE_SIZE;
            ++physicsframecounter;
            totalprocessed += theunitcounter;
            theunitcounter  = 0;
        }
    } else {
        Unit *unit = NULL;
        for (un_iter iter = getUnitList().createIterator(); (unit = *iter); ++iter) {
            unit->ExecuteAI();
            last_collisions.clear();
            unit->UpdatePhysics( identity_transformation, identity_matrix, Vector( 0,
                                                                                   0,
                                                                                   0 ), firstframe,
                                 &this->gravitationalUnits(), unit );
            unit->CollideAll();
        }
    }
}