Issues (1369)

classes/SnTemplate.php (1 issue)

1
<?php
2
3
use Common\Traits\TSingleton;
4
use Core\GlobalContainer;
5
use Fleet\DbFleetStatic;
6
use Note\Note;
7
use \Pages\PageTutorial;
8
use Planet\DBStaticPlanet;
9
use Player\playerTimeDiff;
10
use Template\TemplateMeta;
11
12
/**
13
 * Template manager
14
 */
15
class SnTemplate {
16
17
  use TSingleton;
18
19
  const TPL_HTML = '.tpl.html';
20
  /**
21
   * Partial path to templates root
22
   */
23
  const SN_TEMPLATES_PARTIAL_PATH = 'design/templates/';
24
  const SN_TEMPLATE_NAME_DEFAULT = 'OpenGame';
25
  const P_CONTENT = '__RENDERED_CONTENT';
26
27
  /**
28
   * @param template|string $template
29
   */
30
  public static function displayP($template) {
31
    if (is_object($template)) {
32
      if (empty($template->parsed)) {
33
        self::parsetemplate($template);
34
      }
35
36
      foreach ($template->files as $section => $filename) {
37
        $template->display($section);
38
      }
39
    } else {
40
      print($template);
41
    }
42
  }
43
44
  /**
45
   * @param template|string $template
46
   * @param array|bool      $array
47
   *
48
   * @return mixed
49
   */
50
  public static function parsetemplate($template, $array = false) {
51
    if (is_object($template)) {
52
      return self::templateObjectParse($template, $array);
53
    } else {
54
      $search[]  = '#\{L_([a-z0-9\-_]*?)\[([a-z0-9\-_]*?)\]\}#Ssie';
55
      $replace[] = '((isset($lang[\'\1\'][\'\2\'])) ? $lang[\'\1\'][\'\2\'] : \'{L_\1[\2]}\');';
56
57
      $search[]  = '#\{L_([a-z0-9\-_]*?)\}#Ssie';
58
      $replace[] = '((isset($lang[\'\1\'])) ? $lang[\'\1\'] : \'{L_\1}\');';
59
60
      $search[]  = '#\{([a-z0-9\-_]*?)\}#Ssie';
61
      $replace[] = '((isset($array[\'\1\'])) ? $array[\'\1\'] : \'{\1}\');';
62
63
      return preg_replace($search, $replace, $template);
64
    }
65
  }
66
67
  /**
68
   * @param template   $template
69
   * @param array|bool $array
70
   *
71
   * @return mixed
72
   */
73
  public static function templateObjectParse($template, $array = false) {
74
    global $user;
75
76
    if (!empty($array) && is_array($array)) {
77
      foreach ($array as $key => $data) {
78
        $template->assign_var($key, $data);
79
      }
80
    }
81
82
    $template->assign_vars(array(
83
      'SN_TIME_NOW'      => SN_TIME_NOW,
84
      'SN_TEMPLATE_NAME' => SnTemplate::getPlayerTemplateName(),
85
      'USER_AUTHLEVEL'   => isset($user['authlevel']) ? $user['authlevel'] : -1,
86
      'SN_GOOGLE'        => SN_GOOGLE,
87
    ));
88
89
    $template->parsed = true;
90
91
    return $template;
92
  }
93
94
  /**
95
   * @param array $menu
96
   * @param array $extra
97
   */
98
  public static function tpl_menu_merge_extra(&$menu, &$extra) {
99
    if (!is_array($extra) || !is_array($menu) || empty($menu)) {
100
      return;
101
    }
102
103
    foreach ($extra as $menu_item_id => $menu_item) {
104
      if (empty($menu_item['LOCATION'])) {
105
        $menu[$menu_item_id] = $menu_item;
106
        continue;
107
      }
108
109
      $item_location = $menu_item['LOCATION'];
110
      unset($menu_item['LOCATION']);
111
112
      $is_positioned = $item_location[0];
113
      if ($is_positioned == '+' || $is_positioned == '-') {
114
        $item_location = substr($item_location, 1);
115
      } else {
116
        $is_positioned = '';
117
      }
118
119
      if ($item_location) {
120
        $menu_keys       = array_keys($menu);
121
        $insert_position = array_search($item_location, $menu_keys);
122
        if ($insert_position === false) {
123
          $insert_position = count($menu) - 1;
124
          $is_positioned   = '+';
125
          $item_location   = '';
126
        }
127
      } else {
128
        $insert_position = $is_positioned == '-' ? 0 : count($menu);
129
      }
130
131
      $insert_position     += $is_positioned == '+' ? 1 : 0;
132
      $spliced             = array_splice($menu, $insert_position, count($menu) - $insert_position);
133
      $menu[$menu_item_id] = $menu_item;
134
135
      if (!$is_positioned && $item_location) {
136
        unset($spliced[$item_location]);
137
      }
138
      $menu = array_merge($menu, $spliced);
139
    }
140
141
    $extra = array();
142
  }
143
144
  /**
145
   * @param array $menu
146
   *
147
   * @return array
148
   */
149
  public static function tpl_menu_adminize($menu) {
150
    !is_array($menu) ? $menu = [] : false;
151
152
    foreach ($menu as &$menuItem) {
153
      if (!isset($menuItem[MENU_FIELD_AUTH_LEVEL])) {
154
        $menuItem[MENU_FIELD_AUTH_LEVEL] = AUTH_LEVEL_ADMINISTRATOR;
155
      }
156
    }
157
158
    return $menu;
159
  }
160
161
  /**
162
   * @param array    $sn_menu
163
   * @param template $template
164
   */
165
  public static function tpl_menu_assign_to_template(&$sn_menu, &$template) {
166
    global $lang;
167
168
    if (empty($sn_menu) || !is_array($sn_menu)) {
169
      return;
170
    }
171
172
    foreach ($sn_menu as $menu_item_id => $menu_item) {
173
      if (!$menu_item) {
174
        continue;
175
      }
176
177
      if (is_string($menu_item_id)) {
178
        $menu_item['ID'] = $menu_item_id;
179
      }
180
181
      if ($menu_item['TYPE'] == 'lang') {
182
        $lang_string = &$lang;
183
        if (preg_match('#(\w+)(?:\[(\w+)\])?(?:\[(\w+)\])?(?:\[(\w+)\])?(?:\[(\w+)\])?#', $menu_item['ITEM'], $matches) && count($matches) > 1) {
184
          for ($i = 1; $i < count($matches); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
185
            if (defined($matches[$i])) {
186
              $matches[$i] = constant($matches[$i]);
187
            }
188
            $lang_string = &$lang_string[$matches[$i]];
189
          }
190
        }
191
        $menu_item['ITEM'] = $lang_string && is_string($lang_string) ? $lang_string : "{L_{$menu_item['ITEM']}}";
192
      }
193
194
      $menu_item['ALT']   = htmlentities($menu_item['ALT']);
195
      $menu_item['TITLE'] = htmlentities($menu_item['TITLE']);
196
197
      if (!empty($menu_item['ICON'])) {
198
        if (is_string($menu_item['ICON'])) {
199
          $menu_item['ICON_PATH'] = $menu_item['ICON'];
200
        } else {
201
          $menu_item['ICON'] = $menu_item_id;
202
        }
203
      }
204
205
      $template->assign_block_vars('menu', $menu_item);
206
    }
207
  }
208
209
  /**
210
   * @param template $template
211
   *
212
   * @return template
213
   */
214
  public static function tpl_render_menu($template) {
215
    global $user, $lang, $template_result, $sn_menu_admin_extra, $sn_menu_admin, $sn_menu, $sn_menu_extra;
216
217
    lng_include('admin');
218
219
    $template->assign_vars(array(
220
      'USER_AUTHLEVEL'      => $user['authlevel'],
221
      'USER_AUTHLEVEL_NAME' => $lang['user_level'][$user['authlevel']],
222
      'PAYMENT'             => SN::$gc->modules->countModulesInGroup('payment'),
223
      'MENU_START_HIDE'     => !empty($_COOKIE[SN_COOKIE . '_menu_hidden']) || SN_GOOGLE,
224
    ));
225
226
    if (isset($template_result['MENU_CUSTOMIZE'])) {
227
      $template->assign_vars(array(
228
        'PLAYER_OPTION_MENU_SHOW_ON_BUTTON'   => SN::$user_options[PLAYER_OPTION_MENU_SHOW_ON_BUTTON],
229
        'PLAYER_OPTION_MENU_HIDE_ON_BUTTON'   => SN::$user_options[PLAYER_OPTION_MENU_HIDE_ON_BUTTON],
230
        'PLAYER_OPTION_MENU_HIDE_ON_LEAVE'    => SN::$user_options[PLAYER_OPTION_MENU_HIDE_ON_LEAVE],
231
        'PLAYER_OPTION_MENU_UNPIN_ABSOLUTE'   => SN::$user_options[PLAYER_OPTION_MENU_UNPIN_ABSOLUTE],
232
        'PLAYER_OPTION_MENU_ITEMS_AS_BUTTONS' => SN::$user_options[PLAYER_OPTION_MENU_ITEMS_AS_BUTTONS],
233
        'PLAYER_OPTION_MENU_WHITE_TEXT'       => SN::$user_options[PLAYER_OPTION_MENU_WHITE_TEXT],
234
        'PLAYER_OPTION_MENU_OLD'              => SN::$user_options[PLAYER_OPTION_MENU_OLD],
235
        'PLAYER_OPTION_MENU_HIDE_SHOW_BUTTON' => empty($_COOKIE[SN_COOKIE . '_menu_hidden']) && !SN_GOOGLE
236
          ? SN::$user_options[PLAYER_OPTION_MENU_HIDE_SHOW_BUTTON] : 1,
237
      ));
238
    }
239
240
    if (defined('IN_ADMIN') && IN_ADMIN === true && !empty($user['authlevel']) && $user['authlevel'] > 0) {
241
      SnTemplate::tpl_menu_merge_extra($sn_menu_admin, $sn_menu_admin_extra);
242
      $sn_menu_admin = SnTemplate::tpl_menu_adminize($sn_menu_admin);
243
      SnTemplate::tpl_menu_assign_to_template($sn_menu_admin, $template);
244
    } else {
245
      SnTemplate::tpl_menu_merge_extra($sn_menu, $sn_menu_extra);
246
      SnTemplate::tpl_menu_assign_to_template($sn_menu, $template);
247
    }
248
249
    return $template;
250
  }
251
252
  /**
253
   * @param template[] $page
254
   * @param array      $template_result
255
   */
256
  public static function renderFooter($page, $template_result) {
257
    $templateFooter = self::gettemplate('_page/_99_footer', true);
258
259
    $templateFooter->assign_vars([
260
      'SN_TIME_NOW'      => SN_TIME_NOW,
261
      'SN_VERSION'       => SN_VERSION,
262
      'ADMIN_EMAIL'      => SN::$config->game_adminEmail,
263
      'CURRENT_YEAR'     => date('Y', SN_TIME_NOW),
264
      'DB_PATCH_VERSION' => dbPatchGetCurrent(),
265
    ]);
266
267
    SnTemplate::displayP($templateFooter);
268
  }
269
270
  /**
271
   * @param $page
272
   * @param $title
273
   * @param $template_result
274
   * @param $inLoginLogout
275
   * @param $user
276
   * @param $config
277
   * @param $lang
278
   * @param $planetrow
279
   */
280
  public static function renderHeader($page, $title, &$template_result, $inLoginLogout, &$user, $config, $lang, $planetrow, $renderedContent) {
281
    if (SN::$headerRendered) {
282
      return;
283
    }
284
285
    ob_end_flush();
286
287
    ob_start();
288
//  pdump(microtime(true) - SN_TIME_MICRO, 'Header render started');
289
    $isDisplayTopNav = true;
290
    $isDisplayMenu   = true;
291
292
    isset($template_result['GLOBAL_DISPLAY_MENU']) ? $isDisplayMenu = $template_result['GLOBAL_DISPLAY_MENU'] : false;
293
    isset($template_result['GLOBAL_DISPLAY_NAVBAR']) ? $isDisplayTopNav = $template_result['GLOBAL_DISPLAY_NAVBAR'] : false;
294
295
    // TODO: DEPRECATED! Use $template_result to turn menu and navbar or ond off!
296
    if (is_object($page)) {
297
      isset($page->_rootref['MENU']) ? $isDisplayMenu = $page->_rootref['MENU'] : false;
298
      isset($page->_rootref['NAVBAR']) ? $isDisplayTopNav = $page->_rootref['NAVBAR'] : false;
299
    }
300
301
    $inAdmin         = defined('IN_ADMIN') && IN_ADMIN === true;
302
    $isDisplayMenu   = ($isDisplayMenu || $inAdmin) && !isset($_COOKIE['menu_disable']);
303
    $isDisplayTopNav = $isDisplayTopNav && !$inAdmin;
304
305
    if ($inLoginLogout || empty($user['id']) || !is_numeric($user['id'])) {
306
      $isDisplayMenu   = false;
307
      $isDisplayTopNav = false;
308
    }
309
310
    $template = self::gettemplate('_page/_00_header', true);
311
    $template->assign_vars([
312
      'SN_TIME_NOW'      => SN_TIME_NOW,
313
      'SN_VERSION'       => SN_VERSION,
314
      'ADMIN_EMAIL'      => SN::$config->game_adminEmail,
315
      'CURRENT_YEAR'     => date('Y', SN_TIME_NOW),
316
      'DB_PATCH_VERSION' => dbPatchGetCurrent(),
317
    ]);
318
319
    self::renderJavaScript();
320
321
    self::renderCss($inLoginLogout);
322
323
    $template->assign_vars(array(
324
      self::P_CONTENT => $renderedContent,
325
326
      'LANG_LANGUAGE'  => $lang['LANG_INFO']['LANG_NAME_ISO2'],
327
      'LANG_ENCODING'  => 'utf-8',
328
      'LANG_DIRECTION' => $lang['LANG_INFO']['LANG_DIRECTION'],
329
330
      'SN_ROOT_VIRTUAL' => SN_ROOT_VIRTUAL,
331
332
      'ADV_SEO_META_DESCRIPTION' => $config->adv_seo_meta_description,
333
      'ADV_SEO_META_KEYWORDS'    => $config->adv_seo_meta_keywords,
334
335
      // WARNING! This can be set by page!
336
      // CHANGE CODE TO MAKE IT IMPOSSIBLE!
337
      'GLOBAL_META_TAGS'         => isset($page->_rootref['GLOBAL_META_TAGS']) ? $page->_rootref['GLOBAL_META_TAGS'] : '',
338
339
      'IN_ADMIN' => $inAdmin ? 1 : '',
340
    ));
341
342
    $template->assign_vars(array(
343
      'GLOBAL_DISPLAY_MENU'   => $isDisplayMenu,
344
      'GLOBAL_DISPLAY_NAVBAR' => $isDisplayTopNav,
345
346
      'USER_AUTHLEVEL' => intval($user['authlevel']),
347
348
      'FONT_SIZE'                        => self::playerFontSize(),
349
      'FONT_SIZE_PERCENT_DEFAULT_STRING' => FONT_SIZE_PERCENT_DEFAULT_STRING,
350
351
      'SN_TIME_NOW'          => SN_TIME_NOW,
352
      'LOGIN_LOGOUT'         => $template_result['LOGIN_LOGOUT'],
353
      'GAME_MODE_CSS_PREFIX' => $config->game_mode == GAME_BLITZ ? 'blitz_' : '',
354
      'TIME_DIFF_MEASURE'    => playerTimeDiff::timeDiffTemplate(), // Проводить замер только если не выставлен флаг форсированного замера И (иссяк интервал замера ИЛИ замера еще не было)
355
356
      'title'              => ($title ? "{$title} - " : '') . "{$lang['sys_server']} {$config->game_name} - {$lang['sys_supernova']}",
357
      'ADV_SEO_JAVASCRIPT' => $config->adv_seo_javascript,
358
359
      'SOUND_ENABLED'                        => SN::$user_options[PLAYER_OPTION_SOUND_ENABLED],
360
      'PLAYER_OPTION_ANIMATION_DISABLED'     => SN::$user_options[PLAYER_OPTION_ANIMATION_DISABLED],
361
      'PLAYER_OPTION_PROGRESS_BARS_DISABLED' => SN::$user_options[PLAYER_OPTION_PROGRESS_BARS_DISABLED],
362
363
      'IMPERSONATING'                        => !empty($template_result[F_IMPERSONATE_STATUS]) ? sprintf($lang['sys_impersonated_as'], $user['username'], $template_result[F_IMPERSONATE_OPERATOR]) : '',
364
      'PLAYER_OPTION_DESIGN_DISABLE_BORDERS' => SN::$user_options[PLAYER_OPTION_DESIGN_DISABLE_BORDERS],
365
366
      'WEBP_SUPPORT_NEED_CHECK' => ($webpSupported = SN::$gc->theUser->isWebpSupported()) === null ? 1 : 0,
367
      'WEBP_SUPPORTED'          => $webpSupported ? 1 : 0,
368
    ));
369
    $template->assign_recursive($template_result);
370
371
    if ($isDisplayMenu) {
372
      SnTemplate::tpl_render_menu($template);
373
    }
374
375
    if ($isDisplayTopNav) {
376
      SN::$gc->pimp->tpl_render_topnav($user, $planetrow, $template);
377
    }
378
379
    SnTemplate::displayP($template);
380
    ob_end_flush();
381
382
    SN::$headerRendered = true;
383
384
    ob_start();
385
  }
386
387
  /**
388
   */
389
  public static function renderJavaScript() {
390
    global $sn_mvc, $sn_page_name, $template_result;
391
392
    empty($sn_mvc['javascript']) ? $sn_mvc['javascript'] = ['' => []] : false;
393
394
    $standard_js = self::addFileName([
395
      'js/lib/jquery',
396
      'js/lib/js.cookie',
397
      'js/lib/jquery-ui',
398
      'js/lib/jquery.ui.touch-punch',
399
      'js/lib/ion.sound',
400
      'js/sn_global',
401
      'js/sn_sound',
402
      'js/sn_timer',
403
    ], [], '.js');
404
405
    $standard_js = self::addFileName(!empty($sn_mvc['javascript_filenames']) ? $sn_mvc['javascript_filenames'] : [], $standard_js, '.js');
406
407
    $standard_js = self::cacheFiles($standard_js, '.js');
408
409
    // Prepending standard CSS files
410
    $sn_mvc['javascript'][''] = array_merge($standard_js, $sn_mvc['javascript']['']);
411
412
    self::renderFileListInclude($template_result, $sn_mvc, $sn_page_name, 'javascript');
413
  }
414
415
  /**
416
   * @param $is_login
417
   */
418
  public static function renderCss($is_login) {
419
    global $sn_mvc, $sn_page_name, $template_result;
420
421
    empty($sn_mvc['css']) ? $sn_mvc['css'] = ['' => []] : false;
422
423
    $standard_css = [];
424
    $standard_css = self::addFileName('design/css/jquery-ui', $standard_css);
425
    $standard_css = self::addFileName('design/css/global', $standard_css);
426
    $is_login ? $standard_css = self::addFileName('design/css/login', $standard_css) : false;
427
    $standard_css = self::addFileName('design/css/menu_icons', $standard_css);
428
429
    $standard_css = self::getCurrentTemplate()->cssAddFileName('_template', $standard_css);
430
431
    $standard_css = self::addFileName(SN::$gc->theUser->getSkinPath() . 'skin', $standard_css);
432
    $standard_css = self::addFileName('design/css/global_override', $standard_css);
433
434
    // Trying to add extra CSS to cache file
435
    foreach ($sn_mvc['css'][''] as $css => $cork) {
436
      $cssOriginal = $css;
437
438
      // At first - removing minimization flag from file name
439
      if(($rPos = strrpos($css, '.min.css')) !== false) {
440
        // 4 - string length of substring to cut `.min`
441
        $css = substr_replace($css, '', $rPos, 4);
442
      }
443
      // Also we don't need `.css` extension
444
      if(($rPos = strrpos($css, '.css')) !== false) {
445
        // 4 - string length of substring to cut `.css`
446
        $css = substr_replace($css, '', $rPos, 4);
447
      }
448
449
      // Memorizing size of css filename array
450
      $cssWas = count($standard_css);
451
      // Trying to add newly found filename
452
      $standard_css = self::addFileName($css, $standard_css);
453
      if(count($standard_css) > $cssWas) {
454
        // Removing file from extra CSS list only if everything went well and records was added to list of CSS to cache
455
        // Otherwise something went wrong - so we don't touch this
456
        unset($sn_mvc['css'][''][$cssOriginal]);
457
      }
458
    }
459
460
    // Trying to cache CSS files
461
    $standard_css = self::cacheFiles($standard_css);
462
463
    // Prepending standard CSS files
464
    $sn_mvc['css'][''] = array_merge($standard_css, $sn_mvc['css']['']);
465
466
    self::renderFileListInclude($template_result, $sn_mvc, $sn_page_name, 'css');
467
  }
468
469
  /**
470
   * @param $time
471
   * @param $event
472
   * @param $msg
473
   * @param $prefix
474
   * @param $is_decrease
475
   * @param $fleet_flying_row
476
   * @param $fleet_flying_sorter
477
   * @param $fleet_flying_events
478
   * @param $fleet_event_count
479
   */
480
  public static function tpl_topnav_event_build_helper($time, $event, $msg, $prefix, $is_decrease, $fleet_flying_row, &$fleet_flying_sorter, &$fleet_flying_events, &$fleet_event_count) {
481
    $fleet_flying_sorter[$fleet_event_count] = $time;
482
    $fleet_flying_events[$fleet_event_count] = array(
483
      'ROW'              => $fleet_flying_row,
484
      'FLEET_ID'         => $fleet_flying_row['fleet_id'],
485
      'EVENT'            => $event,
486
      'COORDINATES'      => uni_render_coordinates($fleet_flying_row, $prefix),
487
      'COORDINATES_TYPE' => $fleet_flying_row["{$prefix}type"],
488
      'TEXT'             => "{$msg}",
489
      'DECREASE'         => $is_decrease,
490
    );
491
    $fleet_event_count++;
492
  }
493
494
  /**
495
   * @param template $template
496
   * @param array    $fleet_flying_list
497
   * @param string   $type
498
   */
499
  public static function tpl_topnav_event_build(&$template, $fleet_flying_list, $type = 'fleet') {
500
    if (empty($fleet_flying_list)) {
501
      return;
502
    }
503
504
    global $lang;
505
506
    $fleet_event_count   = 0;
507
    $fleet_flying_sorter = array();
508
    $fleet_flying_events = array();
509
    foreach ($fleet_flying_list as &$fleet_flying_row) {
510
      $will_return = true;
511
      if ($fleet_flying_row['fleet_mess'] == 0) {
512
        // cut fleets on Hold and Expedition
513
        if ($fleet_flying_row['fleet_start_time'] >= SN_TIME_NOW) {
514
          $fleet_flying_row['fleet_mission'] == MT_RELOCATE ? $will_return = false : false;
515
          SnTemplate::tpl_topnav_event_build_helper($fleet_flying_row['fleet_start_time'], EVENT_FLEET_ARRIVE, $lang['sys_event_arrive'], 'fleet_end_', !$will_return, $fleet_flying_row, $fleet_flying_sorter, $fleet_flying_events, $fleet_event_count);
516
        }
517
        if ($fleet_flying_row['fleet_end_stay']) {
518
          SnTemplate::tpl_topnav_event_build_helper($fleet_flying_row['fleet_end_stay'], EVENT_FLEET_STAY, $lang['sys_event_stay'], 'fleet_end_', false, $fleet_flying_row, $fleet_flying_sorter, $fleet_flying_events, $fleet_event_count);
519
        }
520
      }
521
      if ($will_return) {
522
        SnTemplate::tpl_topnav_event_build_helper($fleet_flying_row['fleet_end_time'], EVENT_FLEET_RETURN, $lang['sys_event_return'], 'fleet_start_', true, $fleet_flying_row, $fleet_flying_sorter, $fleet_flying_events, $fleet_event_count);
523
      }
524
    }
525
526
    asort($fleet_flying_sorter);
527
528
    $fleet_flying_count = count($fleet_flying_list);
529
    foreach ($fleet_flying_sorter as $fleet_event_id => $fleet_time) {
530
      $fleet_event = &$fleet_flying_events[$fleet_event_id];
531
      $template->assign_block_vars("flying_{$type}s", array(
532
        'TIME' => max(0, $fleet_time - SN_TIME_NOW),
533
        'TEXT' => $fleet_flying_count,
534
        'HINT' => date(FMT_DATE_TIME, $fleet_time + SN_CLIENT_TIME_DIFF) . " - {$lang['sys_fleet']} {$fleet_event['TEXT']} {$fleet_event['COORDINATES']} {$lang['sys_planet_type_sh'][$fleet_event['COORDINATES_TYPE']]} {$lang['type_mission'][$fleet_event['ROW']['fleet_mission']]}",
535
      ));
536
      $fleet_event['DECREASE'] ? $fleet_flying_count-- : false;
537
    }
538
  }
539
540
  /**
541
   * @return mixed|string
542
   */
543
  public static function playerFontSize() {
544
    $font_size = !empty($_COOKIE[SN_COOKIE_F]) ? $_COOKIE[SN_COOKIE_F] : SN::$user_options[PLAYER_OPTION_BASE_FONT_SIZE];
545
    if (strpos($font_size, '%') !== false) {
546
      // Размер шрифта в процентах
547
      $font_size = min(max(floatval($font_size), FONT_SIZE_PERCENT_MIN), FONT_SIZE_PERCENT_MAX) . '%';
548
549
      return $font_size;
550
    } elseif (strpos($font_size, 'px') !== false) {
551
      // Размер шрифта в пикселях
552
      $font_size = min(max(floatval($font_size), FONT_SIZE_PIXELS_MIN), FONT_SIZE_PIXELS_MAX) . 'px';
553
554
      return $font_size;
555
    } else {
556
      // Не мышонка, не лягушка...
557
      $font_size = FONT_SIZE_PERCENT_DEFAULT_STRING;
558
559
      return $font_size;
560
    }
561
  }
562
563
  /**
564
   * Checks if minified/full-size file variant exists - and adds it if any
565
   *
566
   * @param string|string[] $fileNames
567
   * @param array  $anArray
568
   *
569
   * @return array
570
   */
571
  public static function addFileName($fileNames, $anArray, $ext = '.css') {
572
    if(!is_array($fileNames)) {
573
      $fileNames = [$fileNames];
574
    }
575
576
    foreach($fileNames as $fileName) {
577
      if (file_exists(SN_ROOT_PHYSICAL . $fileName . '.min' . $ext)) {
578
        $anArray[$fileName . '.min' . $ext] = '';
579
      } elseif (file_exists(SN_ROOT_PHYSICAL . $fileName . '.css' . $ext)) {
580
        $anArray[$fileName . $ext] = '';
581
      }
582
    }
583
584
    return $anArray;
585
  }
586
587
  /**
588
   * @param array   $template_result
589
   * @param array[] $sn_mvc
590
   * @param string  $sn_page_name
591
   * @param string  $fileType - 'css' or 'javascript'
592
   */
593
  public static function renderFileListInclude(&$template_result, &$sn_mvc, $sn_page_name, $fileType) {
594
    if (empty($sn_mvc[$fileType])) {
595
      return;
596
    }
597
598
    foreach ($sn_mvc[$fileType] as $page_name => $script_list) {
599
      if (empty($page_name) || $page_name == $sn_page_name) {
600
        foreach ($script_list as $filename => $content) {
601
          $template_result['.'][$fileType][] = array(
602
            'FILE'    => $filename,
603
            'CONTENT' => $content,
604
          );
605
        }
606
      }
607
    }
608
  }
609
610
  /**
611
   * @param $template
612
   * @param $user
613
   */
614
  public static function tpl_navbar_render_notes(&$template, &$user) {
615
    $notes_query = doquery("SELECT * FROM {{notes}} WHERE `owner` = {$user['id']} AND `sticky` = 1 ORDER BY priority DESC, time DESC");
616
    while ($note_row = db_fetch($notes_query)) {
617
      Note::note_assign($template, $note_row);
618
    }
619
  }
620
621
  /**
622
   * @param             $template
623
   * @param             $user
624
   * @param classConfig $config
625
   */
626
  public static function tpl_navbar_render_news(&$template, &$user, $config) {
627
    if ($config->game_news_overview) {
628
      $user_last_read_safe     = intval($user['news_lastread']);
629
      $newsSql                 = "AND UNIX_TIMESTAMP(`tsTimeStamp`) >= {$user_last_read_safe} ";
630
      $newsOverviewShowSeconds = intval($config->game_news_overview_show);
631
      if ($newsOverviewShowSeconds) {
632
        $newsSql .= "AND `tsTimeStamp` >= DATE_SUB(NOW(), INTERVAL {$newsOverviewShowSeconds} SECOND) ";
633
      }
634
      nws_render($user, $template, $newsSql, $config->game_news_overview);
635
    }
636
  }
637
638
  /**
639
   * @param array  $sn_mvc
640
   * @param string $blockName
641
   *
642
   * @return array|false
643
   */
644
  public static function render_button_block(&$sn_mvc, $blockName) {
645
    $result = false;
646
647
    if (!empty($sn_mvc[$blockName]) && is_array($sn_mvc[$blockName])) {
648
      foreach ($sn_mvc[$blockName] as $navbar_button_image => $navbar_button_url) {
649
        $result[] = array(
650
          'IMAGE'        => $navbar_button_image,
651
          'URL_RELATIVE' => $navbar_button_url,
652
        );
653
      }
654
655
      $result = array(
656
        '.' => array(
657
          $blockName =>
658
            $result
659
        ),
660
      );
661
    }
662
663
    return $result;
664
  }
665
666
  /**
667
   * @param array    $sn_mvc
668
   * @param template $template
669
   */
670
  public static function tpl_navbar_extra_buttons(&$sn_mvc, $template) {
671
    ($block = SnTemplate::render_button_block($sn_mvc, 'navbar_prefix_button')) ? $template->assign_recursive($block) : false;
672
    ($block = SnTemplate::render_button_block($sn_mvc, 'navbar_main_button')) ? $template->assign_recursive($block) : false;
673
  }
674
675
  /**
676
   * @param template|string $template
677
   *
678
   * @return false|string|null
679
   */
680
  public static function templateRenderToHtml($template) {
681
    $output = null;
682
683
    ob_start();
684
    SnTemplate::displayP($template);
685
    $output = ob_get_contents();
686
    ob_end_clean();
687
688
    return $output;
689
  }
690
691
  /**
692
   * @param template $template
693
   */
694
  public static function tpl_login_lang(&$template) {
695
    global $language;
696
697
    $url_params = array();
698
699
    $language ? $url_params[] = "lang={$language}" : false;
700
701
    ($id_ref = sys_get_param_id('id_ref')) ? $url_params[] = "id_ref={$id_ref}" : false;
702
703
    $template->assign_vars($q = array(
704
      'LANG'     => $language ? $language : '',
705
      'referral' => $id_ref ? '&id_ref=' . $id_ref : '',
706
707
      'REQUEST_PARAMS' => !empty($url_params) ? '?' . implode('&', $url_params) : '',// "?lang={$language}" . ($id_ref ? "&id_ref={$id_ref}" : ''),
708
      'FILENAME'       => basename($_SERVER['PHP_SELF']),
709
    ));
710
711
    foreach (lng_get_list() as $lng_id => $lng_data) {
712
      if (isset($lng_data['LANG_VARIANTS']) && is_array($lng_data['LANG_VARIANTS'])) {
713
        foreach ($lng_data['LANG_VARIANTS'] as $lang_variant) {
714
          $lng_data1 = $lng_data;
715
          $lng_data1 = array_merge($lng_data1, $lang_variant);
716
          $template->assign_block_vars('language', $lng_data1);
717
        }
718
      } else {
719
        $template->assign_block_vars('language', $lng_data);
720
      }
721
    }
722
  }
723
724
  /**
725
   * @param template $template
726
   * @param string   $blockName
727
   * @param mixed    $values
728
   * @param string   $keyName   - Name for key name
729
   * @param string   $valueName - Name for value name
730
   */
731
  public static function tpl_assign_select(&$template, $blockName, $values, $keyName = 'KEY', $valueName = 'VALUE') {
732
    !is_array($values) ? $values = array($values => $values) : false;
733
734
    foreach ($values as $key => $value) {
735
      $template->assign_block_vars($blockName, array(
736
        $keyName   => HelperString::htmlSafe($key),
737
        $valueName => HelperString::htmlSafe($value),
738
      ));
739
    }
740
  }
741
742
  /**
743
   * Renders unit bonus from unit data
744
   *
745
   * @param array $unitInfo
746
   *
747
   * @return string
748
   */
749
  public static function tpl_render_unit_bonus_data($unitInfo) {
750
    $strBonus = self::tplAddPlus($unitInfo[P_BONUS_VALUE]);
751
    switch ($unitInfo[P_BONUS_TYPE]) {
752
      case BONUS_PERCENT:
753
        $strBonus = "{$strBonus}% ";
754
      break;
755
756
      case BONUS_ABILITY:
757
        $strBonus = '';
758
      break;
759
760
      case BONUS_ADD:
761
      default:
762
      break;
763
    }
764
765
    return $strBonus;
766
  }
767
768
  /**
769
   * Converts number to string then adds "+" sign for positive AND ZERO numbers
770
   *
771
   * @param float $value
772
   *
773
   * @return string
774
   */
775
  public static function tplAddPlus($value) {
776
    return ($value >= 0 ? '+' : '') . $value;
777
  }
778
779
  /**
780
   * Convert number to prettified string then adds "+" sign for positive AND ZERO numbers
781
   *
782
   * @param float $value
783
   *
784
   * @return string
785
   */
786
  public static function tplPrettyPlus($value) {
787
    return ($value >= 0 ? '+' : '') . HelperString::numberFloorAndFormat($value);
788
  }
789
790
  /**
791
   * Add message to result box
792
   *
793
   * If $template specified - message would be added to template supplied. Otherwise - to $template_result
794
   *
795
   * @param string $message
796
   * @param int    $status
797
   * @param null   $template
798
   */
799
  public static function tplAddResult($message, $status = ERR_NONE, $template = null) {
800
    global $template_result;
801
802
    $block = [
803
      'STATUS'  => $status,
804
      'MESSAGE' => $message,
805
    ];
806
807
    if ($template instanceof template) {
808
      $template->assign_block_vars('result', $block);
809
    } else {
810
      $template_result['.']['result'][] = $block;
811
    }
812
  }
813
814
  /**
815
   * @param string    $message
816
   * @param string    $title
817
   * @param string    $redirectTo
818
   * @param int       $timeout
819
   * @param bool|true $showHeader
820
   */
821
  public static function messageBox($message, $title = '', $redirectTo = '', $timeout = 5, $showHeader = true) {
822
    global $lang, $template_result;
823
824
    if (empty($title)) {
825
      $title = $lang['sys_error'];
826
    }
827
828
    $template = self::gettemplate('message_body', true);
829
830
    $template_result['GLOBAL_DISPLAY_NAVBAR'] = $showHeader;
831
832
    $template->assign_vars(array(
833
//    'GLOBAL_DISPLAY_NAVBAR' => $showHeader,
834
835
      'TITLE'       => $title,
836
      'MESSAGE'     => $message,
837
      'REDIRECT_TO' => $redirectTo,
838
      'TIMEOUT'     => $timeout,
839
    ));
840
841
    self::display($template, $title);
842
  }
843
844
  /**
845
   * Admin message box
846
   *
847
   * @param        $message
848
   * @param string $title
849
   * @param string $redirectTo
850
   * @param int    $timeout
851
   *
852
   * @see SnTemplate::messageBox()
853
   */
854
  public static function messageBoxAdmin($message, $title = '', $redirectTo = '', $timeout = 5) {
855
    SnTemplate::messageBox($message, $title, $redirectTo, $timeout, false);
856
  }
857
858
  public static function messageBoxAdminAccessDenied($level = AUTH_LEVEL_ADMINISTRATOR) {
859
    global $user, $lang;
860
861
    if ($user['authlevel'] < $level) {
862
      SnTemplate::messageBoxAdmin($lang['adm_err_denied'], $lang['admin_title_access_denied'], SN_ROOT_VIRTUAL . 'overview.php');
863
    }
864
  }
865
866
  /**
867
   * @param          $prevUser
868
   * @param array    $user
869
   * @param array    $planetrow
870
   * @param template $template
871
   *
872
   * @return array
873
   */
874
  public static function sn_tpl_render_topnav(&$prevUser, $user, $planetrow, $template) {
875
    global $lang, $config, $sn_mvc;
876
877
    // This call was not first one... Using results from previous call
878
    if (!empty($prevUser['username'])) {
879
      $user = $prevUser;
880
    }
881
882
    if (!is_array($user)) {
883
      return $user;
884
    }
885
886
    $GET_mode = sys_get_param_str('mode');
887
888
    $ThisUsersPlanets = DBStaticPlanet::db_planet_list_sorted($user);
889
    foreach ($ThisUsersPlanets as $CurPlanet) {
890
      if ($CurPlanet['destruyed']) {
891
        continue;
892
      }
893
894
      $fleet_listx = flt_get_fleets_to_planet($CurPlanet);
895
      if ($CurPlanet['planet_type'] == PT_MOON) {
896
        $parentPlanet = DBStaticPlanet::db_planet_by_id($CurPlanet['parent_planet']);
897
      } else {
898
        $parentPlanet = $CurPlanet;
899
      }
900
901
      $template->assign_block_vars('topnav_planets', [
902
        'ID'          => $CurPlanet['id'],
903
        'NAME'        => $CurPlanet['name'],
904
        'TYPE'        => $CurPlanet['planet_type'],
905
        'TYPE_TEXT'   => $lang['sys_planet_type_sh'][$CurPlanet['planet_type']],
906
        'IS_CAPITAL'  => $parentPlanet['id'] == $user['id_planet'],
907
        'IS_MOON'     => $CurPlanet['planet_type'] == PT_MOON,
908
        'PLIMAGE'     => $CurPlanet['image'],
909
        'FLEET_ENEMY' => $fleet_listx['enemy']['count'],
910
        'COORDS'      => uni_render_coordinates($CurPlanet),
911
        'SELECTED'    => $CurPlanet['id'] == $user['current_planet'] ? ' selected' : '',
912
      ]);
913
    }
914
915
    $fleet_flying_list = DbFleetStatic::tpl_get_fleets_flying($user);
916
    SnTemplate::tpl_topnav_event_build($template, $fleet_flying_list[0]);
917
    SnTemplate::tpl_topnav_event_build($template, $fleet_flying_list[MT_EXPLORE], 'expedition');
918
919
    que_tpl_parse($template, QUE_STRUCTURES, $user, $planetrow, null, true);
920
    que_tpl_parse($template, QUE_RESEARCH, $user, array(), null, !SN::$user_options[PLAYER_OPTION_NAVBAR_RESEARCH_WIDE]);
921
    que_tpl_parse($template, SUBQUE_FLEET, $user, $planetrow, null, true);
922
    que_tpl_parse($template, SUBQUE_DEFENSE, $user, $planetrow, null, true);
923
924
    SnTemplate::tpl_navbar_extra_buttons($sn_mvc, $template);
925
    SnTemplate::tpl_navbar_render_news($template, $user, $config);
926
    SnTemplate::tpl_navbar_render_notes($template, $user);
927
    $tutorial_enabled = PageTutorial::renderNavBar($template);
928
929
930
    $premium_lvl = mrc_get_level($user, false, UNIT_PREMIUM, true, true);
931
932
    $str_date_format   = "%3$02d %2$0s %1$04d {$lang['top_of_year']} %4$02d:%5$02d:%6$02d";
933
    $time_now_parsed   = getdate(SN_TIME_NOW);
934
    $time_local_parsed = getdate(defined('SN_CLIENT_TIME_LOCAL') ? SN_CLIENT_TIME_LOCAL : SN_TIME_NOW);
935
936
    $template->assign_vars(array(
937
      'QUE_ID'   => QUE_RESEARCH,
938
      'QUE_HTML' => 'topnav',
939
940
      'RESEARCH_ONGOING' => (boolean)$user['que'],
941
942
      'TIME_TEXT'       => sprintf($str_date_format, $time_now_parsed['year'], $lang['months'][$time_now_parsed['mon']], $time_now_parsed['mday'],
943
        $time_now_parsed['hours'], $time_now_parsed['minutes'], $time_now_parsed['seconds']
944
      ),
945
      'TIME_TEXT_LOCAL' => sprintf($str_date_format, $time_local_parsed['year'], $lang['months'][$time_local_parsed['mon']], $time_local_parsed['mday'],
946
        $time_local_parsed['hours'], $time_local_parsed['minutes'], $time_local_parsed['seconds']
947
      ),
948
949
      'GAME_BLITZ_REGISTER'             => $config->game_blitz_register,
950
      'GAME_BLITZ_REGISTER_TEXT'        => $lang['sys_blitz_registration_mode_list'][$config->game_blitz_register],
951
      'BLITZ_REGISTER_OPEN'             => $config->game_blitz_register == BLITZ_REGISTER_OPEN,
952
      'BLITZ_REGISTER_CLOSED'           => $config->game_blitz_register == BLITZ_REGISTER_CLOSED,
953
      'BLITZ_REGISTER_SHOW_LOGIN'       => $config->game_blitz_register == BLITZ_REGISTER_SHOW_LOGIN,
954
      'BLITZ_REGISTER_DISCLOSURE_NAMES' => $config->game_blitz_register == BLITZ_REGISTER_DISCLOSURE_NAMES,
955
      'GAME_BLITZ'                      => $config->game_mode == GAME_BLITZ,
956
957
      'USERS_ONLINE'  => $config->var_online_user_count,
958
      'USERS_TOTAL'   => $config->users_amount,
959
      'USER_RANK'     => $user['total_rank'],
960
      'USER_NICK'     => $user['username'],
961
      'USER_AVATAR'   => $user['avatar'],
962
      'USER_AVATARID' => $user['id'],
963
      'USER_PREMIUM'  => $premium_lvl,
964
      'USER_RACE'     => $user[P_RACE],
965
966
      'TOPNAV_CURRENT_PLANET'       => $user['current_planet'],
967
      'TOPNAV_CURRENT_PLANET_NAME'  => uni_render_planet_full($planetrow), // htmlspecialchars($planetrow['name']),
968
      'TOPNAV_CURRENT_PLANET_IMAGE' => $planetrow['image'],
969
      'TOPNAV_COLONIES_CURRENT'     => get_player_current_colonies($user),
970
      'TOPNAV_COLONIES_MAX'         => get_player_max_colonies($user),
971
      'NAVBAR_MODE'                 => $GET_mode,
972
973
      'TOPNAV_DARK_MATTER'            => mrc_get_level($user, '', RES_DARK_MATTER),
974
      'TOPNAV_DARK_MATTER_TEXT'       => HelperString::numberFloorAndFormat(mrc_get_level($user, '', RES_DARK_MATTER)),
975
      'TOPNAV_DARK_MATTER_PLAIN'      => mrc_get_level($user, '', RES_DARK_MATTER, false, true),
976
      'TOPNAV_DARK_MATTER_PLAIN_TEXT' => HelperString::numberFloorAndFormat(mrc_get_level($user, '', RES_DARK_MATTER, false, true)),
977
      'TOPNAV_METAMATTER'             => mrc_get_level($user, '', RES_METAMATTER),
978
      'TOPNAV_METAMATTER_TEXT'        => HelperString::numberFloorAndFormat(mrc_get_level($user, '', RES_METAMATTER)),
979
980
      // TODO ГРЯЗНЫЙ ХАК!!!
981
      'TOPNAV_PAYMENT'                => SN::$gc->modules->countModulesInGroup('payment') && !SN_GOOGLE,
982
983
      'TOPNAV_MESSAGES_ADMIN'    => $user['msg_admin'],
984
      'TOPNAV_MESSAGES_PLAYER'   => $user['mnl_joueur'],
985
      'TOPNAV_MESSAGES_ALLIANCE' => $user['mnl_alliance'],
986
      'TOPNAV_MESSAGES_ATTACK'   => $user['mnl_attaque'],
987
      'TOPNAV_MESSAGES_ALL'      => $user['new_message'],
988
989
      'TOPNAV_FLEETS_FLYING'      => empty($fleet_flying_list[0]) ? 0 : count($fleet_flying_list[0]),
990
      'TOPNAV_FLEETS_TOTAL'       => GetMaxFleets($user),
991
      'TOPNAV_EXPEDITIONS_FLYING' => empty($fleet_flying_list[MT_EXPLORE]) ? 0 : count($fleet_flying_list[MT_EXPLORE]),
992
      'TOPNAV_EXPEDITIONS_TOTAL'  => get_player_max_expeditons($user),
993
994
      'TOPNAV_QUEST_COMPLETE'    => get_quest_amount_complete($user['id']),
995
      'TOPNAV_QUEST_IN_PROGRESS' => get_quest_amount_in_progress($user['id']),
996
997
      'GAME_NEWS_OVERVIEW'       => $config->game_news_overview,
998
      'GAME_RESEARCH_DISABLED'   => defined('GAME_RESEARCH_DISABLED') && GAME_RESEARCH_DISABLED,
999
      'GAME_DEFENSE_DISABLED'    => defined('GAME_DEFENSE_DISABLED') && GAME_DEFENSE_DISABLED,
1000
      'GAME_STRUCTURES_DISABLED' => defined('GAME_STRUCTURES_DISABLED') && GAME_STRUCTURES_DISABLED,
1001
      'GAME_HANGAR_DISABLED'     => defined('GAME_HANGAR_DISABLED') && GAME_HANGAR_DISABLED,
1002
1003
      'PLAYER_OPTION_NAVBAR_PLANET_VERTICAL'        => SN::$user_options[PLAYER_OPTION_NAVBAR_PLANET_VERTICAL],
1004
      'PLAYER_OPTION_NAVBAR_PLANET_OLD'             => SN::$user_options[PLAYER_OPTION_NAVBAR_PLANET_OLD],
1005
      'PLAYER_OPTION_NAVBAR_PLANET_DISABLE_STORAGE' => SN::$user_options[PLAYER_OPTION_NAVBAR_PLANET_DISABLE_STORAGE],
1006
      'PLAYER_OPTION_NAVBAR_DISABLE_RESEARCH'       => SN::$user_options[PLAYER_OPTION_NAVBAR_DISABLE_RESEARCH],
1007
      'PLAYER_OPTION_NAVBAR_DISABLE_PLANET'         => SN::$user_options[PLAYER_OPTION_NAVBAR_DISABLE_PLANET],
1008
      'PLAYER_OPTION_NAVBAR_DISABLE_HANGAR'         => SN::$user_options[PLAYER_OPTION_NAVBAR_DISABLE_HANGAR],
1009
      'PLAYER_OPTION_NAVBAR_DISABLE_DEFENSE'        => SN::$user_options[PLAYER_OPTION_NAVBAR_DISABLE_DEFENSE],
1010
      'PLAYER_OPTION_NAVBAR_DISABLE_FLYING_FLEETS'  => SN::$user_options[PLAYER_OPTION_NAVBAR_DISABLE_FLYING_FLEETS],
1011
      'PLAYER_OPTION_NAVBAR_DISABLE_EXPEDITIONS'    => SN::$user_options[PLAYER_OPTION_NAVBAR_DISABLE_EXPEDITIONS],
1012
      'PLAYER_OPTION_NAVBAR_DISABLE_QUESTS'         => SN::$user_options[PLAYER_OPTION_NAVBAR_DISABLE_QUESTS],
1013
      'PLAYER_OPTION_NAVBAR_DISABLE_META_MATTER'    => SN::$user_options[PLAYER_OPTION_NAVBAR_DISABLE_META_MATTER],
1014
      'PLAYER_OPTION_NAVBAR_RESEARCH_WIDE'          => SN::$user_options[PLAYER_OPTION_NAVBAR_RESEARCH_WIDE],
1015
1016
      'TUTORIAL_ENABLED' => $tutorial_enabled,
1017
1018
      'PT_MOON'        => PT_MOON,
1019
      'SUBQUE_FLEET'   => SUBQUE_FLEET,
1020
      'SUBQUE_DEFENSE' => SUBQUE_DEFENSE,
1021
      'QUE_RESEARCH'   => QUE_RESEARCH,
1022
      'QUE_STRUCTURES' => QUE_STRUCTURES,
1023
    ));
1024
1025
    if (
1026
      (defined('SN_RENDER_NAVBAR_PLANET') && SN_RENDER_NAVBAR_PLANET === true)
1027
      ||
1028
      ($user['option_list'][OPT_INTERFACE]['opt_int_navbar_resource_force'] && (!defined('SN_RENDER_NAVBAR_PLANET') || SN_RENDER_NAVBAR_PLANET !== false))
1029
    ) {
1030
      tpl_set_resource_info($template, $planetrow);
1031
      $template->assign_vars(array(
1032
        'SN_RENDER_NAVBAR_PLANET' => true,
1033
        'SN_NAVBAR_HIDE_FLEETS'   => true,
1034
      ));
1035
    }
1036
1037
    return $user;
1038
  }
1039
1040
  /**
1041
   * @param array|string  $files
1042
   * @param template|null $template
1043
   * @param string|null   $template_path - path to templates root
1044
   *
1045
   * @return template
1046
   */
1047
  public static function gettemplate($files, $template = null, $template_path = null, $fallBackPath = '') {
1048
    global $sn_mvc, $sn_page_name;
1049
1050
    $template = self::getCurrentTemplate()->getTemplate($template, $template_path, $fallBackPath);
1051
1052
    // TODO ГРЯЗНЫЙ ХАК! Это нужно, что бы по возможности перезаписать инфу из языковых пакетов модулей там, где она была перезаписана раньше инфой из основного пакета. Почему?
1053
    //  - сначала грузятся модули и их языковые пакеты
1054
    //  - затем по ходу дела ОСНОВНОЙ языковой пакет может перезаписать данные из МОДУЛЬНОГО языкового пакета
1055
    // Поэтому и нужен этот грязный хак
1056
    // В норме же - страницы заявляют сами, какие им пакеты нужны. Так что сначала всегда должны грузится основные языковые пакеты, а уже ПОВЕРХ них - пакеты модулей
1057
    !empty($sn_mvc['i18n']['']) ? lng_load_i18n($sn_mvc['i18n']['']) : false;
1058
    $sn_page_name ? lng_load_i18n($sn_mvc['i18n'][$sn_page_name]) : false;
1059
1060
    if (empty($files)) {
1061
      // Make sure that all empty files will translate to empty array
1062
      $files = [];
1063
    } elseif (is_string($files)) {
1064
      // If we have single filename - making array from it
1065
      $files = [basename($files) => $files];
1066
    } elseif (!is_array($files)) {
1067
      // And final touch - all other non-string and non-array inputs converted to empty array
1068
      $files = [];
1069
    }
1070
1071
    foreach ($files as &$filename) {
1072
      $filename = $filename . self::TPL_HTML;
1073
    }
1074
1075
    $template->set_filenames($files);
1076
1077
    return $template;
1078
  }
1079
1080
  /**
1081
   * @param template|string $page
1082
   * @param string          $title
1083
   *
1084
   * @return mixed
1085
   */
1086
  public static function display($page, $title = '') {
1087
    SN::$gSomethingWasRendered = true;
1088
1089
    if (!defined('SN_TIME_RENDER_START')) {
1090
      define('SN_TIME_RENDER_START', microtime(true));
1091
    }
1092
1093
//  return sn_function_call('display', array($page, $title));
1094
//}
1095
//
1096
///**
1097
// * @param template|string $page
1098
// * @param string          $title
1099
// */
1100
//function sn_display($page, $title = '') {
1101
    global $debug, $user, $planetrow, $config, $lang, $template_result, $sn_mvc;
1102
1103
    !empty($sn_mvc['view']['']) and execute_hooks($sn_mvc['view'][''], $page, 'view', '');
1104
1105
    $exitStatus                      = true;
1106
    $template_result['LOGIN_LOGOUT'] = $inLoginLogout = defined('LOGIN_LOGOUT') && LOGIN_LOGOUT === true;
1107
1108
    if (is_object($page)) {
1109
      isset($page->_rootref['PAGE_TITLE']) && empty($title) ? $title = $page->_rootref['PAGE_TITLE'] : false;
1110
      !$title && !empty($page->_rootref['PAGE_HEADER']) ? $title = $page->_rootref['PAGE_HEADER'] : false;
1111
      !isset($page->_rootref['PAGE_HEADER']) && $title ? $page->assign_var('PAGE_HEADER', $title) : false;
1112
    }
1113
1114
    $isRenderGlobal = is_object($page) && isset($template_result['GLOBAL_DISPLAY_HEADER']) ? $template_result['GLOBAL_DISPLAY_HEADER'] : true;
1115
1116
    if (self::getCurrentTemplate()->isRenderWhole()) {
1117
      ob_start();
1118
    } else {
1119
      // Global header
1120
      if ($isRenderGlobal) {
1121
        SnTemplate::renderHeader($page, $title, $template_result, $inLoginLogout, $user, $config, $lang, $planetrow, null);
1122
      }
1123
    }
1124
1125
    // Page content
1126
    !is_array($page) ? $page = array($page) : false;
1127
    $result_added = false;
1128
    foreach ($page as $page_item) {
1129
      /**
1130
       * @var template $page_item
1131
       */
1132
      if (
1133
        !$result_added
1134
        && is_object($page_item)
1135
        && (
1136
          isset($page_item->_tpldata['result'])
1137
          ||
1138
          !empty($template_result['.']['result'])
1139
        )
1140
      ) {
1141
        $resultTemplate = SnTemplate::gettemplate('_result_message');
1142
1143
        $resultTemplate->_tpldata = $page_item->_tpldata;
1144
1145
        // Checking that no duplicates would be merged from template_result to template itself
1146
        $filtered = [];
1147
        if (!empty($template_result['.']['result']) && is_array($template_result['.']['result'])) {
1148
          foreach ($template_result['.']['result'] as $message) {
1149
            if (empty($message['MESSAGE'])) {
1150
              continue;
1151
            }
1152
1153
            foreach ($resultTemplate->_tpldata['result'] as $tplData) {
1154
              if (empty($tplData['MESSAGE'])) {
1155
                continue;
1156
              }
1157
1158
              if ($tplData['MESSAGE'] == $message['MESSAGE']) {
1159
                continue 2;
1160
              }
1161
            }
1162
1163
            $filtered['.']['result'][] = $message;
1164
          }
1165
        }
1166
        $resultTemplate->assign_recursive($filtered);
1167
1168
        SnTemplate::displayP($resultTemplate);
1169
        $result_added = true;
1170
      }
1171
1172
      SnTemplate::displayP($page_item);
1173
    }
1174
1175
    if (is_array($template_result[TEMPLATE_EXTRA_ARRAY]) && !empty($template_result[TEMPLATE_EXTRA_ARRAY])) {
1176
      foreach ($template_result[TEMPLATE_EXTRA_ARRAY] as $extraName => $extraTemplate) {
1177
        /**
1178
         * @var template $extraTemplate
1179
         */
1180
        SnTemplate::displayP($extraTemplate);
1181
      }
1182
    }
1183
1184
    if (
1185
      is_object($page[0])
1186
      &&
1187
      (
1188
        // Checking if hiding page hint flag is present
1189
        empty($template_result['PAGE_HINT_HIDE'])
1190
        &&
1191
        empty($page[0]->_rootref['PAGE_HINT_HIDE'])
1192
      )
1193
      &&
1194
      (
1195
        isset($page[0]->_tpldata['page_hint'])
1196
        ||
1197
        isset($page[0]->_rootref['PAGE_HINT'])
1198
        ||
1199
        !empty($template_result['.']['page_hint'])
1200
        ||
1201
        !empty($template_result['PAGE_HINT'])
1202
      )
1203
    ) {
1204
      $resultTemplate = self::gettemplate('page_hint');
1205
1206
      $resultTemplate->_tpldata = &$page[0]->_tpldata;
1207
      $resultTemplate->_rootref = &$page[0]->_rootref;
1208
      $resultTemplate->assign_recursive($template_result);
1209
1210
      SnTemplate::displayP($resultTemplate);
1211
    }
1212
1213
    if (self::getCurrentTemplate()->isRenderWhole()) {
1214
      $renderedContent = ob_get_clean();
1215
      // Global header
1216
      if ($isRenderGlobal) {
1217
        SnTemplate::renderHeader($page, $title, $template_result, $inLoginLogout, $user, $config, $lang, $planetrow, $renderedContent);
1218
      } else {
1219
        echo $renderedContent;
1220
      }
1221
    }
1222
1223
    // Flushing all opened buffers
1224
    while (@ob_end_flush()) {
1225
      ;
1226
    }
1227
1228
1229
    // Global footer
1230
    if ($isRenderGlobal) {
1231
      SnTemplate::renderFooter($page, $template_result);
1232
    }
1233
1234
    $user['authlevel'] >= 3 && $config->debug ? $debug->echo_log() : false;;
1235
1236
    SN::$db->db_disconnect();
1237
1238
    $exitStatus and die($exitStatus === true ? 0 : $exitStatus);
1239
1240
    return $exitStatus;
1241
  }
1242
1243
  /**
1244
   * @var GlobalContainer|null $gc
1245
   */
1246
  protected $gc = null;
1247
1248
  /**
1249
   * @var TemplateMeta[] $templates
1250
   */
1251
  protected $templates = [];
1252
1253
  public function __construct($gc = null) {
1254
    $this->gc = empty($gc) ? SN::$gc : $gc;
1255
  }
1256
1257
  public function registerTemplate($templateName) {
1258
    if (empty($this->templates[$templateName])) {
1259
      $this->templates[$templateName] = new TemplateMeta($this, $templateName);
1260
    }
1261
1262
    return $this->templates[$templateName];
1263
  }
1264
1265
1266
  /**
1267
   * Дефолтное имя темплейта на сервере
1268
   *
1269
   * @return string
1270
   */
1271
  public static function getServerDefaultTemplateName() {
1272
    return SN::$config->game_default_template ? SN::$config->game_default_template : self::SN_TEMPLATE_NAME_DEFAULT;
1273
  }
1274
1275
  /**
1276
   * Имя темплейта у игрока
1277
   *
1278
   * @return string
1279
   */
1280
  public static function getPlayerTemplateName() {
1281
    return SN::$gc->theUser->getTemplateName();
1282
  }
1283
1284
  /**
1285
   * Относительный путь к сконфигурированному темплейту
1286
   * 'design/templates/(имя_темплейта)
1287
   *
1288
   * @return string
1289
   * @deprecated
1290
   */
1291
  public static function pathRelativeToCurrentTemplate() {
1292
    return self::SN_TEMPLATES_PARTIAL_PATH . self::getPlayerTemplateName();
1293
  }
1294
1295
  /**
1296
   * @return TemplateMeta
1297
   */
1298
  public static function getCurrentTemplate() {
1299
    $templateName = SnTemplate::getPlayerTemplateName();
1300
    $tMeta        = static::me()->registerTemplate($templateName);
1301
1302
    return $tMeta;
1303
  }
1304
1305
  /**
1306
   * @param array  $fileList
1307
   * @param string $extension
1308
   *
1309
   * @return array|string[]
1310
   */
1311
  protected static function cacheFiles($fileList, $extension = '.css') {
1312
    // Calculating file key which include all used filenames and modification time for them
1313
    $key          = '';
1314
    $filesToMerge = [];
1315
    foreach ($fileList as $fileName => $aContent) {
1316
      // If content empty - index is a filename
1317
      if (empty($aContent)) {
1318
        // Checking file modification time. Also we will check if file exists
1319
        if ($fileMTime = filemtime(SN_ROOT_PHYSICAL . $fileName)) {
1320
          // Generating key
1321
          $key .= "$fileName:" . date(FMT_DATE_TIME_SQL, $fileMTime) . "\n";
1322
          // Adding filename to list of merge
1323
          $filesToMerge[$fileName] = "$fileName:" . date(FMT_DATE_TIME_SQL, $fileMTime);
1324
        }
1325
      }
1326
    }
1327
    // Name we will be using to address this file
1328
    $cacheFileName = 'design/cache/' . md5($key) . $extension;
1329
    // If no file exists - trying to create it
1330
    if (!file_exists($fullCacheFileName = SN_ROOT_PHYSICAL . $cacheFileName)) {
1331
      // Caching several files into one
1332
      $contentToCache = '';
1333
      foreach ($filesToMerge as $fileName => $temp) {
1334
        if (file_exists($fName = SN_ROOT_PHYSICAL . $fileName) && !empty($content = file_get_contents($fName))) {
1335
          // Adding content of cached file
1336
          $contentToCache .= $content . "\n";
1337
          // Marking that file was read OK - for future debug purposes if any
1338
          $filesToMerge[$fileName] .= " - OK\n";
1339
        }
1340
      }
1341
      // If we have something to cache...
1342
      if (!empty($contentToCache)) {
1343
        // /* */ works as comment for both JS and CSS
1344
        file_put_contents($fullCacheFileName, "/* Generated content. Safe to delete\n" . implode('', $filesToMerge) . "*/\n\n" . $contentToCache);
1345
      }
1346
    }
1347
1348
    // If CSS cache exists for current combination of files
1349
    if (file_exists($fullCacheFileName)) {
1350
      // Removing from list all CSS files that already in cache
1351
      foreach ($filesToMerge as $fileName => $temp) {
1352
        unset($fileList[$fileName]);
1353
      }
1354
      // Adding to list cache file
1355
      $fileList = [$cacheFileName => ''] + $fileList;
1356
    }
1357
1358
    return $fileList;
1359
  }
1360
1361
}
1362