- Баллы
- 76
- Имя в Minecraft
- witwar
Когда-то давно я выпускал тему про написание ядра на Python. Из за Python'а её и захейтили, так что теперь пишем ядро на Java 8. *Туториал не блещет правильной терминологией*
Мой проект по которому писался туториал на гитхабе: [ТЫК]
Необходимо понимать, что тема предназначена для тех, кто уже имеет понимание основ Java 8 и может более менее самостоятельно на ней писать.
Если вы уже потянулись создавать проект в своей IDE - не спешите этого делать. Для удобства, мы настроим и импортируем свой проект с Spring Initializr. Наш проект будет построен на Maven, поэтому смело выбираем Maven как сборщик. Далее, нам необходимо выбрать версию Spring, мы будем использовать 2.4.5. После этого, нам надо задать основную конфигурацию Maven'а, заполнять её следует используя объяснение приведённое ниже.
groupId - это общая часть пакета всех ваших проектов. Например у меня это net.ifxandy, т.к. в своих проектов я указываю пакет net.ifxandy.[проект].
artifactId - служебное название проекта, необходимое для Maven Central Repo.
Name - название проекта.
Description - небольшое описание проекта.
Package - пакет, в котором будет находится главный класс Spring-приложения. Авто-дополняется используя groupId и artifactId, но можно изменить. [!] ВНИМАНИЕ [!] Если ваш artifactId начинается с заглавной буквы - измените её в Package, иначе, это может привести к тому, что название проекта в Package будет распознаваться как название класса и вызовет некоторые проблемы и лишние заморочки.
Далее идёт поле Packaging, оно отвечает за то, во что будет собираться наш проект(формат файла), нам необходимо. чтобы проект собирался в Jar-файл, выбираем "Jar". Наконец версия Java, выбираем 8-ую.
В данном туториале мы будем использовать именно такие настройки, чтобы у всех всё было одинаково, это же пример. Но вы в своих проектах можете использовать какие хотите, если вы осознаёте и понимаете как и на что они влияют.
Теперь нам нужно добавить некоторые зависимости. Для этого есть панель справа. Нажимаем "ADD DEPENDENCY". В строке поиска вбиваем Lombok [ТЫК] - это библиотека для удобной работы над проектами основанная на аннотациях, которая автоматически дорабатывает ваш код. Она должна быть установлена у вас в IDE.
Далее, нажимаем на кнопку GENERATE снизу и скачиваем ZIP-Файл с шаблоном проекта. Осталось только импортировать проект в нашу среду разработки. Вот пример для Eclipse IDE.
Подготовка среды завершена!
Для этого, зайдём в main/resources в нужный файл .properties и зададим там 2 настройки. Первая - tcp.server.port=25565 отвечает за порт, на котором будет поднят сервер при запуске. Вторая - spring.main.web-environment=false отвечает за то, чтобы отключить запуск TomCat сервера(WEB обёртку Spring'а), ведь нам нужен TCP сервер.
У нас алгоритм довольно прост. Есть фабрика подключений TcpConnectionFactory. При каждом подключении она создаёт, настраивает и возвращает новый инстанс подключения. Клиент посылает по подключению пакеты.
Для удобной работы, мы поднимаемся на 1 абстракцию вверх и работаем не напрямую с байтами(это было бы жуть как неудобно), поэтому мы и задавали в нашем @Bean методе-настройке ConnectionFactory сериалайзер и десериалайзер. Они то нам и помогут в этом деле.
Serializer - класс имплементирующий интерфейс Serializer<?> (в нашем случае Serializer<Packet>). В нём имеется метод serialize принимающий как аргументы сериализуемый объект (у нас это Packet) и OutputStream, в который и отправляет после сериализации результат, т.е. клиенту.
Deserializer - такой же как и Serializer класс, только имплементирует интерфейс Deserializer<?>. Только принимает он в свой метод deserialize только InputStream, а вот возвращает уже сериализуемый класс.
Любой пакет от клиента сначала проходить через Deserializer и превращается в наш сообственный интерфейс Packet, после этого он попадает в TcpEndpoint. Это так скажем диспетчер, он определяет как и почему обрабатывать, что либо. У нас он будет состоять из Сервиса-Обработчика и метода, принимающего Packet класс и возвращающего ответ (или null, если ответа нет).
Сервис-Обработчик - класс, аннотированый как @Service. Чаще всего его реализуют используя интерфейс(без аннотации) и класс, унаследованный от него(имплементацию, которую уже стоить пометить аннотацией). Spring сам находит и обрабатывает его.
TcpEndpoint вызывает обработчик, получает ответ и возвращает его. Далее, наш экземпляр Packet'а проходит через Serializer, коим и отправляется клиенту.
Мой проект по которому писался туториал на гитхабе: [ТЫК]
"Пишем своё ядро на Java"
1. Подготавливаем среду
Ядро мы будем писать с использованием небезызвестного фреймворка Spring. Для нашей работы нам понадобятся:1. Прямые руки
2. Любое IDE (Здесь примеры на Eclipse)
3. Интернет
4. Майнкрафт клиент
Spring - это современный фреймворк, почти что для всего. Изначально, он был нацелен на создание веб-сайтов, но в итоге, может использоваться для чего удобно. Так же он предоставляет очень удобный способ организации TCP-серверов и включает в себя много удобностей.2. Любое IDE (Здесь примеры на Eclipse)
3. Интернет
4. Майнкрафт клиент
Необходимо понимать, что тема предназначена для тех, кто уже имеет понимание основ Java 8 и может более менее самостоятельно на ней писать.
Если вы уже потянулись создавать проект в своей IDE - не спешите этого делать. Для удобства, мы настроим и импортируем свой проект с Spring Initializr. Наш проект будет построен на Maven, поэтому смело выбираем Maven как сборщик. Далее, нам необходимо выбрать версию Spring, мы будем использовать 2.4.5. После этого, нам надо задать основную конфигурацию Maven'а, заполнять её следует используя объяснение приведённое ниже.
groupId - это общая часть пакета всех ваших проектов. Например у меня это net.ifxandy, т.к. в своих проектов я указываю пакет net.ifxandy.[проект].
artifactId - служебное название проекта, необходимое для Maven Central Repo.
Name - название проекта.
Description - небольшое описание проекта.
Package - пакет, в котором будет находится главный класс Spring-приложения. Авто-дополняется используя groupId и artifactId, но можно изменить. [!] ВНИМАНИЕ [!] Если ваш artifactId начинается с заглавной буквы - измените её в Package, иначе, это может привести к тому, что название проекта в Package будет распознаваться как название класса и вызовет некоторые проблемы и лишние заморочки.
Далее идёт поле Packaging, оно отвечает за то, во что будет собираться наш проект(формат файла), нам необходимо. чтобы проект собирался в Jar-файл, выбираем "Jar". Наконец версия Java, выбираем 8-ую.
В данном туториале мы будем использовать именно такие настройки, чтобы у всех всё было одинаково, это же пример. Но вы в своих проектах можете использовать какие хотите, если вы осознаёте и понимаете как и на что они влияют.
Теперь нам нужно добавить некоторые зависимости. Для этого есть панель справа. Нажимаем "ADD DEPENDENCY". В строке поиска вбиваем Lombok [ТЫК] - это библиотека для удобной работы над проектами основанная на аннотациях, которая автоматически дорабатывает ваш код. Она должна быть установлена у вас в IDE.
Далее, нажимаем на кнопку GENERATE снизу и скачиваем ZIP-Файл с шаблоном проекта. Осталось только импортировать проект в нашу среду разработки. Вот пример для Eclipse IDE.
File/Файл -> Import/Импорт -> Maven/Мавен -> Import an existing project/Импортировать существующий проект
И находим через Browse папку своего проекта.
И находим через Browse папку своего проекта.
Подготовка среды завершена!
2. Подготовка конфигурации
Изначально, Spring предоставляет минимум 2 способа конфигурации проекта - конфигурацию через application.properties и конфигурацию через класс аннотируемый @Configuration. Мы же совместим их по максимуму.Для этого, зайдём в main/resources в нужный файл .properties и зададим там 2 настройки. Первая - tcp.server.port=25565 отвечает за порт, на котором будет поднят сервер при запуске. Вторая - spring.main.web-environment=false отвечает за то, чтобы отключить запуск TomCat сервера(WEB обёртку Spring'а), ведь нам нужен TCP сервер.
3. Пишем серверную логику
3.1 Класс конфигурации
Самое время создать тот обещанный класс конфигурации. Ниже представлен его код и разъяснения к нему.3.1 Класс конфигурации
PHP:
@Configuration
public class TcpServerConfig {
@Value("${tcp.server.port}")
private int port;
@Bean
public AbstractServerConnectionFactory serverConnectionFactory() {
TcpNioServerConnectionFactory serverConnectionFactory = new TcpNioServerConnectionFactory(port);
serverConnectionFactory.setUsingDirectBuffers(true);
serverConnectionFactory.setSerializer(new PacketSerializer());
serverConnectionFactory.setDeserializer(new PacketDeserializer());
return serverConnectionFactory;
}
@Bean
public MessageChannel inboundChannel() {
return new DirectChannel();
}
@Bean
public TcpInboundGateway inboundGateway(AbstractServerConnectionFactory serverConnectionFactory,
MessageChannel inboundChannel) {
TcpInboundGateway tcpInboundGateway = new TcpInboundGateway();
tcpInboundGateway.setConnectionFactory(serverConnectionFactory);
tcpInboundGateway.setRequestChannel(inboundChannel);
return tcpInboundGateway;
}
}
Это - классовая конфигурация приложения, она помечается аннотацией @Configuration и находится Spring'ом автоматически. Перейдём к разбору переменных и аннотаций внутри.
Переменная port и аннотация @Value("${tcp.server.port}") необходимы для того, чтобы показать TCP серверу порт для запуска. Аннотация же, определяет, что переменная будет равна переменной из .properties файла приложения, которую мы задавали чуточку ранее.
@Bean аннотация / Бины - это всё те же объекты, но отличие составляет лишь то, что они живут и управляются Spring'ом внутри его DI-Контейнера. Почти все в Spring'е является бинами.
Всё, что аннотировано @Bean является методом настройки*, т.е. методом, который возвращает уже готовый и настроенный инстанс нужного класса. TCP в SpringIntegration построено на фабрике подключений, она управляет
Переменная port и аннотация @Value("${tcp.server.port}") необходимы для того, чтобы показать TCP серверу порт для запуска. Аннотация же, определяет, что переменная будет равна переменной из .properties файла приложения, которую мы задавали чуточку ранее.
@Bean аннотация / Бины - это всё те же объекты, но отличие составляет лишь то, что они живут и управляются Spring'ом внутри его DI-Контейнера. Почти все в Spring'е является бинами.
Всё, что аннотировано @Bean является методом настройки*, т.е. методом, который возвращает уже готовый и настроенный инстанс нужного класса. TCP в SpringIntegration построено на фабрике подключений, она управляет
3.2 Как это работает?
Здесь будет описан алгоритм работы данной системы. Для хорошей реализации всегда нужно понимать алгоритм и то, как работает ваш код.У нас алгоритм довольно прост. Есть фабрика подключений TcpConnectionFactory. При каждом подключении она создаёт, настраивает и возвращает новый инстанс подключения. Клиент посылает по подключению пакеты.
Для удобной работы, мы поднимаемся на 1 абстракцию вверх и работаем не напрямую с байтами(это было бы жуть как неудобно), поэтому мы и задавали в нашем @Bean методе-настройке ConnectionFactory сериалайзер и десериалайзер. Они то нам и помогут в этом деле.
Serializer - класс имплементирующий интерфейс Serializer<?> (в нашем случае Serializer<Packet>). В нём имеется метод serialize принимающий как аргументы сериализуемый объект (у нас это Packet) и OutputStream, в который и отправляет после сериализации результат, т.е. клиенту.
Deserializer - такой же как и Serializer класс, только имплементирует интерфейс Deserializer<?>. Только принимает он в свой метод deserialize только InputStream, а вот возвращает уже сериализуемый класс.
Любой пакет от клиента сначала проходить через Deserializer и превращается в наш сообственный интерфейс Packet, после этого он попадает в TcpEndpoint. Это так скажем диспетчер, он определяет как и почему обрабатывать, что либо. У нас он будет состоять из Сервиса-Обработчика и метода, принимающего Packet класс и возвращающего ответ (или null, если ответа нет).
Сервис-Обработчик - класс, аннотированый как @Service. Чаще всего его реализуют используя интерфейс(без аннотации) и класс, унаследованный от него(имплементацию, которую уже стоить пометить аннотацией). Spring сам находит и обрабатывает его.
TcpEndpoint вызывает обработчик, получает ответ и возвращает его. Далее, наш экземпляр Packet'а проходит через Serializer, коим и отправляется клиенту.
Вторая часть в комментариях. Coming Soon...
Последнее редактирование:
