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++) {
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
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $template is correct as it would always require null to be passed?
Loading history...
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