Advertisement
Guest User

C&CRemasterHarvesterOptimization

a guest
Sep 21st, 2020
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.25 KB | None | 0 0
  1. BuildingClass* UnitClass::Find_Best_Refinery(void) const
  2. {
  3.     /*
  4.     Warning for anyone messing around with this:
  5.     Distance() is ambiguously overloaded -- be careful which verison you're using!
  6.     If the inputs are CELLs, then the output is in terms of cells, but
  7.     If the inputs are COORDINATEs, OBJECTSs, or TARGETs, then the output is in terms of leptons
  8.     (Leptons are 1/256 of a CELL)
  9.     (Also, the CELL version of Distance() uses 1.5 for diagonal distance instead of sqrt(2); should maybe improve that someday...)
  10.     */
  11.    
  12.     static DynamicVectorClass<RefineryData> _refineries;
  13.    
  14.     _refineries.Clear();
  15.     if (ActiveCFEPatchConfig.EnableASPathing){
  16.         for (int i = 0; i < Buildings.Count(); ++i) {
  17.             BuildingClass* refinery = Buildings.Ptr(i);
  18.             if (refinery != NULL &&
  19.                 refinery->House == House &&
  20.                 !refinery->IsInLimbo &&
  21.                 *refinery == STRUCT_REFINERY) {
  22.                     int astar_result = Find_Path_AStar(nullptr, Coord_Cell(Coord), Coord_Cell(refinery->Center_Coord()), 1, MOVE_NO, -1);
  23.                     if (astar_result){
  24.                         _refineries.Add(RefineryData{ refinery, astar_result, 0 });
  25.                     }
  26.                     // A-Star may return zero when you're already right next to the refinery, or because there's no path at all
  27.                     // In the former case, fall back to crow-flies distance
  28.                     // In the latter case, don't add the refinery to the list
  29.                     else{
  30.                         int crowflies_result = Distance(Coord_Cell(refinery->Center_Coord()));
  31.                         if (crowflies_result <= 6){
  32.                             _refineries.Add(RefineryData{ refinery, crowflies_result, 0 });
  33.                         }
  34.                         //else{
  35.                         //    CFE_Debug_Printf("Omitted a refinery! Unreachable?\n");
  36.                         //}
  37.                     }
  38.             }
  39.         }
  40.     }
  41.     else{
  42.         for (int i = 0; i < Buildings.Count(); ++i) {
  43.             BuildingClass* refinery = Buildings.Ptr(i);
  44.             if (refinery != NULL &&
  45.                 refinery->House == House &&
  46.                 !refinery->IsInLimbo &&
  47.                 *refinery == STRUCT_REFINERY) {
  48.                     _refineries.Add(RefineryData{ refinery, Distance(refinery), 0 });
  49.             }
  50.         }
  51.     }
  52.  
  53.     // Base case for zero or one refineries.
  54.     if (_refineries.Count() == 0) {
  55.         return NULL;
  56.     } else if (_refineries.Count() == 1) {
  57.         return _refineries[0].Refinery;
  58.     }
  59.  
  60.     // Count harvesters going to each refinery as well as the total.
  61.     int num_harvesters = 0;
  62.     for (int i = 0; i < Units.Count(); ++i) {
  63.         UnitClass* unit = Units.Ptr(i);
  64.         if (unit->IsActive && unit->Class->IsToHarvest && unit->House == House) {
  65.             BuildingClass* refinery = unit->Tiberium_Unload_Refinery();
  66.             if (refinery != NULL) {
  67.                 int index = _refineries.ID(RefineryData{ refinery });
  68.                 //assert(index >= 0); // Chthon CFE NOTE: Bad! _refineries may not be an exhaustive list because you might have refinieries in multiple zones in RA and/or A-Star may have failed to find paths for some refineries.
  69.                 if (index >= 0){
  70.                      // if queue jumping is enabled, don't count other harvies that are further away b/c you will jump them
  71.                      if (ActiveCFEPatchConfig.EnableHarvyOptimize && ActiveCFEPatchConfig.EnableHarvyQueueJump){
  72.                          int other_harvy_distance;
  73.                          int jumpcutoff;
  74.                          if (ActiveCFEPatchConfig.EnableASPathing){
  75.                              jumpcutoff = ActiveCFEPatchConfig.HarvyQueueJumpCutoff;
  76.                              int other_harvy_distance_astar = unit->Find_Path_AStar(nullptr, Coord_Cell(unit->Coord),  Coord_Cell(refinery->Center_Coord()), 1, MOVE_NO, -1);
  77.                              if (other_harvy_distance_astar){
  78.                                 other_harvy_distance = other_harvy_distance_astar;
  79.                             }
  80.                             // again, A-Star might have returned zero if other harvy is already right by the refinery
  81.                             else {
  82.                                 int other_harvy_distance_astar_crowflies = unit->Distance(Coord_Cell(refinery->Center_Coord()));
  83.                                 if (other_harvy_distance_astar_crowflies <= 6){
  84.                                     other_harvy_distance = other_harvy_distance_astar_crowflies;
  85.                                 }
  86.                                 else{
  87.                                     other_harvy_distance = INT_MAX; //unreachable
  88.                                 }
  89.                             }
  90.                          }
  91.                          // not using A-Star
  92.                          else{
  93.                             jumpcutoff = Cell_To_Lepton(ActiveCFEPatchConfig.HarvyQueueJumpCutoff);
  94.                             other_harvy_distance = unit->Distance(refinery);
  95.                         }
  96.                         if ((_refineries[index].Distance < other_harvy_distance) && (other_harvy_distance > jumpcutoff)){
  97.                             //CFE_Debug_Printf("Expect to jump!\n");
  98.                             continue;
  99.                         }
  100.                     } // end of queue jumping jiggery pokery
  101.                     _refineries[index].Harvesters++;
  102.                     num_harvesters++;
  103.                 }
  104.             }
  105.         }
  106.     }
  107.  
  108.     // Increase distance to account for wait times for other harvies to unload
  109.     // To prevent thrashing, use a lower penalty if you're already very close to the refinery
  110.     if (ActiveCFEPatchConfig.EnableHarvyOptimize){
  111.         int queuedunloadpenalty;
  112.         int thrashingcutoff;
  113.         // If A-Star was used, the stored distances should be in CELL units; otherwise they'll be in lepton units
  114.         if (ActiveCFEPatchConfig.EnableASPathing){
  115.             queuedunloadpenalty = ActiveCFEPatchConfig.HarvyOptimizeUnloadWaitWeight;
  116.             thrashingcutoff = ActiveCFEPatchConfig.HarvyOptimizeThrashingCutoff;
  117.         }
  118.         else {
  119.             queuedunloadpenalty = Cell_To_Lepton(ActiveCFEPatchConfig.HarvyOptimizeUnloadWaitWeight);
  120.             thrashingcutoff = Cell_To_Lepton(ActiveCFEPatchConfig.HarvyOptimizeThrashingCutoff);
  121.         }
  122.         int thrashingpenalty = (queuedunloadpenalty * ActiveCFEPatchConfig.HarvyOptimizeThrashingNumerator) / ActiveCFEPatchConfig.HarvyOptimizeThrashingDenominator;
  123.         for (int i = 0; i < _refineries.Count(); ++i) {
  124.             //CFE_Debug_Printf("Refinery %i distance is %i.\n", i,  _refineries[i].Distance);
  125.             if (_refineries[i].Distance < thrashingcutoff){
  126.                 _refineries[i].Distance += (_refineries[i].Harvesters * thrashingpenalty);
  127.             }
  128.             else{
  129.                 _refineries[i].Distance += (_refineries[i].Harvesters * queuedunloadpenalty);
  130.             }
  131.             // don't do this -- doesn't look like TiberiumUnloadRefinery is cleared until after it leaves
  132.             //if (_refineries[i].ID->Is_Something_Attached()){
  133.             //        _refineries[i].Distance += (queuedunloadpenalty/2); // on average an already-docked harvy has half a load to go.
  134.             //}
  135.             //CFE_Debug_Printf("Refinery %i adjusted distance is %i.\n", i,  _refineries[i].Distance);
  136.         }
  137.     }
  138.    
  139.     // Sort by distance (special case for 2 refineries as that's a single swap).
  140.     if (_refineries.Count() == 2) {
  141.         if (_refineries[0].Distance > _refineries[1].Distance) {
  142.             RefineryData temp = _refineries[0];
  143.             _refineries[0] = _refineries[1];
  144.             _refineries[1] = temp;
  145.         }
  146.     } else {
  147.         qsort(&_refineries[0], _refineries.Count(), sizeof(RefineryData), _refinery_compare);
  148.     }
  149.  
  150.     // Impact of other harvies is now baked into distance values, so just take the lowest
  151.      if (ActiveCFEPatchConfig.EnableHarvyOptimize){
  152.         return _refineries[0].Refinery;
  153.     }
  154.    
  155.     // Evenly distribute harvesters among refineries.
  156.     int harvesters_per_refinery = (num_harvesters + _refineries.Count() - 1) / _refineries.Count();
  157.     for (int i = 0; i < _refineries.Count(); ++i) {
  158.         if (_refineries[i].Harvesters < harvesters_per_refinery) {
  159.             return _refineries[i].Refinery;
  160.         }
  161.     }
  162.  
  163.     // Fall back on closest refinery
  164.     return _refineries[0].Refinery;
  165. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement