_player = $player; $this->_doctrineConnection = $doctrineConnection; $this->_redis = $redis; $this->_redis_spell_map = $redis_spell_map; $this->_cache = $this->_doctrineConnection->getResultCacheDriver(); if($redis_bosses_queue) { $this->_redis_queue = $redis_bosses_queue; } else { $this->_redis_queue = $redis; } if($redis_bosses_queue_free) { $this->_redis_queue_free = $redis_bosses_queue_free; } else { $this->_redis_queue_free = $this->_redis_queue; } if($redis_bosses_logs) { $this->_redis_logs = $redis_bosses_logs; } else { $this->_redis_logs = $redis; } if($redis_bosses_rating) { $this->_redis_rating = $redis_bosses_rating; } else { $this->_redis_rating = $redis; } if ($redis_bosses_ro) { $rnd = rand(1, 10); if($rnd > 8) { $this->_redis_ro = $redis; } elseif($rnd > 4) { $this->_redis_ro = $redis_bosses_ro; } else { if($redis_bosses_ro_2) { $this->_redis_ro = $redis_bosses_ro_2; } else { $this->_redis_ro = $redis_bosses_ro; } } } else { $this->_redis_ro = $redis; } } public function __destruct() { } private function loadBosses() { self::$_bossesCache = $this->_cache->fetch('bosses', false); if(self::$_bossesCache == null) { $q = RepositoryDoctrineQuery::create() ->from('Boss'); $bosses = $q->fetchArray(); foreach ($bosses as &$boss) { $boss['rewards_str'] = $boss['rewards']; $boss['rewards'] = json_decode($boss['rewards'], true);//DispRewards($boss['rewards']); $boss['battle_modes'] = json_decode($boss['battle_modes'], true); $boss['buff_rewards'] = json_decode($boss['buff_rewards'], true); $boss['guild_mode'] = json_decode($boss['guild_mode'], true); $boss['attack_price'] = json_decode($boss['attack_price'], true); } $this->_cache->save('bosses', $bosses, 6*60*60, false); self::$_bossesCache = $bosses; } } public function getBosses() { if (empty(self::$_bossesCache)) { $this->loadBosses(); } return self::$_bossesCache; } public function getBoss($boss_id) { $result = null; $bosses = $this->getBosses(); foreach ($bosses as $boss) { if ($boss['id'] == $boss_id) { $result = $boss; } } return $result; } public function getBattleMode($boss_id, $mode) { $res = null; if(in_array($mode, array('simple', 'cool', 'epic', 'uber'))) { $boss = $this->getBoss($boss_id); if($boss != false) { if(is_array($boss['battle_modes'])) { foreach($boss['battle_modes'] as $m) { if($m['type'] == $mode) { $res = $m; break; } } } elseif($mode == 'simple') { $res = array('type'=>'simple', 'name'=>'Пацанский', 'rewards'=>array()); } } } return $res; } public function getBuffRewards($boss_id, $buff_id) { $res = null; $repBuff = new repBuff(null); if($buff_id == 0) { $res = array('buff_id' => $buff_id, 'rewards' => array()); } else { $buff = $repBuff->getBuff($buff_id); if($buff != null && $buff['combat']) { $boss = $this->getBoss($boss_id); if($boss != false) { if(is_array($boss['buff_rewards'])) { foreach($boss['buff_rewards'] as $br) { if($br['buff_id'] == $buff_id) { $res = $br; break; } } } if ($res == null) { $res = array('buff_id' => $buff_id, 'rewards' => array()); } } } } return $res; } public function getPlayerTodayBattlesCount($player_id, $boss_id) { $key = 'today_battles_counter_' . $boss_id; // return $this->_redis->hget($key, $player_id); return $this->_redis_ro->hget($key, $player_id); } public function incrAndGetPlayerTodayBattlesCount($player_id, $boss_id) { $key = 'today_battles_counter_' . $boss_id; return $this->_redis->hincrby($key, $player_id, 1); } public function deleteTodayBattlesCounter() { $this->_redis->del('today_battles_counter'); for ($i = 1; $i <= 77; $i++) $this->_redis->del('today_battles_counter_'.$i); } public function addDelayedHit($player_id, $player_uid, $spell_damage, $spell_type, $buff_id = 0, $spell_id = 0, $spell_amount = 1, $splash_type = 0) { global $platform, $rabbit_bosses_url, $AppConfig; $nextBossHit = new stdClass(); $nextBossHit->id = $player_id; $nextBossHit->uid = $player_uid; $nextBossHit->dam = $spell_damage; $nextBossHit->t = $spell_type; $nextBossHit->buff = $buff_id; $nextBossHit->s_id = $spell_id; $nextBossHit->s_a = $spell_amount; $nextBossHit->ts = time(); if($splash_type > 0) { $nextBossHit->spt = $splash_type; } // $key = 'delayed_battle_hit'; $key = $this->getQueueNameBySpellType($spell_type); $redis_queue = $this->getQueueRedisBySpellType($spell_type); // $redis_queue->lpush($key, json_encode($nextBossHit)); if($spell_type == 'free' && $AppConfig['boss_battle']->queue == "rabbit") { $amqp = new AMQP_Service($rabbit_bosses_url); $amqp->connect('bosshits'); $amqp->create_queue('bosshits_' . $spell_type); $amqp->bind_exchange_to_queue('hits.' . $spell_type); $amqp->publish(json_encode($nextBossHit), 'hits.' . $spell_type, true); } elseif($spell_type == 'collected' && $AppConfig['boss_battle']->queue == "rabbit") { $amqp = new AMQP_Service($rabbit_bosses_url); $amqp->connect('bosshits'); $queue_postfix = $spell_type; // Raid only mode: if($AppConfig['boss_battle']->raidModeEnabled && $spell_amount > 10 && $spell_damage > 40000) { $queue_postfix = $spell_type.'_high'; } $amqp->create_queue('bosshits_' . $queue_postfix); $amqp->bind_exchange_to_queue('hits.' . $queue_postfix); $amqp->publish(json_encode($nextBossHit), 'hits.' . $queue_postfix, true); } else { $redis_queue->lpush($key, json_encode($nextBossHit)); } } private function getQueueRedisBySpellType($spell_type = 'free') { $redis_queue = $this->_redis_queue; switch($spell_type) { case 'free': $redis_queue = $this->_redis_queue_free; break; case 'collected': $redis_queue = $this->_redis_queue; break; default: $redis_queue = $this->_redis_queue; } return $redis_queue; } private function getQueueNameBySpellType($spell_type = 'free') { $queueName = 'delayed_battle_hit'; switch($spell_type) { case 'free': $queueName = 'delayed_battle_hit_free'; break; case 'collected': $queueName = 'delayed_battle_hit'; break; default: $queueName = 'delayed_battle_hit'; } return $queueName; } public function getDelayedHit($priority = 0) { $hitData = $this->getDelayedHitBySpellType('collected'); // var_dump('hd1', $hitData); if(!$hitData) { $hitData = $this->getDelayedHitBySpellType('free'); // var_dump('hd2', $hitData); } return $hitData; } public function getHitFromBackup() { $key = $this->getQueueNameBySpellType('collected'); $key_backup = $key . '_backup'; $redis_queue = $this->getQueueRedisBySpellType('collected'); $bossHitDataList = $redis_queue->lrange($key_backup, 0, -1); return $bossHitDataList; } public function getHitFromFreeBackup() { $key = $this->getQueueNameBySpellType('free'); $key_backup = $key . '_backup'; $redis_queue = $this->getQueueRedisBySpellType('free'); $bossHitDataList = $redis_queue->lrange($key_backup, 0, -1); return $bossHitDataList; } public function getDelayedHitBySpellType($spell_type) { // $key = 'delayed_battle_hit'; $key = $this->getQueueNameBySpellType($spell_type); // $key_backup = 'delayed_battle_hit_backup'; $key_backup = $key . '_backup'; $redis_queue = $this->getQueueRedisBySpellType($spell_type); //var_dump($key); $nextBossHitData = $redis_queue->rpoplpush($key, $key_backup); if (!empty($nextBossHitData)) { $nextBossHit = json_decode($nextBossHitData); } else { $nextBossHit = null; } return $nextBossHit; } public function removeHitFromBackUpQueue($bossHitData) { // $key_backup = 'delayed_battle_hit_backup'; if($bossHitData instanceof stdClass) { $jsonedBossHitData = json_encode($bossHitData); } else { $jsonedBossHitData = $bossHitData; $bossHitData = json_decode($bossHitData); } $key = $this->getQueueNameBySpellType($bossHitData->t); $key_backup = $key . '_backup'; $redis_queue = $this->getQueueRedisBySpellType($bossHitData->t); return $redis_queue->lrem($key_backup, -1, $jsonedBossHitData); } private static $_spells = array(); public function getSpells() { if (empty(self::$_spells)) { $q = RepositoryDoctrineQuery::create() ->from('Spell'); $raw_spells = $q->fetchArray(); self::$_spells = array(); foreach ($raw_spells as $spell) { if ($spell['type'] == 'free') { self::$_spells['free'][] = $spell; } if ($spell['type'] == 'collected') { self::$_spells['collected'][] = $spell; } } } return self::$_spells; } public function getBossesWithRating($boss_id = null) { return getBossKillRating($boss_id); /* $query = " SELECT plb.players_id as user_id, plb.win_count as value FROM `boss` bb inner join `player_boss` plb ON bb.id = plb.boss_id AND bb.id = " . $boss_id . " order by plb.win_count desc LIMIT 1"; $query_results = $this->_doctrineConnection->fetchAll($query); return $query_results[0];*/ } public function saveRatingToMemcache($boss_id, $user_id, $value) { $key = 'main_user_' . $boss_id; $json = json_encode(array('user_id' => $user_id, 'value' => $value)); $this->_cache->save($key, $json, self::$_24hour, false); } public function getRatingFromMemcache($boss_id) { $key = 'main_user_' . $boss_id; $first_user = $this->_cache->fetch($key, false); $array = json_decode($first_user, true); return $array; } public function newBattleToRedis($player, $boss_data, $mode, $buff_id) { $battle_id = $player->uid; $key = self::$_battle_prefix . $battle_id; try { $actEffect = new actEffect($player); $battleTimeProp = $actEffect->getGOproperty('battle_time', null, $boss_data['battle_time']); //var_dump($battleTimeProp); $bossHealthProp = $actEffect->getGOproperty('boss_health', null, $boss_data['health']); $ts = time(); $battle = array( 'boss_id' => $boss_data['id'], 'h_full' => $bossHealthProp->value, 'h_now' => $bossHealthProp->value, 'cur_damage' => 0, 'start_ts' => $ts, 'end_ts' => $ts + $battleTimeProp->value, 'mode' => $mode, 'status' => 'active', 'buff' => $buff_id ); $this->_redis->hmset($key, $battle); // Добавляем битву в кэш self::$_battlesCache[$battle_id] = $battle; return true; } catch (Exception $e) { log::error('Can not get battle from redis'); return false; } } private static $_battlesCache = array(); public function getBattleFromRedis($player) { $battle_id = $player->uid; if (!array_key_exists($battle_id, self::$_battlesCache) || empty(self::$_battlesCache[$battle_id])) { $key = self::$_battle_prefix . $battle_id; $battle = $this->_redis_ro->hgetall($key); if($battle != null && $battle['mode'] == null) { $battle['mode'] = 'simple'; } if($battle != null && $battle['buff'] == null) { $battle['buff'] = 0; } self::$_battlesCache[$battle_id] = $battle; } else { $battle = self::$_battlesCache[$battle_id]; } $battle['all_info'] = $this->getBoss($battle['boss_id']); return $battle; } public function getPlayerDamage($player) { $res = array(); $spells = $this->getSpells(); $spells = array_merge($spells['free'], $spells['collected']); $battle = $this->getBattleFromRedis($player); foreach($spells as $s) { $res[$s['id']] = intval($battle['sd_'.$s['id']]); } return $res; } public function setBattleLength($player) { $battle_id = $player->uid; if (is_array(self::$_battlesCache) && array_key_exists($battle_id, self::$_battlesCache)) { $length = time() - self::$_battlesCache[$battle_id]['start_ts']; if(self::$_battlesCache[$battle_id]['win_ts'] > 0) { $length = self::$_battlesCache[$battle_id]['win_ts'] - self::$_battlesCache[$battle_id]['start_ts']; } else { if(self::$_battlesCache[$battle_id]['end_ts'] > 0) { $length = self::$_battlesCache[$battle_id]['end_ts'] - self::$_battlesCache[$battle_id]['start_ts']; } } self::$_battlesCache[$battle_id]['length'] = $length; } } public function deleteBattleFromRedis($player) { $battle_id = $player->uid; $key = self::$_battle_prefix . $battle_id; $result = $this->_redis->del($key); // Удаляем битву из кэша - нельзя, ачивы не узнают //unset(self::$_battlesCache[$battle_id]); $log_key = self::$_battle_log_prefix . $battle_id; $result = $this->_redis_logs->del($log_key); $battle_rating_key = self::$_battle_rating_prefix . $battle_id; $result = $this->_redis_rating->del($battle_rating_key); return $result; } public function getFriendsInWar($uid, $player_id, $splash_type = 0, &$splash_coefs = array()) { // $friends_list_all = repPlayer::getFriendsList($uid, $player_id); $bosses = array(); $bs = $this->getBosses(); foreach($bs as $b) { $bosses[$b['id']] = $b; } switch ($splash_type) { case 1: $act = new actGuildUtils($uid); $gm = $act->getMembers(); if(is_array($gm)) { unset($gm[$uid]); $friends_list_all = array_keys($gm); } else { $friends_list_all = array(); } $splash = 'guild'; break; default: $friends_list_all = repPlayer::getFriendsList($uid, $player_id); $splash = 'friends'; break; } //$t = implode(',', $friends_list_all); //echo "gfiw: uid $uid, splash $splash, targets $t\n"; $friends_list_chunked = array_chunk($friends_list_all, 250); $res = array(); foreach($friends_list_chunked as $friends_list) { $friendIds = array(); $result = array(); if(is_array($friends_list) && count($friends_list) > 0) { $pipe = $this->_redis_ro->pipeline(); foreach ($friends_list as $friend_uid) { if ($friend_uid != $uid) { $friendIds[] = $friend_uid; $key = self::$_battle_prefix . $friend_uid; $pipe->hmget($key, 'boss_id', 'h_now', 'end_ts', 'type', 'spt', 'spcf'); } } $result = $pipe->execute(); } if (count($friendIds) != count($result) || count($friendIds) == 0) { // $friends_in_war = array(); } else { $result = array_combine($friendIds, $result); $currentTime = time(); foreach ($result as $friend_uid => $battle) { if ($battle[1] > 0 && $battle[2] > $currentTime && !empty($friend_uid)) { $type = 'boss'; if($battle[3] == 'node') { $type = 'node'; } $sp = 'friends'; if($battle[4] == null && $type == 'boss') { $sp = $bosses[$battle[0]]['splash']; } if($battle[4] == 'f') { $sp = 'friends'; } if($battle[4] == 'g') { $sp = 'guild'; } if($battle[4] == 'n') { $sp = 'none'; } if($sp == $splash) { $res[] = $friend_uid; if($battle[5] != null) { $splash_coefs[$friend_uid] = array(); $spcf = explode(',', $battle[5]); if(is_array($spcf)) { foreach($spcf as $spcfItem) { if($spcfItem != null) { list($spellId, $coef) = explode('_', $spcfItem); $spellId = intval($spellId); $coef = min(intval($coef), 100); if($coef > 0) { $splash_coefs[$friend_uid][$spellId] = $coef; } } } } } } /* var_dump(array( 'uid' => $friend_uid, 'boss_id' => $battle[0], 'def_splash' => $bosses[$battle[0]]['splash'], 'sp' => $sp, 'tsp' => $battle[4], 'dmg_sp' => $splash)); */ } } } } // $friends_in_war = $res; return $res; //$friends_in_war; } public function getBattleStatus($player) { $battle_id = $player->uid; if (array_key_exists($battle_id, self::$_battlesCache) && !empty(self::$_battlesCache[$battle_id])) { $status = self::$_battlesCache[$battle_id]['status']; } else { $key = self::$_battle_prefix . $battle_id; $status = $this->_redis_ro->hget($key, 'status'); } return $status; } public function setBattleStatus($player, $status = 'completed') { $battle_id = $player->uid; if (array_key_exists($battle_id, self::$_battlesCache) && !empty(self::$_battlesCache[$battle_id])) { self::$_battlesCache[$battle_id]['status'] = $status; } $key = self::$_battle_prefix . $battle_id; $status = $this->_redis->hset($key, 'status', $status); return $status; } public function setResultOfBattle($player, $result) { $battle_id = $player->uid; if (array_key_exists($battle_id, self::$_battlesCache) && !empty(self::$_battlesCache[$battle_id])) { self::$_battlesCache[$battle_id]['result'] = $result; } $key = self::$_battle_prefix . $battle_id; $result = $this->_redis->hset($key, 'result', $result); return $result; } public function reduceBossHealth($player, $spell_id, $spell_damage) { $battle_id = $player->uid; $spell_damage = ceil($spell_damage); $key = self::$_battle_prefix . $battle_id; $result = $this->_redis->hincrby($key, 'h_now', $spell_damage * (-1)); if($spell_id > 0) { $this->_redis->hincrby($key, 'sd_'.$spell_id, $spell_damage); actChanges::getInstance()->addSpellDamage($spell_id, $spell_damage); } if($result < 0) { $win_ts = time(); $this->_redis->hset($key, 'win_ts', $win_ts); } if (array_key_exists($battle_id, self::$_battlesCache) && !empty(self::$_battlesCache[$battle_id])) { self::$_battlesCache[$battle_id]['h_now'] = $result; if($spell_id > 0) { self::$_battlesCache[$battle_id]['sd_'.$spell_id] += $spell_damage; } if($result < 0) { self::$_battlesCache[$battle_id]['win_ts'] = $win_ts; } } return $result; } public function deleteMissedDamage($player) { $battle_id = $player->uid; $key = self::$_battle_prefix . $battle_id; $result = $this->_redis->hdel($key, 'dmg_missed'); if (array_key_exists($battle_id, self::$_battlesCache) && !empty(self::$_battlesCache[$battle_id])) { self::$_battlesCache[$battle_id]['dmg_missed'] = 0; } } public function setCurrentDamage($player, $dmg) { $battle_id = $player->uid; $key = self::$_battle_prefix . $battle_id; $result = $this->_redis->hset($key, 'cur_damage', $dmg); if (array_key_exists($battle_id, self::$_battlesCache) && !empty(self::$_battlesCache[$battle_id])) { self::$_battlesCache[$battle_id]['cur_damage'] = $result; } return $result; } public function logUserAction($battle_id, $friend_uid, $spell_damage, $spell_type) { $key = self::$_battle_log_prefix . $battle_id; $result = $this->_redis_logs->lpush($key, $this->encodeLogRecord($friend_uid, $spell_damage, $spell_type)); return $result; } public function getAllLogOfUserActions($player) { $battle_id = $player->uid; $key = self::$_battle_log_prefix . $battle_id; $action_json_objects = $this->_redis_logs->lrange($key, 0, -1); if (count($action_json_objects) > 0) { $actions = array(); foreach ($action_json_objects as $action) { list($uid, $damage, $type_code) = explode('_', $action); if ($type_code == 1) { $type = 'collected'; } else { $type = 'free'; } $friend_who_help_me = array( 'uid' => $uid, 'damage' => $damage, 'type' => $type ); $actions[] = $friend_who_help_me; } } else { $actions = null; } return $actions; } private function encodeLogRecord($uid, $damage, $spell_type) { return $uid . '_' . $damage . '_' . ($spell_type == 'free' ? 0 : 1); } public function deleteLog($player) { $battle_id = $player->uid; $key = self::$_battle_log_prefix . $battle_id; $result = $this->_redis_logs->del($key); return $result; } public function splashDamageAndLog($battlesForDamage_all, $hitterUid, $damage, $spell_type, $buff_id) { if (empty($battlesForDamage_all) || $damage <= 0 || $hitterUid == '') { return; } $damage = $damage > 0 ? ceil($damage) : floor($damage); $ts = time(); // $fireAndForgetExecuterOptions = array('executor' => new \Predis\Pipeline\FireAndForgetExecutor()); $actBuff = new actBuff(null); $damage_multipliers = $actBuff->damageMultiplier($battlesForDamage_all); $max_dm = $actBuff->damageMultiplierMaximum(); $under_buff = $actBuff->damageFlowFilter($buff_id, $battlesForDamage_all); $battlesForDamage_chunked = array_chunk($battlesForDamage_all, 250); foreach($battlesForDamage_chunked as $battlesForDamage) { $splashed_battles = array(); $pipe = $this->_redis->pipeline(); $pipe2 = $this->_redis_logs->pipeline(); $pipe3 = $this->_redis->pipeline(); $pipe4 = $this->_redis_rating->pipeline(); foreach ($battlesForDamage as $battle_id) { $boss_battle_key = self::$_battle_prefix . $battle_id; $battle_rating_key = self::$_battle_rating_prefix . $battle_id; $boss_battle_log_key = self::$_battle_log_prefix . $battle_id; $m = $damage_multipliers[$battle_id]; if($m == 0) { $m = 1; } $dmg = intval($m * $damage); if($buff_id == 0 || ($buff_id > 0 && $under_buff[$battle_id] > 0)) { $friend_who_help_me = $this->encodeLogRecord($hitterUid, $dmg, $spell_type); $pipe->hincrby($boss_battle_key, 'h_now', $dmg * (-1)); $pipe2->lpush($boss_battle_log_key, $friend_who_help_me); $pipe4->zincrby($battle_rating_key, $dmg, $hitterUid); $lost = intval(($max_dm - $m) * $damage); if($lost > 0) { $pipe3->hincrby($boss_battle_key, 'dmg_missed', $lost); } $splashed_battles[] = $battle_id; } else { $pipe3->hincrby($boss_battle_key, 'dmg_missed', $damage); } // И коррекция кол-во записей в логе действий друзей (оставляем только 100 самых свежих записей) if ($hitterUid % 4 == 0) { $pipe2->ltrim($boss_battle_log_key, 0, 99); } } $result = $pipe->execute(); $pipe2->execute(); $pipe3->execute(); $pipe4->execute(); //var_dump($damage_multipliers); // $chunked = array_chunk($result, 3); $chunked = $result; // TODO: Протестить, что эта вот шняга не сломалась... и цикл ниже правильно работает и $hitResult[0] в ифе возвращает то же что и раньше! $combined = count($splashed_battles) > 0 ? array_combine($splashed_battles, $chunked) : array(); $pipe = $this->_redis->pipeline(); $toStopBattle = array(); //var_dump('combined', $combined); foreach ($combined as $battle_id => $hitResult) { //if ($hitResult[0] <= 0) это для $chunked = array_chunk($result, 3); if($hitResult <= 0) { $boss_battle_key = self::$_battle_prefix . $battle_id; $toStopBattle[] = $battle_id; //$cmd_params = array('end_ts' => -1, 'win_ts' => $ts); //$pipe->hmset($boss_battle_key, $cmd_params); $pipe->hset($boss_battle_key, 'win_ts', $ts); } } //var_dump('stopped', $toStopBattle); $pipe->execute(); echo "Processed:\t" . count($chunked) . "\t" . count($toStopBattle) . "\n"; } } public function splashDamageAndLog2($battlesForDamage_all, $hitterUid, $damage, $spell_type, $buff_id, $spell_id, $splash_coefs) { if (empty($battlesForDamage_all) || $damage <= 0 || $hitterUid == '') { return; } $damage = $damage > 0 ? ceil($damage) : floor($damage); $ts = time(); // $fireAndForgetExecuterOptions = array('executor' => new \Predis\Pipeline\FireAndForgetExecutor()); $actBuff = new actBuff(null); $damage_multipliers = $actBuff->damageMultiplier($battlesForDamage_all); $max_dm = $actBuff->damageMultiplierMaximum(); $under_buff = $actBuff->damageFlowFilter($buff_id, $battlesForDamage_all); $battlesForDamage_chunked = array_chunk($battlesForDamage_all, 250); foreach($battlesForDamage_chunked as $battlesForDamage) { $splashed_battles = array(); $pipe = $this->_redis->pipeline(); $pipe2 = $this->_redis_logs->pipeline(); $pipe3 = $this->_redis->pipeline(); $pipe4 = $this->_redis_rating->pipeline(); foreach ($battlesForDamage as $battle_id) { $boss_battle_key = self::$_battle_prefix . $battle_id; $battle_rating_key = self::$_battle_rating_prefix . $battle_id; $boss_battle_log_key = self::$_battle_log_prefix . $battle_id; $m = $damage_multipliers[$battle_id]; if($m == 0) { $m = 1; } $dmg = intval($m * $damage); if(is_array($splash_coefs[$battle_id]) && count($splash_coefs[$battle_id]) > 0) { if($splash_coefs[$battle_id][0] > 0) { $dmg = intval($dmg * (100 - $splash_coefs[$battle_id][0])/100); } else { if($splash_coefs[$battle_id][$spell_id] > 0) { $dmg = intval($dmg * (100 - $splash_coefs[$battle_id][$spell_id])/100); } } $dmg = max($dmg, 1); } if($buff_id == 0 || ($buff_id > 0 && $under_buff[$battle_id] > 0)) { $friend_who_help_me = $this->encodeLogRecord($hitterUid, $dmg, $spell_type); $pipe->hincrby($boss_battle_key, 'h_now', $dmg * (-1)); $pipe2->lpush($boss_battle_log_key, $friend_who_help_me); $pipe4->zincrby($battle_rating_key, $dmg, $hitterUid); $lost = intval(($max_dm - $m) * $damage); if($lost > 0) { $pipe3->hincrby($boss_battle_key, 'dmg_missed', $lost); } $splashed_battles[] = $battle_id; } else { $pipe3->hincrby($boss_battle_key, 'dmg_missed', $damage); } // И коррекция кол-во записей в логе действий друзей (оставляем только 100 самых свежих записей) if ($hitterUid % 4 == 0) { $pipe2->ltrim($boss_battle_log_key, 0, 99); } } $result = $pipe->execute(); $pipe2->execute(); $pipe3->execute(); $pipe4->execute(); //var_dump($damage_multipliers); // $chunked = array_chunk($result, 3); $chunked = $result; // TODO: Протестить, что эта вот шняга не сломалась... и цикл ниже правильно работает и $hitResult[0] в ифе возвращает то же что и раньше! $combined = count($splashed_battles) > 0 ? array_combine($splashed_battles, $chunked) : array(); $pipe = $this->_redis->pipeline(); $toStopBattle = array(); $botMSG = array( 'ts' => $ts, 'hitterUid' => $hitterUid, 'damage' => $damage, 'spellType' => $spell_type, 'splash' => array() ); //var_dump('combined', $combined); foreach ($combined as $battle_id => $hitResult) { //if ($hitResult[0] <= 0) это для $chunked = array_chunk($result, 3); $botLog = array( 'uid' => $battle_id, 'h_now' => $hitResult ); if($hitResult <= 0) { $boss_battle_key = self::$_battle_prefix . $battle_id; $toStopBattle[] = $battle_id; //$cmd_params = array('end_ts' => -1, 'win_ts' => $ts); //$pipe->hmset($boss_battle_key, $cmd_params); $pipe->hset($boss_battle_key, 'win_ts', $ts); $botLog['win_ts'] = $ts; } $botMSG['splash'][] = $botLog; } //var_dump('stopped', $toStopBattle); $pipe->execute(); $ac = AppConfig::instance(); if($ac['boss_battle']->botQueue && $spell_type == 'collected') { try { global $rabbit_bosses_url; $amqp = new AMQP_Service($rabbit_bosses_url); $amqp->connect('botdamage'); $amqp->create_queue('botdamage_' . $spell_type); $amqp->bind_exchange_to_queue('splash.' . $spell_type); $amqp->publish(json_encode($botMSG), 'splash.' . $spell_type, true); } catch(Exception $e) { // } } //var_dump('ass', $botMSG); echo "Processed:\t" . count($chunked) . "\t" . count($toStopBattle) . "\n"; } } public function updateUserRating($battle_id, $friend_uid, $spell_damage) { $redis_key = self::$_battle_rating_prefix . $battle_id; $result = $this->_redis_rating->zincrby($redis_key, $spell_damage, $friend_uid); return $result; } public function getFullRating($player) { $battle_id = $player->uid; $redis_key = self::$_battle_rating_prefix . $battle_id; $rating_data = $this->_redis_rating->zrevrange($redis_key, 0, -1, 'withscores'); $rating = array(); foreach ($rating_data as $key => $value) { $rating[$value[0]] = $value[1]; } return $rating; } public function getRating($player) { $battle_id = $player->uid; $redis_key = self::$_battle_rating_prefix . $battle_id; $rating_data = $this->_redis_rating->zrevrange($redis_key, 0, 7, 'withscores'); $rating = array(); foreach ($rating_data as $key => $value) { $rating[] = array('uid' => $value[0], 'damage' => $value[1] ); } return $rating; } public function updateUserVictory($player, $boss_id, $battle_mode) { $player_id = $player->id; $boss_id = intval($boss_id); ///TODO:on duplicate fix switch($battle_mode) { case 'cool': $query = 'INSERT INTO player_boss (players_id, boss_id ,win_count, cool_win_count, dropped_keys) VALUES (' . $player_id . ', ' . $boss_id . ', 1, 1, 0) ON DUPLICATE KEY UPDATE win_count = win_count + 1, cool_win_count = cool_win_count + 1'; $query_update = 'UPDATE player_boss SET win_count = win_count + 1, cool_win_count = cool_win_count + 1 WHERE players_id = '.$player_id.' AND boss_id = '.$boss_id; $query_insert = 'INSERT INTO player_boss (players_id, boss_id ,win_count, cool_win_count, dropped_keys) VALUES (' . $player_id . ', ' . $boss_id . ', 1, 1, 0)'; break; case 'epic': $query = 'INSERT INTO player_boss (players_id, boss_id ,win_count, epic_win_count, dropped_keys) VALUES (' . $player_id . ', ' . $boss_id . ', 1, 1, 0) ON DUPLICATE KEY UPDATE win_count = win_count + 1, epic_win_count = epic_win_count + 1'; $query_update = 'UPDATE player_boss SET win_count = win_count + 1, epic_win_count = epic_win_count + 1 WHERE players_id = '.$player_id.' AND boss_id = '.$boss_id; $query_insert = 'INSERT INTO player_boss (players_id, boss_id ,win_count, epic_win_count, dropped_keys) VALUES (' . $player_id . ', ' . $boss_id . ', 1, 1, 0)'; break; default: $query = 'INSERT INTO player_boss (players_id, boss_id ,win_count, dropped_keys) VALUES (' . $player_id . ', ' . $boss_id . ', 1, 0) ON DUPLICATE KEY UPDATE win_count = win_count + 1'; $query_update = 'UPDATE player_boss SET win_count = win_count + 1 WHERE players_id = '.$player_id.' AND boss_id = '.$boss_id; $query_insert = 'INSERT INTO player_boss (players_id, boss_id ,win_count, dropped_keys) VALUES (' . $player_id . ', ' . $boss_id . ', 1, 0)'; } try { $result = execNativeSQL($query_update, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); if(!$result) { $result = execNativeSQL($query_insert, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); } //$result = execNativeSQL($query, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); // $result = $this->_doctrineConnection->exec($query); } catch (Exception $e) { log::error('Can not update user victory'); $result = null; } try { global $AppConfig; if(!$AppConfig['boss_battle']->kill_switch) { $this->saveRatingToMemcache($boss_id, $player->uid, 1); } } catch (Exception $e) { } return $result; } public function getFreeUserSpells($player) { $battle_id = $player->uid; if (array_key_exists($battle_id, self::$_battlesCache) && !empty(self::$_battlesCache[$battle_id])) { $battle = self::$_battlesCache[$battle_id]; $spell_id = $battle['spell_id']; $spell_st = $battle['spell_st']; $spell_cd = $battle['spell_cd']; } else { $key = self::$_battle_prefix . $battle_id; list($spell_id, $spell_st, $spell_cd) = $this->_redis_ro->hmget($key, array('spell_id', 'spell_st', 'spell_cd')); } $free_spell = array(); $currentTime = time(); $timeleft = $spell_cd - ($currentTime - $spell_st); $timeleft = $timeleft > 0 ? $timeleft : 0; $free_spell[] = array('spell_id' => $spell_id, 'timeleft' => $timeleft, 'end_ts' => $spell_st + $spell_cd ); return $free_spell; } public function getConcreteFreeUserSpell($player, $spell_id) { $battle_id = $player->uid; if (empty(self::$_freeUserSpells[$battle_id][$spell_id])) { if (array_key_exists($battle_id, self::$_battlesCache) && !empty(self::$_battlesCache[$battle_id])) { $cd = self::$_battlesCache[$battle_id]['spell_cd']; $st = self::$_battlesCache[$battle_id]['spell_st']; $sid = self::$_battlesCache[$battle_id]['spell_id']; } else { $key = self::$_battle_prefix . $battle_id; list($cd, $st, $sid) = $this->_redis_ro->hmget($key, 'spell_cd', 'spell_st', 'spell_id'); } $spell = array( 'cooldown' => $cd, 'start_time' => $st, 'spell_id' => $sid ); self::$_freeUserSpells[$battle_id][$spell_id] = $spell; } return self::$_freeUserSpells[$battle_id][$spell_id]; } public function useFreeSpell($player, $spell) { $battle_id = $player->uid; $key = self::$_battle_prefix . $battle_id; $used_free_spell = array( 'cooldown' => $spell['cooldown'], 'start_time' => time(), 'spell_id' => $spell['id'] ); $spell_to_save = array( 'spell_cd' => $used_free_spell['cooldown'], 'spell_st' => $used_free_spell['start_time'], 'spell_id' => $spell['id'] ); $result = $this->_redis->hmset($key, $spell_to_save); self::$_freeUserSpells[$battle_id][$spell['id']] = $used_free_spell; if (array_key_exists($battle_id, self::$_battlesCache) && !empty(self::$_battlesCache[$battle_id])) { self::$_battlesCache[$battle_id]['spell_cd'] = $used_free_spell['cooldown']; self::$_battlesCache[$battle_id]['spell_st'] = $used_free_spell['start_time']; self::$_battlesCache[$battle_id]['spell_id'] = $spell['id']; } return $result; } public function reduceFreeSpellTime($player, $spell, $amount = 1) { $battle_id = $player->uid; $key = self::$_battle_prefix . $battle_id; $result = $this->_redis->hincrby($key, 'spell_cd', $spell['restoretime'] * $amount * (-1)); self::$_freeUserSpells[$battle_id][$spell['id']]['cooldown'] -= $spell['restoretime'] * $amount; if (array_key_exists($battle_id, self::$_battlesCache) && !empty(self::$_battlesCache[$battle_id])) { self::$_battlesCache[$battle_id]['spell_cd'] = $result; } return $result; } // public function deleteUsedFreeSpell($battle_id, $spell_id) // { // $key = self::$_battle_prefix . $battle_id; // // $pipe = $this->_redis->pipeline(); // // $pipe->hdel($key, 'spell_cd'); // $pipe->hdel($key, 'spell_st'); // // $replies = $pipe->execute(); // // $result = $replies[0] && $replies[1]; // // if (array_key_exists($battle_id, self::$_battlesCache) && !empty(self::$_battlesCache[$battle_id])) // { // unset(self::$_battlesCache[$battle_id]['spell_cd']); // unset(self::$_battlesCache[$battle_id]['spell_st']); // unset(self::$_battlesCache[$battle_id]['spell_id']); // } // // return $result; // } public function getCollectedUserSpells($player, $spell_id = null) { $user_id = $player->id; $q = CustomDoctrineQuery::create($player->uid) ->from('PlayerSpell') ->where('players_id = ?', $user_id); if ($spell_id) { $q->andWhere('spell_id = ?', $spell_id); } $spell = $q->fetchArray(); // var_dump($spell); return $spell; } public function incrCollectedSpell($player, $spell_id, $value) { $player_id = $player->id; $spell_id = intval($spell_id); $value = intval($value); ///TODO:on duplicate fix $query = "INSERT INTO player_spell (players_id, spell_id ,spell_num) VALUES (" . $player_id . ", " . $spell_id . ", " . $value . ") ON DUPLICATE KEY UPDATE spell_num = spell_num + " . $value; $query_update = 'UPDATE player_spell SET spell_num = spell_num + '.$value.' WHERE players_id = '.$player_id.' AND spell_id = '.$spell_id; $query_insert = 'INSERT INTO player_spell (players_id, spell_id ,spell_num) VALUES ('.$player_id.', '.$spell_id.', '.$value.')'; try { // $res = $this->_doctrineConnection->exec($query); //$res = execNativeSQL($query, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); $res = execNativeSQL($query_update, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); if(!$res) { $res = execNativeSQL($query_insert, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); } if($res) { actChanges::getInstance()->addSpellAmount($spell_id, $value); } } catch (Exception $e) { log::error('Can not set collected user spells'); //var_dump($e); $res = null; } return $res; } public function setCollectedSpell($player, $spell_id, $value) { $player_id = $player->id; $spell_id = intval($spell_id); $value = intval($value); $query_update = 'UPDATE player_spell SET spell_num = '.$value.' WHERE players_id = '.$player_id.' AND spell_id = '.$spell_id; $query_insert = 'INSERT INTO player_spell (players_id, spell_id ,spell_num) VALUES ('.$player_id.', '.$spell_id.', '.$value.')'; try { $res = execNativeSQL($query_update, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); if(!$res) { $res = execNativeSQL($query_insert, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); } if($res) { actChanges::getInstance()->addSpellAmount($spell_id, $value); } } catch (Exception $e) { log::error('Can not set collected user spells'); $res = null; } return $res; } public function decreaseCollectedSpell($player, $spell_id, $value) { $user_id = $player->id; if ($value <= 0) { log::error('decreaseCollectedSpell error: value < 0 = ' . $value); return 0; } $query = 'UPDATE player_spell SET spell_num = spell_num - ' . $value . ' WHERE players_id = ' . $user_id . ' and spell_id = ' . $spell_id . ' and spell_num >= ' . $value . ';'; try { $res = execNativeSQL($query, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); // $res = $this->_doctrineConnection->exec($query); actChanges::getInstance()->addSpellAmount($spell_id, $value*(-1)); } catch (Exception $e) { log::error('Can not set collected user spells'); $res = null; } return $res; } public function getKeys($key_id = null) { $q = RepositoryDoctrineQuery::create() ->from('Boss'); if ($key_id) { $q->where('id = ?', $key_id)->andWhere('key_price > 0'); } $keys = $q->fetchArray(); return $keys; } //TODO: Мне кажется или этот метод делает 2 разных дела в зависимости от параметров... не гуд. public function getUserKeys($player, $key_id = null) { $user_id = $player->id; $keys = array(); if ($key_id === null) { $bosses = $this->getBosses(); $player_boss = $this->getPlayerBoss($player); foreach ($bosses as $boss) { // if($boss['key_price'] > 0) { foreach ($player_boss as $pb) { if ($pb['boss_id'] == $boss['id']) { $boss['PlayerBosses'] = $pb; } } $keys[] = $boss; } } } if ($key_id !== null) { $q = CustomDoctrineQuery::create($player->uid) ->from('PlayerBoss') ->where('players_id = ?', $user_id) ->andWhere('boss_id = ?', $key_id); $keys = $q->fetchArray(); } return $keys; } public function getPlayerBoss($player) { $user_id = $player->id; $keys = array(); if ($user_id !== null) { $q = CustomDoctrineQuery::create($player->uid) ->from('PlayerBoss') ->where('players_id = ?', $user_id); $keys = $q->fetchArray(); } return $keys; } public function decreaseNumOfUserKeys($player, $keys_id, $value) { $user_id = $player->id; if ($value <= 0) { log::error('decreaseNumOfUserKeys error: value < 0 = ' . $value); return 0; } $query = 'UPDATE player_boss SET dropped_keys = dropped_keys - ' . $value . ' WHERE players_id = ' . $user_id . ' and boss_id = ' . $keys_id . ' and dropped_keys >= ' . $value . ';'; try { $res = execNativeSQL($query, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); // $res = $this->_doctrineConnection->exec($query); } catch (Exception $e) { log::error('Can not decrease num of user keys: ' . $e->getMessage()); $res = 0; } return $res; } public function setLastAttack($player, $boss_id, $ts) { $user_id = $player->id; if ($ts <= 0) { log::error('setLastAttack error: $ts < 0 = ' . $ts); return 0; } $query_update = 'UPDATE player_boss SET last_attack = '.$ts.' WHERE players_id = ' . $user_id . ' and boss_id = ' . $boss_id . ';'; $query_insert = 'INSERT INTO player_boss (players_id, boss_id, win_count, last_attack) VALUES (' . $user_id . ', ' . $boss_id . ', 0, ' . $ts . ')'; try { $res = execNativeSQL($query_update, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); if(!$res) { $res = execNativeSQL($query_insert, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); } // $res = $this->_doctrineConnection->exec($query); } catch (Exception $e) { log::error('Can not set last attack ts: ' . $e->getMessage()); //var_dump($e->getMessage()); $res = 0; } return $res; } public function changeNumOfUserKeys($player, $keys_id, $value) { $player_id = $player->id; $keys_id = intval($keys_id); $value = intval($value); $res = false; ///TODO:on duplicate fix $query = "INSERT INTO player_boss (players_id, boss_id, win_count, dropped_keys) VALUES (" . $player_id . ", " . $keys_id . ", 0, " . $value . ") ON DUPLICATE KEY UPDATE dropped_keys = dropped_keys + " . $value; $query_update = 'UPDATE player_boss SET dropped_keys = dropped_keys + '.$value.' WHERE players_id = '.$player_id.' AND boss_id = '.$keys_id; $query_insert = 'INSERT INTO player_boss (players_id, boss_id, win_count, dropped_keys) VALUES (' . $player_id . ', ' . $keys_id . ', 0, ' . $value . ')'; try { $res = execNativeSQL($query_update, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); //var_dump($query_update, $query_insert, $player_id, $keys_id, $value, $res); if(!$res) { $res = execNativeSQL($query_insert, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); } //$result = execNativeSQL($query, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); // $this->_doctrineConnection->exec($query); //$res = true; } catch (Exception $e) { log::error('Can not change num of user keys: ' . $e->getMessage()); //var_dump($e); $res = false; } return $res; } public function setNumOfUserKeys($player, $key_id, $value) { $player_id = $player->id; $key_id = intval($key_id); $value = intval($value); $res = false; $query_update = 'UPDATE player_boss SET dropped_keys = '.$value.' WHERE players_id = '.$player_id.' AND boss_id = '.$key_id; $query_insert = 'INSERT INTO player_boss (players_id, boss_id, win_count, dropped_keys) VALUES (' . $player_id . ', ' . $key_id . ', 0, ' . $value . ')'; try { $res = execNativeSQL($query_update, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); //var_dump($query_update, $query_insert, $player_id, $keys_id, $value, $res); if(!$res) { $res = execNativeSQL($query_insert, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); } } catch (Exception $e) { //var_dump($e); $res = false; } return $res; } private $spellMapCache; public function getSpellMapMaxPlace() { return 15; } private function spellMapKey() { return 'spell_maps'; } public function getSpellMap($uid) { if ($this->spellMapCache[$uid] == null) { $r = $this->_redis_spell_map->hget($this->spellMapKey(), $uid); if (!$r) { $recs = array('s_4_1_1', 's_5_1_2', 's_6_1_3', 's_1_1_5', 's_2_1_6', 's_3_1_7'); } else { $recs = explode(',', $r); } //var_dump($r); $this->spellMapCache = array(); foreach ($recs as $value) { list($t, $id, $qnty, $place) = explode('_', $value); $type = $t == 's' ? 'spell' :'buff'; $id = intval($id); $qnty = intval($qnty); $place = intval($place); if ($id > 0 && $qnty > 0 && $place >= 0) { $this->spellMapCache[$uid][] = array( 'id' => $id, 'type' => $type, 'qnty' => $qnty, 'place' => $place ); } } } return $this->spellMapCache[$uid]; } public function setSpellMap($uid, $map) { $this->spellMapCache[$uid] = $map; $to_save = array(); foreach ($map as $record) { $type = $record['type'] == 'spell' ? 's' : 'b'; $to_save[] = $type . '_' . $record['id'] . '_' . $record['qnty'] . '_' . $record['place']; } return $this->_redis_spell_map->hset($this->spellMapKey(), $uid, implode(',', $to_save)); } public function setPlayerWins($player, $boss_id, $wins, $cool_wins, $epic_wins) { $player_id = $player->id; $boss_id = intval($boss_id); $wins = intval($wins); $cool_wins = intval($cool_wins); $epic_wins = intval($epic_wins); $query_update = 'UPDATE player_boss SET win_count = '.$wins.', cool_win_count = '.$cool_wins.', epic_win_count = '.$epic_wins.' WHERE players_id = '.$player_id.' AND boss_id = '.$boss_id; $query_insert = 'INSERT INTO player_boss (players_id, boss_id ,win_count, cool_win_count, epic_win_count, dropped_keys) VALUES ('.$player_id.', '.$boss_id.', '.$wins.', '.$cool_wins.', '.$epic_wins.', 0)'; try { $result = execNativeSQL($query_update, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); if(!$result) { $result = execNativeSQL($query_insert, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); } } catch (Exception $e) { $result = null; } return $result; } // для наливалки public function setWins($player, $boss_id, $value) { $player_id = $player->id; $boss_id = intval($boss_id); $query_update = 'UPDATE player_boss SET win_count = ' . $value . ' WHERE players_id = '.$player_id.' AND boss_id = '.$boss_id; $query_insert = 'INSERT INTO player_boss (players_id, boss_id, win_count, dropped_keys) VALUES (' . $player_id . ', ' . $boss_id . ', '. $value .', 0)'; try { $result = execNativeSQL($query_update, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); if(!$result) { $result = execNativeSQL($query_insert, $player->uid, PrisonConnectionDomains::BOSSES_DOMAIN); } } catch (Exception $e) { log::error('Can not update user victory'); $result = null; } return $result; } public function kill($player) { return $this->_redis->hset(self::$_battle_prefix . $player->uid, 'h_now', 0); } // public function startTransaction() // { // $this->_doctrineConnection->beginTransaction(); // } // // public function commitTransaction() // { // $this->_doctrineConnection->commit(); // } // // public function rollbackTransaction() // { // $this->_doctrineConnection->rollback(); // } } ?>