Теперь чтобы тестирование и разработка пошли более ускоренно нам понадобятся простые элементы управления процессом игры, и одно из этого – возможность перемещать наш объект в игровом пространстве. Поскольку мы имеем дело не со стандартным окном отображения, а кастомным (мы его сами делаем), то и элементы управления тоже придётся создавать самим. Но это и к лучшему – например, нам потребуются кнопки, которых нет ни в одном стандартном интерфейсе.
Начнем делать кнопку направления движения. Для этого создадим сначала класс наших кнопок и дадим ему общие для всех методы и свойства, а также объявим переменную для хранения экземпляров этого класса:
Дадим константы идентификаторов будущих кнопок:
Добавим пока только одну кнопку:
А теперь её отображение:
Проверим что получилось:
Отлично! Кнопка готова. Теперь нужно сделать так чтобы она принимала действия пользователя, но вначале изменим немного построение системы координат игрока. Уберём лишнюю координату и укажем ещё две:
Координата игрока на экране по Y больше будет не нужна, её заменит новая координата игрового поля по Y, т.к. диапазон доступный для перемещения игрока по Y соответствует размеру игрового поля по Y. По X конечно же всё как и было, т.к. размер игрового поля по X составляет несколько экранов по X.
Теперь добавим ещё парочку методов для самого движения:
Добавлю имплементацию в класс интерфейса ответственного за перехват кликов по экрану устройства:
Теперь инициализируем в конструкторе GameEngine на этот интерфейс, указывая текущий класс для реализации его методов:
Далее реализуем метод (он единственный) этого интерфейса. Он будет таким:
Теперь сделаем отображение рельефа местности исходя из текущих координат игрока:
А положение рельефа получается таким:
В результате получается как-то так:
Как теперь стало понятно, в зависимости от клика внутри круглой кнопки (даже в зависимости от области внутри этой кнопки), корабль начинает двигаться в любом направлении.
Задание по уроку:
1. Сделайте так, чтобы при движении рельефа также двигались вместе с ним и юниты инопланетян, ведь они тоже должны двигаться относительно корабля игрока (кроме ещё собственного их движение, которое пока не реализовано).
2. Попробуйте изменить поведение чтобы положение внутри кнопки определяло не координату игрока, а ускорение движение игрока.
3. Сделайте чтобы после группирования частей на центре этого группирования образовывался инопланетный корабль, после этого он “жил” 5 секунд и затем взрывался.
Если всё получилось как нужно – молодцы! Если нет, давайте разберёмся что не так.
Итак, к этому уроку, опираясь на ваши домашние задания, вы уже должны быть готовы чтобы сделать это:
Что тут есть:
Рельеф, который при движении влево или вправо никогда не кончается; он подобно Земному шару, если идти по экватору – придёшь в ту же точку, откуда вышел.
Сначала генерирует точка сбора каждого инопланетянина. После его группировки он появляется, а затем через несколько секунд он самовзрывается.
Движение всех объектов на экране согласовано в относительном движении игрока
Движение игрока выполнено с учетом физики движение (есть скорость движения, есть учёт ускорения/торможения, есть учет сопротивления воздуха). Это позволяет создавать эффект инерционного движения, когда при смене направления движения корабль игрока не мгновенно начинает лететь в обратную сторону, а сначала замедляется, и лишь потом разгоняется в обратную сторону.
То, что мы в прошлых уроках использовали для тестирования геймплея (игрового процесса), было удобно и эффективно, однако, с новыми реалиями и физикой некоторые моменты нужно будет упростить, изменить и добавить новые. Начнём.
Инициализацию параметров игрока делаем так:
К координатам игрока я добавил переменные, которые будут хранить его скорость и ускорение, а также их предельные значения (у игрока не должна бесконечно возрастать скорость, иначе это будет противоречить канонам физики). Заметьте, предел ускорения по X и Y различны, оно и понятно – двигатели нашего корабля развивают разную мощность по вертикали и горизонтали))). Тут ещё не мешало бы вспомнить школьный курс физики и математики, что
, где:
L – перемещение объекта
L0 – начальная координата
V0 – начальная скорость
a – ускорение
t – время
Однако, увы, эта формула будет для нас не пригодна, т.к. у нас нет показателя времени – t. Связано это как раз с тем, что обновление экрана мы выполняем квантами времени, как помните,- 25 раз в секунду. Т.е. с точки зрения математики мы обладаем не параметром t, а параметром ∂t (дифференциал t). Исходя из этого и перемещение объекта будем определять через совершенное за единицу времени перемещение. Так и поступим. Изменим для начала метод onButtonDown() как и было это в домашнем задании – он теперь будет определять не какие-то тестовые координаты, а именно само ускорение. С точки зрения моделирования это так и есть – как в автомобиле, чем сильнее нажимаем на педаль газа, тем с большим ускорением разгоняемся. Добавим ещё один параметр с радиусом кнопки, чтобы более универсально можно было настраивать параметры размеров интерфейса.
Разумеется при вызовах тоже нужно это учесть:
Сам расчет расстояния перемещения выведен туда, где он более всего логичен – в метод вызываемый 25 раз в секунду:
Сначала мы находим текущую скорость от ускорения. Затем изменение расстояние от этой скорости, тут вроде должно быть понятно. Подчеркиваю, метод вызывается 25 раз в секунду, по этому с точки зрения динамического моделируемого процесса, мы имеем расчет параметров за единицу времени ∂t. Просто она в математике стремится к нулю, а в жизни для игрока уже всё что чаще 24 кадров в секунду уже незаметно и кажется непрерывным движением, и этого оказывается достаточным. С таким ∂t идеально точный математический расчет траектории мы конечно же не получим, но визуально мы разницы не заметим. Далее в коде идут условия, по которым я ограничиваю и текущую скорость и координаты чтобы корабль игрока не вышел за пределы игрового поля или не развил скорость, при которой уже станет не понятным что на экране вообще происходит. После этого я умножаю на числовую константу ускорение и скорость. Это таким образом я создал эффект сопротивления воздуха, т.е. если игрок отпустит кнопку управления, то через какое-то время его корабль сам плавно остановится. Если бы это был космос, где нет сопротивления воздуха, то корабль летел бы сколь угодно долго пока не столкнулся бы с каким-либо объектом, но в нашей игровой реальности, пардон, виртуальности, условия другие.
Но с этим методом ещё не всё, давайте сразу же добавим в него и ещё кое что:
Основное предназначение этой части кода – управление трансформацией инопланетных объектов. Для каждого объекта выполняется сначала метод run(), далее посмотрим что он делает. Затем определяется тип объекта, что это ещё только группирующийся/взрывающийся объект или уже готовый инопланетянин. Тут же определяется, что если группировка уже завершена, то нужно на этом месте создать инопланетянина, а сам группирующийся объект удалить из списка игровых объектов. Если инопланетянин “прожил” некоторый лимит времени, то должен удалиться из списка игровых объектов, но в этот же момент на этом же месте нужно создать взрыв ( метод explosion() ).
Заметьте, я не сразу прямо в цикле объектов gameObjects удаляю “старый” объект из списка и добавляю туда новый, а изначально создал два временных списка, один для удаления, другой для добавления, и делаю работу над ними уже после выполнения основного цикла. Делается это для того, чтобы не получилось исключительной ситуации. Если циклом перебираем список, и сам цикл зависим от этого массива, то менять состав этого списка внутри этого цикла строго нельзя (иначе результат такого функционала может стать не предсказуемым) !
Завершает метод всё тот же invalidate(), который запускает цепочку системных вызовов по обновлению экрана и запуску метода onDraw().
Претерпел изменения класс GameObject (изменил немного формат некоторых методов). Конструктор теперь не содержит начальных координат, т.к. они генерятся в burn() дочернего класса GroupingParts и больше генерить их пока негде; в конструктор добавлен тип:
Дочерние классы:
Заметьте выполнения класса explosion() также как и burn() только координаты при этом не генерятся и лимиты наоборот, а так всё тоже самое.
Инициализация местности немного изменена (понижена), а инициализация объектов теперь использует тип:
Заметьте, инициализируется группирующийся объект, который (как я вначале написал) после схлопывания удаляется и создаётся одновременно новый уже типа Alien. Сгенерировал сразу 100 объектов чтобы оценить будет ли хромать производительность.
Батон, пардон, кнопку увеличил в размерах и перенёс выше и правее, т.к. испытав на своём телефоне с разрешением 1920 х 1080 понял, что кнопка для управления для пальца слишком мала. Также изменил и настройки виртуального мобильника на аналогичные:
В изображение кнопки добавил функционал делающие её слегка прозрачной, это позволяет и видеть что находится за ней и при этом видеть саму кнопку (если делали домашнее задание в одном из уроков то поняли, что я о setAlpha():
Рельеф Земли теперь изображается с учетом того, что она якобы круглая, т.е. летим в одну сторону, вылетаем из другой (циклически повторяется). Для этого пришлось сделать её отображение с учетом этого:
Тут было два очевидных варианта решения, либо оставить всё как есть и адаптировать под существующий функционал, либо математически представить её действительно круглой (ввести полярную систему координат и измерять не координатами по x и y, а углами alpha и beta. Но расчеты в полярной системе потребовали бы вычисления косинусов и синусов в вещественных числах, а это существенно забрало бы вычислительных ресурсов. В связи с этим, если вы ещё раз посмотрите на код объектов, то увидите, что вычисление координат при отрисовке претерпело явные изменения. Для рельефа же потребовалось сделать не только цикл его отрисовки, но и два цикла дорисовки на случай, если мы подлетаем к краю рельефа (слева или справа) – визуально он не должен обрываться, а должен дорисовываться его началом до границ экрана, создавая иллюзию циклической поверхности, вроде экватора планеты. Но делать три цикла подряд тут как-то некрасиво, по этому я сделал цикл в цикле.
По факту получилось даже лучше, чем планировалось:
Задание по уроку:
1. Снова оптимизируйте отрисовку рельефа так, чтобы его куски за пределами экрана не отрисовывались. Аналогично оптимизируйте отрисовку объектов и частей группировки / взрыва.
2. Самостоятельно разберите вопрос рисования текста на холсте.
3. Сделайте чтобы корабли инопланетян случайно двигались тоже с учетом физики
Если всё получилось как нужно – молодцы! Если нет, давайте разберёмся что не так.
Итак, отключаем тестовый процесс самоликвидации инопланетян, просто закомментировав эту строку (мало ли ещё пригодится, а оно так):
Перенесём парочку полезных методов генерации диапазона чисел из GroupingParts в GameObject, т.к. теперь эти метода мы будем использовать ещё как минимум и в классе Alien:
Добавим в Alien аналогичные игроку свойства для перемещения:
Реализуем ещё не задействованный от родительского класса метод run(). Если помните, он вызывается для каждого объекта 25 раз в секунду (до этого тоже вызывался для Alien, просто был “пустым” из родительского класса, заглушкой):
Теперь этот метод в Alien устраивает хаос, причём в прямом смысле этого слова. Мы получаем броуновское движение:
Добавим в класс GameObject заглушку-метод contact() который будет вызываться аналогично run() (и вместе с ней 25 раз в секунду):
Для класса Alien выполним реализацию:
Здесь всё просто – мы находим разницу между координатами игрока и объекта, и если она меньше некой допустимой, значит будем запускать цикл взрыва объекта (переменная waitToExplosion как раз и создана в Alien для этого).
По формуле тоже просто – вспоминаем школу, геометрию, теорему Пифагора:
Заметьте как я нахожу разницу координат по X – у меня стоит знак плюс. Это не ошибка, дело в том, что изначально я спозиционировал игровой процесс в относительном движении (только по X) игрока и всего остального, таким образом его координата всегда будет противоположной всем остальным объектам игры. Также необходимо пройти условия, когда объекты оказываются на границе рельефа местности, когда, например, у одного относительная координата -5000 и у другого 5000, но тут нужно просто из суммы вычесть константу.
Чтобы выполнить взрыв мне будет достаточно просто добавить это в уже существующее условие:
Результат будет очевиден, но придётся хорошенько погоняться за объектами, и это оказалось задачей не из простых))):
Приступим теперь к тому, что нужно было вам подготовить в домашнем задании – отображение текста. Начнем с того текста, который отображает бонусы при уничтожении инопланетян. Для начала добавим новый класс:
Теперь выполним то, что должно создавать текст и убирать его по прошествии некоторого времени (в данном случае 2 сек):
В результате получится как-то так:
Задание по уроку:
1. Сделайте подсчет игровых очков в верхнем левом углу как сумму показываемых бонусов при уничтожении инопланетян.
2. Импортируйте шрифт из игры “Быки и коровы”, которую мы делали и используйте его для п.1
3. Сделайте чтобы корабли инопланетян если находятся ближе определенного расстояния к игроку переставали хаотически двигаться и начинали сами на него нападать вызывая столкновение:
Если всё получилось как нужно – молодцы! Если нет, давайте разберёмся что не так.
Этот урок будет посвящен небольшому приведению игры в чувства, создание динамизма и зрелищности. Когда что-то много меняется, это для аркады то, что как раз и нужно. Всё внимание должно быть приковано к игре, особенно если она это внимание к себе требует. Будем сейчас делать что-то вроде этого:
Правда, не в тесте нужно будет убегать от инопланетян, избегать с ними столкновения, а не наоборот догонять. Это они будут стараться атаковать всеми своими средствами. Сейчас у них это и таран и ракеты (белые летящие точки). На нашем корабле что-то моргает, на их тоже самое. Это всё создаёт необходимый антураж аркады.
Итак, теперь для начала нужно немного изменить код отвечающий за полёт корабля игрока. Вообще, это частое явление, когда вы пишите некоторые части исключительно чтобы пройти следующую стадию разработки, а потом оптимизируете и меняете код уже под новые реалии и функционал.
Сделаем для всего, что связано с игроком отдельный класс и дадим ему имя Gamer:
Как видите, я перенес сюда и хранение координат и метод отрисовки, теперь это уже не просто круг, а что-то похожее на летательный аппарат, который умеет поворачиваться в ту сторону, куда направлен вектор тяги. Также добавлены для антуража некоторые моргалки на его поверхности, придающие живость, ну, живенько чтобы было)).
Для инопланетян отрисовка идёт тоже несколько по другому:
Код, отвечающий за движение инопланетян, и вызывающий у них броуновское движение тоже изменил, ведь в домашнем задании вам нужно было сделать чтобы на некотором расстоянии от игрока, их броуновское движение прекращалось и она начинали идти на таран. Посмотрим, как это сделал я:
Метод getR() (расчет расстояния от инопланетянина до игрока) работает на первый взгляд немного странно. Можно заметить, что dx, dy и r – это не локальные переменные метода, а всего класса, при этом метод ещё этот r и возвращает в качестве результата. Всё дело в том, что я использую его и тут и ещё далее сразу для двух функционалов.
Всплывающий текст с бонусами – это такой же игровой объект, как и инопланетяне и группирующиеся объекты:
Ракеты – тоже игровой объект:
Вызываемый метод normalizeCords() – это оптимизация расчета координат реализованная в родительском классе:
Paint для отображения бонусных очков шрифтом из прошлых циклов уроков, мы делаем так – за это отвечает Typeface:
Теперь для работы с этими новыми объектами нужно всего лишь добавить логику взаимодействия с игровым процессом, а делается это как раз в методе, который запускается 25 раз в секунду (не забываем, что ракеты и текст с бонусами нужно ставить на ожидание и последующее удаление, иначе они так и будут создаваться и загромождать интерфейс и отбирать ресурсы):
Задание по уроку:
1. Сделайте так, чтобы у корабля игрока отображался хвост
2. Добавьте кнопку стрельбы, чтобы игрок мог стрелять, причем только горизонтально и в том направлении, куда направлен корабль.
3. Сделайте функционал уничтожения инопланетян, если луч бластера примерно входит в область инопланетянина.
По результатам домашнего задания должно получиться как-то так:
Если всё получилось как нужно – молодцы! Если нет, давайте разберёмся что не так.
Продолжаем практическое изучение Java Android на примере игры Salvador. На этом уроке и в его домашнем задании будем делать следующее, т.е. заставку к игре:
Сделать её можно используя тысячи методов, но нужно было что-то выбрать и я решил попробовать тот, который ещё ни разу не проверял.
Для начала добавим переменную roundTime класса GameEngine, которая будет фиксировать прошедшее в раунде время. Также добавим переменную mainGameLogic, которая будет определять логику игры, т.к. что сейчас у нас на экране, игровой процесс, заставка или ещё что-то иное:
Объект GameObject теперь хранит много самостоятельной информации общей для всех его дочерних классов, а некоторые функции и переменные из дочерних вынесены в этот:
Класс Alien теперь умеет работать с несколькими подтипами:
Сам метод поведения Alien тоже изменился:
Начальная инициализация объектов теперь начинается с группировки корабля игрока, а логика игры – заставка:
Заметьте, теперь информация о будущем объекте после группировки передаётся прямо в конструктор GroupingParts.
Основной код метода 1/25 секунды тоже поменялся, и чтобы уже определиться, переименовал его в mainStrob():
тут дальше следует череда разного рода действий заставки возникающих как только время раунда достигает нового значения 2000 мс, 3000 мс и т.д., тут то группируется корабль игрока, потом группируется инопланетянин, через 4 сек это стреляет в того ракетой, через 4.4 сек наш стреляет бластером в этого и т.д.
Ключевой код работы с объектами теперь упростился, т.к. часть функционала взял на себя GameObject и его дочерние классы:
Теперь посмотрим зачем в сначала вводил переменную позиция по X корабля игрока на экране. До этого момента это была лишняя переменная, т.к. корабль всегда находился по горизонтали в центре, так спрашивается, а зачем тогда она нужна. Нужна она вот для чего:
Правильно, чтобы расширить возможности игрового пространства. Когда корабль игрока летит по рельефу вправо, то его корабль отодвигается влево, чтобы улучшить реакцию на инопланетян появляющихся по ходу движения. При этом и игровая ситуация для манёвров более предсказуема. Как можно заметить, это не влияет на реальную скорость, т.к. определяет только визуальное представление, но не координату в игровом пространстве. Однако, учитывая как у нас организован функционал, сделать это оказалось крайне просто:
А в стробе просто делаю так:
“300” – это та самая граница в которую корабль упирается слева или справа.
onScreenVX – определяет с какой скоростью он будет перемещаться по экрану в эту граничную область.
Задание по уроку:
1. Сделайте другие подюниты класса Alien
2. Сделайте так, чтобы заставка циклически повторялась, а по клику завершалась и начиналась игра
3. Добавьте на отображением суммы бонусов отображение времени раунда.
Если всё получилось как нужно – молодцы! Если нет, давайте разберёмся что не так.
Т.е. как можно понять, будем разрабатывать отображение сканера (масштабную карту местности) игрового пространства. Соответственно и все условные объекты на ней тоже должны отображаться.
Отображение ландшафта на сканере я делаю так:
Метод получения координат похож на тот, что используется для отображения на игровом поле, только в конце формулы я масштабирую к размеру topper и добавляю константу его центра.
Задание по уроку:
1. Аналогично отображению рельефа, сделайте отображение на сканере игрока и всех инопланетян
2. Сделайте так, чтобы заставка циклически повторялась, а по клику завершалась и начиналась игра
3. Добавьте на отображением суммы бонусов отображение времени раунда.
Если всё получилось как нужно – молодцы! Если нет, давайте разберёмся что не так.
Торренты прочно вошли в нашу жизнь как удобное средство обмена файлами через сеть интернет. Однако, рано или поздно встаёт вопрос, насколько безопасно это использование и рационально ли мы используем для этого компьютер. Торрент-обмен строится на базе пиринговой сети, о которой я упоминал в другой своей статье – о клиенте и сервере, а пользователь использует клиентское приложение, которое и выполняет всю работу по файловому обмену. Весь вопрос безопасности сводится к тому, кем изготовлено это приложение и насколько качественно оно сделано. Если на компьютере, где установлен торрент-клиент, находится какая-либо конфиденциальная информация (личные файлы, семейные фотографии, сканы документов), то я не считаю установку торрент-клиента на такой компьютер хотя бы сколько-нибудь безопасной. Гораздо было бы удобнее разместить торрент-клиента на отдельном компьютере или виртуальной машине, давать удаленно задачи на файловый обмен и забирать готовые файлы по мере выполнения. Об этом речь в этой статье, а устанавливать будем софт на Ubuntu 22.04 Server. В качестве клиента будет использоваться веб-интерфейс.
Сначала устанавливаем сам сервер Deluge и его вспомогательный веб-сервис:
sudo apt-get install deluged deluge-web
В Ubuntu 22.04 вместе с установкой Deluge не происходит автоматического формирования файлов настройки сервиса, по этому их нужно создать вручную. Для этого нужно открыть необходимый каталог:
Проверьте, действительно ли исполняемые файлы находятся по этому пути (ну кто его знает куда их в следующий раз запихнут):
/usr/bin/deluged
/usr/bin/deluge-web
Если вдруг оказалось, что там их нет, то найдём их, для этого сначала возвратимся в корневой каталог и запустим поиск:
cd /
find / -name deluged
Лично у меня с этим проблем не возникло:
Теперь нужно создать пользователя, того самого, которого указали в настройках сервиса (это был пользователь deluge). От его имени будет выполняться сервис. Создаётся он просто:
sudo adduser deluge
Пароль вводится любой, он всё равно нам вряд ли понадобится, в конце выражаем согласие игреком:
Далее включаем и запускаем работу сервисов:
sudo systemctl enable deluged.service
sudo systemctl enable deluge-web.service
sudo systemctl start deluged.service
sudo systemctl start deluge-web.service
Теперь открываем браузер и вводим путь к вашему Ubuntu серверу с Deluge. У меня это 192.168.1.24 (не забываем указать специальный порт интерфейса):
Пароль входа – это НЕ тот пароль, который вы ставили для пользователя deluge. Это пароль по-умолчанию, который тоже deluge.
На вопрос не хочу ли я сменить этот пароль, лично я отвечаю “Нет”, т.к. кроме меня в сети никто файлы качать не будет, и админить их тоже:
Далее появится окно выбора сервера. Нужно кликнуть (выбрать) по одной единственной строке и далее по кнопке “Start Daemon”:
Сервис веб состыкуется с сервисом deluged (это почему-то обозначается как старт демона) и теперь можно подключиться (нажать кнопку Connect – она станет доступна):
Появится рабочее окно списка торрентов:
Теперь, когда мы убедились, что всё работает, нужно донастроить сервер. Добавлять вручную торренты дело заморочное, по этому хорошо бы каталог, куда мы сразу записывали торрент-файлы (файлы с расширением .torrent) и хорошо бы иметь доступ к папке с уже скачанными файлами, но об этом позже. А пока создадим два каталога внутри домашнего каталога deluge:
sudo mkdir /home/deluge/data
sudo mkdir /home/deluge/torrents
Первая – для данных, вторая для торрент-файлов
Установим хозяина владельца на папки:
sudo chown deluge:deluge /home/deluge/data
sudo chown deluge:deluge /home/deluge/torrents
и проверим, всё ли норм:
Теперь объясню зачем это сделано именно так. Дело в том, что Deluge я устанавливаю на чистый виртуальный свежеустановленный Ubuntu server с минимальными настройками, в частности – 16 ГБ жесткого диска. Конечно, такого размера не хватит практически ни на что. Для того чтобы иметь много пространства, я подключу физический старый дряхлых жесткий диск и прокину его внутрь этой виртуальной. Делаю я так, потому что мне для торрентов жалко нового диска, и рано или поздно он своё отслужит, и когда накроется, я не хочу снова устанавливать Ubuntu, Deluge, Samba и т.п., я просто хочу прокинуть новый такой же старый и дряхлых (извиняюсь за каламбур) жесткий диск и продолжить сразу же работу. Вопрос будет только в том, чтобы перемонтировать этот диск в папку /home/deluge/data и проблема будет решена. Вот для чего я создал папку data – туда будет монтироваться диск большого объёма. Для торрент-файлов такой подход будет избыточным – это небольшие файлики, содержащие только управляющую информацию на закачку.
После подключения диска для готовых файлов к виртуальной (или физической) машине (это не имеет значения), на нём хорошо бы переопределить разделы и отформатировать, но сначала я его найду в списке устройств:
cd /dev
ls -al | grep sd
В результате система покажет какие диски у нас присутствуют:
Вот этот sdb без номера и есть наш новый старый дряхлый диск…хотя вру, у меня это новый виртуальный, новее некуда…на старом дряхлом физическом)))
Я дам ему один единственный раздел всего объёма:
sudo fdisk /dev/sdb
Введем сначала команду n и всё “отэнтерим”, проверим разделы командой p, а затем введем команду w для сохранения и выхода:
Да, диск я взял новый не такой уж и большой – 64 ГБ (не оказалось свободного места на датасторе перед написанием статьи), но это не так критично )).
Проверим, что нового появилось в дисках:
Всё верно – появился диск sdb1. Это как раз и есть наш раздел, но прежде чем сможем его использовать, нужно его отформатировать. Для этого я буду использовать следующую команду (опять отэнтерив вопросы):
sudo mkfs.ext4 /dev/sdb1
Получим результат:
Убедимся, что всё прошло ровно командой blkid:
Видим, что диск sdb1 имеет идентификатор и признак файловой системы ext4.
Создадим на диск папку, куда будем при загрузке системы монтировать этот диск:
Сохраним файл в новом виде и перезагрузим машину командой reboot.
После загрузки проверим всё ли мы сделали правильно командой:
df -h /torrents-disk
Должно получиться как-то так:
Информация свидетельствует о том, что при загрузке системы диск автоматически примонтировался успешно.
Создадим внутри каталога /torrents-disk каталог data:
sudo mkdir /torrents-disk/data
Примонтируем его в папку /home/deluge/data (если вы ещё не забыли зачем мы его вообще в систему добавили):
sudo mount -o bind /torrents-disk/data /home/deluge/data
Убеждаемся, что и папка /home/deluge/data ссылается теперь на наш “большой” диск:
Теперь, возможно у вас возник вопрос,- почему я прямо в fstab не примонтировал диск внутрь /home/deluge. Ответ прост – мне так удобнее в обслуживании, и ещё диск этот может мне понадобиться не только для торрентов, и захочу отдельную папку его примонтировать в другую совсем не связанную с торрент-сервисом. Если 2-3 ТБ, пусть он старый, но использовать его для торрентов, как-то неправдоподобно и бессмысленно. Я такой объем торрентов точно не буду вводить в обмен, по этому буду разделять диск с ещё другими сервисами, какими – потом решу.
Вторую команду монтирования тоже хорошо бы запихнуть куда-нибудь для автоматического выполнения при загрузке системы. Запихну-ка я её в rc.local. Однако, если мы посмотрим внимательно на свежий Ubuntu 22.04, там этого файла нет, а сервис находится в полной отключке))). Исправим это недоразумение)).
Создадим файл /etc/rc.local:
sudo nano /etc/rc.local
Содержимое его будет такое:
#!/bin/sh -e
mount -o bind /torrents-disk/data /home/deluge/data
exit
Сохраним его и дадим права и установим как исполняемый:
chmod 0744 /etc/rc.local
Создадим файл настройки сервиса:
sudo nano /etc/systemd/system/rc-local.service
Должно получиться так:
Включим, стартанём и проверим сервис rc-local.service:
sudo systemctl enable rc-local.service
sudo systemctl start rc-local.service
sudo systemctl status rc-local.service
Должно быть так:
Давайте перезагрузим наш сервачок и убедимся, что после ребута он будет делать ровно то, что должен. Проверим папку /home/deluge/data:
Теперь создадим три каталога внутри /torrents-disk/data.
sudo mkdir /torrents-disk/data/downloads
sudo mkdir /torrents-disk/data/downloaded
sudo mkdir /torrents-disk/data/autouploads
downloads будет хранить торренты пока они находятся в процессе закачки (до конца незакачанные торренты)
downloaded будет хранить файлы, которые полностью закачены и готовы к употреблению, так сказать
autouploads будет хранить торрент файлы .torrents. В эту папку мы будем сохранять задания на закачку, т.е. сами торренты.
На каталог autouploads нужно дать все права, чтобы гостевой пользователь мог туда сохранять торренты:
sudo chmod 0777 /torrents-disk/data/autouploads
На папку /torrents-disk/data и всех, которые внутри устанавливаем владельца:
sudo chown -R deluge:deluge /torrents-disk/data
Теперь организуем сетевой доступ к папке с торрентами и к папке с готовыми загруженными файлами. Делать я это буду путём установки в систему сервиса Samba:
sudo apt-get install samba
Настроим чтобы сервис мог видеть наши папки, для этого отредактируем необходимый файл:
sudo nano /etc/samba/smb.conf
В конец файла допишем:
[autouploads] comment = Auto uploads browseable = yes path = /torrents-disk/data/autouploads guest ok = yes read only = no create mask = 0777
В папку autouploads можно будет писать файлы, а из папки downloaded можно будет только читать файлы (оно и логично).
Перезапустим сервис Samba:
sudo /etc/init.d/smbd restart
Проверим, что по сети стал доступен сам сервер \\192.168.1.24\(вместо моего IP тут будет IP вашего), а папка autouploads доступна для записи (я просто создал тестовый файл):
Попробуем сохранить туда торрент файл:
Файл торрента действительно сохранился в сетевой папке, однако, ожидать его закачки ещё рановато. Нужно настроить сам Deluge и привязать его к нашим каталогам. Откроем эти настройки в веб-интерфейсе:
Сразу же видим, что папка загрузки указано неверно. В Линуксе имеет значение заглавная буква имен или нет. Правильный каталог не Downloads, а downloads. Также сами каталоги находятся внутри /home/deluge/data. Укажем и остальные каталоги и нажмем кнопку Apply:
Переходим в раздел Plugins и добавляем новый плагин AutoAdd. Он нужен чтобы Deluge автоматически забирал файлы из каталога с торрентами (где у нас уже ожидает по крайней мере один файл с торрентом), потом также нажимаем Apply:
Переходим во вновь появившийся раздел AutoAdd и добавляем папку слежения за торрентами, а затем кнопку Add и опять-таки кнопку Apply:
После этого окно закрывается и торрент сразу же начинает скачиваться:
Файл скачался и мы можем его теперь скопировать из папки (по факту это оказался не просто один файл, а сразу каталог с несколькими файлами):
Snap – это система упаковки программного обеспечения, разработанная Canonical в первую очередь для использования в системах Linux с системой инициализации systemd. Он направлен на решение ряда проблем, связанных с упаковкой и распространением программного обеспечения, но также имеет свой набор недостатков. В этом руководстве мы рассмотрим недостатки использования Snap и узнаем, как отключить или удалить его.
Все команды были протестированы в Snap 2.58.2, запущенной в Ubuntu Desktop 22.04.02 LTS. Однако они также должны быть совместимы с большинством других дистрибутивов Linux.
2. Введение в проблему
Хотя Snap предоставляет ряд преимуществ, у него также есть некоторые потенциальные недостатки, такие как использование дискового пространства, производительность и ограниченная интеграция и настройка.
Из-за этих проблем и некоторых спорных решений, принятых Canonical за последние несколько лет, некоторые дистрибутивы отключили или вообще удалили Snap из своих выпусков.
2.1. Недостатки Snap
По сравнению с традиционными системами упаковки, такими как .deb или другими форматами, такими как Flatpak и AppImage, пакеты Snap, как правило, занимают больше места на диске. Более того, они запускаются медленнее, поскольку требуют инициализации среды выполнения и загрузки зависимостей в память.
Поскольку пакеты Snap являются автономными и изолированными от хост-системы, они предлагают ограниченную интеграцию с системными ресурсами и другими приложениями. Это может вызвать проблемы с доступом к определенным системным ресурсам, таким как системные темы и шрифты.
2.2. Противоречия с браузером Chromium
Начиная с Ubuntu версии 19.10, Canonical обязала пользователей Ubuntu и ее производных использовать Snap для установки Chromium. Пакет chromium-browser .deb теперь включает только скрипты-оболочки, которые облегчают загрузку пакета Snap.
В результате этого решения, Linux Mint удалил Snap из своего пакета выпуска, начиная с версии 20 – Ulyana. Команда apt также предотвращает установку snapd.
2.3. Автоматическое обновление по умолчанию
По умолчанию Snap выполняет четыре проверки в день на наличие обновлений и автоматически обновляется, когда они доступны. Однако эта функция может вызвать проблемы в системах с ограниченными ресурсами. Когда ресурсы, такие как оперативная память и процессоры, ограничены, операционная система может завершить другие важные процессы, чтобы приспособиться к процессу автоматического обновления.
2.4. Ubuntu не поддерживает Flatpak
Компания Canonical объявила, что она не будет включать программное обеспечение Flatpak в пакет Ubuntu, начиная с версии 23.04 – Lunar Lobster, в попытке стимулировать использование Snap вместо него.
3. Удаление и отключение Snap
Давайте отключим и удалим Snap из нашей системы.
При новой установке Ubuntu 22.04.2 LTS у нас предварительно установлены следующая версия Snap и пакеты:
$ snap --version
snap 2.58.2
snapd 2.58.2
series 16
ubuntu 22.04
kernel 5.19.0-35-generic
$ snap list
Name Version Rev Tracking Publisher Notes
bare 1.0 5 latest/stable canonical✓ base
core20 20230126 1822 latest/stable canonical✓ base
firefox 110.0-3 2356 latest/stable/… mozilla✓ -
gnome-3-38-2004 0+git.6f39565 119 latest/stable/… canonical✓ -
gtk-common-themes 0.1-81-g442e511 1535 latest/stable/… canonical✓ -
snap-store 41.3-66-gfe1e325 638 latest/stable/… canonical✓ -
snapd 2.58.2 18357 latest/stable canonical✓ snapd
snapd-desktop-integration 0.1 49 latest/stable/… canonical✓ -
3.1. Удаление существующих пакетов Snap
Теперь давайте приступим к удалению пакетов Snap, или привязок, в следующем порядке:
Прежде чем перейти к следующему шагу, давайте убедимся, что список snaps пуст:
$ snap list
No snaps are installed yet. Try 'snap install hello-world'.
Если бы остались какие-либо привязки, мы могли бы вернуться к их перечислению и попытаться удалить их с помощью snap remove.
3.2. Удаление демона snapd
Далее давайте остановим, отключим, удалим и удержим демон snapd:
$ sudo systemctl stop snapd
Warning: Stopping snapd.service, but it can still be activated by:
snapd.socket
$ sudo systemctl disable snapd
Removed /etc/systemd/system/multi-user.target.wants/snapd.service.
$ sudo systemctl mask snapd
Created symlink /etc/systemd/system/snapd.service → /dev/null.
$ sudo apt purge snapd -y
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages will be REMOVED:
snapd*
...
Removing snapd state
$ sudo apt-mark hold snapd
snapd set on hold.
Команда ‘apt-mark hold‘ означает, что пакет помечен как отложенный, что предотвратит автоматическую установку, обновление или удаление пакета.
3.3. Удаление каталогов пакетов Snap
Snap по умолчанию хранит все пакеты в каталоге ~/snap/. Давайте удалим его.:
$ rm -rf ~/snap/
Поскольку каталог находится в каталоге home, нам не нужно использовать sudo для его удаления. Однако важно быть осторожным при вводе команды, поскольку она удалит каталог рекурсивно.
Мы также должны убедиться, что путь ~/snap/ указан правильно.
3.4. Предотвращение установки Snap с помощью команды apt
Canonical изменила пакет chromium-browser .deb, теперь он включает только скрипты-оболочки, которые запускают установку Snap.
Чтобы предотвратить подобные случаи, мы можем использовать следующую команду, предложенную Linux Mint:
В результате, когда мы пытаемся установить браузер Chromium с помощью команды apt:
$ sudo apt install chromium-browser
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:
The following packages have unmet dependencies:
chromium-browser : PreDepends: snapd but it is not installable
E: Unable to correct problems, you have held broken packages.
Как мы можем видеть из приведенной выше команды, Snap не сможет установить себя без нашего согласия.
3.5. Удаление всех оставшихся каталогов Snap
Если наша система не была установлена заново, нам может потребоваться проверить и удалить некоторые каталоги.
Давайте убедимся, что мы вводим эти команды правильно, поскольку мы будем использовать sudo для рекурсивного удаления каталогов:
В этой статье мы рассмотрели процесс удаления и отключения Snap из нашей системы, а также предотвращение его установки без нашего согласия при использовании команды apt.
Для начала необходимо создать файл скрипта /etc/snake-backup-script по бэкапированию со следующим содержимым:
#!/bin/bash -e
declare -a databases=("buh" "ut" "zup")
for dbname in "${databases[@]}"
do
FILENAME=/backups-postgre/backup-$dbname-$(date +"%Y-%m-%dT%H-%m-%S")".dump.gz"
if sudo -u postgres pg_dump $dbname | gzip > $FILENAME ; then
echo $FILENAME "OK"
else
echo $FILENAME "ERROR"
fi
done
find /backups-postgre -type f -ctime +20 -delete
exit 0
Этот файл при запуске будет перебирать массив баз данных PostgreSQL и делать по ним выборочный бэкап и отправлять каждую БД в отдельный gz файл. Файл будет иметь имя включающее признак backup, название БД и дату/время. Таким образом, каждый бэкап будет уникальным и весь вопрос будет только в том чтобы следить за свободным пространством. Важно, чтобы бэкап выполнялся от имени postgres, для этого в скрипте используется модификатор sudo. Запись find будет искать бэкапы старше 20 дней и удалять их. Это сделано чтобы не загромождать диск.
Файл будет запускаться из Cron каждые три часа. Для этого нужно настроить Cron.
sudo crontab -e
Чтобы бэкап запускался каждый день в 7 утра, в файл внести запись: