function flt_get_fleets($condition, $phalanx = false) { $fleet_db_list = array(); if (!$condition) { $missile_query = $condition = 1; } elseif (is_array($condition)) { $missile_query = "\n (fleet_start_galaxy = {$condition['galaxy']} AND fleet_start_system = {$condition['system']} AND fleet_start_planet = {$condition['planet']} AND fleet_start_type = {$condition['planet_type']})\n OR\n (fleet_end_galaxy = {$condition['galaxy']} AND fleet_end_system = {$condition['system']} AND fleet_end_planet = {$condition['planet']} AND fleet_end_type = {$condition['planet_type']})"; $condition = "\n (fleet_start_galaxy = {$condition['galaxy']} AND fleet_start_system = {$condition['system']} AND fleet_start_planet = {$condition['planet']} AND fleet_start_type = {$condition['planet_type']}" . ($phalanx ? '' : ' AND fleet_mess = 1') . ")\n OR\n (fleet_end_galaxy = {$condition['galaxy']} AND fleet_end_system = {$condition['system']} AND fleet_end_planet = {$condition['planet']} AND fleet_end_type = {$condition['planet_type']}" . ($phalanx ? '' : ' AND fleet_mess = 0') . ")"; } else { $missile_query = "`fleet_owner` = '{$condition}' OR `fleet_target_owner` = '{$condition}'"; $condition = $missile_query; } $sql_fleets = doquery("SELECT DISTINCT * FROM {{fleets}} WHERE {$condition};"); while ($fleet = db_fetch($sql_fleets)) { $fleet_db_list[] = $fleet; } // Missile attack $sql_fleets = doquery("SELECT * FROM `{{iraks}}` WHERE {$missile_query};"); while ($irak = db_fetch($sql_fleets)) { if ($irak['fleet_end_time'] >= SN_TIME_NOW) { $irak['fleet_start_type'] = PT_PLANET; $planet_start = db_planet_by_vector($irak, 'fleet_start_', false, 'name'); $irak['fleet_id'] = -$irak['id']; $irak['fleet_mission'] = MT_MISSILE; $irak['fleet_array'] = UNIT_DEF_MISSILE_INTERPLANET . ",{$irak['fleet_amount']};"; $irak['fleet_start_name'] = $planet_start['name']; } $fleet_db_list[] = $irak; } return $fleet_db_list; }
function flt_flying_fleet_handler($skip_fleet_update = false) { /* [*] Нужно ли заворачивать ВСЕ в одну транзакцию? С одной стороны - да, что бы данные были гарантированно на момент снапшота С другой стороны - нет, потому что при большой активности это все будет блокировать слишком много рядов, да и таймаут будет большой для ожидания всего разлоченного Стоит завернуть каждую миссию отдельно? Это сильно увеличит количество запросов, зато так же сильно снизит количество блокировок. Resume: НЕТ! Надо оставить все в одной транзакции! Так можно будет поддерживать consistency кэша. Там буквально сантисекунды блокировки [*] Убрать кэшированние данных о пользователях и планета. Офигенно освободит память - проследить! НЕТ! Считать, скольким флотам нужна будет инфа и кэшировать только то, что используется больше раза! Заодно можно будет исключить перересчет очередей/ресурсов - сильно ускорит дело! Особенно будет актуально, когда все бонусы будут в одной таблице Ну и никто не заставляет как сейчас брать ВСЕ из таблицы - только по полям. Гемор, но не сильный - сделать запрос по группам sn_data И писать в БД только один раз результат [*] Нужно ли на этом этапе знать полную информацию о флотах? Заблокировать флоты можно и неполным запросом. Блокировка флотов - это не страшно. Ну, не пройдет одна-две отмены - так никто и не гарантировал реалтайма! С одной стороны - да, уменьшит количество запросов С другой стооны - расход памяти Все равно надо будет знать полную инфу о флоте в момент обработки [*] Сделать тестовую БД для расчетов [*] Но не раньше, чем переписать все миссии */ global $config, $debug; if ($config->game_disable != GAME_DISABLE_NONE || $skip_fleet_update) { return; } sn_db_transaction_start(); if ($config->db_loadItem('game_disable') != GAME_DISABLE_NONE || SN_TIME_NOW - strtotime($config->db_loadItem('fleet_update_last')) <= $config->fleet_update_interval) { sn_db_transaction_rollback(); return; } // Watchdog timer if ($config->db_loadItem('fleet_update_lock')) { if (SN_TIME_NOW - strtotime($config->fleet_update_lock) <= mt_rand(240, 300)) { sn_db_transaction_rollback(); return; } else { $debug->warning('Flying fleet handler was locked too long - watchdog unlocked', 'FFH Error', 504); } } $config->db_saveItem('fleet_update_lock', SN_TIME_SQL); $config->db_saveItem('fleet_update_last', SN_TIME_SQL); sn_db_transaction_commit(); //log_file('Начинаем обсчёт флотов'); //log_file('Обсчёт ракет'); sn_db_transaction_start(); coe_o_missile_calculate(); sn_db_transaction_commit(); $fleet_list = array(); $fleet_event_list = array(); $missions_used = array(); sn_db_transaction_start(); //log_file('Запрос на флоты'); $_fleets = doquery("SELECT * FROM `{{fleets}}` WHERE\n (`fleet_start_time` <= " . SN_TIME_NOW . " AND `fleet_mess` = 0)\n OR (`fleet_end_stay` <= " . SN_TIME_NOW . " AND fleet_end_stay > 0 AND `fleet_mess` = 0)\n OR (`fleet_end_time` <= " . SN_TIME_NOW . ")\n FOR UPDATE;"); //log_file('Выборка флотов'); while ($fleet_row = db_fetch($_fleets)) { set_time_limit(15); // Унифицировать код с темплейтным разбором эвентов на планете! $fleet_list[$fleet_row['fleet_id']] = $fleet_row; $missions_used[$fleet_row['fleet_mission']] = 1; if ($fleet_row['fleet_start_time'] <= SN_TIME_NOW && $fleet_row['fleet_mess'] == 0) { $fleet_event_list[] = array('fleet_row' => &$fleet_list[$fleet_row['fleet_id']], 'fleet_time' => $fleet_list[$fleet_row['fleet_id']]['fleet_start_time'], 'fleet_event' => EVENT_FLT_ARRIVE); } if ($fleet_row['fleet_end_stay'] > 0 && $fleet_row['fleet_end_stay'] <= SN_TIME_NOW && $fleet_row['fleet_mess'] == 0) { $fleet_event_list[] = array('fleet_row' => &$fleet_list[$fleet_row['fleet_id']], 'fleet_time' => $fleet_list[$fleet_row['fleet_id']]['fleet_end_stay'], 'fleet_event' => EVENT_FLT_ACOMPLISH); } if ($fleet_row['fleet_end_time'] <= SN_TIME_NOW) { $fleet_event_list[] = array('fleet_row' => &$fleet_list[$fleet_row['fleet_id']], 'fleet_time' => $fleet_list[$fleet_row['fleet_id']]['fleet_end_time'], 'fleet_event' => EVENT_FLT_RETURN); } } sn_db_transaction_commit(); //log_file('Сортировка и подгрузка модулей'); uasort($fleet_event_list, 'flt_flyingFleetsSort'); unset($_fleets); // TODO: Грузить только используемые модули из $missions_used $mission_files = array(MT_ATTACK => 'flt_mission_attack', MT_AKS => 'flt_mission_attack', MT_DESTROY => 'flt_mission_attack', MT_TRANSPORT => 'flt_mission_transport', MT_RELOCATE => 'flt_mission_relocate', MT_HOLD => 'flt_mission_hold', MT_SPY => 'flt_mission_spy', MT_COLONIZE => 'flt_mission_colonize', MT_RECYCLE => 'flt_mission_recycle', MT_EXPLORE => 'flt_mission_explore'); foreach ($missions_used as $mission_id => $cork) { require_once SN_ROOT_PHYSICAL . "includes/includes/{$mission_files[$mission_id]}" . DOT_PHP_EX; } //log_file('Обработка миссий'); $sn_groups_mission = sn_get_groups('missions'); foreach ($fleet_event_list as $fleet_event) { // TODO: Указатель тут потом сделать // TODO: СЕЙЧАС НАДО ПРОВЕРЯТЬ ПО БАЗЕ - А ЖИВОЙ ЛИ ФЛОТ?! $fleet_row = $fleet_event['fleet_row']; if (!$fleet_row) { // Fleet was destroyed in course of previous actions continue; } //log_file('Миссия'); // TODO Обернуть всё в транзакции. Начинать надо заранее, блокируя все таблицы внутренним локом SELECT 1 FROM {{users}} sn_db_transaction_start(); $config->db_saveItem('fleet_update_last', SN_TIME_SQL); $mission_data = $sn_groups_mission[$fleet_row['fleet_mission']]; // Формируем запрос, блокирующий сразу все нужные записи db_flying_fleet_lock($mission_data, $fleet_row); $fleet_row = doquery("SELECT * FROM {{fleets}} WHERE fleet_id = {$fleet_row['fleet_id']} FOR UPDATE", true); if (!$fleet_row || empty($fleet_row)) { // Fleet was destroyed in course of previous actions sn_db_transaction_commit(); continue; } if ($fleet_event['fleet_event'] == EVENT_FLT_RETURN) { // Fleet returns to planet RestoreFleetToPlanet($fleet_row, true, false, true); sn_db_transaction_commit(); continue; } if ($fleet_event['fleet_event'] == EVENT_FLT_ARRIVE && $fleet_row['fleet_mess'] != 0) { // При событии EVENT_FLT_ARRIVE флот всегда должен иметь fleet_mess == 0 // В противном случае это означает, что флот уже был обработан ранее - например, при САБе sn_db_transaction_commit(); continue; } // TODO: Здесь тоже указатели // TODO: Кэширование // TODO: Выбирать только нужные поля // шпионаж не дает нормальный ID fleet_end_planet_id 'dst_planet' $mission_data = array('fleet' => &$fleet_row, 'dst_user' => $mission_data['dst_user'] || $mission_data['dst_planet'] ? db_user_by_id($fleet_row['fleet_target_owner'], true) : null, 'dst_planet' => $mission_data['dst_planet'] ? db_planet_by_vector($fleet_row, 'fleet_end_', true, '`id`, `id_owner`, `name`') : null, 'src_user' => $mission_data['src_user'] || $mission_data['src_planet'] ? db_user_by_id($fleet_row['fleet_owner'], true) : null, 'src_planet' => $mission_data['src_planet'] ? db_planet_by_vector($fleet_row, 'fleet_start_', true, '`id`, `id_owner`, `name`') : null, 'fleet_event' => $fleet_event['fleet_event']); if ($mission_data['dst_planet']) { // $mission_data['dst_planet'] = sys_o_get_updated($mission_data['dst_user'], $mission_data['dst_planet']['id'], $fleet_row['fleet_start_time']); if ($mission_data['dst_planet']['id_owner']) { $mission_data['dst_planet'] = sys_o_get_updated($mission_data['dst_planet']['id_owner'], $mission_data['dst_planet']['id'], $fleet_row['fleet_start_time']); } $mission_data['dst_user'] = $mission_data['dst_user'] ? $mission_data['dst_planet']['user'] : null; $mission_data['dst_planet'] = $mission_data['dst_planet']['planet']; } switch ($fleet_row['fleet_mission']) { // Для боевых атак нужно обновлять по САБу и по холду - таки надо возвращать данные из обработчика миссий! case MT_AKS: case MT_ATTACK: case MT_DESTROY: $attack_result = flt_mission_attack($mission_data); $mission_result = CACHE_COMBAT; break; /* case MT_DESTROY: $attack_result = flt_mission_destroy($mission_data); $mission_result = CACHE_COMBAT; break; */ /* case MT_DESTROY: $attack_result = flt_mission_destroy($mission_data); $mission_result = CACHE_COMBAT; break; */ case MT_TRANSPORT: $mission_result = flt_mission_transport($mission_data); break; case MT_HOLD: $mission_result = flt_mission_hold($mission_data); break; case MT_RELOCATE: $mission_result = flt_mission_relocate($mission_data); break; case MT_EXPLORE: $mission_result = flt_mission_explore($mission_data); break; case MT_RECYCLE: $mission_result = flt_mission_recycle($mission_data); break; case MT_COLONIZE: $mission_result = flt_mission_colonize($mission_data); break; case MT_SPY: $mission_result = flt_mission_spy($mission_data); break; case MT_MISSILE: // Missiles !! break; // default: // doquery("DELETE FROM `{{fleets}}` WHERE `fleet_id` = '{$fleet_row['fleet_id']}' LIMIT 1;"); // break; } sn_db_transaction_commit(); } sn_db_transaction_start(); $config->db_saveItem('fleet_update_last', SN_TIME_SQL); $config->db_saveItem('fleet_update_lock', ''); sn_db_transaction_commit(); // log_file('Закончили обсчёт флотов'); }
/** * Copyright (c) 2009-2010 by Gorlum for http://supernova.ws * OpenSource as long as you don't remove this Copyright * V3 2009-11-13 * V2 2009-10-10 */ function coe_o_missile_calculate() { sn_db_transaction_check(true); global $lang; $iraks = doquery("SELECT * FROM {{iraks}} WHERE `fleet_end_time` <= " . SN_TIME_NOW . " FOR UPDATE;"); while ($fleetRow = db_fetch($iraks)) { set_time_limit(15); $db_changeset = array(); $targetUser = db_user_by_id($fleetRow['fleet_target_owner'], true); $target_planet_row = sys_o_get_updated($targetUser, array('galaxy' => $fleetRow['fleet_end_galaxy'], 'system' => $fleetRow['fleet_end_system'], 'planet' => $fleetRow['fleet_end_planet'], 'planet_type' => PT_PLANET), SN_TIME_NOW); $target_planet_row = $target_planet_row['planet']; $rowAttacker = db_user_by_id($fleetRow['fleet_owner'], true); if ($target_planet_row['id']) { $planetDefense = array(); foreach (sn_get_groups('defense_active') as $unit_id) { $planetDefense[$unit_id] = array(mrc_get_level($targetUser, $target_planet_row, $unit_id, true, true)); } $message = ''; $interceptors = mrc_get_level($targetUser, $target_planet_row, UNIT_DEF_MISSILE_INTERCEPTOR, true, true); //$target_planet_row[$interceptor_db_name]; // Number of interceptors $missiles = $fleetRow['fleet_amount']; // Number of MIP if ($interceptors >= $missiles) { $message = $lang['mip_all_destroyed']; $db_changeset['unit'][] = sn_db_unit_changeset_prepare(UNIT_DEF_MISSILE_INTERCEPTOR, -$missiles, $targetUser, $target_planet_row['id']); } else { if ($interceptors) { $message = sprintf($lang['mip_destroyed'], $interceptors); $db_changeset['unit'][] = sn_db_unit_changeset_prepare(UNIT_DEF_MISSILE_INTERCEPTOR, -$interceptors, $targetUser, $target_planet_row['id']); } // $message .= $lang['mip_defense_destroyed']; $attackResult = COE_missileAttack($targetUser, $rowAttacker, $missiles - $interceptors, $planetDefense, $fleetRow['primaer']); foreach ($attackResult['structures'] as $key => $structure) { $destroyed = $planetDefense[$key][0] - $structure[0]; if ($destroyed) { $db_changeset['unit'][] = sn_db_unit_changeset_prepare($key, -$destroyed, $targetUser, $target_planet_row['id']); $message .= " {$lang['tech'][$key]} - {$destroyed} {$lang['quantity']}<br>"; } } if (!empty($message)) { $message = $lang['mip_defense_destroyed'] . $message . "{$lang['mip_recycled']}{$lang['Metal']}: {$attackResult['metal']}, {$lang['Crystal']}: {$attackResult['crystal']}<br>"; db_planet_set_by_id($target_planet_row['id'], "`metal` = `metal` + {$attackResult['metal']}, `crystal` = `crystal` + {$attackResult['crystal']}"); } // $message .= "{$lang['mip_recycled']}{$lang['Metal']}: {$attackResult['metal']}, {$lang['Crystal']}: {$attackResult['crystal']}<br>"; } db_changeset_apply($db_changeset); $fleetRow['fleet_start_type'] = PT_PLANET; $sourcePlanet = db_planet_by_vector($fleetRow, 'fleet_start_', false, 'name'); $message_vorlage = sprintf($lang['mip_body_attack'], $fleetRow['fleet_amount'], addslashes($sourcePlanet['name']), $fleetRow['fleet_start_galaxy'], $fleetRow['fleet_start_system'], $fleetRow['fleet_start_planet'], addslashes($target_planet_row['name']), $fleetRow['fleet_end_galaxy'], $fleetRow['fleet_end_system'], $fleetRow['fleet_end_planet']); empty($message) ? $message = $lang['mip_no_defense'] : false; // empty($message) && ($message = $lang['mip_no_defense']); msg_send_simple_message($fleetRow['fleet_owner'], '', SN_TIME_NOW, MSG_TYPE_SPY, $lang['mip_sender_amd'], $lang['mip_subject_amd'], $message_vorlage . $message); msg_send_simple_message($fleetRow['fleet_target_owner'], '', SN_TIME_NOW, MSG_TYPE_SPY, $lang['mip_sender_amd'], $lang['mip_subject_amd'], $message_vorlage . $message); } doquery("DELETE FROM {{iraks}} WHERE id = '{$fleetRow['id']}';"); } }
function uni_planet_teleport_check($user, $planetrow, $new_coordinates = null) { global $lang, $config; try { if ($planetrow['planet_teleport_next'] && $planetrow['planet_teleport_next'] > SN_TIME_NOW) { throw new exception($lang['ov_teleport_err_cooldown'], ERR_ERROR); } if (mrc_get_level($user, false, RES_DARK_MATTER) < $config->planet_teleport_cost) { throw new exception($lang['ov_teleport_err_no_dark_matter'], ERR_ERROR); } // TODO: Replace quick-check with using gathered flying fleet data $incoming = doquery("SELECT COUNT(*) AS incoming FROM {{fleets}} WHERE \n (fleet_start_galaxy = {$planetrow['galaxy']} and fleet_start_system = {$planetrow['system']} and fleet_start_planet = {$planetrow['planet']})\n or\n (fleet_end_galaxy = {$planetrow['galaxy']} and fleet_end_system = {$planetrow['system']} and fleet_end_planet = {$planetrow['planet']})", true); if (!empty($incoming['incoming'])) { throw new exception($lang['ov_teleport_err_fleet'], ERR_ERROR); } //$incoming = doquery("SELECT COUNT(*) AS incoming FROM {{iraks}} WHERE fleet_end_galaxy = {$planetrow['galaxy']} and fleet_end_system = {$planetrow['system']} and fleet_end_planet = {$planetrow['planet']}", true); //if($incoming['incoming']) { // throw new exception($lang['ov_teleport_err_fleet'], ERR_ERROR); //} if (is_array($new_coordinates)) { $new_coordinates['planet_type'] = PT_PLANET; $incoming = db_planet_by_vector($new_coordinates, '', true, 'id'); if ($incoming['id']) { throw new exception($lang['ov_teleport_err_destination_busy'], ERR_ERROR); } } $response = array('result' => ERR_NONE, 'message' => ''); } catch (exception $e) { $response = array('result' => $e->getCode(), 'message' => $e->getMessage()); } return $response; }
$target_coord = array('galaxy' => $target_galaxy = sys_get_param_int('galaxy'), 'system' => $target_system = sys_get_param_int('system'), 'planet' => $target_planet = sys_get_param_int('planet')); if (!uni_coordinates_valid($target_coord)) { die($lang['gs_c02']); } $target_mission = sys_get_param_int('mission'); $sn_group_missions = sn_get_groups('missions'); if (!isset($sn_group_missions[$target_mission]['AJAX']) || !$sn_group_missions[$target_mission]['AJAX']) { die($lang['gs_c00']); } sn_db_transaction_start(); $user = db_user_by_id($user['id'], true); $planetrow = db_planet_by_id($user['current_planet'], true); $target_planet_type = sys_get_param_int('planet_type'); $target_planet_check = $target_planet_type == PT_DEBRIS ? PT_PLANET : $target_planet_type; $target_coord['planet_type'] = $target_planet_check; $target_row = db_planet_by_vector($target_coord); if (empty($target_row)) { $target_row = array('galaxy' => $target_coord['galaxy'], 'system' => $target_coord['system'], 'planet' => $target_coord['planet'], 'planet_type' => $target_planet_check, 'id_owner' => 0); } $fleet_array = array(); switch ($target_mission) { case MT_SPY: $fleet_array[SHIP_SPY] = min(mrc_get_level($user, $planetrow, SHIP_SPY), abs($user['spio_anz'])); $unit_group = 'flt_spies'; break; case MT_RECYCLE: foreach (sn_get_groups('flt_recyclers') as $unit_id) { if ($unit_count = mrc_get_level($user, $planetrow, $unit_id)) { $fleet_array[$unit_id] = $unit_count; } }
function sys_o_get_updated($user, $planet, $UpdateTime, $simulation = false, $no_user_update = false) { sn_db_transaction_check(true); $no_data = array('user' => false, 'planet' => false, 'que' => false); if (!$planet) { return $no_data; } if (!$no_user_update) { $user = intval(is_array($user) && $user['id'] ? $user['id'] : $user); if (!$user) { // TODO - Убрать позже print '<h1>СООБЩИТЕ ЭТО АДМИНУ: sys_o_get_updated() - USER пустой!</h1>'; $backtrace = debug_backtrace(); array_shift($backtrace); pdump($backtrace); die; } $user = db_user_by_id($user, !$simulation, '*', true); } if (empty($user['id'])) { return $no_data; } if (is_array($planet) && isset($planet['galaxy']) && $planet['galaxy']) { $planet = db_planet_by_vector($planet, '', !$simulation); } else { $planet = intval(is_array($planet) && isset($planet['id']) ? $planet['id'] : $planet); $planet = db_planet_by_id($planet, !$simulation); } if (!is_array($planet) || !isset($planet['id'])) { return $no_data; } $que = que_process($user, $planet, $UpdateTime); $ProductionTime = max(0, $UpdateTime - $planet['last_update']); $planet['prev_update'] = $planet['last_update']; $planet['last_update'] += $ProductionTime; /* $que = eco_que_process($user, $planet, $ProductionTime); $hangar_built = $ProductionTime && !$simulation ? eco_bld_que_hangar($user, $planet, $ProductionTime) : array(); */ // TODO ЭТО НАДО ДЕЛАТЬ ТОЛЬКО ПРИ СПЕЦУСЛОВИЯХ $caps_real = eco_get_planet_caps($user, $planet, $ProductionTime); $resources_increase = array(RES_METAL => 0, RES_CRYSTAL => 0, RES_DEUTERIUM => 0); switch ($planet['planet_type']) { case PT_PLANET: foreach ($resources_increase as $resource_id => &$increment) { $resource_name = pname_resource_name($resource_id); $increment = $caps_real['total'][$resource_id] * $ProductionTime / 3600; $store_free = $caps_real['total_storage'][$resource_id] - $planet[$resource_name]; $increment = min($increment, max(0, $store_free)); if ($planet[$resource_name] + $increment < 0 && !$simulation) { global $debug; $debug->warning("Player ID {$user['id']} have negative resources on ID {$planet['id']}.{$planet['planet_type']} [{$planet['galaxy']}:{$planet['system']}:{$planet['planet']}]. Difference {$planet[$resource_name]} of {$resource_name}", 'Negative Resources', 501); } $planet[$resource_name] += $increment; $planet[$resource_name . '_perhour'] = $caps_real['total'][$resource_id]; } break; case PT_MOON: default: $planet['metal_perhour'] = 0; $planet['crystal_perhour'] = 0; $planet['deuterium_perhour'] = 0; $planet['energy_used'] = 0; $planet['energy_max'] = 0; break; } // TODO пересчитывать размер планеты только при постройке чего-нибудь и при покупке сектора $planet['field_current'] = 0; $sn_group_build_allow = sn_get_groups('build_allow'); if (is_array($sn_group_build_allow[$planet['planet_type']])) { foreach ($sn_group_build_allow[$planet['planet_type']] as $building_id) { $planet['field_current'] += mrc_get_level($user, $planet, $building_id, !$simulation, true); } } if ($simulation) { return array('user' => $user, 'planet' => $planet, 'que' => $que); } db_planet_set_by_id($planet['id'], "`last_update` = '{$planet['last_update']}', `field_current` = {$planet['field_current']},\n `metal` = `metal` + '{$resources_increase[RES_METAL]}', `crystal` = `crystal` + '{$resources_increase[RES_CRYSTAL]}', `deuterium` = `deuterium` + '{$resources_increase[RES_DEUTERIUM]}',\n `metal_perhour` = '{$planet['metal_perhour']}', `crystal_perhour` = '{$planet['crystal_perhour']}', `deuterium_perhour` = '{$planet['deuterium_perhour']}',\n `energy_used` = '{$planet['energy_used']}', `energy_max` = '{$planet['energy_max']}'"); return array('user' => $user, 'planet' => $planet, 'que' => $que); }