Войти или зарегистрироваться
  • Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.
  • Данный раздел создан исключительно для релизов! Вопросы по лаунчеру или обвязке задавайте ТОЛЬКО в соответсвующей теме автора. Любые другие темы будут удалены, а авторы понесут наказание.

Способы запуска клиента игры из Лаунчера Часть 1

Racvol

Старожил
Пользователь
Баллы
123
I Для кого предназначена статья​
Данная статья предназначена в первую очередь для Разработчиков и людей собирающихся разрабатывать собственный лаунчер.

II Основные способы запуска клиента из Лаунчера​
  • Запуск клиента игры из Java Launcher
  • Запуск клиента игры с использованием Java.exe
  • Запуск клиента игры с собственной реализацией Java.exe на низкоуровневом языке С/C++
III a) Запуск клиента игры из Java Launcher​

Преимущества:
  1. Простота разработки
  2. Кросс платформенный код
Недостатки:
  1. Промежуточный код, позволяет любому без особых усилий посмотреть код лаунчера и изменить его.
  2. Невозможность интеграции серьезной защиты (вытекает из первого недостатка)
Реализация:
За основу к данному примеру был взят microLauncher написанный @DmitriyMX​
, реализацию обертки MinecraftApplet из кода ниже можно посмотреть в исходниках​
​
Java:
    public static void main(String[] args) {
        try{
            //Узнаем путь до bin папки.
            String mc_bin_path = getWorkPath("DmitriyMX").toString() + File.separator + "bin" + File.separator;
            //Генерируем url-пути для 4х основных файлов
            //(я не стал ради 4х файлов делать цикл)
            URL[] urls = new URL[4];
            urls[0] = new File(mc_bin_path, "minecraft.jar").toURI().toURL();
            urls[1] = new File(mc_bin_path, "lwjgl.jar").toURI().toURL();
            urls[2] = new File(mc_bin_path, "jinput.jar").toURI().toURL();
            urls[3] = new File(mc_bin_path, "lwjgl_util.jar").toURI().toURL();
 
            //Создаем класс-обёртку для net.minecraft.client.MinecraftApplet
            MinecraftApplet mineApplet = new MinecraftApplet(mc_bin_path, urls);
            //Указываем параметры(собственно из-за них и писалать обёртка)
            mineApplet.customParameters.put("stand-alone", "true");
            mineApplet.customParameters.put("username", "Player");
 
            //Создаем фрейм
            JFrame frame = new JFrame();
            frame.setTitle("Minecraft");
            frame.setSize(640, 480);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new BorderLayout());
            frame.add(mineApplet, BorderLayout.CENTER);
            frame.validate();
            frame.setVisible(true);
            //Только после показа окна нужно инициализировать mineApplet
            //Связано это с тем, что до того как окно нарисуется, функции getWidth() и getHeight() у mineApplet возвращают 0
            mineApplet.init();
            mineApplet.start();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
​




Автор уже достаточно неплохо задокументировал main функцию, основная идея состоит в том чтобы создать Applet класс обертку над стандартным классом net.minecraft.client.MinecraftApplet из файла minecraft.jar, и в этот класс добавить собственные параметры для аплейта такие как:
Код:
mineApplet.customParameters.put("stand-alone", "true");
mineApplet.customParameters.put("username", "Player");

Все возможные параметры для minecraftApplet приведены в таблице ниже взяты из версии Minecraft 1.4.6 от 20.12.12:
Ключ-----------------Значение----------Коментарий
"username" ----------"UserName"-------Ник пользователя
"stand-alone"---------"true"или"false"---unknown
"demo"----------------"true"или"false"---Этот параметр недавно появился
"fullscreen"------------"true"или"false"---Задает полноэкранные режим при запуске
"sessionid"-------------"-"------------------Необходим при аунтификации на сервере
"server" ---------------"127.0.0.1"---------К данному IP будет произведено подключение при запуске
"port"------------------"25555-------------и его порт
Существует еще один менее гибкий метод, вместо того чтобы создавать класс обертку можно вызвать статическую функцию main из minecraft.jar она находится в классе net.minecraft.client.Minecraft и принимает масив строк.

Возможные значения для main функции из net.minecraft.client.Minecraft UserName SessionId [-demo || --applet || --password]
Первый параметр Имя пользователя, второй сессия, далее идет взаимоисключающие атрибуты
За что отвечаю атрибуты [-demo || --applet || --password] мне не известно, эти атрибуты появились недавно и их еше предстоит изучить.

III б) Запуск клиента игры с использованием Java.exe​

Запустить клиент из низкоуровневого языка можно с использованием Java.exe, это основной метод большинства, если не всех, лаунчеров написанных на низкоуровнивых языках

Преимущества:
  1. Низкоуровневые языки не позволяют с такой простотой декомпилировать их бинарные файлы как языки с промежуточным кодом, по сути дела их можно тока дисасемблировать, что гарантирует сохранность исходного кода.
  2. Повышенная безопасность
Недостатки​
  1. Необходимо запускать стотонную программу Java.exe
  2. Сложность в разработке
  3. Необходимо прибегать к дополнительным усилиям для приобретения кросс платформенного кода
  4. Самый существенный недостаток состоит в том что нельзя задать параметры описанные в предыдущем разделе кроме тех что принимает net.minecraft.client.Minecraft в функции main
Реализация:​
Весь код написан мной на С++ с использованием WinAPI ​
​
Чтобы реализовать данный метод необходимы следующие действия​
  • Определить где установлена Java (можно надеяться на переменную окружения PATH)
  • Создать новый процесс Java.exe и передать ей параметры запуска
Строка запуска из консоли через Java.exe выглядит примерно седлающим образом​
Java:
java -Djava.class.path=%APPDATA%\.minecraft\bin\lwjgl.jar;%APPDATA%\.minecraft\bin\jinput.jar;%APPDATA%\.minecraft\bin\lwjgl_util.jar;%APPDATA%\.minecraft\bin\minecraft.jar; -Djava.library.path=%APPDATA%\.minecraft\bin\natives net.minecraft.client.Minecraft UserName SessionId [-demo || --applet || --password]
В -Djava.class.path указывается путь до jar файлов игры
В -Djava.library.path указывается путь до нативных библиотеки
Далее вызывается main функция из net.minecraft.client.Minecraft
Отсюда реализация на С/С++
Java:
#include <windows.h>
#include <tchar.h>
 
#define JAVA_HOME "C:\\Program Files\\Java\\jre8"
#define GAME_PATH "C:\\Users\\Алексей\\AppData\\Roaming\\.minecraft"
 
int _tmain(int argc, _TCHAR* argv[])
{
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;
    //Указываем VM где искать классы и нативные библиотеки
    LPTSTR commLine =_T("-Djava.class.path=")    _T(GAME_PATH) _T("\\bin\\lwjgl_util.jar;")
                                                _T(GAME_PATH) _T("\\bin\\lwjgl.jar;")
                                                _T(GAME_PATH) _T("\\bin\\jinput.jar;")
                                                _T(GAME_PATH) _T("\\bin\\minecraft.jar;")
                      _T(" -Djava.library.path=") _T(GAME_PATH) _T("\\bin\\natives net.minecraft.client.Minecraft MyName MySessiaId");
    //Создаем новый процесс
    CreateProcess(TEXT(JAVA_HOME) TEXT("\\bin\\java.exe"), commLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
 
    Sleep(100000);
    return 0;
}

Можно также объединить предыдущие два способа чтобы достичь большей гибкости при реализации Лаунчера на низкоуровневом языке, однако я считаю этот метод достаточно плохим тк запуск игры все равно придется писать в java которое также без труда декомпилируется, + у вас будет целых два Лаунчера вместо одного что очень некрасиво.

В седлающем разделе описан способ снимавший основные ограничения с низкоуровневого языка

III в) Запуск клиента игры с собственной реализацией Java.exe на низкоуровневом языке С/C++​
​
В предыдущем разделе был описан пример где вызывалась java.exe однако этот бинарник является низкоуровневым, а следовательно и мы можем реализовать свой собственный бинарник без вызова java.exe, в седлающей реализации мне удалось снять основное ограничения которое описаны в предыдущем разделе, мне удалось создать java классы в коде С++ и вызывать Java методы и классы из C++, перспектив у данного метода очень много, однако я не видел ни одного лаунчера его реализующего.

http://rubukkit.org/threads/Способ-запуска-клиента-игры-из-Лаунчера-Часть-2.26970/
 
Эти переменные могут быть переопределены что очень опасно с точки зрения безопасности, но не в этом суть, да конечно их можно использовать, данная статья не претендует на самую лучшую реализацию, а просто как пример запуска игры различными методиками
 

Ну зачем так?
Данный метод заставляет программу зависнуть (всеми известная надпись Программа не отвечает)
Достаточно process.exec();
 
Зависаю тока GUI тк они не могут обрабатывать вызовы к оконной процедуре, у CUI нет окна он не виснет.
WTF? process.exec();
 
Откуда этот класс process? Припоминаю такое в Qt было
 
process это Объект полученный в результате использования функции CreateProcess

Если написать на языке Qt то выглядеть это будет так.

Код:
QProcces game = new QProcces(this);
game.start(траляляля);
game.exec();
То есть после того как игра запуститься будет работать наш называемый exec() И код который под ним не выполниться.
Но игре стоит закрыться exec() умирает и выполняется код который стоял после exec();
Данный пример очень ярко выражен в много потоковом загрузчике.

Правдо в этом коде есть множество ньюансов которые не стал публиковать.
Это же не уроки по с++ ;)
 
Не знаю может ты не заметил, но где ты увидел что я использую библиотеку Qt ?
BOOL CreateProcess(
PCTSTR pszApplicationName,
PTSTR pszCommandLine,
PSECURITY_ATTRIBUTES psaProcess,
PSECURITY.ATTRIBUTES psaThread,
BOOL bInheritHandles,
DWORD fdwCreate,
PVOID pvEnvironment,
PCTSTR pszCurDir,
PSTARTUPINFO psiStartInfo,
PPROCESS_INFORMATION ppiProcInfo);
Все что возвращает функция CreateProcess это BOOL говорящая об успехе операции, также она заполняет структуру PPROCESS_INFORMATION (в коде видно) что является просто информацией об созданном процессе
 
Дело не в Qt - Это FrameWork Того же с++
я когда кодил на C# под веб, там тоже есть тот же вызов exec()
По этому это единая функция для C/с++

Все что возвращает функция CreateProcess
все правильно он возвращает что в Qt что и у тебя это bool, но как я говорил это уже нюансы которые я не писал..

почитай про весь класс Process, примеры посмотри. И может поймешь меня..
 
С# это не С/C++, покажи мне заголовочный файл где определена функция exec()
 
:why: Где-же мне взять этот могучий класс, в STL про него не слухом не духом, Страуструп молчит, Рихтер на звонки не отвечает
 
Ну ок, давай ссылку, или скажи в каком заголовочном файле он определен
 
А как выделить оперативную память в апплет (mineApplet java) ?
 
Что то я не припомню строчку кода, вопрос решается в одну строчку вызовом функции из java библиотеки. Или при запуске лаунчера указывать параметры -Xms и -Xmx
 

Поделиться этой страницей

Назад
Верх