Что такое скрипты в играх и для чего они

Что такое скрипты в играх и для чего они

При создании игры скрипты используются во многом так же, как кинорежиссер использует сценарий — для контроля каждого аспекта вашего «произведения». Игровые скрипты подобны программному коду, который вы пишете, когда создаете игру, за исключением того, что скрипты являются внешними по отношению к игровому движку. Поскольку они внешние, вы можете быстро изменить скрипт не компилируя заново весь игровой движок. Вообразите себе проект, в котором больше миллиона строк кода, и вам надо компилировать весь этот проект заново только для того, чтобы изменить одну строку в диалоге!

Со скриптами совсем не трудно работать, и почти каждая часть вашей игры может извлечь пользу от использования скриптов. Вы можете использовать скрипты при навигации по меню, для управления сражениями, для работы с имуществом игрока и многого другого. Представьте себе, что при разработке игры вам захотелось, предоставлять во время битвы игроку список магических заклинаний, которые он регулярно использует для атак. Теперь представьте, что в ходе разработки вы решили изменить некоторые из этих заклинаний. Если информация о заклинаниях жестко закодирована, вы столкнетесь с серьезной проблемой; вам придется изменить каждый экземпляр программного кода, который управляет заклинаниями, не говоря уже о том, что новый код придется тестировать и отлаживать, чтобы добиться правильной работы. Зачем тратить так много времени на подобные изменения?

Вместо этого вы можете написать код для магических заклинаний и их действий на персонажей игры в нескольких небольших скриптах. Всякий раз, когда начинается сражение, загружаются эти скрипты и отображается панемль выбора магических заклинаний. Когда выбирается заклинание, скрипт обрабатывает все эффекты — от наносимых повреждений до перемещений и анимации графических эффектов заклинания.

Для этой книги я колебался между двумя различными типами скриптовых систем. Первая из них предполагает использование языка, похожего на С++. В файле скрипта вы печатаете команды, компилируете его и исполняете скомпилированный скрипт из вашей игры. Вторая система скриптов является значительно упрощенным вариантом первой. Вместо того, чтобы позволить вам печатать команды в файле, эта система обеспечивает создание скриптов путем выбора команд из предварительно определенного набора.

Поскольку моей целью было как можно быстрее предоставить вам работающий скриптовый движок, я выбрал использование второго типа скриптовой системы. Эта система, которую я назвал Mad Lib Scripting, работает используя набор предопределенных команд, называемых действия (actions), с каждым из которых связана игровая функция. Возьмем, для примера, действия из таблицы 10.1 — у каждого действия есть конкретная выполняемая функция.

Таблица 10.1. Примеры команд действий

ДействиеФункция
PrintПечатает строку текста на экране.
EndЗавершает выполнение скрипта.
Move CharacterПеремещает указанный персонаж в заданном направлении.
Play SoundВоспроизводит указанный звуковой эффект.

С таким ограниченным набором действий вам не нужна мощь сложных компилируемых скриптовых языков; вместо этого вам нужна возможность спросить скриптовую систему, какое действие выполняется, и какие параметры действия должны использоваться при выполнении игровой функции. Самое замечательное в этом методе то, что вместо написания строк кода, определяющих простое действие, вы ссылаетесь на действия и их параметры с помощью чисел.

Для примера скажем, что действию Play Sound соответствует номер 4, и действие требует единственного параметра — номера воспроизводимого звука. В скрипте вам потребуется сохранить только два числа: одно для действия, и одно, представляющее звук. Использование чисел для представления действий (вместо текста) делает обработку скриптов такого типа быстрой и простой.

Источник

Игровое программирование. Уроки скриптописания

Для многих начинающих игростроевцев, которые уже собирают свою команду, чтобы слепить на коленке очередной шедевр, программирование часто видится жутким монстром, с которым непонятно как бороться. Вроде и в 3D уже рисовать умеют, и в Photoshop кисточкой сноровисто работают, и другие полезные программы неплохо знают. Но как только дело доходит до кода, начинается паника и неразбериха: “ Кто спрограммирует? Кто напишет заветные строчки? А если и напишет, то как в них потом разобраться?! ”.

Данный материал открывает серию статей, в которых мы на простых примерах научим вас читать с листа и писать несложный программный код. Суперкрутыми программистами вы, разумеется, не станете (для этого надо учиться значительно дольше), но иероглифы кода перестанут быть для вас чем-то непонятным, от чего нужно держаться подальше.

Установка среды разработки

Классы игры и иерархия

Распаковка игровых скриптов

Настройка среды разработки

В ООП существуют три основных принципа, на которых строятся практически все логические манипуляции с объектами.

Инкапсуляция — объединение внутри объекта данных с методами для их обработки. Например, если рассматривается класс “Лампочка”, то у него должны быть методы “включить свет” и “выключить свет”.

Наследование — создание класса объектов на основе уже существующего класса. При этом создаваемый класс будет не только содержать все данные и методы базового класса, но и обладать своими собственными. Методы базового класса могут быть переопределены. Примеры наследования и переопределения: если класс “Пегас” наследуется от класса “Лошадь”, то у первого появляется новое свойство — “крылья” и соответствующий метод “махать крыльями”. Все остальное у этих двух классов одинаковое. Если мы рассмотрим класс “Русалка”, основанный на классе “Человек”, то в данном случае будет иметь место переопределение свойства “ноги” на “рыбий хвост”, а метод “двигаться” будет вместо движения ног отвечать за перемещение хвоста.

Полиморфизм — что это такое, проще всего рассмотреть на конкретном примере. Рассмотрим два класса объектов — “Пегас” и “Лошадь”. Полиморфизм заключается в том, что мы можем рассматривать любого пегаса как лошадь и, например, у обоих объектов выполнять метод “кушать траву” или “бежать галопом”.

Многие начинающие программисты не различают понятия “класс” и “объект”. Но при этом эти два понятия различаются примерно так же, как и, скажем, чертеж устройства и готовое устройство в магазине. В жизни их спутать трудно.

Создание проекта

К сожалению, в UDE кнопка “Создать новый проект” отсутствует. Поэтому создаем в корневой папке UT2004 файл CreateNewClass.bat с командами:

echo class %pkg% extends //base class>> %pkg%\Classes\%pkg%.uc

Значение переменной pkg — это имя нашего проекта (в данном случае — Megakiller ). Остальные строки генерируют “пустой” скрипт.

Идея модификации

Перед изучением нижеследующей информации настоятельно рекомендуется изучить текстовый блок “ Анатомия Unreal-класса ”.

Внимание! Читая нижеследующие абзацы, смотрите соответствующие строки в листинге кода, приведенном на отдельной странице (номера строк указаны слева от кода).

Класс оружия

Рис. 1. Диалог создания дерева классов и архивов.

Класс альтернативной стрельбы

Рис. 2. Окна с деревом классов и списком архивов.

В начале файла объявляем несколько новых свойств для объектов класса ( строки 2-5 ): визуальный тип взрыва ( ExplosionClass ), визуальный тип следа от взрыва, например на стенах ( ExplosionDecalClass ). Тип луча при альтернативной стрельбе ( BeamEffectClass ) и радиус поражения при взрыве ( DamageRadius ).

Рис. 3. Диалог создания подкласса.

Классы повреждения

Рис. 4. Окно компиляции.

Класс игрового мутатора

— просто лежать на карте ( строка 15 ). Тут нам помогает класс WeaponPickup ( строка 15 ). Подмена осуществляется функцией ReplaceWith ( строка 19 ).

Рис. 5. Сообщение об ошибке и справка.

Дуэли на «Мегакиллерах» иногда превращают обычный бой в феерическое зрелище.

Чернокожий стрелок пытается безуспешно подстрелить «античную» мадам.

Местные леди способны просто-таки заряжать вас энергией!

Каждый Чебурашка мечтает о большой пушке!

Компиляция и тестирование

Для того чтобы вы сразу могли оценить действие мутатора и поиграть в него, мы выкладываем полную версию “Мегакиллера” на наш диск.

Принципы объектно-ориентированного программирования

Класс игры имеет унифицированную архитектуру. Структура файла следующая.

— Заголовок, содержащий объявление класса:

class ClassName extends BaseClass config(user); где ClassName — название нашего класса, BaseClass — базовый класс, на основе которого создается новый класс, config(user) — пример параметра в объявлении класса — указывает, что используются конфигурационные параметры из файла User.ini. Все игровые классы имеют в качестве родительского класс Object или любой из его классов-потомков. Лексемы class и extends являются зарезервированными обязательными атрибутами объявления игрового класса. Важно запомнить, что корректным является только тот uc-файл, имя которого совпадает с названием объявленного в нем класса. И в одном uc-файле должен быть описан только один класс.

— Объявления новых переменных (свойств класса) в следующем формате:

PropertyName; или var() SimpleType PropertyName; где PropertyClass — название класса создаваемого свойства, SimpleType — элементарный тип, такой как byte (байтовое значение от 0 до 255), int (знаковый целый тип), bool (логический тип), float (знаковый вещественный тип), string (символьная строка) и т.д. (полный список элементарных типов можно посмотреть в справке UDE), PropertyName — имя нового свойства.

— Объявления новых методов или переопределение унаследованных от базового класса имеют следующий вид:

— Задание параметров (свойств) по умолчанию класса:

defaultproperties где defaultproperties — лексема, указывающая начало блока свойств, Variable1Name — название свойства, представляющего собой некоторый другой объект класса ClassName, содержащегося в u-файле с именем Package. Параметр Variable2Name имеет элементарный тип, поэтому и присваиваемое значение Variable2Value должно иметь тот же тип. Символ «=» означает операцию присвоения значения справа переменной слева. Фигурные скобки обособляют в коде блок присвоений.

Вот и подошел к концу наш первый экскурс в мир игрового программирования. Мы не только сделали интересный мутатор, но и научились читать несложный программный код. В одном из ближайших номеров “Мании” мы продолжим разбираться в азах программирования и, изучив более продвинутые строки кода, создадим более сложный мутатор.

Источник

Что такое скрипты и с чем их едят — Lua & C++

Добрый день, Хабрахабр!
Решил написать этот топик на тему скриптов

Что такое скрипты в играх и для чего они. Смотреть фото Что такое скрипты в играх и для чего они. Смотреть картинку Что такое скрипты в играх и для чего они. Картинка про Что такое скрипты в играх и для чего они. Фото Что такое скрипты в играх и для чего они

Что нужно знать?

Но есть способ, на голову выше — использование скриптов.

Решение проблемы

«Окей, для таких дел хватает обычного файла с описанием характеристиков игрока. Но что делать, если в бурно развивающемся проекте почти каждый день приходится немножко изменять логику главного игрока, и, следовательно, много раз компилировать проект?»
Хороший вопрос. В этом случае нам на помощь приходят скрипты, держащие именно логику игрока со всеми характеристиками либо какой-либо другой части игры.
Естественно, удобнее всего держать, логику игрока в виде кода какого-нибудь языка программирования.
Первая мысль — написать свой интерпретатор своего скриптового языка, выкидывается из мозга через несколько секунд. Логика игрока определенно не стоит таких жутких затрат.
К счастью, есть специальные библиотеки скриптовых языков для С++, которые принимают на вход текстовый файл и выполняют его.

Об одном таком скриптовом языке Lua пойдет речь.

Как это работает?

Прежде чем начать, важно понимать, как работает скриптовый язык. Дело в том, что в скриптовых языках есть очень мало функций, при наличии конструкций for, while, if, прочих.
В основном это функции вывода текста в консоль, математические функции и функции для работы с файлами.
Как же тогда можно управлять игроком через скрипты?

Мы в С++-программе делаем какие-либо функции, «регистрируем» их под каким-нибудь именем в скрипте и вызываем в скрипте. То есть если мы зарегистрировали функцию SetPos(x,y) для определения позиции игрока в С++-программе, то, встретив эту функцию в скрипте, «интерпретатор» из библиотеки скриптового языка вызывает эту функцию в С++-программе, естественно, с передачей всех методов.
Удивительно, да? 🙂

UPD: Внимание! Один юзер обратился мне с мейлом, что, когда я заливал код, я не полностью устранил все ошибки — habrahabr.ru/post/196272/#comment_6850016
В коде с позволения хабра проникли жучки
Замените участки кода вроде

И еще вместо lua_CFunction проскакивает lua_cfunction
Спасибо!

Я готов!

Когда вы поняли преимущества скриптовых языков программирования, самое время начать работать!
Скачайте из репозитория на гитхабе (низ топика) lib’у и includ’ы Lua, либо возмите их на официальном сайте.

Создаем консольный проект либо Win32 (это неважно) в Visual Studio (у меня стоит версия 2012)

Заходим в Проект->Свойства->Свойства конфигурации->Каталоги VC++ и в «каталоги включения» и «каталоги библиотек» добавьте папку Include и Lib из репозитория соответственно.

Теперь создаем файл main.cpp, пишем в нем:

Как вы догадались, у меня консольное приложение.

Теперь переходим к кодингу

Обещаю, что буду тщательно объяснять каждый момент

У нас за скрипты будет отвечать класс Script. Я буду объявлять и одновременно реализовывать функции в Script.h/.cpp
Создаем Script.cpp и пишем в нем

Создаем Script.h и пишем в нем

После 2 строчки и перед #endif мы определяем класс скриптов
Этот код пишется для предотвращения взаимного включения файлов. Допустим, что файл Game.h подключает Script.h, а Script.h подключает Game.h — непорядок! А с таким кодом включение выполняется только 1 раз

Теперь пишем внутри этого кода вот это

Первая строчка подключает сам lua.lib из архива.
Для чего нужен extern «C»? Дело в том, что lua написан на С и поэтому такой код необходим для подключения библиотек.

Дальше идет подключение хорошо известных многим файлов для работы с консолью

Теперь приступим к определению класса

Самый главный объект библиотеки Lua для C++ — lua_State, он необходим для выполнения скриптов

Дальше идут публичные функции

Эта функция инициализирует lua_State

Его определение в Script.cpp

Первой строчкой мы инициализируем наш lua_State.
Потом мы объявляем список «подключенных библиотек». Дело в том, что в «чистом» виде в луа есть только функция print(). Для математических и прочих функций требуется подключать специальные библиотеки и потом вызывать их как math.foo, base.foo, io.foo. Для подключения других библиотек добавьте в lualibs, например, <«math», luaopen_math>. Все названия библиотек начинаются с luaopen_. в конце lialibs должен стоять

Просто используем lua_close()

А эта функция выполняет файл. На вход она принимает название файла, например, «C:\\script.lua».
Почему она возвращает int? Просто некоторые скрипты могут содержать return, прерывая работу скрипта и возвращая какое-нибудь значение.

Как вы видите, я выполняю скрипт и возвращаю int. Но возращать функция может не только int, но еще и bool и char*, просто я всегда возвращаю числа (lua_toboolean, lua_tostring)

Теперь мы сделаем функцию, регистрирующую константы (числа, строки, функции)

Мы действуем через шаблоны. Пример вызова функции:
Ее определение

Для каждого возможного значения class T мы определяем свои действия.
*Капитан* последнее определение — регистрация функции
Функции, годные для регистрации, выглядят так:

Где n — количество возвращаемых значений. Если n = 2, то в Луа можно сделать так:

Читайте мануалы по Луа, если были удивлены тем, что одна функция возвращает несколько значений 🙂

Следующая функция создает таблицу для Луа. Если непонятно, что это значит, то тамошная таблица все равно что массив

Следующая функция регистрирует элемент в таблице.

Если вы не знаете Lua, вы, наверное, удивлены тем, что в один массив помещается столько типов? 🙂
На самом деле в элементе таблицы может содержаться еще и таблица, я так никогда не делаю.

Наконец, заполненную таблицу нужно зарегистрировать

Ничего особенного нет

Следующие функции предназначены в основном только для функций типа int foo(lua_State*), которые нужны для регистрации в Луа.

Первая из них — получает количество аргументов

Эта функция нужна, например, для функции Write(), куда можно запихать сколь угодно аргументов, а можно и ни одного
Подобную функцию мы реализуем позже

Следующая функция получает аргумент, переданный функции в скрипте

Можно получить все типы, описывавшиеся ранее, кроме таблиц и функций
index — это номер аргумента. И первый аргумент начинается с 1.

Наконец, последняя функция, которая возвращает значение в скрипт

Боевой код

Пора что-нибудь сделать!
Изменяем main.cpp

Компилируем. Теперь можно приступить к тестированию нашего класса

Помните, я обещал сделать функцию Write? 🙂
Видоизменяем main.cpp

А в папке с проектом создаем файл script.lua

Что такое скрипты в играх и для чего они. Смотреть фото Что такое скрипты в играх и для чего они. Смотреть картинку Что такое скрипты в играх и для чего они. Картинка про Что такое скрипты в играх и для чего они. Фото Что такое скрипты в играх и для чего они

Компилируем и запускаем проект.

Что такое скрипты в играх и для чего они. Смотреть фото Что такое скрипты в играх и для чего они. Смотреть картинку Что такое скрипты в играх и для чего они. Картинка про Что такое скрипты в играх и для чего они. Фото Что такое скрипты в играх и для чего они

Теперь изменяем script.lua

Теперь программа будет выводить по 2 строки («\n» — создание новой строки), ждать нажатия Enter и снова выводить строки.

Что такое скрипты в играх и для чего они. Смотреть фото Что такое скрипты в играх и для чего они. Смотреть картинку Что такое скрипты в играх и для чего они. Картинка про Что такое скрипты в играх и для чего они. Фото Что такое скрипты в играх и для чего они

Экспериментируйте со скриптами!

Вот пример main.cpp с функциями и пример script.lua

Полезные советы
Вопросы и ответы

Источник

Скрипты в Dota 2: плюсы и минусы

В Доте на определенных персонажей иногда необходимо прожимать несколько умений и предметов. Придется много тренироваться, чтобы сделать это только своими руками. При этом надо быстро думать и реагировать. Но ошибаются иногда даже рейтинговые игроки. О том, что нужно продавливать некоторые клавиши, иногда не помнят даже профессионалы. Чтобы не допускать таких ошибок, программисты создают скрипты для Dota 2. Они представляют собой перечень команд, выполняемых продавливанием одной горячей клавиши.

Что такое скрипты в играх и для чего они. Смотреть фото Что такое скрипты в играх и для чего они. Смотреть картинку Что такое скрипты в играх и для чего они. Картинка про Что такое скрипты в играх и для чего они. Фото Что такое скрипты в играх и для чего они

Что такое скрипты в играх и для чего они. Смотреть фото Что такое скрипты в играх и для чего они. Смотреть картинку Что такое скрипты в играх и для чего они. Картинка про Что такое скрипты в играх и для чего они. Фото Что такое скрипты в играх и для чего они

Что нужно знать?

В матче за набор действий отвечает соответствующая горячая клавиша. Чтобы сработало одновременно несколько предустановленных команд, что и делает скрипт по сути. Например, по клику одной кнопки с помощью скрипта может нажаться несколько навыков и вещей.

Установка скриптов

Горячих клавиш, назначенных в коде скрипта, не должно быть в настройках, которые являются стандартными для игры. Тогда инсталляция пройдет с успехом. В противном случае, по поводу идентичных кнопок могут возникнуть конфликты. В результате они станут причиной сбоев и зависаний. Обратите внимание, что несколько десятков горячих клавиш скрыто в кнопке «дополнительное». Она располагается в настройках. Перед тем, как через console активизировать в игре скрипт (то есть до его инсталляции), все они должны быть проверены.

Что такое скрипты в играх и для чего они. Смотреть фото Что такое скрипты в играх и для чего они. Смотреть картинку Что такое скрипты в играх и для чего они. Картинка про Что такое скрипты в играх и для чего они. Фото Что такое скрипты в играх и для чего они

Скрипты Dota 2 устанавливаются в специальной папке. Чтобы ее найти, нужно действовать по следующему алгоритму:

Что такое скрипты в играх и для чего они. Смотреть фото Что такое скрипты в играх и для чего они. Смотреть картинку Что такое скрипты в играх и для чего они. Картинка про Что такое скрипты в играх и для чего они. Фото Что такое скрипты в играх и для чего они

В качестве скриптов игра воспринимает только файлы формата «.cfg». Открыть такой документ можно с помощью простого блокнота. Читать и стараться вникнуть в его содержимое вам не понадобится. Напротив слова «bind» есть возможность назначать клавиши на какие-либо определенные действия. После этой надписи расположено число или буква, которую нужно изменить, чтобы назначить кнопку на выполнение определенного скрипта.

Что такое скрипты в играх и для чего они. Смотреть фото Что такое скрипты в играх и для чего они. Смотреть картинку Что такое скрипты в играх и для чего они. Картинка про Что такое скрипты в играх и для чего они. Фото Что такое скрипты в играх и для чего они

Какие бывают скрипты?

Обычно Scripts Dota 2 необходимы не всем персонажам. Мипо – один из самых придирчивых. Он нуждается в тщательном надзоре. Поэтому, чтобы управлять им, можно использовать списки команд, приготовленные заблаговременно.

С их помощью все Мипо способны подскочить одновременно на месте или телепортироваться к одному. Представляете, какое количество клавиш придется нажать, чтобы проделать это собственноручно? На каждого из 5 клонов придется прожать 3 кнопки. То есть, получается всего 15 нажатий. В первую очередь продавить прыжок, затем клавишу мышки, куда именно нужно прыгнуть. Потом вы должны будете перейти на следующего и повторить эти же действия. Какая бы молниеносная реакция у вас ни была, нажать всего одну кнопку займет много меньше времени.

Что такое скрипты в играх и для чего они. Смотреть фото Что такое скрипты в играх и для чего они. Смотреть картинку Что такое скрипты в играх и для чего они. Картинка про Что такое скрипты в играх и для чего они. Фото Что такое скрипты в играх и для чего они

Такие скрипты существуют практически для любого героя. Особенно они популярны для Тинкера, Инвокера и других персонажей, которым нужно прожимать много предметов и умений за один раз. Также многие ищут скрипты на Петуха и Течиса. Их работа базируется на основе функции консоли в игре.

Консоль в Доте предназначена для того, чтобы помогать геймерам получать информацию о настройке их персональной игры. Однако многие хакеры на этом не остановились. Читеры используют консоль в личных целях и создают собственные модификации кодов для упрощения игрового процесса.

Используя определенные скрипты без особенного труда можно поднять свой рейтинг. Античит Valve очень редко определяет нечестных игроков и, соответственно, почти не блокирует. Поэтому, как правило, владельцы приватных скриптов, остаются безнаказанными. То есть продолжительного решения на перспективу для предупреждения использования скриптов или читов в игре до сих пор не придумано. На данный момент только явных мошенников могут забанить по жалобе.

Часто читеры продают инструмент на собственных сайтах и получают денежные средства незаконно. Если вы наберете купить скрипты дота 2 в одном из поисковиков, то сразу получите в выдаче несколько миллионов результатов. К сожалению, игроку легче за секунду приобрести и установить такой скрипт, чтобы побеждать, чем длительное время тренировать свои игровые навыки.

Что такое скрипты в играх и для чего они. Смотреть фото Что такое скрипты в играх и для чего они. Смотреть картинку Что такое скрипты в играх и для чего они. Картинка про Что такое скрипты в играх и для чего они. Фото Что такое скрипты в играх и для чего они

Иными словами, скрипт дает игроку огромные преимущества, выполняя сложные вещи в игре на автомате. Читы в Dota 2 сильно отличаются друг от друга. Например, это может быть автоматическое использование вещей, авто-комбо навыков, автоматических добиваний последним ударов своих или чужих крипов, добивание собственных войск или самого себя, блокирования крипов на автомате, приобретения способности видеть в мареве битвы.

Вышеупомянутый скрипт на автоблок крипов дает многочисленные команды на передвижение персонажа. Непосредственно перед крипом он изменяет местонахождение персонажа. В результате скорость волны creeps на направлении значительно уменьшается.

Это приводит к тому, что вы получаете превосходство оптимального расположения на центральной линии. Если у вас нет скрипта, чтобы преуспеть, вам потребуется многочасовой опыт. Так как в этом случае речь идет о навыке высокого уровня.

Популярные скрипты могут обладать общими для всех персонажей командами, а могут быть сделаны под каких-либо определенных героев. Они помогают игроку быть всегда впереди как в макро, так и в микро игре. Например, самодействующее употребление вещей представляет собой на самом деле сложный набор команд.

Что такое скрипты в играх и для чего они. Смотреть фото Что такое скрипты в играх и для чего они. Смотреть картинку Что такое скрипты в играх и для чего они. Картинка про Что такое скрипты в играх и для чего они. Фото Что такое скрипты в играх и для чего они

Минусы

Бесплатные скрипты Dota 2 необходимо активизировать в консоли при каждом вашем входе. Этот элемент управления еще не автоматизирован. Скиллы очень быстро используются – это еще один недостаток. Бывает, что игра не успевает осуществить все команды. Еще один важный момент, о котором стоит не забывать: можно легко найти скрипты для скачивания, но они нередко будут заражены вирусами. Так что помните, если вдруг решите использовать, что делаете это исключительно на свой страх и риск.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Анатомия Unreal-класса