Test Failed
Push — trunk ( 132e87...b3f953 )
by SuperNova.WS
11:54
created

FleetDispatcher::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
ccs 0
cts 3
cp 0
crap 2
1
<?php /** @noinspection PhpUnnecessaryCurlyVarSyntaxInspection */
2
/** @noinspection PhpDeprecationInspection */
3
4
/**
5
 * Created by Gorlum 15.06.2017 4:12
6
 */
7
8
namespace Fleet;
9
10
use Core\Scheduler\Lock;
11
use DBAL\db_mysql;
12
use SN;
13
use debug;
14
use classConfig;
15
use Core\GlobalContainer;
16
use Planet\DBStaticPlanet;
17
18
/**
19
 * Class Fleet\FleetDispatcher
20
 *
21
 */
22
class FleetDispatcher {
23
  const TASK_COMPLETE = 0;
24
  const TASK_TERMINATED = 1;
25
26
  const F_FLEET_EVENT = 'fleet_event';
27
  const F_FLEET_MISSION = 'fleet_mission';
28
  /** @var array[] $fleet_list */
29
  public static $fleet_list = [];
30
  /** @var FleetDispatchEvent[] $fleet_event_list */
31
  public static $fleet_event_list = [];
32
  /** @var int[] $missions_used */
33
  public $missions_used = [];
34
  /**
35
   * @var GlobalContainer $gc
36
   */
37
  protected $gc;
38
39
  /**
40
   * @var classConfig $gameConfig
41
   */
42
  protected $gameConfig;
43
44
  /**
45
   * @var debug $debug
46
   */
47
  protected $debug;
48
49
  public function __construct(GlobalContainer $gc) {
50
    $this->gc = $gc;
51
52
    $this->gameConfig = $gc->config;
53
    $this->debug      = $gc->debug;
54
  }
55
56
  /**
57
   * @deprecated
58
   */
59
  public function dispatch() {
60
    if (
61
      SN::$options[PAGE_OPTION_FLEET_UPDATE_SKIP]
62
      ||
63
      SN::gameIsDisabled()
64
      ||
65
      !$this->getLockOld()
0 ignored issues
show
Deprecated Code introduced by
The function Fleet\FleetDispatcher::getLockOld() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

65
      !/** @scrutinizer ignore-deprecated */ $this->getLockOld()
Loading history...
66
    ) {
67
      return;
68
    }
69
70
    $this->flt_flying_fleet_handler();
71
72
    $this->releaseLock();
73
74
    set_time_limit(60);
75
  }
76
77
78
  /**
79
   * @return bool
80
   * @deprecated
81
   */
82
  protected function getLockOld() {
83
    db_mysql::db_transaction_start();
84
85
    // Watchdog timer
86
    if ($this->gameConfig->db_loadItem('fleet_update_lock')) {
87
//      var_dump($this->gameConfig->db_loadItem('fleet_update_lock'));
88
//      var_dump(SN_TIME_NOW - strtotime($this->gameConfig->fleet_update_lock));
89
//      if (SN_TIME_NOW - strtotime($this->gameConfig->fleet_update_lock) <= mt_rand(90, 120)) {
90
      if (SN_TIME_NOW - strtotime($this->gameConfig->fleet_update_lock) <= mt_rand(20, 40)) {
91
        db_mysql::db_transaction_rollback();
92
93
        return false;
94
      } else {
95
        $this->debug->warning('Fleet dispatcher was locked too long - watchdog unlocked', 'FFH Error', 504);
96
      }
97
    }
98
99
    $this->gameConfig->db_saveItem('fleet_update_last', SN_TIME_SQL);
100
    $this->gameConfig->db_saveItem('fleet_update_lock', SN_TIME_SQL);
101
    db_mysql::db_transaction_commit();
102
103
    return true;
104
  }
105
106
  /**
107
   * @deprecated
108
   */
109
  protected function releaseLock() {
110
    db_mysql::db_transaction_start();
111
    $this->gameConfig->db_saveItem('fleet_update_lock', '');
112
    db_mysql::db_transaction_commit();
113
  }
114
115
116
  // ------------------------------------------------------------------
117
118
  /**
119
   * @return int|int[]
120
   */
121
  public function flt_flying_fleet_handler() {
122
    /*
123
124
    [*] Нужно ли заворачивать ВСЕ в одну транзакцию?
125
        С одной стороны - да, что бы данные были гарантированно на момент снапшота
126
        С другой стороны - нет, потому что при большой активности это все будет блокировать слишком много рядов, да и таймаут будет большой для ожидания всего разлоченного
127
        Стоит завернуть каждую миссию отдельно? Это сильно увеличит количество запросов, зато так же сильно снизит количество блокировок.
128
129
        Resume: НЕТ! Надо оставить все в одной транзакции! Так можно будет поддерживать consistency кэша. Там буквально сантисекунды блокировки
130
131
    [*] Убрать кэшированние данных о пользователях и планета. Офигенно освободит память - проследить!
132
        НЕТ! Считать, скольким флотам нужна будет инфа и кэшировать только то, что используется больше раза!
133
        Заодно можно будет исключить перересчет очередей/ресурсов - сильно ускорит дело!
134
        Особенно будет актуально, когда все бонусы будут в одной таблице
135
        Ну и никто не заставляет как сейчас брать ВСЕ из таблицы - только по полям. Гемор, но не сильный - сделать запрос по группам sn_data
136
        И писать в БД только один раз результат
137
138
    [*] Нужно ли на этом этапе знать полную информацию о флотах?
139
        Заблокировать флоты можно и неполным запросом. Блокировка флотов - это не страшно. Ну, не пройдет одна-две отмены - так никто и не гарантировал реалтайма!
140
        С одной стороны - да, уменьшит количество запросов
141
        С другой стооны - расход памяти
142
        Все равно надо будет знать полную инфу о флоте в момент обработки
143
144
    [*] Сделать тестовую БД для расчетов
145
146
    [*] Но не раньше, чем переписать все миссии
147
148
    */
149
//    $this->log_file('Dispatch started');
150
    $watchdog = new FleetWatchdog();
151
    if (($result = $watchdog->acquireLock()) == FleetWatchdog::TASK_ALREADY_LOCKED) {
152
      return $result;
153
    }
154
155
    $result = ['code' => self::TASK_COMPLETE];
156
157
    set_time_limit(max(3, SN::$gc->config->fleet_update_max_run_time - 3));
158
159
    //log_file('Начинаем обсчёт флотов');
160
161
//    $this->log_file('Обсчёт ракет');
162
    coe_o_missile_calculate();
163
164
    // Filling self::$fleet_event_list with FleetDispatchEvent
165
    self::$fleet_event_list = $this->getFleetEvents();
166
    $this->loadMissionFiles();
167
168
    $sn_groups_mission = sn_get_groups('missions');
0 ignored issues
show
Unused Code introduced by
The assignment to $sn_groups_mission is dead and can be removed.
Loading history...
169
    foreach (self::$fleet_event_list as $fleetEvent) {
170
      $result['code'] = $watchdog->begin($fleetEvent);
171
      if ($result['code'] === FleetWatchdog::TASK_TOO_LONG) {
172
        $result['message'] = $watchdog->getTerminationMessage();
173
        break;
174
      } elseif ($result['code'] === FleetWatchdog::FLEET_IS_EMPTY) {
175
        continue;
176
      }
177
178
      db_mysql::db_transaction_start();
179
      // Locking further fleet dispatcher tasks
180
      SN::$gc->config->pass()->fleet_update_last = date(FMT_DATE_TIME_SQL, time());
181
182
      // Locking all event-related records
183
      $fleetEvent->lockEventRecords();
184
185
      // Refreshing fleet record
186
      if (empty($fleetEvent->refreshFleet())) {
187
        // Fleet was destroyed in course of previous actions
188
        db_mysql::db_transaction_commit();
189
        continue;
190
      } elseif ($fleetEvent->event == EVENT_FLT_RETURN && $fleetEvent->fleet['fleet_mess'] == FLEET_STATUS_RETURNING) {
191
        // Fleet returns to planet
192
        RestoreFleetToPlanet($fleetEvent->fleet, true, false, true);
0 ignored issues
show
Deprecated Code introduced by
The function RestoreFleetToPlanet() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

192
        /** @scrutinizer ignore-deprecated */ RestoreFleetToPlanet($fleetEvent->fleet, true, false, true);
Loading history...
193
        db_mysql::db_transaction_commit();
194
        continue;
195
      } elseif ($fleetEvent->event == EVENT_FLT_ARRIVE && $fleetEvent->fleet['fleet_mess'] != FLEET_STATUS_FLYING) {
196
        // При событии EVENT_FLT_ARRIVE флот всегда должен иметь fleet_mess == 0 / FLEET_STATUS_FLYING
197
        // В противном случае это означает, что флот уже был обработан ранее - например, при САБе
198
        db_mysql::db_transaction_commit();
199
        continue;
200
      }
201
202
      // From now on we have only events of types [EVENT_FLT_ARRIVE, EVENT_FLT_ACCOMPLISH] and $fleet_row['fleet_mess'] == FLEET_STATUS_FLYING (0)
203
204
      // Here we refresh dstPlanetRow (by calling sys_o_get_updated() and using its result - so below this call we will have actual dst planet/dst user records
205
      // In same vein we refresh srcPlanetRow
206
      $fleetEvent->refreshMissionData();
207
208
      switch ($fleetEvent->missionId) {
209
        // Для боевых атак нужно обновлять по САБу и по холду - таки надо возвращать данные из обработчика миссий!
210
        case MT_ATTACK:
211
        case MT_AKS:
212
        case MT_DESTROY:
213
          flt_mission_attack($fleetEvent);
214
        break;
215
216
        case MT_TRANSPORT:
217
          flt_mission_transport($fleetEvent);
218
        break;
219
220
        case MT_HOLD:
221
          flt_mission_hold($fleetEvent);
222
        break;
223
224
        case MT_RELOCATE:
225
          flt_mission_relocate($fleetEvent);
226
        break;
227
228
        case MT_EXPLORE:
229
          // TODO - THIS NEED TO BE ADRESSED!
230
          flt_mission_explore($fleetEvent);
231
          // TODO - there is untested class below !!!
232
233
//          $theMission = \Fleet\MissionExplore::buildFromArray($mission_data);
234
//          $theMission->process();
235
//
236
//          unset($theMission);
237
        break;
238
239
        case MT_RECYCLE:
240
          flt_mission_recycle($fleetEvent);
241
        break;
242
243
        case MT_COLONIZE:
244
          flt_mission_colonize($fleetEvent);
245
        break;
246
247
        case MT_SPY:
248
          require_once(SN_ROOT_PHYSICAL . 'includes/includes/coe_simulator_helpers.php');
249
250
          $theMission = MissionEspionage::buildFromArray($fleetEvent);
251
          $theMission->flt_mission_spy();
252
253
          unset($theMission);
254
        break;
255
256
        case MT_MISSILE:  // Missiles !!
257
        break;
258
259
//      default:
260
//        doquery("DELETE FROM `{{fleets}}` WHERE `fleet_id` = '{$fleet_row['fleet_id']}' LIMIT 1;");
261
//      break;
262
      }
263
      db_mysql::db_transaction_commit();
264
    }
265
266
    $watchdog->unlock();
267
268
//    $that->log_file('Dispatch finished - NORMAL SHUTDOWN');
269
270
    return $result;
271
  }
272
273
  /**
274
   * @param $workTime
275
   * @param $eventsProcessed
276
   * @param $lastMissionId
277
   * @param $lastEventId
278
   * @param $lastEventLength
279
   * @param $totalEvents
280
   */
281
  public function logTermination($workTime, $eventsProcessed, $lastMissionId, $lastEventId, $lastEventLength, $totalEvents) {
282
    SN::$debug->warning(sprintf(
283
      'Flying fleet handler works %1$s (> %2$s) seconds - skip rest. Processed %3$d / %7$d events. Last event: mission %4$s event %6$s (%5$ss)',
284
      number_format($workTime, 4),
285
      SN::$config->fleet_update_dispatch_time,
286
      $eventsProcessed,
287
      $lastMissionId ? SN::$lang['type_mission'][$lastMissionId] : '!TERMINATED BY TIMEOUT!',
288
      number_format($lastEventLength, 4),
289
      $lastEventId ? SN::$lang['fleet_events'][$lastEventId] : '!TERMINATED BY TIMEOUT!',
290
      $totalEvents
291
    ),
292
      'FFH Warning',
293
      504
294
    );
295
  }
296
297
  /**
298
   * @return Lock
299
   */
300
  public function buildLock() {
301
    return new Lock($this->gc, classConfig::FLEET_UPDATE_RUN_LOCK, SN::$gc->config->fleet_update_max_run_time, 1, classConfig::DATE_TYPE_UNIX);
302
  }
303
304
  public function getFleetEvents() {
305
    $fleet_event_list = [];
306
307
    // Gets active fleets on current tick for Flying Fleet Handler
308
    $fleet_list_current_tick = DbFleetStatic::db_fleet_list(
309
      "
310
        (`fleet_start_time` <= " . SN_TIME_NOW . " AND `fleet_mess` = 0)
311
        OR
312
        (`fleet_end_stay` <= " . SN_TIME_NOW . " AND `fleet_end_stay` > 0 AND `fleet_mess` = 0)
313
        OR
314
        (`fleet_end_time` <= " . SN_TIME_NOW . ")
315
      ", DB_SELECT_PLAIN
316
    );
317
318
    foreach ($fleet_list_current_tick as $fleet_row) {
319
      if ($fleet_row['fleet_start_time'] <= SN_TIME_NOW && $fleet_row['fleet_mess'] == 0) {
320
        $fleet_event_list[] = new FleetDispatchEvent($fleet_row, EVENT_FLT_ARRIVE);
321
      }
322
323
      if ($fleet_row['fleet_end_stay'] > 0 && $fleet_row['fleet_end_stay'] <= SN_TIME_NOW && $fleet_row['fleet_mess'] == 0) {
324
        $fleet_event_list[] = new FleetDispatchEvent($fleet_row, EVENT_FLT_ACCOMPLISH);
325
      }
326
327
      if ($fleet_row['fleet_end_time'] <= SN_TIME_NOW) {
328
        $fleet_event_list[] = new FleetDispatchEvent($fleet_row, EVENT_FLT_RETURN);
329
      }
330
331
      $this->missions_used[$fleet_row[self::F_FLEET_MISSION]] = 1;
332
    }
333
334
    FleetDispatchEvent::sortEvents($fleet_event_list);
335
336
    return $fleet_event_list;
337
  }
338
339
  /**
340
   * @return void
341
   */
342
  public function loadMissionFiles() {
343
    $mission_files = [
344
      MT_ATTACK  => 'flt_mission_attack',
345
      MT_AKS     => 'flt_mission_attack',
346
      MT_DESTROY => 'flt_mission_attack',
347
348
      MT_TRANSPORT => 'flt_mission_transport',
349
      MT_RELOCATE  => 'flt_mission_relocate',
350
      MT_HOLD      => 'flt_mission_hold',
351
      MT_SPY       => '',
352
      MT_COLONIZE  => 'flt_mission_colonize',
353
      MT_RECYCLE   => 'flt_mission_recycle',
354
      // MT_MISSILE => 'flt_mission_missile.php',
355
      MT_EXPLORE   => 'flt_mission_explore',
356
    ];
357
    foreach ($this->missions_used as $mission_id => $cork) {
358
      if (empty($mission_files[$mission_id])) {
359
        continue;
360
      }
361
362
      require_once(SN_ROOT_PHYSICAL . "includes/includes/{$mission_files[$mission_id]}" . DOT_PHP_EX);
363
    }
364
  }
365
366
  /**
367
   * @param string $msg
368
   *
369
   * @noinspection PhpUnused
370
   */
371
  public function log_file($msg) {
372
    file_put_contents(__DIR__ . '/../../.ffh-event.log', date(FMT_DATE_TIME_SQL, time()) . ' ' . $msg . "\r\n", FILE_APPEND);
373
  }
374
375
}
376