• Страница 1 из 1
  • 1
Архив - только для чтения
Модератор форума: andycrowz  
Защита от Alt+F4
Stormtrooper
Командир
Добрый день всем
Уже не в первый раз возникает вопрос - возможно ли сделать так чтобы игрок нажавший Alt+F4 ещё какое-то время находился в игре? (тоесть сервер считал что игрок всё ещё в игре, не выкидывал его перса сразу)
обыскиваю сейчас WorldSession и CharacterHandler но пока безуспешно
Если помог, ставь плюсик в репу :)

Сообщение # 1 написано 02.10.2012 в 10:15
Ma_aelKoT
Скаут
Разве Alt+F4 не закрывает саму игру? соединение прерывается = игрока нет в сети

Каким то образом сделать, чтобы был онлайн статус пользователя, при прекращении соединения... начерта?.. confused

(название темы как бы подразумевает, что alt+f4 - это новый вирус, или опасный читкод, или, там, отака на сервер какаято:
собирается толпа детей, например, в Даларане, и все разом жмут alt+f4 )
Сообщение # 2 отредактировано Ma_aelKoT - Вторник, 02.10.2012, 11:33
Stormtrooper
Командир
за нахождение перса в игре отвечает СЕРВЕР
Мне нужен не статус а сам персонаж
По-моему очевидно для чего это нужно - многих бесит что начинаешь с кем-нибудь драться а он чтобы не дать фраг берёт и дискается
так вот чтобы победитель всё-таки получил свой фраг надо чтобы альт+ф4 не давало возможности свалить из игры мгновенно!
Если помог, ставь плюсик в репу :)

Сообщение # 3 написано 02.10.2012 в 11:32
Just_Max
Рыцарь
Stormtrooper, на trinity-core.ru ищи там было я когда (в мае-июне) там себе нашол) ТАкая же беда была и помогло) Поиском у них пройдись)


Человек не может жить без сердца, без печени, без почек.
Зато, сука, без мозгов спокойно живут целыми поколениями.
Сообщение # 4 написано 02.10.2012 в 11:51
Stormtrooper
Командир
Нашёл только изменение времени АФК
в поиске alt+f4 (и аналогичные запросы) задать нельзя - не ищет sad

Добавлено (02.10.2012, 15:27)
---------------------------------------------
Подозреваю что тут но как исправить пока не знаю sad
Code

// Kick a player out of the World
void WorldSession::KickPlayer()
{
      if (m_Socket)
          m_Socket->CloseSocket();
}


Вот ещё возможно:
Code

// WorldSession destructor
WorldSession::~WorldSession()
{
     // unload player if not unloaded
     if (_player)
         LogoutPlayer(true);

     // If have unclosed socket, close it
     if (m_Socket)
     {
         m_Socket->CloseSocket();
         m_Socket->RemoveReference();
         m_Socket = NULL;
     }

     if (m_Warden)
         delete m_Warden;

     // empty incoming packet queue
     WorldPacket* packet;
     while (_recvQueue.next(packet))
         delete packet;

     LoginDatabase.PExecute("UPDATE account SET active_realm_id = 0 WHERE id = %u;", GetAccountId());
     CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = %u;", GetAccountId());
}
Если помог, ставь плюсик в репу :)

Сообщение # 5 отредактировано Stormtrooper - Вторник, 02.10.2012, 16:02
_dm666
<3 Death Metal
На сколько я знаю, ALT+F4 закрывает активное окно у пользователя на компьютере/ноуте.
Сообщение # 6 написано 02.10.2012 в 16:08
Stormtrooper
Командир
Правильно знаешь но сокет-то закрывает сервер и перса соответственно выкидывает из игры тоже сервер
Сейчас попытался сделать так:
Code

// unload player if not unloaded
     if (_player && !_player->isInCombat())
         LogoutPlayer(true);


Перс остался в игре после ALT+F4 (в бою) но как только я шевельнул вторым персом сервер сразу упал
Вобщем править надо именно это место но пока не знаю как

Добавлено (02.10.2012, 16:52)
---------------------------------------------
Есть какие-нибудь идеи?

Добавлено (02.10.2012, 21:20)
---------------------------------------------
Ребят ну помогите а?

Если помог, ставь плюсик в репу :)

Сообщение # 7 написано 02.10.2012 в 21:20
_dm666
<3 Death Metal
Тут мало людей, кто неплохо знает ядро, а особенно эту тематику.
Сообщение # 8 написано 02.10.2012 в 21:31
Stormtrooper
Командир
ну по крайней мере 1 уже есть у кого патчик стоит только он жадничает и посылает на Тринити-кор (к слову сказать я прогнал поиском все возможные и невозможные комбинации фраз и так ничего и не нашёл + искал через Гугл и через Яндекс - и снова ничего)
Если помог, ставь плюсик в репу :)

Сообщение # 9 написано 02.10.2012 в 23:30
Dimitro
Praise the sun!
Лично у меня, все нормально на тринити, даже участок кода нашел, который за это отвечает.
Может укажете свое ядро и его ревизию?
Arcanum Core © Dev.
Для запросов на выдачу наград/снятие замечаний есть темы в Работе Портала. Не пишите по этому поводу в личку.
Сообщение # 10 написано 03.10.2012 в 00:16
Stormtrooper
Командир
Oregon Core Last Rev
Если помог, ставь плюсик в репу :)

Сообщение # 11 написано 03.10.2012 в 08:06
Dimitro
Praise the sun!
Киньте ка сюда свой метод WorldSession::LogoutPlayer.
Arcanum Core © Dev.
Для запросов на выдачу наград/снятие замечаний есть темы в Работе Портала. Не пишите по этому поводу в личку.
Сообщение # 12 написано 03.10.2012 в 12:14
Stormtrooper
Командир
Code

// Log the player out
void WorldSession::LogoutPlayer(bool Save)
{
     // finish pending transfers before starting the logout
     while (_player && _player->IsBeingTeleportedFar())
         HandleMoveWorldportAckOpcode();

     m_playerLogout = true;
     m_playerSave = Save;

     if (_player)
     {
         if (uint64 lguid = GetPlayer()->GetLootGUID())
             DoLootRelease(lguid);

         // If the player just died before logging out, make him appear as a ghost
         // FIXME: logout must be delayed in case lost connection with client in time of combat
         if (_player->GetDeathTimer())
         {
             _player->getHostileRefManager().deleteReferences();
             _player->BuildPlayerRepop();
             _player->RepopAtGraveyard();
         }
         else if (!_player->getAttackers().empty())
         {
             _player->CombatStop();
             _player->getHostileRefManager().setOnlineOfflineState(false);
             _player->RemoveAllAurasOnDeath();

             // build set of player who attack _player or who have pet attacking of _player
             std::set<Player*> aset;
             for (Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr)
             {
                 Unit* owner = (*itr)->GetOwner();           // including player controlled case
                 if (owner)
                 {
                     if (owner->GetTypeId() == TYPEID_PLAYER)
                         aset.insert(owner->ToPlayer());
                 }
                 else
                 if ((*itr)->GetTypeId() == TYPEID_PLAYER)
                     aset.insert((*itr)->ToPlayer());
             }

             _player->SetPvPDeath(!aset.empty());
             _player->KillPlayer();
             _player->BuildPlayerRepop();
             _player->RepopAtGraveyard();

             // give honor to all attackers from set like group case
             for (std::set<Player*>::const_iterator itr = aset.begin(); itr != aset.end(); ++itr)
                 (*itr)->RewardHonor(_player,aset.size());

             // give bg rewards and update counters like kill by first from attackers
             // this can't be called for all attackers.
             if (!aset.empty())
                 if (BattleGround *bg = _player->GetBattleGround())
                     bg->HandleKillPlayer(_player,*aset.begin());
         }
         else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
         {
             // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION
             _player->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
             //_player->SetDeathPvP(*); set at SPELL_AURA_SPIRIT_OF_REDEMPTION apply time
             _player->KillPlayer();
             _player->BuildPlayerRepop();
             _player->RepopAtGraveyard();
         }
         //drop a flag if player is carrying it
         if (BattleGround *bg = _player->GetBattleGround())
             bg->EventPlayerLoggedOut(_player);

         // Teleport to home if the player is in an invalid instance
         if (!_player->m_InstanceValid && !_player->isGameMaster())
         {
             _player->TeleportToHomebind();
             //this is a bad place to call for far teleport because we need player to be in world for successful logout
             //maybe we should implement delayed far teleport logout?
         }

         // FG: finish pending transfers after starting the logout
         // this should fix players beeing able to logout and login back with full hp at death position
         while (_player->IsBeingTeleportedFar())
             HandleMoveWorldportAckOpcode();

         sOutdoorPvPMgr.HandlePlayerLeaveZone(_player,_player->GetZoneId());

         for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
         {
             if (int32 bgTypeId = _player->GetBattleGroundQueueId(i))
             {
                 _player->RemoveBattleGroundQueueId(bgTypeId);
                 sBattleGroundMgr.m_BattleGroundQueues[ bgTypeId ].RemovePlayer(_player->GetGUID(), true);
             }
         }

         // If the player is in a guild, update the guild roster and broadcast a logout message to other guild members
         if (Guild *guild = objmgr.GetGuildById(_player->GetGuildId()))
         {
             guild->LoadPlayerStatsByGuid(_player->GetGUID());
             guild->UpdateLogoutTime(_player->GetGUID());

             guild->BroadcastEvent(GE_SIGNED_OFF, _player->GetGUID(), _player->GetName());
         }

         // Remove pet
         _player->RemovePet(NULL, PET_SAVE_AS_CURRENT, true);

         // empty buyback items and save the player in the database
         // some save parts only correctly work in case player present in map/player_lists (pets, etc)
         if (Save)
         {
             uint32 eslot;
             for (int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; ++j)
             {
                 eslot = j - BUYBACK_SLOT_START;
                 _player->SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), 0);
                 _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0);
                 _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0);
             }
             _player->SaveToDB();
         }

         // Leave all channels before player delete...
         _player->CleanupChannels();

         // If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group.
         _player->UninviteFromGroup();

         // remove player from the group if he is:
         // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected)
         if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket)
             _player->RemoveFromGroup();

         // Send update to group
         if (_player->GetGroup())
             _player->GetGroup()->SendUpdate();

         // Broadcast a logout message to the player's friends
         sSocialMgr.SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true);
         sSocialMgr.RemovePlayerSocial (_player->GetGUIDLow ());

         // Remove the player from the world
         // the player may not be in the world when logging out
         // e.g if he got disconnected during a transfer to another map
         // calls to GetMap in this case may cause crashes
         _player->CleanupsBeforeDelete();
         Map* _map = _player->GetMap();
         _map->Remove(_player, true);
         _player = NULL;                    // deleted in Remove call

         // Send the 'logout complete' packet to the client
         WorldPacket data(SMSG_LOGOUT_COMPLETE, 0);
         SendPacket(&data);

         // Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline
         //No SQL injection as AccountId is uint32
         CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = '%u'",
             GetAccountId());
         sLog.outDebug("SESSION: Sent SMSG_LOGOUT_COMPLETE Message");
     }

     //Hook for OnLogout Event
     sScriptMgr.OnLogout(_player);

     m_playerLogout = false;
     m_playerSave = false;
     m_playerRecentlyLogout = true;
     LogoutRequest(0);
}
Если помог, ставь плюсик в репу :)

Сообщение # 13 написано 03.10.2012 в 13:05
Dimitro
Praise the sun!
В вашем коде всем игрокам, которые атаковали игрока, вышедшего из игры начисляется хонор и киллы.
Не пойму, чем вас это не устраивает.

Если же надо копать дальше, то копайте в сторону:

Quote
void WorldSession::LogoutPlayer(bool Save)  
  {  
      // finish pending transfers before starting the logout  
      while (_player && _player->IsBeingTeleportedFar())  
          HandleMoveWorldportAckOpcode();  

      m_playerLogout = true;  
      m_playerSave = Save;  

      if (_player)  
      {  
          if (uint64 lguid = GetPlayer()->GetLootGUID())  
              DoLootRelease(lguid);  

          // If the player just died before logging out, make him appear as a ghost  
          // FIXME: logout must be delayed in case lost connection with client in time of combat  
          if (_player->GetDeathTimer())  
          {  
              _player->getHostileRefManager().deleteReferences();  
              _player->BuildPlayerRepop();  
              _player->RepopAtGraveyard();  
          }  
else if (!_player->getAttackers().empty())  
          {  
              _player->CombatStop();  
              _player->getHostileRefManager().setOnlineOfflineState(false);  
              _player->RemoveAllAurasOnDeath();  

              // build set of player who attack _player or who have pet attacking of _player  
              std::set<Player*> aset;  
              for (Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr)  
              {  
                  Unit* owner = (*itr)->GetOwner();           // including player controlled case  
                  if (owner)  
                  {  
                      if (owner->GetTypeId() == TYPEID_PLAYER)  
                          aset.insert(owner->ToPlayer());  
                  }  
                  else  
                  if ((*itr)->GetTypeId() == TYPEID_PLAYER)  
                      aset.insert((*itr)->ToPlayer());  
              }  

              _player->SetPvPDeath(!aset.empty());  
              _player->KillPlayer();  
              _player->BuildPlayerRepop();  
              _player->RepopAtGraveyard();  

              // give honor to all attackers from set like group case  
              for (std::set<Player*>::const_iterator itr = aset.begin(); itr != aset.end(); ++itr)  
                  (*itr)->RewardHonor(_player,aset.size());  

              // give bg rewards and update counters like kill by first from attackers  
              // this can't be called for all attackers.  
              if (!aset.empty())  
                  if (BattleGround *bg = _player->GetBattleGround())  
                      bg->HandleKillPlayer(_player,*aset.begin());  
          }

          else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))  
          {  
              // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION  
              _player->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);  
              //_player->SetDeathPvP(*); set at SPELL_AURA_SPIRIT_OF_REDEMPTION apply time  
              _player->KillPlayer();  
              _player->BuildPlayerRepop();  
              _player->RepopAtGraveyard();  
          }  
          //drop a flag if player is carrying it  
          if (BattleGround *bg = _player->GetBattleGround())  
              bg->EventPlayerLoggedOut(_player);  

          // Teleport to home if the player is in an invalid instance  
          if (!_player->m_InstanceValid && !_player->isGameMaster())  
          {  
              _player->TeleportToHomebind();  
              //this is a bad place to call for far teleport because we need player to be in world for successful logout  
              //maybe we should implement delayed far teleport logout?  
          }  

          // FG: finish pending transfers after starting the logout  
          // this should fix players beeing able to logout and login back with full hp at death position  
          while (_player->IsBeingTeleportedFar())  
              HandleMoveWorldportAckOpcode();  

          sOutdoorPvPMgr.HandlePlayerLeaveZone(_player,_player->GetZoneId());  

          for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)  
          {  
              if (int32 bgTypeId = _player->GetBattleGroundQueueId(i))  
              {  
                  _player->RemoveBattleGroundQueueId(bgTypeId);  
                  sBattleGroundMgr.m_BattleGroundQueues[ bgTypeId ].RemovePlayer(_player->GetGUID(), true);  
              }  
          }  

          // If the player is in a guild, update the guild roster and broadcast a logout message to other guild members  
          if (Guild *guild = objmgr.GetGuildById(_player->GetGuildId()))  
          {  
              guild->LoadPlayerStatsByGuid(_player->GetGUID());  
              guild->UpdateLogoutTime(_player->GetGUID());  

              guild->BroadcastEvent(GE_SIGNED_OFF, _player->GetGUID(), _player->GetName());  
          }  

          // Remove pet  
          _player->RemovePet(NULL, PET_SAVE_AS_CURRENT, true);  

          // empty buyback items and save the player in the database  
          // some save parts only correctly work in case player present in map/player_lists (pets, etc)  
          if (Save)  
          {  
              uint32 eslot;  
              for (int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; ++j)  
              {  
                  eslot = j - BUYBACK_SLOT_START;  
                  _player->SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), 0);  
                  _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0);  
                  _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0);  
              }  
              _player->SaveToDB();  
          }  

          // Leave all channels before player delete...  
          _player->CleanupChannels();  

          // If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group.  
          _player->UninviteFromGroup();  

          // remove player from the group if he is:  
          // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected)  
          if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket)  
              _player->RemoveFromGroup();  

          // Send update to group  
          if (_player->GetGroup())  
              _player->GetGroup()->SendUpdate();  

          // Broadcast a logout message to the player's friends  
          sSocialMgr.SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true);  
          sSocialMgr.RemovePlayerSocial (_player->GetGUIDLow ());  

          // Remove the player from the world  
          // the player may not be in the world when logging out  
          // e.g if he got disconnected during a transfer to another map  
          // calls to GetMap in this case may cause crashes  
          _player->CleanupsBeforeDelete();  
          Map* _map = _player->GetMap();  
          _map->Remove(_player, true);  
          _player = NULL;                    // deleted in Remove call  

          // Send the 'logout complete' packet to the client  
          WorldPacket data(SMSG_LOGOUT_COMPLETE, 0);  
          SendPacket(&data);  

          // Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline  
          //No SQL injection as AccountId is uint32  
          CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = '%u'",  
              GetAccountId());  
          sLog.outDebug("SESSION: Sent SMSG_LOGOUT_COMPLETE Message");  
      }  

      //Hook for OnLogout Event  
      sScriptMgr.OnLogout(_player);  

      m_playerLogout = false;  
      m_playerSave = false;  
      m_playerRecentlyLogout = true;  
      LogoutRequest(0);  
  }
Arcanum Core © Dev.
Для запросов на выдачу наград/снятие замечаний есть темы в Работе Портала. Не пишите по этому поводу в личку.
Сообщение # 14 отредактировано Dimitro - Среда, 03.10.2012, 13:35
Stormtrooper
Командир
хех если бы начислялось я бы не парился
я видел кусок кода который за это должен отвечать но к сожалению он почему-то не работает (только что проверил - зашёл в 2 окна начал драться и одним игроком вышел из игры через Alt+F4 - ничего не начислили)
я думал поставить таймер но честно говоря так пока и не разобрался со структурой таймеров sad
это на сколько я понимаю надо создавать VOID типа void Timer(const uint32 diff) а дальше уже задавать условия, но МОЖНО ЛИ такое создавать внутри void WorldSession::LogoutPlayer(bool Save) вот это вопрос вопросов
Если помог, ставь плюсик в репу :)

Сообщение # 15 отредактировано Stormtrooper - Среда, 03.10.2012, 13:45
Dimitro
Praise the sun!
Ха-ха, смешная ситуация, сейчас кину решение.
Arcanum Core © Dev.
Для запросов на выдачу наград/снятие замечаний есть темы в Работе Портала. Не пишите по этому поводу в личку.
Сообщение # 16 написано 03.10.2012 в 13:54
Dimitro
Praise the sun!
Code
diff -r af889f221f44 src/server/game/Server/WorldSession.cpp
--- a/src/server/game/Server/WorldSession.cpp    Sun Sep 23 13:33:58 2012 +0300
+++ b/src/server/game/Server/WorldSession.cpp    Wed Oct 03 12:55:49 2012 +0300
@@ -417,10 +417,6 @@
          }
          else if (!_player->getAttackers().empty())
          {
-            _player->CombatStop();
-            _player->getHostileRefManager().setOnlineOfflineState(false);
-            _player->RemoveAllAurasOnDeath();
-
              // build set of player who attack _player or who have pet attacking of _player
              std::set<Player*> aset;
              for (Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr)
@@ -432,11 +428,6 @@
                      aset.insert((Player*)(*itr));
              }
   
-            _player->SetPvPDeath(!aset.empty());
-            _player->KillPlayer();
-            _player->BuildPlayerRepop();
-            _player->RepopAtGraveyard();
-
              // give honor to all attackers from set like group case
              for (std::set<Player*>::const_iterator itr = aset.begin(); itr != aset.end(); ++itr)
                  (*itr)->RewardHonor(_player, aset.size());
@@ -446,6 +437,14 @@
              if (!aset.empty())
                  if (Battleground* bg = _player->GetBattleground())
                      bg->HandleKillPlayer(_player, *aset.begin());
+
+            _player->CombatStop();
+            _player->getHostileRefManager().setOnlineOfflineState(false);
+            _player->RemoveAllAurasOnDeath();
+            _player->SetPvPDeath(!aset.empty());
+            _player->KillPlayer();
+            _player->BuildPlayerRepop();
+            _player->RepopAtGraveyard();
          }
          else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
          {

Arcanum Core © Dev.
Для запросов на выдачу наград/снятие замечаний есть темы в Работе Портала. Не пишите по этому поводу в личку.
Сообщение # 17 написано 03.10.2012 в 13:56
Stormtrooper
Командир
опаньки....
тоесть вся проблема просто в расположении строк?
походу я так мало ещё знаю .............. sad
просто не могу понять логики а ОЧЕНЬ хочется понять
Ставлю плюс так как решение работает - но я не понял как получилось sad
Если помог, ставь плюсик в репу :)

Сообщение # 18 отредактировано Stormtrooper - Среда, 03.10.2012, 14:07
Dimitro
Praise the sun!
Логика в том, что метод CombatStop() удаляет список всех атакующих.
Если поставить его до выдачи наград, то ясное дело, награды никому не выдадутся.
Arcanum Core © Dev.
Для запросов на выдачу наград/снятие замечаний есть темы в Работе Портала. Не пишите по этому поводу в личку.
Сообщение # 19 написано 03.10.2012 в 14:06
Stormtrooper
Командир
Спасибо огромное! Плюсы поставил
Понял наконец smile
Если помог, ставь плюсик в репу :)

Сообщение # 20 написано 03.10.2012 в 14:08
Dimitro
Praise the sun!
Данная тема была перемещена из раздела [TrinityCore] Help.
Причина перемещения: Решено, пошел делать пулл реквест в офф. репо.

Переместил: Dimitro.
Arcanum Core © Dev.
Для запросов на выдачу наград/снятие замечаний есть темы в Работе Портала. Не пишите по этому поводу в личку.
Сообщение # 21 написано 03.10.2012 в 14:10
  • Страница 1 из 1
  • 1
Поиск: