Completed
Push — work-fleets ( fff2b6...e0e753 )
by SuperNova.WS
06:54
created

eco_queue.php ➔ que_process()   F

Complexity

Conditions 41
Paths 5719

Size

Total Lines 192
Code Lines 107

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 41
eloc 107
nc 5719
nop 3
dl 0
loc 192
rs 2
c 2
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
function que_get_unit_que($unit_id) {
4
  $que_type = false;
5
  foreach(sn_get_groups('ques') as $que_id => $que_data) {
6
    if(in_array($unit_id, $que_data['unit_list'])) {
7
      $que_type = $que_id;
8
      break;
9
    }
10
  }
11
12
  return $que_type;
13
}
14
15
16
function que_get_max_que_length($user, $planet, $que_id, $que_data = null) {
17
  if(empty($que_data)) {
18
    $que_data = sn_get_groups('ques');
19
    $que_data = $que_data[$que_id];
20
  }
21
22
23
  $que_length = 1;
0 ignored issues
show
Unused Code introduced by
$que_length is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
24
  switch($que_id) {
25
    case QUE_RESEARCH:
26
      $que_length = classSupernova::$config->server_que_length_research + mrc_get_level($user, null, UNIT_PREMIUM); // TODO - вынести в модуль
27
    break;
28
29
    default:
30
      $que_length = isset($que_data['length']) ? $que_data['length'] + mrc_get_level($user, $planet, $que_data['mercenary']) : 1;
31
  }
32
33
  return $que_length;
34
}
35
36
function eco_que_str2arr($que_str) {
37
  $que_arr = explode(';', $que_str);
38
  foreach($que_arr as $que_index => &$que_item) {
39
    if($que_item) {
40
      $que_item = explode(',', $que_item);
41
    } else {
42
      unset($que_arr[$que_index]);
43
    }
44
  }
45
46
  return $que_arr;
47
}
48
49
function eco_que_arr2str($que_arr) {
50
  foreach($que_arr as &$que_item) {
51
    $que_item = implode(',', $que_item);
52
  }
53
54
  return implode(';', $que_arr);
55
}
56
57
58
function que_build($user, $planet, $build_mode = BUILD_CREATE, $redirect = true) {
59
  $classLocale = classLocale::$lang;
60
61
  $is_autoconvert = false;
62
  if($build_mode == BUILD_AUTOCONVERT || sys_get_param_int('auto_convert')) {
63
    $build_mode = BUILD_CREATE;
64
    $is_autoconvert = true;
65
  }
66
67
  $unit_amount_qued = 0;
68
  try {
69
    if(!$user['id']) {
70
      throw new exception('{Нет идентификатора пользователя - сообщите Администрации}', ERR_ERROR); // TODO EXCEPTION
71
    }
72
73
    $unit_id = sys_get_param_int('unit_id');
74
    /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
75
    if(!$unit_id && is_array($unit_list = sys_get_param('fmenge')))
76
    {
77
      foreach($unit_list as $unit_id => $unit_amount) if($unit_amount) break;
78
    }
79
    */
80
    if(!$unit_id) {
81
      throw new exception('{Нет идентификатора юнита - сообщите Администрации}', ERR_ERROR); // TODO EXCEPTION
82
    }
83
84
    $que_id = que_get_unit_que($unit_id);
85
    if(!$que_id) {
86
      throw new exception('{Неправильный тип очереди - сообщите Администрации}', ERR_ERROR); // TODO EXCEPTION
87
    }
88
89
    if($build_mode == BUILD_DESTROY && $que_id != QUE_STRUCTURES) {
90
      throw new exception('{Уничтожать можно только здания на планете}', ERR_ERROR); // TODO EXCEPTION
91
    }
92
93
    $que_data = sn_get_groups('ques');
94
    $que_data = $que_data[$que_id];
95
96
    // TODO Переделать под подочереди
97
    if($que_id == QUE_STRUCTURES) {
98
      $sn_groups_build_allow = sn_get_groups('build_allow');
99
      $que_data['unit_list'] = $sn_groups_build_allow[$planet['planet_type']];
100
101
      if(!isset($que_data['unit_list'][$unit_id])) {
102
        throw new exception('{Это здание нельзя строить на ' . ($planet['planet_type'] == PT_PLANET ? 'планете' : 'луне'), ERR_ERROR); // TODO EXCEPTION
103
      }
104
    }
105
    /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
106
    // TODO Разделить очереди для Верфи и Обороны
107
    elseif($que_id == QUE_HANGAR)
108
    {
109
      $que_data['mercenary'] = in_array($unit_id, sn_get_groups('defense')) ? MRC_FORTIFIER : MRC_ENGINEER;
110
    }
111
    elseif($que_id == QUE_HANGAR)
112
    {
113
      $que_data['mercenary'] = in_array($unit_id, sn_get_groups('defense')) ? MRC_FORTIFIER : MRC_ENGINEER;
114
    }
115
    */
116
117
118
    sn_db_transaction_start();
119
    // Это нужно, что бы заблокировать пользователя и работу с очередями
120
    $user = db_user_by_id($user['id']);
121
    // Это нужно, что бы заблокировать планету от списания ресурсов
122
    if(isset($planet['id']) && $planet['id']) {
123
      $planet = db_planet_by_id($planet['id'], true);
124
    } else {
125
      $planet['id'] = 0;
126
    }
127
128
    $planet_id = $que_id == QUE_RESEARCH ? 0 : intval($planet['id']);
129
130
    $que = que_get($user['id'], $planet['id'], $que_id, true);
0 ignored issues
show
Documentation introduced by
$que_id is of type integer|string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
131
    $in_que = &$que['in_que'][$que_id][$user['id']][$planet_id];
132
    $que_max_length = que_get_max_que_length($user, $planet, $que_id, $que_data);
133
    // TODO Добавить вызовы функций проверок текущей и максимальной длин очередей
134
    if(count($in_que) >= $que_max_length) {
135
      throw new exception('{Все слоты очереди заняты}', ERR_ERROR); // TODO EXCEPTION
136
    }
137
138
    // TODO Отдельно посмотреть на уничтожение зданий - что бы можно было уничтожать их без планов
139
    switch(eco_can_build_unit($user, $planet, $unit_id)) {
140
      case BUILD_ALLOWED:
141
      break;
142
      case BUILD_UNIT_BUSY:
143
        throw new exception('{Строение занято}', ERR_ERROR);
144
      break; // TODO EXCEPTION eco_bld_msg_err_laboratory_upgrading
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
145
      // case BUILD_REQUIRE_NOT_MEET:
146
      default:
147
        if($build_mode == BUILD_CREATE) {
148
          throw new exception('{Требования не удовлетворены}', ERR_ERROR);
149
        }
150
      break; // TODO EXCEPTION eco_bld_msg_err_requirements_not_meet
151
    }
152
153
    $unit_amount = floor(sys_get_param_float('unit_amount', 1));
154
    $unit_amount_qued = $unit_amount;
155
    $units_qued = isset($in_que[$unit_id]) ? $in_que[$unit_id] : 0;
156
    $unit_level = mrc_get_level($user, $planet, $unit_id, true, true) + $units_qued;
157
    if($unit_max = get_unit_param($unit_id, P_MAX_STACK)) {
158
      if($unit_level >= $unit_max) {
159
        throw new exception('{Максимальное количество юнитов данного типа уже достигнуто или будет достигнуто по окончанию очереди}', ERR_ERROR); // TODO EXCEPTION
160
      }
161
      $unit_amount = max(0, min($unit_amount, $unit_max - $unit_level));
162
    }
163
164
    if($unit_amount < 1) {
165
      throw new exception('{Неправильное количество юнитов - сообщите Администрации}', ERR_ERROR); // TODO EXCEPTION
166
    }
167
168
    // TODO Переделать eco_unit_busy для всех типов зданий
169
    //  if(eco_unit_busy($user, $planet, $que, $unit_id))
0 ignored issues
show
Unused Code Comprehensibility introduced by
71% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
170
    //  {
171
    //    die('Unit busy'); // TODO EXCEPTION
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
172
    //  }
173
    if(get_unit_param($unit_id, P_STACKABLE)) {
174
      // TODO Поле 'max_Lot_size' для ограничения размера стэка в очереди - то ли в юниты, то ли в очередь
175
      if(in_array($unit_id, $group_missile = sn_get_groups('missile'))) {
176
        // TODO Поле 'container' - указывает на родительску структуру, в которой хранится данный юнит и по вместительности которой нужно применять размер юнита
177
        $used_silo = 0;
178 View Code Duplication
        foreach($group_missile as $missile_id) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
179
          $missile_qued = isset($in_que[$missile_id]) ? $in_que[$missile_id] : 0;
180
          $used_silo += (mrc_get_level($user, $planet, $missile_id, true, true) + $missile_qued) * get_unit_param($missile_id, P_UNIT_SIZE);
181
        }
182
        $free_silo = mrc_get_level($user, $planet, STRUC_SILO) * get_unit_param(STRUC_SILO, P_CAPACITY) - $used_silo;
183
        if($free_silo <= 0) {
184
          throw new exception('{Ракетная шахта уже заполнена или будет заполнена по окончанию очереди}', ERR_ERROR); // TODO EXCEPTION
185
        }
186
        $unit_size = get_unit_param($unit_id, P_UNIT_SIZE);
187
        if($free_silo < $unit_size) {
188
          throw new exception("{В ракетной шахте нет места для {$classLocale['tech'][$unit_id]}}", ERR_ERROR); // TODO EXCEPTION
189
        }
190
        $unit_amount = max(0, min($unit_amount, floor($free_silo / $unit_size)));
191
      }
192
      $unit_level = $new_unit_level = 0;
193
    } else {
194
      $unit_amount = 1;
195
      if($que_id == QUE_STRUCTURES) {
196
        // if($build_mode == BUILD_CREATE && eco_planet_fields_max($planet) - $planet['field_current'] - $que['sectors'][$planet['id']] <= 0)
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
197
        $sectors_qued = is_array($in_que) ? array_sum($in_que) : 0;
198
        if($build_mode == BUILD_CREATE && eco_planet_fields_max($planet) - $planet['field_current'] - $sectors_qued <= 0) {
199
          throw new exception('{Не хватает секторов на планете}', ERR_ERROR); // TODO EXCEPTION
200
        }
201
        // И что это я такое написал? Зачем?
202
        //if($build_mode == BUILD_DESTROY && $planet['field_current'] <= $que['amounts'][$que_id])
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
203
        //{
204
        //  die('Too much buildings'); // TODO EXCEPTION
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
205
        //}
206
      }
207
      $build_multiplier = $build_mode == BUILD_CREATE ? 1 : -1;
208
      $new_unit_level = $unit_level + $unit_amount * $build_multiplier;
209
    }
210
211
    $build_data = eco_get_build_data($user, $planet, $unit_id, $unit_level);
212
213
    $exchange = array();
214
    $market_get_autoconvert_cost = market_get_autoconvert_cost();
215
    if($is_autoconvert && $build_data[BUILD_AUTOCONVERT]) {
216
      $dark_matter = mrc_get_level($user, null, RES_DARK_MATTER);
217
      if(mrc_get_level($user, null, RES_DARK_MATTER) < $market_get_autoconvert_cost) {
218
        throw new exception("{Нет хватает " . ($market_get_autoconvert_cost - $dark_matter) . "ТМ на постройки с автоконвертацией ресурсов}", ERR_ERROR); // TODO EXCEPTION
219
      }
220
221
      !get_unit_param($unit_id, P_STACKABLE) ? $unit_amount = 1 : false;
222
      $resources_loot = sn_get_groups('resources_loot');
223
      $resource_got = array();
224
      $resource_exchange_rates = array();
225
      $resource_diff = array();
226
      $all_positive = true;
227
      foreach($resources_loot as $resource_id) {
228
        $resource_db_name = pname_resource_name($resource_id);
229
        $resource_got[$resource_id] = floor(mrc_get_level($user, $planet, $resource_id));
230
        $resource_exchange_rates[$resource_id] = classSupernova::$config->__get("rpg_exchange_{$resource_db_name}");
231
        $resource_diff[$resource_id] = $resource_got[$resource_id] - $build_data[BUILD_CREATE][$resource_id] * $unit_amount;
232
        $all_positive = $all_positive && ($resource_diff[$resource_id] > 0);
233
      }
234
      // Нужна автоконвертация
235
      if($all_positive) {
236
        $is_autoconvert = false;
237
      } else {
238
        foreach($resource_diff as $resource_diff_id => &$resource_diff_amount) {
239
          if($resource_diff_amount >= 0) {
240
            continue;
241
          }
242
          foreach($resource_diff as $resource_got_id => &$resource_got_amount) {
243
            if($resource_got_amount <= 0) {
244
              continue;
245
            }
246
            $current_exchange = $resource_exchange_rates[$resource_got_id] / $resource_exchange_rates[$resource_diff_id];
247
248
            $will_exchage_to = min(-$resource_diff_amount, floor($resource_got_amount * $current_exchange));
249
            $will_exchage_from = $will_exchage_to / $current_exchange;
250
251
            $resource_diff_amount += $will_exchage_to;
252
            $resource_got_amount -= $will_exchage_from;
253
            $exchange[$resource_diff_id] += $will_exchage_to;
254
            $exchange[$resource_got_id] -= $will_exchage_from;
255
          }
256
        }
257
258
        $is_autoconvert_ok = true;
259
        foreach($resource_diff as $resource_diff_amount2) {
260
          if($resource_diff_amount2 < 0) {
261
            $is_autoconvert_ok = false;
262
            break;
263
          }
264
        }
265
266
        if($is_autoconvert_ok) {
267
          $build_data['RESULT'][$build_mode] = BUILD_ALLOWED;
268
          $build_data['CAN'][$build_mode] = $unit_amount;
269
        } else {
270
          $unit_amount = 0;
271
        }
272
      }
273
    }
274
    $unit_amount = min($build_data['CAN'][$build_mode], $unit_amount);
275
    if($unit_amount <= 0) {
276
      throw new exception('{Не хватает ресурсов}', ERR_ERROR); // TODO EXCEPTION
277
    }
278
279
    if($new_unit_level < 0) {
280
      throw new exception('{Нельзя уничтожить больше юнитов, чем есть}', ERR_ERROR); // TODO EXCEPTION
281
    }
282
283
    if($build_data['RESULT'][$build_mode] != BUILD_ALLOWED) {
284
      throw new exception('{Строительство блокировано}', ERR_ERROR); // TODO EXCEPTION
285
    }
286
287
    if($is_autoconvert) {
288
      ksort($exchange);
289
      ksort($resource_got);
290
      db_change_units($user, $planet, array(
291
        RES_METAL     => !empty($exchange[RES_METAL]) ? $exchange[RES_METAL] : 0,
292
        RES_CRYSTAL   => !empty($exchange[RES_CRYSTAL]) ? $exchange[RES_CRYSTAL] : 0,
293
        RES_DEUTERIUM => !empty($exchange[RES_DEUTERIUM]) ? $exchange[RES_DEUTERIUM] : 0,
294
      ));
295
      rpg_points_change($user['id'], RPG_BUILD_AUTOCONVERT, -$market_get_autoconvert_cost, sprintf(
296
        classLocale::$lang['bld_autoconvert'], $unit_id, $unit_amount, uni_render_planet_full($planet, '', false, true), classLocale::$lang['tech'][$unit_id],
297
        sys_unit_arr2str($build_data[BUILD_CREATE]), sys_unit_arr2str($resource_got), sys_unit_arr2str($exchange)
298
      ));
299
    }
300
301
    $unit_amount_qued = 0;
302
    while($unit_amount > 0 && count($que['ques'][$que_id][$user['id']][$planet_id]) < $que_max_length) {
303
      $place = min($unit_amount, MAX_FLEET_OR_DEFS_PER_ROW);
304
      que_add_unit($unit_id, $user, $planet, $build_data, $new_unit_level, $place, $build_mode);
305
      $unit_amount -= $place;
306
      $que = que_get($user['id'], $planet['id'], $que_id, true);
0 ignored issues
show
Documentation introduced by
$que_id is of type integer|string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
307
      $unit_amount_qued += $place;
308
    }
309
310
    sn_db_transaction_commit();
311
312
    if($redirect) {
313
      sys_redirect("{$_SERVER['PHP_SELF']}?mode=" . sys_get_param_str('mode') . "&ally_id=" . sys_get_param_id('ally_id'));
314
      die();
315
    }
316
317
    $operation_result = array(
318
      'STATUS'  => ERR_NONE,
319
      'MESSAGE' => '{Строительство начато}',
320
    );
321
  } catch(exception $e) {
322
    sn_db_transaction_rollback();
323
    $operation_result = array(
324
      'STATUS'  => in_array($e->getCode(), array(ERR_NONE, ERR_WARNING, ERR_ERROR)) ? $e->getCode() : ERR_ERROR,
325
      'MESSAGE' => $e->getMessage()
326
    );
327
  }
328
329
  if(!empty($operation_result['MESSAGE'])) {
330
    $operation_result['MESSAGE'] .= ' ' . ($unit_amount_qued ? $unit_amount_qued : $unit_amount) . 'x[' . classLocale::$lang['tech'][$unit_id] . ']';
0 ignored issues
show
Bug introduced by
The variable $unit_amount does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $unit_id does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
331
  }
332
333
  return $operation_result;
334
}
335
336
337
function que_recalculate($old_que) {
338
  $new_que = array();
339
340
  if(!is_array($old_que['items'])) {
341
    return $new_que;
342
  }
343
  foreach($old_que['items'] as $row) {
344
    if(!isset($row) || !$row || $row['que_unit_amount'] <= 0) {
345
      continue;
346
    }
347
348
    $new_que['items'][] = $row;
349
350
    $new_que['in_que'][$row['que_type']][$row['que_player_id']][intval($row['que_planet_id'])][$row['que_unit_id']] += $row['que_unit_amount'] * ($row['que_unit_mode'] == BUILD_CREATE ? 1 : -1);
351
    $new_que['in_que_abs'][$row['que_type']][$row['que_player_id']][intval($row['que_planet_id'])][$row['que_unit_id']] += $row['que_unit_amount'];
352
353
    $last_id = count($new_que['items']) - 1;
354
355
    if($row['que_planet_id']) {
356
      $new_que['planets'][$row['que_planet_id']][$row['que_type']][] = &$new_que['items'][$last_id];
357
    } elseif($row['que_type'] == QUE_RESEARCH) {
358
      $new_que['players'][$row['que_player_id']][$row['que_type']][] = &$new_que['items'][$last_id];
359
    }
360
    $new_que['ques'][$row['que_type']][$row['que_player_id']][intval($row['que_planet_id'])][] = &$new_que['items'][$last_id];
361
362
    // Это мы можем посчитать по длине очереди в players и planets
363
    //$ques['used_slots'][$row['que_type']][$row['que_player_id']][intval($row['que_planet_id'])][$row['que_unit_id']]++;
0 ignored issues
show
Unused Code Comprehensibility introduced by
97% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
364
  }
365
366
  return $new_que;
367
}
368
369
function que_get($user_id, $planet_id = null, $que_type = false, $for_update = false) {
370
  return classSupernova::db_que_list_by_type_location($user_id, $planet_id, $que_type, $for_update);
371
}
372
373
function que_add_unit($unit_id, $user = array(), $planet = array(), $build_data, $unit_level = 0, $unit_amount = 1, $build_mode = BUILD_CREATE) {
374
  // TODO Унифицировать проверки
375
376
  // TODO que_process() тут
377
378
  sn_db_transaction_check(true);
379
380
  $build_mode = $build_mode == BUILD_CREATE ? BUILD_CREATE : BUILD_DESTROY;
381
382
  // TODO: Some checks
383
  db_change_units($user, $planet, array(
384
    RES_METAL     => -$build_data[$build_mode][RES_METAL] * $unit_amount,
385
    RES_CRYSTAL   => -$build_data[$build_mode][RES_CRYSTAL] * $unit_amount,
386
    RES_DEUTERIUM => -$build_data[$build_mode][RES_DEUTERIUM] * $unit_amount,
387
  ));
388
389
  $que_type = que_get_unit_que($unit_id);
390
  $planet_id_origin = $planet['id'] ? $planet['id'] : 'NULL';
391
  $planet_id = $que_type == QUE_RESEARCH ? 'NULL' : $planet_id_origin;
392
  if(is_numeric($planet_id)) {
393
    db_planet_set_by_id($planet_id, "`que_processed` = UNIX_TIMESTAMP(NOW())");
394
  } elseif(is_numeric($user['id'])) {
395
    db_user_set_by_id($user['id'], '`que_processed` = UNIX_TIMESTAMP(NOW())');
396
  }
397
398
  $resource_list = sys_unit_arr2str($build_data[$build_mode]);
399
400
  db_que_set_insert(
401
    "`que_player_id` = {$user['id']},
402
      `que_planet_id` = {$planet_id},
403
      `que_planet_id_origin` = {$planet_id_origin},
404
      `que_type` = {$que_type},
405
      `que_time_left` = {$build_data[RES_TIME][$build_mode]},
406
      `que_unit_id` = {$unit_id},
407
      `que_unit_amount` = {$unit_amount},
408
      `que_unit_mode` = {$build_mode},
409
      `que_unit_level` = {$unit_level},
410
      `que_unit_time` = {$build_data[RES_TIME][$build_mode]},
411
      `que_unit_price` = '{$resource_list}'"
412
  );
413
}
414
415
function que_delete($que_type, $user = array(), $planet = array(), $clear = false) {
416
  $planets_locked = array();
417
418
  // TODO: Some checks
419
  sn_db_transaction_start();
420
  $user = db_user_by_id($user['id'], true);
421
  $planet['id'] = $planet['id'] && $que_type !== QUE_RESEARCH ? $planet['id'] : 0;
422
  $global_que = que_get($user['id'], $planet['id'], $que_type, true);
423
424
  if(!empty($global_que['ques'][$que_type][$user['id']][$planet['id']])) {
425
    $que = array_reverse($global_que['ques'][$que_type][$user['id']][$planet['id']]);
426
427
    foreach($que as $que_item) {
428
      db_que_delete_by_id($que_item['que_id']);
429
430
      if($que_item['que_planet_id_origin']) {
431
        $planet['id'] = $que_item['que_planet_id_origin'];
432
      }
433
434
      if(!isset($planets_locked[$planet['id']])) {
435
        $planets_locked[$planet['id']] = $planet['id'] ? db_planet_by_id($planet['id'], true) : $planet;
436
      }
437
438
      $build_data = sys_unit_str2arr($que_item['que_unit_price']);
439
440
      db_change_units($user, $planets_locked[$planet['id']], array(
441
        RES_METAL     => $build_data[RES_METAL] * $que_item['que_unit_amount'],
442
        RES_CRYSTAL   => $build_data[RES_CRYSTAL] * $que_item['que_unit_amount'],
443
        RES_DEUTERIUM => $build_data[RES_DEUTERIUM] * $que_item['que_unit_amount'],
444
      ));
445
446
      if(!$clear) {
447
        break;
448
      }
449
    }
450
451
    if(is_numeric($planet['id'])) {
452
      db_planet_set_by_id($planet['id'], "`que_processed` = UNIX_TIMESTAMP(NOW())");
453
    } elseif(is_numeric($user['id'])) {
454
      db_user_set_by_id($user['id'], '`que_processed` = UNIX_TIMESTAMP(NOW())');
455
    }
456
457
    sn_db_transaction_commit();
458
  } else {
459
    sn_db_transaction_rollback();
460
  }
461
//die();
462
  header("Location: {$_SERVER['PHP_SELF']}?mode={$que_type}" . "&ally_id=" . sys_get_param_id('ally_id'));
0 ignored issues
show
Security Response Splitting introduced by
"Location: {$_SERVER['PH...get_param_id('ally_id') can contain request data and is used in response header context(s) leading to a potential security vulnerability.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
463
}
464
465
466
function que_tpl_parse_element($que_element, $short_names = false) {
467
  return
468
    array(
469
      'ID'        => $que_element['que_unit_id'],
470
      'QUE'       => $que_element['que_type'],
471
      'NAME'      => $short_names && !empty(classLocale::$lang['tech_short'][$que_element['que_unit_id']])
472
        ? classLocale::$lang['tech_short'][$que_element['que_unit_id']]
473
        : classLocale::$lang['tech'][$que_element['que_unit_id']],
474
      'TIME'      => $que_element['que_time_left'],
475
      'TIME_FULL' => $que_element['que_unit_time'],
476
      'AMOUNT'    => $que_element['que_unit_amount'],
477
      'LEVEL'     => $que_element['que_unit_level'],
478
    );
479
}
480
481
/**
482
 * Процедура парсит очереди текущего игрока в темплейт
483
 *
484
 * TODO: Переместить в хелперы темплейтов
485
 * TODO: Сделать поддержку нескольких очередей
486
 *
487
 * $que_type - тип очереди ОБЯЗАТЕЛЬНО
488
 * $que - либо результат $que_get(), либо конкретная очередь
489
 *
490
 * @param template $template
491
 * @param          $que_type
492
 * @param          $user
493
 * @param array    $planet
494
 * @param null     $que
495
 * @param bool     $short_names
496
 */
497
function que_tpl_parse(&$template, $que_type, $user, $planet = array(), $que = null, $short_names = false) {
498
  // TODO: Переделать для $que_type === false
499
  $planet['id'] = $planet['id'] ? $planet['id'] : 0;
500
501
  if(!is_array($que)) {
502
    $que = que_get($user['id'], $planet['id'], $que_type);
503
  }
504
505
  if(is_array($que) && isset($que['items'])) {
506
    $que = $que['ques'][$que_type][$user['id']][$planet['id']];
507
  }
508
509
  if($que) {
510
    foreach($que as $que_element) {
511
      $template->assign_block_vars('que', que_tpl_parse_element($que_element, $short_names));
512
    }
513
  }
514
515
  if($que_type == QUE_RESEARCH) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
516
  }
517
}
518
519
520
/*
521
 *
522
 * Эта процедура должна вызываться исключительно в транзакции!!!
523
 *
524
 * $user_id
525
 *   (integer) - обрабатываются глообальные очереди пользователя
526
 * $planet_id
527
 *   null - обработка очередей планет не производится
528
 * // TODO    false/0 - обрабатываются очереди всех планет по $user_id
529
 *   (integer) - обрабатываются локальные очереди для планеты. Нужно, например, в обработчике флотов
530
 *
531
 */
532
function que_process(&$user, $planet = null, $on_time = SN_TIME_NOW) {
533
  sn_db_transaction_check(true);
534
535
  $que = array();
536
537
  // Блокируем пользователя. Собственно, запись о нём нам не нужна - будем использовать старую
538
  $user = db_user_by_id($user['id'], true);
539
540
  $time_left[$user['id']][0] = max(0, $on_time - $user['que_processed']);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$time_left was never initialized. Although not strictly required by PHP, it is generally a good practice to add $time_left = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
541
  if($planet === null && !$time_left[$user['id']][0]) {
542
    // TODO
543
    return $que;
544
  }
545
546
  // Определяем, какие очереди нам нужны и получаем их
547
  $que_type_id = $planet === null ? QUE_RESEARCH : false;
548
  $planet = intval(is_array($planet) ? $planet['id'] : $planet); // В $planet у нас теперь только её ID или шаблон null/0/false
549
  $que = que_get($user['id'], $planet, $que_type_id, true);
0 ignored issues
show
Bug introduced by
It seems like $que_type_id defined by $planet === null ? QUE_RESEARCH : false on line 547 can also be of type integer; however, que_get() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
550
  if(empty($que['items'])) {
551
    return $que;
552
  }
553
554
  $planet_list = array();
555
  if($planet !== null) {
556
    // Если нужно изменять данные на планетах - блокируем планеты и получаем данные о них
557
    // TODO - от них не надо ничего, кроме ID и que_processed
558
    $planet_row = db_planet_list_by_user_or_planet($user['id'], $planet);
559
    $planet_list[$planet_row['id']] = $planet_row;
560
    $time_left[$planet_row['id_owner']][$planet_row['id']] = max(0, $on_time - $planet_row['que_processed']);
561
  }
562
563
  // Теперь в $time_left лежит время обсчета всех очередей по каждой из планеты
564
  if(array_sum($time_left[$user['id']]) == 0) {
565
    return $que;
566
  }
567
568
  $db_changeset = array();
569
  $unit_changes = array();
570
  foreach($que['items'] as &$que_item) {
571
    $que_player_id = &$que_item['que_player_id'];
572
    $que_planet_id = intval($que_item['que_planet_id']);
573
574
    $que_time_left = &$que['time_left'][$que_player_id][$que_planet_id][$que_item['que_type']];
575
    if(!isset($que_time_left)) {
576
      $que_time_left = $time_left[$que_player_id][$que_planet_id];
577
    }
578
    if($que_time_left <= 0 || $que_item['que_unit_amount'] <= 0) {
579
      continue;
580
    }
581
    // Дальше мы идем, если только осталось время в очереди И юниты к постройке
582
583
    // Вычисляем, сколько целых юнитов будет построено - от 0 до количества юнитов в очереди
584
    $unit_processed = min($que_item['que_unit_amount'] - 1, floor($que_time_left / $que_item['que_unit_time']));
585
    // Вычитаем это время из остатков
586
    $que_time_left -= $unit_processed * $que_item['que_unit_time'];
587
588
    // Теперь работаем с остатком времени на юните. Оно не может быть равно или меньше нуля
589
590
    // Если времени в очереди осталось не меньше, чем время текущего юнита - значит мы достроили юнит
591
    if($que_time_left >= $que_item['que_time_left']) {
592
      // Увеличиваем количество отстроенных юнитов
593
      $unit_processed++;
594
      // Вычитаем из времени очереди потраченное на постройку время
595
      $que_time_left -= $que_item['que_time_left'];
596
      // Полное время юнита равно времени нового юнита
597
      $que_item['que_time_left'] = $que_item['que_unit_time'];
598
      // Тут у нас может остатся время очереди - если постройка была не последняя
599
    }
600
    // Изменяем количество оставшихся юнитов
601
    $que_item['que_unit_amount'] -= $unit_processed;
602
603
    // Если еще остались юниты - значит ВСЁ оставшееся время приходится на достройку следующего юнита
604
    if($que_item['que_unit_amount'] > 0) {
605
      $que_item['que_time_left'] = $que_item['que_time_left'] - $que_time_left;
606
      $que_time_left = 0;
607
    }
608
609
    if($que_item['que_unit_amount'] <= 0) {
610
      $db_changeset['que'][] = array(
611
        'action'  => SQL_OP_DELETE,
612
        P_VERSION => 1,
613
        'where'   => array(
614
          "que_id" => $que_item['que_id'],
615
        ),
616
      );
617
    } else {
618
      $db_changeset['que'][] = array(
619
        'action'  => SQL_OP_UPDATE,
620
        P_VERSION => 1,
621
        'where'   => array(
622
          "que_id" => $que_item['que_id'],
623
        ),
624
        'fields'  => array(
625
          'que_unit_amount' => array(
626
            'delta' => -$unit_processed
627
          ),
628
          'que_time_left'   => array(
629
            'set' => $que_item['que_time_left']
630
          ),
631
        ),
632
      );
633
    }
634
635
    if($unit_processed) {
636
      $unit_processed_delta = $unit_processed * ($que_item['que_unit_mode'] == BUILD_CREATE ? 1 : -1);
637
      $unit_changes[$que_player_id][$que_planet_id][$que_item['que_unit_id']] += $unit_processed_delta;
638
    }
639
  }
640
641
  foreach($time_left as $player_id => $planet_data) {
642
    foreach($planet_data as $planet_id => $time_on_planet) {
643
      $table = $planet_id ? 'planets' : 'users';
644
      $id = $planet_id ? $planet_id : $player_id;
645
      $db_changeset[$table][] = array(
646
        'action'  => SQL_OP_UPDATE,
647
        P_VERSION => 1,
648
        'where'   => array(
649
          "id" => $id,
650
        ),
651
        'fields'  => array(
652
          'que_processed' => array(
653
            'set' => $on_time,
654
          ),
655
        ),
656
      );
657
658
      if(is_array($unit_changes[$player_id][$planet_id])) {
659
        foreach($unit_changes[$player_id][$planet_id] as $unit_id => $unit_amount) {
660
          $db_changeset['unit'][] = sn_db_unit_changeset_prepare($unit_id, $unit_amount, $user, $planet_id ? $planet_id : null);
661
        }
662
      }
663
    }
664
  }
665
666
  $que = que_recalculate($que);
667
668
  // TODO: Re-enable quests for Alliances
669
  if(!empty($unit_changes) && !$user['user_as_ally']) {
670
    $quest_list = qst_get_quests($user['id']);
671
    $quest_triggers = qst_active_triggers($quest_list);
672
    $quest_rewards = array();
673
674
675
    $xp_incoming = array();
676
    foreach($unit_changes as $user_id => $planet_changes) {
677
      foreach($planet_changes as $planet_id => $changes) {
678
        $planet_this = $planet_id ? classSupernova::db_get_record_by_id(LOC_PLANET, $planet_id) : array();
679
        foreach($changes as $unit_id => $unit_value) {
680
          $que_id = que_get_unit_que($unit_id);
681
          $unit_level_new = mrc_get_level($user, $planet_this, $unit_id, false, true) + $unit_value;
682
          if($que_id == QUE_STRUCTURES || $que_id == QUE_RESEARCH) {
683
            $build_data = eco_get_build_data($user, $planet_this, $unit_id, $unit_level_new - 1);
684
            $build_data = $build_data[BUILD_CREATE];
685
            foreach(sn_get_groups('resources_loot') as $resource_id) {
686
              $xp_incoming[$que_id] += $build_data[$resource_id]; // TODO - добавить конверсию рейтов обмена
687
            }
688
          }
689
690
          if(is_array($quest_triggers)) {
691
            // TODO: Check mutiply condition quests
692
            $quest_trigger_list = array_keys($quest_triggers, $unit_id);
693
            if(is_array($quest_trigger_list)) {
694
              foreach($quest_trigger_list as $quest_id) {
695
                $quest_unit_level = $unit_level_new;
696
                if(get_unit_param($unit_id, P_UNIT_TYPE) == UNIT_SHIPS) {
697
                  $quest_unit_level = db_unit_count_by_user_and_type_and_snid($user_id, 0, $unit_id);
698
                  $quest_unit_level = $quest_unit_level[$unit_id]['qty'];
699
                }
700
                if($quest_list[$quest_id]['quest_status_status'] != QUEST_STATUS_COMPLETE && $quest_list[$quest_id]['quest_unit_amount'] <= $quest_unit_level) {
701
                  $quest_rewards[$quest_id][$user_id][$planet_id] = $quest_list[$quest_id]['quest_rewards_list'];
702
                  $quest_list[$quest_id]['quest_status_status'] = QUEST_STATUS_COMPLETE;
703
                }
704
              }
705
            }
706
          }
707
        }
708
      }
709
    }
710
    // TODO: Изменить начисление награды за квесты на ту планету, на которой происходил ресеч
711
    qst_reward($user, $quest_rewards, $quest_list);
712
713
    foreach($xp_incoming as $que_id => $xp) {
714
      rpg_level_up($user, $que_id == QUE_RESEARCH ? RPG_TECH : RPG_STRUCTURE, $xp / 1000);
715
    }
716
  }
717
718
  db_changeset_apply($db_changeset);
719
720
  // TODO Сообщения о постройке
721
722
  return $que;
723
}
724