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

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

Тема в разделе "Веб-обвязки и лаунчеры", создана пользователем Racvol, 21 дек 2012.

  1. Автор темы
    Racvol

    Racvol Старожил Пользователь

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

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

    Преимущества:
    1. Простота разработки
    2. Кросс платформенный код
    Недостатки:
    1. Промежуточный код, позволяет любому без особых усилий посмотреть код лаунчера и изменить его.
    2. Невозможность интеграции серьезной защиты (вытекает из первого недостатка)
    Реализация:
    За основу к данному примеру был взят microLauncher написанный @DmitriyMX
    , реализацию обертки MinecraftApplet из кода ниже можно посмотреть в исходниках​

    Код:
        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:
    Существует еще один менее гибкий метод, вместо того чтобы создавать класс обертку можно вызвать статическую функцию 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 -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
    Отсюда реализация на С/С++
    Код:
    #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/
     
    Hephest, DavidShabaev, saharin94 и 11 другим нравится это.
  2. Хостинг MineCraft
    <
  3. Klever

    Klever Старожил Пользователь

    Баллы:
    103
    Какой старательный! ^_^
     
    Hephest, Пароль123456789, CryBot и ещё 1-му нравится это.
  4. alexandrage

    alexandrage Администратор

    Баллы:
    173
    Skype:
    alexandr0116
    А не проще использовать переменные %programfiles% и %appdata%
    и патом на jre8 почти никто не сидит еще.
     
  5. Автор темы
    Racvol

    Racvol Старожил Пользователь

    Баллы:
    123
    Эти переменные могут быть переопределены что очень опасно с точки зрения безопасности, но не в этом суть, да конечно их можно использовать, данная статья не претендует на самую лучшую реализацию, а просто как пример запуска игры различными методиками
     
  6. hummer

    hummer Старожил Пользователь

    Баллы:
    123
    Skype:
    bond_russia

    Ну зачем так?
    Данный метод заставляет программу зависнуть (всеми известная надпись Программа не отвечает)
    Достаточно process.exec();
     
    Goldenix нравится это.
  7. Автор темы
    Racvol

    Racvol Старожил Пользователь

    Баллы:
    123
    Зависаю тока GUI тк они не могут обрабатывать вызовы к оконной процедуре, у CUI нет окна он не виснет.
    WTF? process.exec();
     
  8. hummer

    hummer Старожил Пользователь

    Баллы:
    123
    Skype:
    bond_russia
    exec() выполняет туже роль что и sleep но программа не зависает.
     
  9. Автор темы
    Racvol

    Racvol Старожил Пользователь

    Баллы:
    123
    Откуда этот класс process? Припоминаю такое в Qt было
     
  10. hummer

    hummer Старожил Пользователь

    Баллы:
    123
    Skype:
    bond_russia
    process это Объект полученный в результате использования функции CreateProcess

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

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

    Правдо в этом коде есть множество ньюансов которые не стал публиковать.
    Это же не уроки по с++ ;)
     
    Сникерсни нравится это.
  11. Автор темы
    Racvol

    Racvol Старожил Пользователь

    Баллы:
    123
    Не знаю может ты не заметил, но где ты увидел что я использую библиотеку 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 (в коде видно) что является просто информацией об созданном процессе
     
  12. hummer

    hummer Старожил Пользователь

    Баллы:
    123
    Skype:
    bond_russia
    Дело не в Qt - Это FrameWork Того же с++
    я когда кодил на C# под веб, там тоже есть тот же вызов exec()
    По этому это единая функция для C/с++

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

    почитай про весь класс Process, примеры посмотри. И может поймешь меня..
     
  13. Автор темы
    Racvol

    Racvol Старожил Пользователь

    Баллы:
    123
    С# это не С/C++, покажи мне заголовочный файл где определена функция exec()
     
  14. hummer

    hummer Старожил Пользователь

    Баллы:
    123
    Skype:
    bond_russia
    С# я просто так написал без решетки просто у меня проблемы с этой решоткой поэтому я пишу C как C#
    Разводить трепло не будем, ты главное почитай про классы..
     
  15. Автор темы
    Racvol

    Racvol Старожил Пользователь

    Баллы:
    123
    :why: Где-же мне взять этот могучий класс, в STL про него не слухом не духом, Страуструп молчит, Рихтер на звонки не отвечает
     
  16. hummer

    hummer Старожил Пользователь

    Баллы:
    123
    Skype:
    bond_russia
    Документации msdn.
     
  17. Автор темы
    Racvol

    Racvol Старожил Пользователь

    Баллы:
    123
    Ну ок, давай ссылку, или скажи в каком заголовочном файле он определен
     
  18. Cs_nik

    Cs_nik Активный участник Пользователь

    Баллы:
    78
    Апну, а то искать очень долго.
     
  19. Antivirus1221

    Antivirus1221 Активный участник Пользователь

    Баллы:
    93
    Skype:
    mr_samar
    Имя в Minecraft:
    Samar
    А как выделить оперативную память в апплет (mineApplet java) ?
     
  20. Автор темы
    Racvol

    Racvol Старожил Пользователь

    Баллы:
    123
    Что то я не припомню строчку кода, вопрос решается в одну строчку вызовом функции из java библиотеки. Или при запуске лаунчера указывать параметры -Xms и -Xmx
     
    Antivirus1221 нравится это.
  21. Teremok

    Teremok Активный участник

    Баллы:
    63
    А я, товарищи, Delphi'ец...
     
    _Klesh_ нравится это.

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