Coder Social home page Coder Social logo

wow-apl-search's Introduction

WoW-APL-Search

Searches through the space of Action Priority Lists to find the best one.

Code Structure

Main is in sc_main.cpp as basically just

sim_t sim;
sim.main( io::utf8_args( argc, argv ) );

And sim_t is in sim.hpp (which is a child of sc_thread_t, basically just so it can run()).

sim_t::main() does some bookkeeping and reporting, then calls simt_t::execute(), which is in sim.cpp:

bool success = false;
{
  auto merge_final_action = gsl::finally([&](){ merge(); }); // Always merge, even in cases of unsuccessful simulation!
  partition();
  success = iterate();
}
return success;

sim_t::partition() allocates work iterations (work_queue -> size()) amongst threads via children.push_back( new sim_t( this, i + 1, child_control ) )

sim_t::execute() calls sim_t::iterate(), which is basically

init();
activate_actors();

do
{
  ++current_iteration;
  ++work_done;
  combat();
  // Progress bar
  do_pause();
  if ( ! canceled )
  {
    current_index = work_queue -> pop();
    more_work = work_queue -> more_work();
    if ( more_work && current_index != old_active )
    {
      // Work indices, etc. for updating Progress Bar
      activate_actors();
    }
  }
} while ( more_work && ! canceled );

And here's sim_t::init():

const auto start_time = chrono::wall_clock::now();

event_mgr.init();

// Seed RNG

// Set lag_stddev values

// Challenge mode or scaling item level

// set scaling metric

// Make the buffs (on `auras`) arcane_intellect, battle_shout, mark_of_the_wild, and power_word_fortitude

// Find Already defined target, otherwise create a new one.

// create additional enemies here

// Determine whether we have healers or tanks.

raid_event_t::init( this );

init_actors();

simulation_length.reserve( std::min( iterations, 10000 ) );

// For each actor in actor_list, call init_finished()

// If save= option is used, don't bother initializing profilesets

And here's sim_t::activate_actors():

// Call reset_callbacks() on lots of lists

if ( ! single_actor_batch ) {
  range::for_each( player_list, []( player_t* p ) { p -> activate(); } );
}
// Single-actor batch mode activates the current active actor
else
{
  range::for_each( target_list, []( player_t* t ) { t -> actor_changed(); } );

  // Deactivate old actor
  if ( current_index > 0 )
  {
    player_no_pet_list[ current_index - 1 ] -> deactivate();
  }

  // Activate new actor
  player_no_pet_list[ current_index ] -> activate();
  if ( ! profileset_enabled )
  {
    progress_bar.set_phase( player_no_pet_list[ current_index ] -> name_str );
  }
}

Events

struct event_t is in event.hpp.

Combat

So the next interesting function is sim_t::combat() which is just

combat_begin();
event_mgr.execute();
combat_end();

sim_t::combat_begin() is like this:

// Debug stuff

reset();

iteration_dmg = priority_iteration_dmg = iteration_heal = 0;
datacollection_begin();
for ( auto& target : target_list ) target -> combat_begin();

// Override arcane_intellect, battle_shout, mark_of_the_wild, and power_word_fortitude

// Call combat_begin() on each module_t in module_t::get( i ) for i PLAYER_NONE to PLAYER_MAX

// Call combat_begin() on each player_t in player_list, player_no_pet_list, and their pets

// If required, call make_event() for regen_event_t, bloodlust_check_t, sim_end_event_t, and sim_safeguard_end_event_t

raid_event_t::combat_begin( this );

Event Manager

The event_manager_t struct definition is in event_manager.hpp. It has:

  • std::vector<event_t*> timing_wheel

Moreover, event_manager_t::execute() is like this:

unsigned n_events = 0U;

while ( event_t* e = next_event() )
{
  if ( e->time == current_time ) {
    if ( ++n_events == MAX_EVENTS ) {
      cancel_stuck();
    }
  } else {
    n_events = 0U;
  }

  current_time = e->time;

  if ( e->reschedule_time > e->time ) {
    reschedule_event( e ); continue;
  } else {
    // Optionally monitor CPU of the event
    e->execute();
  }

  recycle_event( e );
}

return true;

And here is event_manager_t::next_event():

  if ( events_remaining == 0 )
    return nullptr;

  while ( true )
  {
    event_t*& event_list = timing_wheel[ timing_slice ];
    if ( event_list )
    {
      event_t* e = event_list;
      event_list = e->next;
      events_remaining--;
      events_processed++;
      return e;
    }

    timing_slice++;
    if ( timing_slice == timing_wheel.size() )
    {
      timing_slice = 0;
      // Time Wheel turns around.
    }
  }

  return nullptr;

sim_t::sim_t() constructs event_mgr( this ), and sim_t::init() calls event_mgr.init(). event_manager_t::event_manager_t() is basic and non-interesting. On the other hand, event_manager_t::init is slightly more interesting:

<<<<<<< HEAD
// Set wheel_seconds to 1024 and wheel_granularity to 32

wheel_time = timespan_t::from_seconds( wheel_seconds );

// Only valid for integer based timespan_t
=======
// Conditionally set wheel_seconds to 1024 and wheel_granularity to 32

wheel_time = timespan_t::from_seconds( wheel_seconds );

>>>>>>> 86fc4c5809e8bee4592976a895fa39ab20952b8b
wheel_size = ( uint32_t )( wheel_time.total_millis() >> wheel_shift );

// Round up the wheel depth to the nearest power of 2 to enable a fast "mod"
// operation.
for ( wheel_mask = 2; wheel_mask < wheel_size; wheel_mask *= 2 )
{
  continue;
}
wheel_size = wheel_mask;
wheel_mask--;

// The timing wheel represents an array of event lists: Each time slice has an
// event list.
timing_wheel.resize( wheel_size );

APL Codegen (.simc --> .cpp)

APLs are typically written in human-readable form (TCI, aka TextualConfigurationInterface ), usually in files with the .simc extension. For example, T29_Death_Knight_Unholy.simc:

deathknight="T29_Death_Knight_Unholy"
source=default
spec=unholy
# ...

# Default consumables
potion=elemental_potion_of_ultimate_power_3
# ...

# Executed before combat begins. Accepts non-harmful actions only.
actions.precombat=flask
# ...

# Executed every time the actor is available.
actions=auto_attack

# Also do actions.aoe, actions.cooldowns, actions.generic, actions.opener, actions.racials, actions.trinkets

head=maw_of_the_haunted_frostbrood,id=200408,bonus_id=4800/4786/1498/6935,gem_id=192985
# ...

# Gear Summary
# gear_ilvl=422.20
# gear_strength=5445
# ...

simc is converted into cpp code via ConvertAPL.py

For example, apl_death_knight.cpp:

// Headers

namespace death_knight_apl {

std::string potion( const player_t* p )
{
  // ...
}

//blood_apl_start
void blood( player_t* p )
{
  action_priority_list_t* default_ = p->get_action_priority_list( "default" );
  // ...

  precombat->add_action( "flask" );

  // Also add actions to default_, drw_up, racials, standard, trinkets
}
//blood_apl_end

//frost_apl_start

// ...

}  // namespace death_knight_apl

The C++ code is what's actually used by the simuation.

<<<<<<< HEAD

SIMC Generation

TL;DR

  1. The class-based .simc files in profiles/generators/Tier29 are basically just lists of gear and talents
  2. The generators/Tier29/T29_Generate.simc file "includes" all of the other class-based .simc files in profiles/generators/Tier29
  3. The profiles/Tier29 .simc files are generated by running the simc executable on generators/Tier29/T29_Generate.simc

=======

SIMC Generation

86fc4c5809e8bee4592976a895fa39ab20952b8b The .simc file that's converted to C++ code is, itself, codegen'd.

There is one file per class in profiles/generators/Tier29/ that has one section like this per spec (basically just metadata and gear), e.g. T29_Generate_Death_Knight.simc:

deathknight="T29_Death_Knight_Blood"
level=70
# etc.

head=maw_of_the_haunted_frostbrood,id=200408,bonus_id=4800/4786/1498/1808,gem_id=192925
# etc.

save=T29_Death_Knight_Blood.simc

There is also a special .simc file T29_Generate.simc that just includes every profile in the folder, e.g.

# ...

# Death Knight
T29_Generate_Death_Knight.simc

# ...

That file is fed into the simc executable in the shell script generate_profiles.sh, which boils down to

SIMC=${SIMC:-../../engine/simc}
# ...
for tier in 29
do
  PROFDIR="Tier$tier"
  echo "---$PROFDIR---"
  if [ ! -d $PROFDIR ]; then
    echo "Skipped $PROFDIR, directory not found."
    continue
  fi
  cd $PROFDIR/
  ${SIMC} '../generators/Tier'$tier'/T'$tier'_Generate.simc'
  cd ../
done

So that command is really

simc ../generators/Tier29/T29_Generate.simc

That generates all of the .simc files in the engine folder. I'm assuming that they're then moved over to the profiles/Tier29 folder.

Project Info

Python version 3.7.4.

wow-apl-search's People

Contributors

lucasmolander avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.