supernova-ws /
SuperNova
| 1 | <?php |
||||
| 2 | /** @noinspection PhpDeprecationInspection */ |
||||
| 3 | /** @noinspection SqlResolve */ |
||||
| 4 | |||||
| 5 | /** @noinspection PhpUnnecessaryCurlyVarSyntaxInspection */ |
||||
| 6 | |||||
| 7 | use DBAL\db_mysql; |
||||
| 8 | use Player\userOptions; |
||||
| 9 | use Common\Vector; |
||||
| 10 | use Core\GlobalContainer; |
||||
| 11 | use Unit\DBStaticUnit; |
||||
| 12 | |||||
| 13 | /** |
||||
| 14 | * Class SN |
||||
| 15 | * |
||||
| 16 | * Singleton |
||||
| 17 | */ |
||||
| 18 | class SN { |
||||
| 19 | /** |
||||
| 20 | * Flag that something was rendered |
||||
| 21 | * |
||||
| 22 | * @var bool |
||||
| 23 | */ |
||||
| 24 | public static $gSomethingWasRendered = false; |
||||
| 25 | |||||
| 26 | /** |
||||
| 27 | * @var GlobalContainer $gc |
||||
| 28 | */ |
||||
| 29 | public static $gc; |
||||
| 30 | |||||
| 31 | /** |
||||
| 32 | * Основная БД для доступа к данным |
||||
| 33 | * |
||||
| 34 | * @var db_mysql $db |
||||
| 35 | */ |
||||
| 36 | public static $db; |
||||
| 37 | public static $db_name = ''; |
||||
| 38 | |||||
| 39 | /** |
||||
| 40 | * Настройки из файла конфигурации |
||||
| 41 | * |
||||
| 42 | * @var string |
||||
| 43 | */ |
||||
| 44 | public static $cache_prefix = 'sn_'; |
||||
| 45 | public static $sn_secret_word = ''; |
||||
| 46 | |||||
| 47 | /** |
||||
| 48 | * Конфигурация игры |
||||
| 49 | * |
||||
| 50 | * @var classConfig $config |
||||
| 51 | */ |
||||
| 52 | public static $config; |
||||
| 53 | |||||
| 54 | |||||
| 55 | /** |
||||
| 56 | * Кэш игры |
||||
| 57 | * |
||||
| 58 | * @var classCache $cache |
||||
| 59 | */ |
||||
| 60 | public static $cache; |
||||
| 61 | |||||
| 62 | /** |
||||
| 63 | * @var classLocale $lang |
||||
| 64 | */ |
||||
| 65 | public static $lang; |
||||
| 66 | |||||
| 67 | |||||
| 68 | /** |
||||
| 69 | * @var core_auth $auth |
||||
| 70 | */ |
||||
| 71 | public static $auth = null; |
||||
| 72 | |||||
| 73 | |||||
| 74 | public static $user = array(); |
||||
| 75 | /** |
||||
| 76 | * @var userOptions |
||||
| 77 | */ |
||||
| 78 | public static $user_options; |
||||
| 79 | |||||
| 80 | /** @var ?debug $debug */ |
||||
| 81 | public static $debug = null; |
||||
| 82 | |||||
| 83 | |||||
| 84 | public static $options = array(); |
||||
| 85 | |||||
| 86 | /** |
||||
| 87 | * Is header already rendered? |
||||
| 88 | * |
||||
| 89 | * @var bool $headerRendered |
||||
| 90 | */ |
||||
| 91 | public static $headerRendered = false; |
||||
| 92 | |||||
| 93 | /** @var bool $sys_user_logged_in Is user logged in? TODO - move to user-related */ |
||||
| 94 | public static $sys_user_logged_in = false; |
||||
| 95 | |||||
| 96 | /* |
||||
| 97 | TODO Кэш: |
||||
| 98 | 1. Всегда дешевле использовать процессор, чем локальную память |
||||
| 99 | 2. Всегда дешевле использовать локальную память, чем общую память всех процессов |
||||
| 100 | 3. Всегда дешевле использовать общую память всех процессов, чем обращаться к БД |
||||
| 101 | |||||
| 102 | Кэш - многоуровневый: локальная память-общая память-БД |
||||
| 103 | БД может быть сверх-кэширующей - см. HyperNova. Это реализуется на уровне СН-драйвера БД |
||||
| 104 | Предусмотреть вариант, когда уровни кэширования совпадают, например когда нет xCache и используется общая память |
||||
| 105 | */ |
||||
| 106 | //public static $cache; // Кэширующий объект - либо встроенная память, либо кэш в памяти с блокировками - находится внутри $db!!!! |
||||
| 107 | //public static $db; // Объект-БД - либо кэширующий объект с блокировками, либо БД |
||||
| 108 | |||||
| 109 | // protected static $info = array(); // Кэш информации - инфо о юнитах, инфо о группах итд |
||||
| 110 | |||||
| 111 | // TODO Автоматически заполнять эту таблицу. В случае кэша в памяти - делать show table при обращении к таблице |
||||
| 112 | public static $location_info = array( |
||||
| 113 | LOC_USER => array( |
||||
| 114 | P_TABLE_NAME => 'users', |
||||
| 115 | P_ID => 'id', |
||||
| 116 | P_OWNER_INFO => array(), |
||||
| 117 | ), |
||||
| 118 | |||||
| 119 | LOC_PLANET => array( |
||||
| 120 | P_TABLE_NAME => 'planets', |
||||
| 121 | P_ID => 'id', |
||||
| 122 | P_OWNER_INFO => array( |
||||
| 123 | LOC_USER => array( |
||||
| 124 | P_LOCATION => LOC_USER, |
||||
| 125 | P_OWNER_FIELD => 'id_owner', |
||||
| 126 | ), |
||||
| 127 | ), |
||||
| 128 | ), |
||||
| 129 | |||||
| 130 | LOC_UNIT => array( |
||||
| 131 | P_TABLE_NAME => 'unit', |
||||
| 132 | P_ID => 'unit_id', |
||||
| 133 | P_OWNER_INFO => array( |
||||
| 134 | LOC_USER => array( |
||||
| 135 | P_LOCATION => LOC_USER, |
||||
| 136 | P_OWNER_FIELD => 'unit_player_id', |
||||
| 137 | ), |
||||
| 138 | ), |
||||
| 139 | ), |
||||
| 140 | |||||
| 141 | LOC_QUE => array( |
||||
| 142 | P_TABLE_NAME => 'que', |
||||
| 143 | P_ID => 'que_id', |
||||
| 144 | P_OWNER_INFO => array( |
||||
| 145 | array( |
||||
| 146 | P_LOCATION => LOC_USER, |
||||
| 147 | P_OWNER_FIELD => 'que_player_id', |
||||
| 148 | ), |
||||
| 149 | |||||
| 150 | array( |
||||
| 151 | P_LOCATION => LOC_PLANET, |
||||
| 152 | P_OWNER_FIELD => 'que_planet_id_origin', |
||||
| 153 | ), |
||||
| 154 | |||||
| 155 | array( |
||||
| 156 | P_LOCATION => LOC_PLANET, |
||||
| 157 | P_OWNER_FIELD => 'que_planet_id', |
||||
| 158 | ), |
||||
| 159 | ), |
||||
| 160 | ), |
||||
| 161 | |||||
| 162 | LOC_FLEET => array( |
||||
| 163 | P_TABLE_NAME => 'fleets', |
||||
| 164 | P_ID => 'fleet_id', |
||||
| 165 | P_OWNER_INFO => array( |
||||
| 166 | array( |
||||
| 167 | P_LOCATION => LOC_USER, |
||||
| 168 | P_OWNER_FIELD => 'fleet_owner', |
||||
| 169 | ), |
||||
| 170 | |||||
| 171 | array( |
||||
| 172 | P_LOCATION => LOC_USER, |
||||
| 173 | P_OWNER_FIELD => 'fleet_target_owner', |
||||
| 174 | ), |
||||
| 175 | |||||
| 176 | array( |
||||
| 177 | P_LOCATION => LOC_PLANET, |
||||
| 178 | P_OWNER_FIELD => 'fleet_start_planet_id', |
||||
| 179 | ), |
||||
| 180 | |||||
| 181 | array( |
||||
| 182 | P_LOCATION => LOC_PLANET, |
||||
| 183 | P_OWNER_FIELD => 'fleet_end_planet_id', |
||||
| 184 | ), |
||||
| 185 | ), |
||||
| 186 | ), |
||||
| 187 | ); |
||||
| 188 | |||||
| 189 | /** |
||||
| 190 | * @var callable[] $afterInit |
||||
| 191 | */ |
||||
| 192 | public static $afterInit = []; |
||||
| 193 | |||||
| 194 | public function __construct() { |
||||
| 195 | |||||
| 196 | } |
||||
| 197 | |||||
| 198 | |||||
| 199 | public static function log_file($message, $spaces = 0) { |
||||
| 200 | if (self::$debug) { |
||||
| 201 | self::$debug->log_file($message, $spaces); |
||||
| 202 | } |
||||
| 203 | } |
||||
| 204 | |||||
| 205 | |||||
| 206 | /** |
||||
| 207 | * Возвращает информацию о записи по её ID |
||||
| 208 | * |
||||
| 209 | * @param int $location_type |
||||
| 210 | * @param int|array $record_id_unsafe |
||||
| 211 | * <p>int - ID записи</p> |
||||
| 212 | * <p>array - запись пользователя с установленным полем P_ID</p> |
||||
| 213 | * |
||||
| 214 | * @return array|false |
||||
| 215 | * <p>false - Нет записи с указанным ID</p> |
||||
| 216 | * <p>array - запись</p> |
||||
| 217 | */ |
||||
| 218 | public static function db_get_record_by_id($location_type, $record_id_unsafe) { |
||||
| 219 | $id_field = static::$location_info[$location_type][P_ID]; |
||||
| 220 | $record_id_safe = idval(is_array($record_id_unsafe) && isset($record_id_unsafe[$id_field]) ? $record_id_unsafe[$id_field] : $record_id_unsafe); |
||||
| 221 | |||||
| 222 | return static::db_get_record_list($location_type, "`{$id_field}` = {$record_id_safe}", true); |
||||
| 223 | } |
||||
| 224 | |||||
| 225 | public static function db_get_record_list($location_type, $filter = '', $fetch = false, $no_return = false) { |
||||
| 226 | $location_info = &static::$location_info[$location_type]; |
||||
| 227 | $id_field = $location_info[P_ID]; |
||||
| 228 | $tableName = $location_info[P_TABLE_NAME]; |
||||
| 229 | |||||
| 230 | $result = false; |
||||
| 231 | |||||
| 232 | // $sqlResult = static::db_query_select( |
||||
| 233 | // "SELECT * FROM {{{$tableName}}}" . (($filter = trim($filter)) ? " WHERE {$filter}" : '') |
||||
| 234 | // ); |
||||
| 235 | $query = "SELECT * FROM {{{$tableName}}}" . (($filter = trim($filter)) ? " WHERE {$filter}" : ''); |
||||
| 236 | $query .= db_mysql::db_transaction_check(db_mysql::DB_TRANSACTION_WHATEVER) ? ' FOR UPDATE' : ''; |
||||
| 237 | |||||
| 238 | $sqlResult = self::$db->doquery($query, false); |
||||
| 239 | |||||
| 240 | while ($row = db_fetch($sqlResult)) { |
||||
|
0 ignored issues
–
show
Deprecated Code
introduced
by
Loading history...
|
|||||
| 241 | $result[$row[$id_field]] = $row; |
||||
| 242 | if ($fetch) { |
||||
| 243 | break; |
||||
| 244 | } |
||||
| 245 | } |
||||
| 246 | |||||
| 247 | if ($no_return) { |
||||
| 248 | return true; |
||||
| 249 | } else { |
||||
| 250 | return $fetch ? (is_array($result) ? reset($result) : false) : $result; |
||||
| 251 | } |
||||
| 252 | } |
||||
| 253 | |||||
| 254 | public static function db_upd_record_by_id($location_type, $record_id, $set) { |
||||
| 255 | if (!($record_id = idval($record_id)) || !($set = trim($set))) { |
||||
| 256 | return false; |
||||
| 257 | } |
||||
| 258 | |||||
| 259 | $location_info = &static::$location_info[$location_type]; |
||||
| 260 | $id_field = $location_info[P_ID]; |
||||
| 261 | $table_name = $location_info[P_TABLE_NAME]; |
||||
| 262 | if ($result = self::$db->doquery("UPDATE {{{$table_name}}} SET {$set} WHERE `{$id_field}` = {$record_id}", false)) // TODO Как-то вернуть может быть LIMIT 1 ? |
||||
| 263 | { |
||||
| 264 | if (static::$db->db_affected_rows()) { |
||||
| 265 | // Обновляем данные только если ряд был затронут |
||||
| 266 | DBStaticUnit::cache_clear(); |
||||
| 267 | } |
||||
| 268 | } |
||||
| 269 | |||||
| 270 | return $result; |
||||
| 271 | } |
||||
| 272 | |||||
| 273 | public static function db_upd_record_list($location_type, $condition, $set) { |
||||
| 274 | if (!($set = trim($set))) { |
||||
| 275 | return false; |
||||
| 276 | } |
||||
| 277 | |||||
| 278 | $condition = trim($condition); |
||||
| 279 | $table_name = static::$location_info[$location_type][P_TABLE_NAME]; |
||||
| 280 | |||||
| 281 | if ($result = self::$db->doquery("UPDATE {{{$table_name}}} SET " . $set . ($condition ? ' WHERE ' . $condition : ''))) { |
||||
| 282 | |||||
| 283 | if (static::$db->db_affected_rows()) { // Обновляем данные только если ряд был затронут |
||||
| 284 | // Поскольку нам неизвестно, что и как обновилось - сбрасываем кэш этого типа полностью |
||||
| 285 | DBStaticUnit::cache_clear(); |
||||
| 286 | } |
||||
| 287 | } |
||||
| 288 | |||||
| 289 | return $result; |
||||
| 290 | } |
||||
| 291 | |||||
| 292 | public static function db_ins_record($location_type, $set) { |
||||
| 293 | $set = trim($set); |
||||
| 294 | $table_name = static::$location_info[$location_type][P_TABLE_NAME]; |
||||
| 295 | if ($result = self::$db->doquery("INSERT INTO `{{{$table_name}}}` SET {$set}")) { |
||||
| 296 | if (static::$db->db_affected_rows()) // Обновляем данные только если ряд был затронут |
||||
| 297 | { |
||||
| 298 | $record_id = SN::$db->db_insert_id(); |
||||
| 299 | // Вытаскиваем запись целиком, потому что в $set могли быть "данные по умолчанию" |
||||
| 300 | $result = static::db_get_record_by_id($location_type, $record_id); |
||||
|
0 ignored issues
–
show
It seems like
$record_id can also be of type string; however, parameter $record_id_unsafe of SN::db_get_record_by_id() does only seem to accept array|integer, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 301 | // Очищаем второстепенные кэши - потому что вставленная запись могла повлиять на результаты запросов или локация или еще чего |
||||
| 302 | DBStaticUnit::cache_clear(); |
||||
| 303 | } |
||||
| 304 | } |
||||
| 305 | |||||
| 306 | return $result; |
||||
| 307 | } |
||||
| 308 | |||||
| 309 | public static function db_del_record_by_id($location_type, $safe_record_id) { |
||||
| 310 | if (!($safe_record_id = idval($safe_record_id))) { |
||||
| 311 | return false; |
||||
| 312 | } |
||||
| 313 | |||||
| 314 | $location_info = &static::$location_info[$location_type]; |
||||
| 315 | $id_field = $location_info[P_ID]; |
||||
| 316 | $table_name = $location_info[P_TABLE_NAME]; |
||||
| 317 | if ($result = self::$db->doquery("DELETE FROM `{{{$table_name}}}` WHERE `{$id_field}` = {$safe_record_id}")) { |
||||
| 318 | if (static::$db->db_affected_rows()) // Обновляем данные только если ряд был затронут |
||||
| 319 | { |
||||
| 320 | DBStaticUnit::cache_clear(); |
||||
| 321 | } |
||||
| 322 | } |
||||
| 323 | |||||
| 324 | return $result; |
||||
| 325 | } |
||||
| 326 | |||||
| 327 | public static function db_del_record_list($location_type, $condition) { |
||||
| 328 | if (!($condition = trim($condition))) { |
||||
| 329 | return false; |
||||
| 330 | } |
||||
| 331 | |||||
| 332 | $table_name = static::$location_info[$location_type][P_TABLE_NAME]; |
||||
| 333 | |||||
| 334 | if ($result = self::$db->doquery("DELETE FROM `{{{$table_name}}}` WHERE {$condition}")) { |
||||
| 335 | if (static::$db->db_affected_rows()) // Обновляем данные только если ряд был затронут |
||||
| 336 | { |
||||
| 337 | // Обнуление кэша, потому что непонятно, что поменялось |
||||
| 338 | DBStaticUnit::cache_clear(); |
||||
| 339 | } |
||||
| 340 | } |
||||
| 341 | |||||
| 342 | return $result; |
||||
| 343 | } |
||||
| 344 | |||||
| 345 | |||||
| 346 | /* |
||||
| 347 | * С $for_update === true эта функция должна вызываться только из транзакции! Все соответствующие записи в users и planets должны быть уже блокированы! |
||||
| 348 | * |
||||
| 349 | * $que_type |
||||
| 350 | * !$que_type - все очереди |
||||
| 351 | * QUE_XXX - конкретная очередь по планете |
||||
| 352 | * $user_id - ID пользователя |
||||
| 353 | * $planet_id |
||||
| 354 | * $que_type == QUE_RESEARCH - игнорируется |
||||
| 355 | * null - обработка очередей планет не производится |
||||
| 356 | * false/0 - обрабатываются очереди всех планет по $user_id |
||||
| 357 | * (integer) - обрабатываются локальные очереди для планеты. Нужно, например, в обработчике флотов |
||||
| 358 | * иначе - $que_type для указанной планеты |
||||
| 359 | * $for_update - true == нужно блокировать записи |
||||
| 360 | * |
||||
| 361 | * TODO Работа при !$user_id |
||||
| 362 | * TODO Переформатировать вывод данных, что бы можно было возвращать данные по всем планетам и юзерам в одном запросе: добавить под-массивы 'que', 'planets', 'players' |
||||
| 363 | * |
||||
| 364 | */ |
||||
| 365 | /** @noinspection PhpUnusedParameterInspection */ |
||||
| 366 | public static function db_que_list_by_type_location($user_id, $planet_id = null, $que_type = false, $for_update = false) { |
||||
| 367 | if (!$user_id) { |
||||
| 368 | pdump(debug_backtrace()); |
||||
| 369 | die('No user_id for que_get_que()'); |
||||
|
0 ignored issues
–
show
|
|||||
| 370 | } |
||||
| 371 | |||||
| 372 | $ques = array(); |
||||
| 373 | |||||
| 374 | $query = array(); |
||||
| 375 | |||||
| 376 | if ($user_id = idval($user_id)) { |
||||
| 377 | $query[] = "`que_player_id` = {$user_id}"; |
||||
| 378 | } |
||||
| 379 | |||||
| 380 | if ($que_type == QUE_RESEARCH || $planet_id === null) { |
||||
| 381 | $query[] = "`que_planet_id` IS NULL"; |
||||
| 382 | } elseif ($planet_id) { |
||||
| 383 | $query[] = "(`que_planet_id` = {$planet_id}" . ($que_type ? '' : ' OR que_planet_id IS NULL') . ")"; |
||||
| 384 | } |
||||
| 385 | if ($que_type) { |
||||
| 386 | $query[] = "`que_type` = {$que_type}"; |
||||
| 387 | } |
||||
| 388 | |||||
| 389 | $ques['items'] = static::db_get_record_list(LOC_QUE, implode(' AND ', $query)); |
||||
| 390 | |||||
| 391 | return que_recalculate($ques); |
||||
| 392 | } |
||||
| 393 | |||||
| 394 | |||||
| 395 | public static function loadFileSettings() { |
||||
| 396 | $dbsettings = array(); |
||||
| 397 | |||||
| 398 | require(SN_CONFIG_PATH); |
||||
| 399 | //self::$db_prefix = $dbsettings['prefix']; |
||||
| 400 | self::$cache_prefix = !empty($dbsettings['cache_prefix']) ? $dbsettings['cache_prefix'] : $dbsettings['prefix']; |
||||
| 401 | self::$db_name = $dbsettings['name']; |
||||
| 402 | /** @noinspection SpellCheckingInspection */ |
||||
| 403 | self::$sn_secret_word = $dbsettings['secretword']; |
||||
| 404 | |||||
| 405 | self::services(); |
||||
| 406 | |||||
| 407 | unset($dbsettings); |
||||
| 408 | } |
||||
| 409 | |||||
| 410 | public static function init_global_objects() { |
||||
| 411 | global $sn_cache, $config, $debug; |
||||
| 412 | |||||
| 413 | $debug = self::$debug = self::$gc->debug; |
||||
| 414 | self::$db = self::$gc->db; |
||||
| 415 | self::$db->sn_db_connect(); |
||||
| 416 | |||||
| 417 | self::$user_options = new userOptions(0); |
||||
| 418 | |||||
| 419 | // Initializing global `cache` object |
||||
| 420 | $sn_cache = static::$cache = self::$gc->cache; |
||||
| 421 | $tables = SN::$db->schema()->getSnTables(); |
||||
| 422 | empty($tables) && die('DB error - cannot find any table. Halting...'); |
||||
|
0 ignored issues
–
show
|
|||||
| 423 | |||||
| 424 | // Initializing global `config` object |
||||
| 425 | $config = self::$config = self::$gc->config; |
||||
| 426 | |||||
| 427 | // Initializing statics |
||||
| 428 | Vector::_staticInit(self::$config); |
||||
| 429 | |||||
| 430 | // After init callbacks |
||||
| 431 | foreach (static::$afterInit as $callback) { |
||||
| 432 | if (is_callable($callback)) { |
||||
| 433 | $callback(); |
||||
| 434 | } |
||||
| 435 | } |
||||
| 436 | } |
||||
| 437 | |||||
| 438 | /** |
||||
| 439 | * @param int $newStatus |
||||
| 440 | * @param string $newMessage |
||||
| 441 | * |
||||
| 442 | * @return int |
||||
| 443 | * @noinspection PhpUnusedParameterInspection |
||||
| 444 | */ |
||||
| 445 | public static function gameDisable($newStatus = GAME_DISABLE_REASON, $newMessage = '') { |
||||
| 446 | /** @noinspection PhpCastIsUnnecessaryInspection */ |
||||
| 447 | $old_server_status = intval(self::$config->pass()->game_disable); |
||||
| 448 | |||||
| 449 | self::$config->pass()->game_disable = $newStatus; |
||||
| 450 | |||||
| 451 | return $old_server_status; |
||||
| 452 | } |
||||
| 453 | |||||
| 454 | // public static function gameEnable() { |
||||
| 455 | // self::$config->pass()->game_disable = GAME_DISABLE_NONE; |
||||
| 456 | // } |
||||
| 457 | |||||
| 458 | /** |
||||
| 459 | * Is game disabled? |
||||
| 460 | * |
||||
| 461 | * @return bool |
||||
| 462 | */ |
||||
| 463 | public static function gameIsDisabled() { |
||||
| 464 | return self::$config->pass()->game_disable != GAME_DISABLE_NONE; |
||||
| 465 | } |
||||
| 466 | |||||
| 467 | |||||
| 468 | /** |
||||
| 469 | * @return GlobalContainer |
||||
| 470 | */ |
||||
| 471 | public static function services() { |
||||
| 472 | if (empty(self::$gc)) { |
||||
| 473 | self::$gc = new GlobalContainer(array( |
||||
| 474 | 'cachePrefix' => self::$cache_prefix, |
||||
| 475 | )); |
||||
| 476 | } |
||||
| 477 | |||||
| 478 | return self::$gc; |
||||
| 479 | } |
||||
| 480 | |||||
| 481 | } |
||||
| 482 |