Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdcd3ea7c1 |
No files matched your search
@@ -1,280 +0,0 @@
|
|||||||
# Сборка BiLauncher под Windows, Linux и macOS и публикация в Gitea Releases.
|
|
||||||
#
|
|
||||||
# push тега vX.Y.Z (или vX.Y.Z-rc1 → pre-release):
|
|
||||||
# create-release создаёт черновик релиза → три сборки прикладывают к нему файлы →
|
|
||||||
# publish добавляет SHA256SUMS.txt и снимает флаг черновика. Если какая-то сборка
|
|
||||||
# упала, релиз остаётся черновиком и пользователям не виден.
|
|
||||||
# Ручной запуск (workflow_dispatch): те же сборки, но результат — артефакты прогона,
|
|
||||||
# релиз не создаётся.
|
|
||||||
#
|
|
||||||
# Пути к Qt на раннерах задаются в их config.yaml (runner.envs): QT_ROOT — kit Qt,
|
|
||||||
# QT_TOOLS — папка Tools из Qt Online Installer (там CMake и Ninja).
|
|
||||||
# Секрет RELEASE_TOKEN — PAT с правом repository: write.
|
|
||||||
|
|
||||||
name: release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags: ["v*"]
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
create-release:
|
|
||||||
runs-on: linux
|
|
||||||
outputs:
|
|
||||||
version: ${{ steps.meta.outputs.version }}
|
|
||||||
tag: ${{ steps.meta.outputs.tag }}
|
|
||||||
release_id: ${{ steps.release.outputs.id }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- id: meta
|
|
||||||
name: Версия из CMakeLists.txt и сверка с тегом
|
|
||||||
run: |
|
|
||||||
version=$(sed -nE 's/^project\(BiLauncher VERSION ([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' CMakeLists.txt)
|
|
||||||
[ -n "$version" ] || { echo "Не нашёл project(BiLauncher VERSION ...)"; exit 1; }
|
|
||||||
tag=""
|
|
||||||
if [ "${GITHUB_REF_TYPE}" = "tag" ]; then
|
|
||||||
tag="${GITHUB_REF_NAME}"
|
|
||||||
base="${tag#v}"; base="${base%%-*}"
|
|
||||||
if [ "$base" != "$version" ]; then
|
|
||||||
echo "Тег $tag не совпадает с версией $version в CMakeLists.txt"; exit 1
|
|
||||||
fi
|
|
||||||
version="${tag#v}"
|
|
||||||
fi
|
|
||||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "Версия: $version, тег: ${tag:-нет}"
|
|
||||||
|
|
||||||
- id: release
|
|
||||||
name: Черновик релиза
|
|
||||||
if: steps.meta.outputs.tag != ''
|
|
||||||
env:
|
|
||||||
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
TAG: ${{ steps.meta.outputs.tag }}
|
|
||||||
run: |
|
|
||||||
# Описание релиза — раздел CHANGELOG.md для этой версии
|
|
||||||
base="${TAG#v}"; base="${base%%-*}"
|
|
||||||
notes=$(awk -v v="$base" '
|
|
||||||
/^## \[/ { if (on) exit; if (index($0, "[" v "]")) { on=1; next } }
|
|
||||||
on' CHANGELOG.md)
|
|
||||||
prerelease=false; case "$TAG" in *-*) prerelease=true;; esac
|
|
||||||
body=$(python3 -c 'import json,sys; print(json.dumps({"tag_name":sys.argv[1],"name":"BiLauncher "+sys.argv[1],"body":sys.argv[2],"draft":True,"prerelease":sys.argv[3]=="true"}))' \
|
|
||||||
"$TAG" "$notes" "$prerelease")
|
|
||||||
id=$(curl -fsS -X POST "$API/releases" \
|
|
||||||
-H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
|
||||||
-d "$body" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')
|
|
||||||
echo "id=$id" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "Создан черновик релиза $TAG (id $id)"
|
|
||||||
|
|
||||||
build-linux:
|
|
||||||
needs: create-release
|
|
||||||
runs-on: linux
|
|
||||||
env:
|
|
||||||
VERSION: ${{ needs.create-release.outputs.version }}
|
|
||||||
RELEASE_ID: ${{ needs.create-release.outputs.release_id }}
|
|
||||||
outputs:
|
|
||||||
sums: ${{ steps.pack.outputs.sums }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Сборка
|
|
||||||
run: |
|
|
||||||
export PATH="$QT_TOOLS/CMake/bin:$QT_TOOLS/Ninja:$PATH"
|
|
||||||
rm -rf build AppDir dist
|
|
||||||
# LIBDIR=lib: zlibreference.cpp ищет libz рядом, в ../lib/BiLauncher,
|
|
||||||
# а на Ubuntu по умолчанию был бы lib/x86_64-linux-gnu.
|
|
||||||
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-DCMAKE_PREFIX_PATH="$QT_ROOT" \
|
|
||||||
-DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib
|
|
||||||
# На ВМ 6 ГБ памяти: без ограничения 42 параллельных компилятора уходят в OOM.
|
|
||||||
cmake --build build -j 8
|
|
||||||
cmake --install build --prefix "$PWD/AppDir/usr"
|
|
||||||
|
|
||||||
- id: pack
|
|
||||||
name: AppImage и tar.gz
|
|
||||||
run: |
|
|
||||||
mkdir -p dist
|
|
||||||
cp AppDir/usr/share/applications/bilauncher.desktop AppDir/
|
|
||||||
cp AppDir/usr/share/icons/hicolor/256x256/apps/bilauncher.png AppDir/
|
|
||||||
ln -sf usr/bin/BiLauncher AppDir/AppRun
|
|
||||||
ARCH=x86_64 appimagetool --no-appstream AppDir "dist/BiLauncher-$VERSION-x86_64.AppImage"
|
|
||||||
cp -a AppDir/usr "BiLauncher-$VERSION"
|
|
||||||
tar -czf "dist/BiLauncher-$VERSION-linux-x86_64.tar.gz" "BiLauncher-$VERSION"
|
|
||||||
rm -rf "BiLauncher-$VERSION"
|
|
||||||
ls -lh dist
|
|
||||||
echo "sums=$(cd dist && sha256sum * | base64 -w0)" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Загрузка в релиз
|
|
||||||
if: env.RELEASE_ID != ''
|
|
||||||
env:
|
|
||||||
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
run: |
|
|
||||||
for f in dist/*; do
|
|
||||||
curl -fsS -X POST -H "Authorization: token $TOKEN" \
|
|
||||||
-F "attachment=@$f" "$API/releases/$RELEASE_ID/assets?name=$(basename "$f")" > /dev/null
|
|
||||||
echo "Загружен $(basename "$f")"
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Артефакты прогона
|
|
||||||
if: env.RELEASE_ID == ''
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: linux
|
|
||||||
path: dist/
|
|
||||||
|
|
||||||
build-windows:
|
|
||||||
needs: create-release
|
|
||||||
runs-on: windows
|
|
||||||
env:
|
|
||||||
VERSION: ${{ needs.create-release.outputs.version }}
|
|
||||||
RELEASE_ID: ${{ needs.create-release.outputs.release_id }}
|
|
||||||
outputs:
|
|
||||||
sums: ${{ steps.build.outputs.sums }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- id: build
|
|
||||||
name: Сборка, установщик и portable-архив
|
|
||||||
shell: powershell
|
|
||||||
run: |
|
|
||||||
$ErrorActionPreference = "Stop"
|
|
||||||
# Короткие пути: дерево WebEngine легко вылезает за MAX_PATH.
|
|
||||||
$build = "C:\r\bl-build"; $stage = "C:\r\bl-stage"; $dist = "$PWD\dist"
|
|
||||||
Remove-Item -Recurse -Force $build, $stage, $dist -ErrorAction SilentlyContinue
|
|
||||||
|
|
||||||
$vs = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * `
|
|
||||||
-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
|
|
||||||
Import-Module "$vs\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
|
|
||||||
Enter-VsDevShell -VsInstallPath $vs -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64"
|
|
||||||
$env:PATH = "$env:QT_TOOLS\CMake_64\bin;$env:QT_TOOLS\Ninja;$env:PATH"
|
|
||||||
|
|
||||||
cmake -S . -B $build -G Ninja -DCMAKE_BUILD_TYPE=Release "-DCMAKE_PREFIX_PATH=$env:QT_ROOT"
|
|
||||||
if ($LASTEXITCODE) { throw "cmake configure" }
|
|
||||||
cmake --build $build
|
|
||||||
if ($LASTEXITCODE) { throw "cmake build" }
|
|
||||||
cmake --install $build --prefix $stage
|
|
||||||
if ($LASTEXITCODE) { throw "cmake install" }
|
|
||||||
|
|
||||||
New-Item -ItemType Directory -Force $dist | Out-Null
|
|
||||||
& "$env:ISCC_DIR\ISCC.exe" /Q "/DAppVersion=$env:VERSION" "/DSourceDir=$stage" "/DOutputDir=$dist" packaging\windows\BiLauncher.iss
|
|
||||||
if ($LASTEXITCODE) { throw "iscc" }
|
|
||||||
|
|
||||||
# Portable: то же дерево, что ставит установщик, без vc_redist
|
|
||||||
# (в portable-варианте среда выполнения MSVC должна уже стоять в системе).
|
|
||||||
Remove-Item "$stage\bin\vc_redist.x64.exe" -ErrorAction SilentlyContinue
|
|
||||||
$portable = "C:\r\BiLauncher-$env:VERSION"
|
|
||||||
Remove-Item -Recurse -Force $portable -ErrorAction SilentlyContinue
|
|
||||||
Move-Item $stage $portable
|
|
||||||
# Системный bsdtar по полному пути: в PATH раннера раньше стоит GNU tar из Git,
|
|
||||||
# который не умеет zip и принимает «C:» за имя удалённого хоста.
|
|
||||||
& "$env:SystemRoot\System32\tar.exe" -a -c -f "$dist\BiLauncher-$env:VERSION-win64-portable.zip" -C C:\r "BiLauncher-$env:VERSION"
|
|
||||||
if ($LASTEXITCODE) { throw "zip" }
|
|
||||||
Remove-Item -Recurse -Force $portable
|
|
||||||
|
|
||||||
Get-ChildItem $dist | Format-Table Name, Length
|
|
||||||
$sums = Get-ChildItem $dist | ForEach-Object {
|
|
||||||
"{0} {1}" -f (Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLower(), $_.Name }
|
|
||||||
$b64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes(($sums -join "`n") + "`n"))
|
|
||||||
# Не Out-File: PowerShell 5.1 пишет UTF-8 с BOM, и имя первой переменной ломается.
|
|
||||||
[IO.File]::AppendAllText($env:GITHUB_OUTPUT, "sums=$b64`n")
|
|
||||||
|
|
||||||
- name: Загрузка в релиз
|
|
||||||
if: env.RELEASE_ID != ''
|
|
||||||
shell: powershell
|
|
||||||
env:
|
|
||||||
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
run: |
|
|
||||||
foreach ($f in Get-ChildItem dist) {
|
|
||||||
curl.exe -fsS -X POST -H "Authorization: token $env:TOKEN" `
|
|
||||||
-F "attachment=@$($f.FullName)" "$env:API/releases/$env:RELEASE_ID/assets?name=$($f.Name)" | Out-Null
|
|
||||||
if ($LASTEXITCODE) { throw "Не удалось загрузить $($f.Name)" }
|
|
||||||
"Загружен $($f.Name)"
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Артефакты прогона
|
|
||||||
if: env.RELEASE_ID == ''
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: windows
|
|
||||||
path: dist/
|
|
||||||
|
|
||||||
build-macos:
|
|
||||||
needs: create-release
|
|
||||||
runs-on: macos
|
|
||||||
env:
|
|
||||||
VERSION: ${{ needs.create-release.outputs.version }}
|
|
||||||
RELEASE_ID: ${{ needs.create-release.outputs.release_id }}
|
|
||||||
outputs:
|
|
||||||
sums: ${{ steps.pack.outputs.sums }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Сборка (universal, arm64 + x86_64)
|
|
||||||
run: |
|
|
||||||
export PATH="$QT_TOOLS/CMake/CMake.app/Contents/bin:$QT_TOOLS/Ninja:$PATH"
|
|
||||||
rm -rf build stage dist dmgroot
|
|
||||||
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-DCMAKE_PREFIX_PATH="$QT_ROOT" \
|
|
||||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
|
|
||||||
cmake --build build
|
|
||||||
cmake --install build --prefix "$PWD/stage"
|
|
||||||
|
|
||||||
- id: pack
|
|
||||||
name: Ad-hoc подпись и DMG
|
|
||||||
run: |
|
|
||||||
# Без Developer ID: ad-hoc подпись нужна, чтобы приложение вообще
|
|
||||||
# запускалось на Apple Silicon; Gatekeeper всё равно спросит подтверждение.
|
|
||||||
codesign --force --deep --sign - stage/BiLauncher.app
|
|
||||||
codesign --verify --deep --strict stage/BiLauncher.app
|
|
||||||
mkdir -p dmgroot dist
|
|
||||||
cp -R stage/BiLauncher.app dmgroot/
|
|
||||||
ln -s /Applications dmgroot/Applications
|
|
||||||
hdiutil create -volname "BiLauncher" -srcfolder dmgroot -ov -format UDZO \
|
|
||||||
"dist/BiLauncher-$VERSION-macOS-universal.dmg"
|
|
||||||
rm -rf dmgroot
|
|
||||||
ls -lh dist
|
|
||||||
echo "sums=$(cd dist && shasum -a 256 * | base64 | tr -d '\n')" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Загрузка в релиз
|
|
||||||
if: env.RELEASE_ID != ''
|
|
||||||
env:
|
|
||||||
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
run: |
|
|
||||||
for f in dist/*; do
|
|
||||||
curl -fsS -X POST -H "Authorization: token $TOKEN" \
|
|
||||||
-F "attachment=@$f" "$API/releases/$RELEASE_ID/assets?name=$(basename "$f")" > /dev/null
|
|
||||||
echo "Загружен $(basename "$f")"
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Артефакты прогона
|
|
||||||
if: env.RELEASE_ID == ''
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: macos
|
|
||||||
path: dist/
|
|
||||||
|
|
||||||
publish:
|
|
||||||
needs: [create-release, build-linux, build-windows, build-macos]
|
|
||||||
if: needs.create-release.outputs.release_id != ''
|
|
||||||
runs-on: linux
|
|
||||||
env:
|
|
||||||
RELEASE_ID: ${{ needs.create-release.outputs.release_id }}
|
|
||||||
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
steps:
|
|
||||||
- name: SHA256SUMS.txt и публикация
|
|
||||||
run: |
|
|
||||||
{
|
|
||||||
echo "${{ needs.build-windows.outputs.sums }}" | base64 -d
|
|
||||||
echo "${{ needs.build-linux.outputs.sums }}" | base64 -d
|
|
||||||
echo "${{ needs.build-macos.outputs.sums }}" | base64 -d
|
|
||||||
} | tr -d '\r' | sed '/^$/d' > SHA256SUMS.txt
|
|
||||||
cat SHA256SUMS.txt
|
|
||||||
curl -fsS -X POST -H "Authorization: token $TOKEN" \
|
|
||||||
-F "attachment=@SHA256SUMS.txt" "$API/releases/$RELEASE_ID/assets?name=SHA256SUMS.txt" > /dev/null
|
|
||||||
curl -fsS -X PATCH -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
|
||||||
-d '{"draft": false}' "$API/releases/$RELEASE_ID" > /dev/null
|
|
||||||
echo "Релиз опубликован"
|
|
||||||
@@ -1,12 +1,51 @@
|
|||||||
# Changelog
|
# First Level Heading
|
||||||
|
|
||||||
## [1.0.0] — 2026-10-07
|
Paragraph.
|
||||||
### Добавлено
|
|
||||||
- Настройки запуска Minecraft
|
## Second Level Heading
|
||||||
- Автоматическая загрузка версий java из предложенного списка
|
|
||||||
- Система хранения сборок, автоматического скачивания версий игры из меню и модлоадеры к каждой версии
|
Paragraph.
|
||||||
- Сохранение сборок в zip формате и отображение в списке
|
|
||||||
- Система сезонных сборок: полная автоматизация в один клик
|
- bullet
|
||||||
- Авторизация через ely.by и\или лицензию, с возможностью работы скинов
|
+ other bullet
|
||||||
### Исправлено
|
* another bullet
|
||||||
- UI фиксы
|
* child bullet
|
||||||
|
|
||||||
|
1. ordered
|
||||||
|
2. next ordered
|
||||||
|
|
||||||
|
### Third Level Heading
|
||||||
|
|
||||||
|
Some *italic* and **bold** text and `inline code`.
|
||||||
|
|
||||||
|
An empty line starts a new paragraph.
|
||||||
|
|
||||||
|
Use two spaces at the end
|
||||||
|
to force a line break.
|
||||||
|
|
||||||
|
A horizontal ruler follows:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Add links inline like [this link to the Qt homepage](https://www.qt.io),
|
||||||
|
or with a reference like [this other link to the Qt homepage][1].
|
||||||
|
|
||||||
|
Add code blocks with
|
||||||
|
four spaces at the front.
|
||||||
|
|
||||||
|
> A blockquote
|
||||||
|
> starts with >
|
||||||
|
>
|
||||||
|
> and has the same paragraph rules as normal text.
|
||||||
|
|
||||||
|
First Level Heading in Alternate Style
|
||||||
|
======================================
|
||||||
|
|
||||||
|
Paragraph.
|
||||||
|
|
||||||
|
Second Level Heading in Alternate Style
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
Paragraph.
|
||||||
|
|
||||||
|
[1]: https://www.qt.io
|
||||||
@@ -70,12 +70,8 @@ qt_add_resources(BiLauncher "appicon"
|
|||||||
icons/icon_512x512@2x.png
|
icons/icon_512x512@2x.png
|
||||||
)
|
)
|
||||||
|
|
||||||
# OUTPUT_DIRECTORY: по умолчанию модуль с URI BiLauncher кладёт qmldir в
|
|
||||||
# ${CMAKE_BINARY_DIR}/BiLauncher — на Linux это имя занято самим исполняемым
|
|
||||||
# файлом (у него нет расширения), и линковка падает с «Is a directory».
|
|
||||||
qt_add_qml_module(BiLauncher
|
qt_add_qml_module(BiLauncher
|
||||||
URI BiLauncher
|
URI BiLauncher
|
||||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/qml/BiLauncher"
|
|
||||||
SOURCES
|
SOURCES
|
||||||
localization.h
|
localization.h
|
||||||
localization.cpp
|
localization.cpp
|
||||||
@@ -131,9 +127,12 @@ qt_add_qml_module(BiLauncher
|
|||||||
${LAUNCHER_MSA_QML_FILES}
|
${LAUNCHER_MSA_QML_FILES}
|
||||||
RESOURCES images/Folder/Folder_Active.svg images/Folder/Folder_Idle.svg images/Folder/Folder_Pressed.svg images/Options/Options_active.svg images/Options/Options_Idle.svg images/Options/Options_Pressed.svg images/Play_Button/Play_Active.svg images/Play_Button/Play_Idle.svg images/Play_Button/Play_pressed.svg images/Profile_Box/Asset_23.jpg images/Profile_Box/Asset_23.svg images/Profile_Box/Asset_24.jpg images/Profile_Box/Asset_24.svg images/Profile_Box/Kishka_Profile_Active.svg images/Profile_Box/Kishka_Profile_Idle.svg images/Profile_Box/Kishka_Profile_open.svg images/Scroll/Scroll_Lever.svg images/Scroll/Scroll_palka.svg images/Version_box/Kishka_Profile_Open.svg images/Version_box/Kishka_Ver_Active.svg images/Version_box/Kishka_Ver_idle.svg images/Trash.svg images/Pencil.svg images/GovuztTW8AAHqBf.jpeg images/photo_2025-12-16_15-04-17.jpg images/photo_2025-12-21_02-30-09.jpg i18n/translations.json
|
RESOURCES images/Folder/Folder_Active.svg images/Folder/Folder_Idle.svg images/Folder/Folder_Pressed.svg images/Options/Options_active.svg images/Options/Options_Idle.svg images/Options/Options_Pressed.svg images/Play_Button/Play_Active.svg images/Play_Button/Play_Idle.svg images/Play_Button/Play_pressed.svg images/Profile_Box/Asset_23.jpg images/Profile_Box/Asset_23.svg images/Profile_Box/Asset_24.jpg images/Profile_Box/Asset_24.svg images/Profile_Box/Kishka_Profile_Active.svg images/Profile_Box/Kishka_Profile_Idle.svg images/Profile_Box/Kishka_Profile_open.svg images/Scroll/Scroll_Lever.svg images/Scroll/Scroll_palka.svg images/Version_box/Kishka_Profile_Open.svg images/Version_box/Kishka_Ver_Active.svg images/Version_box/Kishka_Ver_idle.svg images/Trash.svg images/Pencil.svg images/GovuztTW8AAHqBf.jpeg images/photo_2025-12-16_15-04-17.jpg images/photo_2025-12-21_02-30-09.jpg i18n/translations.json
|
||||||
RESOURCES images/launcherBackground.png
|
RESOURCES images/launcherBackground.png
|
||||||
RESOURCES images/launcherBackground2static.jpg
|
RESOURCES images/launcherBackground2.mp4 images/launcherBackground2static.jpg
|
||||||
RESOURCES CHANGELOG.md
|
RESOURCES CHANGELOG.md
|
||||||
RESOURCES LICENSE
|
RESOURCES LICENSE
|
||||||
|
RESOURCES icons/icon.rc
|
||||||
|
RESOURCES icons/icon.rc.in
|
||||||
|
RESOURCES icons/icon.rc
|
||||||
RESOURCES README.md
|
RESOURCES README.md
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
// Комбобокс в общем тёмном стиле окна.
|
||||||
ComboBox {
|
ComboBox {
|
||||||
id: darkCombo
|
id: darkCombo
|
||||||
|
|
||||||
|
// Та же стрелка, что у комбобоксов профиля и версии на главном окне,
|
||||||
|
// вместо двойного шеврона Basic-стиля.
|
||||||
indicator: Image {
|
indicator: Image {
|
||||||
width: 10; height: 10
|
width: 10; height: 10
|
||||||
x: darkCombo.width - width - 12
|
x: darkCombo.width - width - 12
|
||||||
|
|||||||
@@ -4,16 +4,22 @@ import QtQuick
|
|||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
import QtQuick.Layouts 2.15
|
import QtQuick.Layouts 2.15
|
||||||
|
|
||||||
|
// Выбор сборки Java отдельным окном: слева типы, справа сами версии с поиском.
|
||||||
|
// Устроено так же, как выбор версии Minecraft, но выбранное здесь ещё и
|
||||||
|
// качается — в отличие от версий игры, где загрузку начинает сама сборка.
|
||||||
Dialog {
|
Dialog {
|
||||||
id: picker
|
id: picker
|
||||||
|
|
||||||
required property var backend
|
required property var backend
|
||||||
|
|
||||||
|
// Сборка, с которой окно открылось: по «Отмене» выбор к ней и возвращается.
|
||||||
property string selectedId: ""
|
property string selectedId: ""
|
||||||
property string category: "java"
|
property string category: "java"
|
||||||
property string filterText: ""
|
property string filterText: ""
|
||||||
property bool installedOnly: false
|
property bool installedOnly: false
|
||||||
|
|
||||||
|
// Java, ниже которой выбранной версии игры не запуститься. 0 — версия игры
|
||||||
|
// не выбрана, предупреждать не о чем.
|
||||||
property int requiredMajor: 0
|
property int requiredMajor: 0
|
||||||
|
|
||||||
signal runtimeChosen(string runtimeId)
|
signal runtimeChosen(string runtimeId)
|
||||||
@@ -37,6 +43,8 @@ Dialog {
|
|||||||
{ key: "jre", title: Loc.t.common.java.kind.jre, hint: Loc.t.java.filter.temurinJre }
|
{ key: "jre", title: Loc.t.common.java.kind.jre, hint: Loc.t.java.filter.temurinJre }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// Каталог приходит из C++ уже отсортированным (новые сверху, скачанные
|
||||||
|
// первыми), поэтому здесь только отбор — порядок не трогаем.
|
||||||
readonly property var visibleEntries: {
|
readonly property var visibleEntries: {
|
||||||
const query = picker.filterText.trim().toLowerCase()
|
const query = picker.filterText.trim().toLowerCase()
|
||||||
const source = picker.backend.javaCatalog
|
const source = picker.backend.javaCatalog
|
||||||
@@ -99,6 +107,7 @@ Dialog {
|
|||||||
runtimeList.positionViewAtIndex(index, ListView.Center)
|
runtimeList.positionViewAtIndex(index, ListView.Center)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// «Выбрать» и скачивает: сборка, которой нет на диске, запуску не поможет.
|
||||||
function acceptSelection() {
|
function acceptSelection() {
|
||||||
const entry = picker.selectedEntry
|
const entry = picker.selectedEntry
|
||||||
if (!entry)
|
if (!entry)
|
||||||
@@ -129,6 +138,7 @@ Dialog {
|
|||||||
contentItem: RowLayout {
|
contentItem: RowLayout {
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
|
// ── Типы сборок ─────────────────────────────────────────────────
|
||||||
Rectangle {
|
Rectangle {
|
||||||
Layout.preferredWidth: 170
|
Layout.preferredWidth: 170
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
@@ -185,6 +195,8 @@ Dialog {
|
|||||||
|
|
||||||
Item { width: 1; height: 8 }
|
Item { width: 1; height: 8 }
|
||||||
|
|
||||||
|
// Требование выбранной сборки — чтобы не пришлось держать в
|
||||||
|
// голове, какая Java нужна какой версии игры.
|
||||||
Text {
|
Text {
|
||||||
width: parent.width - 4
|
width: parent.width - 4
|
||||||
visible: picker.requiredMajor > 0
|
visible: picker.requiredMajor > 0
|
||||||
@@ -203,6 +215,7 @@ Dialog {
|
|||||||
color: "#333333"
|
color: "#333333"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Версии ──────────────────────────────────────────────────────
|
||||||
Item {
|
Item {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
@@ -304,7 +317,8 @@ Dialog {
|
|||||||
required property int index
|
required property int index
|
||||||
|
|
||||||
readonly property bool chosen: picker.selectedId === runtimeRow.modelData.id
|
readonly property bool chosen: picker.selectedId === runtimeRow.modelData.id
|
||||||
|
// Сборка ниже требования игры выбирается, но помечается: она
|
||||||
|
// может пригодиться для другой сборки.
|
||||||
readonly property bool tooOld: picker.requiredMajor > 0
|
readonly property bool tooOld: picker.requiredMajor > 0
|
||||||
&& runtimeRow.modelData.major < picker.requiredMajor
|
&& runtimeRow.modelData.major < picker.requiredMajor
|
||||||
|
|
||||||
@@ -339,6 +353,8 @@ Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
// Колонка растянута якорями, поэтому её ширина
|
||||||
|
// задана, а не выведена из детей — цикла тут нет.
|
||||||
width: parent.width
|
width: parent.width
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
color: runtimeRow.chosen ? "#1e1e1e"
|
color: runtimeRow.chosen ? "#1e1e1e"
|
||||||
@@ -372,6 +388,8 @@ Dialog {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Сборки весят по двести мегабайт — удалять их нужно
|
||||||
|
// прямо здесь, иначе папка лаунчера растёт молча.
|
||||||
Image {
|
Image {
|
||||||
visible: runtimeRow.modelData.installed
|
visible: runtimeRow.modelData.installed
|
||||||
source: "images/Trash.svg"
|
source: "images/Trash.svg"
|
||||||
@@ -412,6 +430,7 @@ Dialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Пустая категория, ничего не нашлось или каталог ещё не пришёл.
|
||||||
Text {
|
Text {
|
||||||
anchors.centerIn: runtimeList
|
anchors.centerIn: runtimeList
|
||||||
width: runtimeList.width - 20
|
width: runtimeList.width - 20
|
||||||
|
|||||||
@@ -1,201 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [2026] [GaleonDev dertiellis@gmail.com]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
// Подпись + поле ввода одной колонкой — используется в настройках.
|
||||||
Column {
|
Column {
|
||||||
id: labelled
|
id: labelled
|
||||||
|
|
||||||
@@ -9,6 +10,7 @@ Column {
|
|||||||
property string label: ""
|
property string label: ""
|
||||||
property string placeholder: ""
|
property string placeholder: ""
|
||||||
|
|
||||||
|
// Правка закончена: поле потеряло фокус или пользователь нажал Enter.
|
||||||
signal editingFinished()
|
signal editingFinished()
|
||||||
|
|
||||||
spacing: 3
|
spacing: 3
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
// Один модлоадер в карточке сборки: чекбокс и, когда он отмечен, список версий
|
||||||
|
// именно под выбранную версию Minecraft.
|
||||||
|
//
|
||||||
|
// Совместимость проверять не нужно: backend.loaderVersions() отдаёт список уже
|
||||||
|
// под конкретную версию игры, поэтому несовместимой строки в нём не бывает.
|
||||||
|
// Пустой список — это «лоадер не поддерживает эту версию игры», и он тоже
|
||||||
|
// показывается словами, а не пустым выпадающим списком.
|
||||||
Column {
|
Column {
|
||||||
id: loaderRow
|
id: loaderRow
|
||||||
|
|
||||||
@@ -8,13 +15,21 @@ Column {
|
|||||||
required property string loaderKey
|
required property string loaderKey
|
||||||
required property string title
|
required property string title
|
||||||
|
|
||||||
|
// Версия Minecraft, выбранная в карточке. Её смена сбрасывает выбор.
|
||||||
property string gameVersion: ""
|
property string gameVersion: ""
|
||||||
|
|
||||||
property alias checked: box.checked
|
property alias checked: box.checked
|
||||||
property string selectedVersion: ""
|
property string selectedVersion: ""
|
||||||
property var entries: []
|
property var entries: []
|
||||||
|
|
||||||
|
// Пользователь щёлкнул чекбокс — карточка снимет отметки с остальных
|
||||||
|
// лоадеров: одновременно в .minecraft может жить только один.
|
||||||
signal userChecked()
|
signal userChecked()
|
||||||
|
// Отметка или версия изменились — карточке пора сохранить сборку.
|
||||||
signal changed()
|
signal changed()
|
||||||
|
|
||||||
|
// Ставится, пока карточка заполняет строку данными сборки: в это время
|
||||||
|
// обработчики не должны считать изменения пользовательскими.
|
||||||
property bool applying: false
|
property bool applying: false
|
||||||
|
|
||||||
spacing: 4
|
spacing: 4
|
||||||
@@ -27,9 +42,16 @@ Column {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Единственное место, где меняются entries и selectedVersion. Через него
|
||||||
|
// проходят все три пути — кэш, ответ сети и заполнение из сборки, — потому
|
||||||
|
// что выбранная версия обязана существовать в списке под текущую версию
|
||||||
|
// игры. Раньше проверял только путь из сети, и версия лоадера от прошлой
|
||||||
|
// версии игры доживала до сохранения сборки.
|
||||||
function applyEntries(list) {
|
function applyEntries(list) {
|
||||||
loaderRow.entries = list
|
loaderRow.entries = list
|
||||||
|
|
||||||
|
// Список отсортирован новыми вперёд, поэтому максимально доступная
|
||||||
|
// версия для этой версии игры — всегда первая строка.
|
||||||
if (loaderRow.versionIndex(loaderRow.selectedVersion) < 0) {
|
if (loaderRow.versionIndex(loaderRow.selectedVersion) < 0) {
|
||||||
const fallback = list.length > 0 ? list[0].version : ""
|
const fallback = list.length > 0 ? list[0].version : ""
|
||||||
const changedValue = loaderRow.selectedVersion !== fallback
|
const changedValue = loaderRow.selectedVersion !== fallback
|
||||||
@@ -46,20 +68,26 @@ Column {
|
|||||||
loaderRow.applyEntries([])
|
loaderRow.applyEntries([])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Сначала из кэша — список появляется мгновенно, — потом обновление сети.
|
||||||
loaderRow.applyEntries(loaderRow.backend.loaderVersions(loaderRow.loaderKey,
|
loaderRow.applyEntries(loaderRow.backend.loaderVersions(loaderRow.loaderKey,
|
||||||
loaderRow.gameVersion))
|
loaderRow.gameVersion))
|
||||||
loaderRow.backend.refreshLoaderVersions(loaderRow.loaderKey, loaderRow.gameVersion)
|
loaderRow.backend.refreshLoaderVersions(loaderRow.loaderKey, loaderRow.gameVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Заполнение из сохранённой сборки: без сигналов changed().
|
||||||
function applyBuild(loader, loaderVersion) {
|
function applyBuild(loader, loaderVersion) {
|
||||||
loaderRow.applying = true
|
loaderRow.applying = true
|
||||||
box.checked = loader === loaderRow.loaderKey
|
box.checked = loader === loaderRow.loaderKey
|
||||||
|
// Версию из сборки берём как пожелание: если под выбранную версию игры
|
||||||
|
// её нет, applyEntries() заменит её на максимально доступную.
|
||||||
loaderRow.selectedVersion = box.checked ? loaderVersion : ""
|
loaderRow.selectedVersion = box.checked ? loaderVersion : ""
|
||||||
loaderRow.reload()
|
loaderRow.reload()
|
||||||
loaderRow.applying = false
|
loaderRow.applying = false
|
||||||
}
|
}
|
||||||
|
|
||||||
onGameVersionChanged: {
|
onGameVersionChanged: {
|
||||||
|
// Сборка лоадера привязана к версии игры: под новой версией прежний
|
||||||
|
// выбор недействителен, и список перезапрашивается заново.
|
||||||
loaderRow.selectedVersion = ""
|
loaderRow.selectedVersion = ""
|
||||||
loaderRow.reload()
|
loaderRow.reload()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,19 @@ import QtQuick
|
|||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
import QtWebEngine
|
import QtWebEngine
|
||||||
|
|
||||||
|
// Вход в аккаунт Microsoft — то же самое, что делает официальный лаунчер:
|
||||||
|
// страница входа показывается внутри приложения, а лаунчер ждёт, когда браузер
|
||||||
|
// уйдёт на redirect_uri с кодом авторизации в адресе.
|
||||||
Dialog {
|
Dialog {
|
||||||
id: msLogin
|
id: msLogin
|
||||||
|
|
||||||
required property var backend
|
required property var backend
|
||||||
|
|
||||||
|
// Окно ничего не знает про тосты главного окна: о неудаче сообщает сигналом.
|
||||||
signal failed(string message)
|
signal failed(string message)
|
||||||
|
|
||||||
|
// Код уже отдан backend — второй раз по тому же адресу не реагируем:
|
||||||
|
// WebEngineView успевает сообщить об urlChanged несколько раз.
|
||||||
property bool codeTaken: false
|
property bool codeTaken: false
|
||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
@@ -25,6 +32,8 @@ Dialog {
|
|||||||
open()
|
open()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Разбор адреса живёт в C++: правила совпадения должны совпадать с теми,
|
||||||
|
// по которым сервис строит сам redirect_uri.
|
||||||
function handleUrl(url) {
|
function handleUrl(url) {
|
||||||
if (codeTaken)
|
if (codeTaken)
|
||||||
return
|
return
|
||||||
@@ -67,6 +76,9 @@ Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Item {
|
contentItem: Item {
|
||||||
|
// Профиль без storageName — значит без диска: куки живут только пока
|
||||||
|
// работает лаунчер и в общий браузер не попадают. За выбор аккаунта в
|
||||||
|
// пределах сессии отвечает prompt=select_account в адресе входа.
|
||||||
WebEngineProfilePrototype {
|
WebEngineProfilePrototype {
|
||||||
id: msProfile
|
id: msProfile
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
// Плашка хода долгой операции в левом нижнем углу: не задевает кнопку запуска,
|
||||||
|
// сообщение по центру и кнопки папки с настройками.
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: panel
|
id: panel
|
||||||
|
|
||||||
property string title: ""
|
property string title: ""
|
||||||
property string status: ""
|
property string status: ""
|
||||||
|
// -1 — итог ещё неизвестен, показываем «…» вместо процентов.
|
||||||
property double fraction: -1
|
property double fraction: -1
|
||||||
|
// Необязательная вторая строка: мегабайты у загрузки, путь у архивации.
|
||||||
property string detail: ""
|
property string detail: ""
|
||||||
property bool cancellable: true
|
property bool cancellable: true
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +1,3 @@
|
|||||||
# BiLauncher
|
# BiLauncher
|
||||||
|
|
||||||
Самописный простой лаунчер для Minecraft без рекламы и лишнего мусора.
|
Самописный простой лаунчер для Minecraft без рекламы и ненужного мусора.
|
||||||
|
|
||||||
<img src="https://projects-live.galeonworx.com/galeon/BiLauncher/raw/branch/master/Screenshots/menu.png" alt="drawing" width="65%"/>
|
|
||||||
|
|
||||||
# Основной функционал
|
|
||||||
|
|
||||||
<h3>Возможность гибкой настройки параметров запуска игры с динамическим выбором версии Java под каждую версию Minecraft</h3>
|
|
||||||
|
|
||||||
<p float="left">
|
|
||||||
<img src="https://projects-live.galeonworx.com/galeon/BiLauncher/raw/branch/master/Screenshots/settings.png" alt="drawing" width="45%"/>
|
|
||||||
<img src="https://projects-live.galeonworx.com/galeon/BiLauncher/raw/branch/master/Screenshots/javaSelect.png" alt="drawing" width="52%"/>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3>Сохранение профилей пользователей и авторизация тремя доступными способами</h3>
|
|
||||||
|
|
||||||
<p float="left">
|
|
||||||
<img src="https://projects-live.galeonworx.com/galeon/BiLauncher/raw/branch/master/Screenshots/profiles.png" alt="drawing" width="45%"/>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3>Сборки: централизованное управление вашей сборкой с возможностью выбора любой версии игры, добавления модлоадеров и сохранение каждой сборки без необходимости очищать .minecraft</h3>
|
|
||||||
|
|
||||||
<p float="left">
|
|
||||||
<img src="https://projects-live.galeonworx.com/galeon/BiLauncher/raw/branch/master/Screenshots/versions.png" alt="drawing" width="65%"/>
|
|
||||||
<img src="https://projects-live.galeonworx.com/galeon/BiLauncher/raw/branch/master/Screenshots/versionsLoaders.png" alt="drawing" width="65%"/>
|
|
||||||
<img src="https://projects-live.galeonworx.com/galeon/BiLauncher/raw/branch/master/Screenshots/versionsSelect.png" alt="drawing" width="65%"/>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3>Сезонные сборки: централизованное управление сборками со стороны команды разработчика, полная автоматизация скачивания, установки и разрешения зависиомстей для конечных пользователей</h3>
|
|
||||||
|
|
||||||
<p float="left">
|
|
||||||
<img src="https://projects-live.galeonworx.com/galeon/BiLauncher/raw/branch/master/Screenshots/seasonal.png" alt="drawing" width="75%"/>
|
|
||||||
</p>
|
|
||||||
|
Before Width: | Height: | Size: 307 KiB |
|
Before Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 225 KiB |
|
Before Width: | Height: | Size: 169 KiB |
|
Before Width: | Height: | Size: 245 KiB |
|
Before Width: | Height: | Size: 244 KiB |
|
Before Width: | Height: | Size: 219 KiB |
|
Before Width: | Height: | Size: 225 KiB |
@@ -3,11 +3,23 @@ pragma ComponentBehavior: Bound
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
// Готовые сезонные сборки с сервера лаунчера: таблица со всем, что нужно
|
||||||
|
// решить, ставить её или нет, и одна кнопка, которая делает всё остальное —
|
||||||
|
// заводит сборку, ставит версию игры, модлоадер, Java и раскладывает файлы.
|
||||||
|
//
|
||||||
|
// Таблица собрана из Row фиксированных колонок, а не из TableView: в проекте
|
||||||
|
// нет ни одной модели QAbstractItemModel, а строки приходят готовыми
|
||||||
|
// QVariantMap — заводить ради семи колонок отдельную модель незачем.
|
||||||
Dialog {
|
Dialog {
|
||||||
id: seasons
|
id: seasons
|
||||||
|
|
||||||
required property var backend
|
required property var backend
|
||||||
|
|
||||||
|
// Выбранная строка. Хранится по id, а не по индексу: список обновляется
|
||||||
|
// под руками, и индекс после обновления указывал бы на другую сборку.
|
||||||
property string selectedId: ""
|
property string selectedId: ""
|
||||||
|
|
||||||
|
// Ширины колонок в одном месте: их повторяют и шапка, и делегат.
|
||||||
readonly property var columns: [
|
readonly property var columns: [
|
||||||
{ key: "name", title: Loc.t.common.header.name, width: 250, align: Text.AlignLeft },
|
{ key: "name", title: Loc.t.common.header.name, width: 250, align: Text.AlignLeft },
|
||||||
{ key: "minecraftVersion", title: Loc.t.common.header.version, width: 90, align: Text.AlignLeft },
|
{ key: "minecraftVersion", title: Loc.t.common.header.version, width: 90, align: Text.AlignLeft },
|
||||||
@@ -22,6 +34,8 @@ Dialog {
|
|||||||
padding: 0
|
padding: 0
|
||||||
width: 960
|
width: 960
|
||||||
height: 560
|
height: 560
|
||||||
|
// Пока идёт установка, окно закрывается только кнопкой: случайный щелчок
|
||||||
|
// мимо не должен спрятать единственную видимую отмену.
|
||||||
closePolicy: seasons.backend.seasonalInstalling
|
closePolicy: seasons.backend.seasonalInstalling
|
||||||
? Popup.NoAutoClose
|
? Popup.NoAutoClose
|
||||||
: (Popup.CloseOnEscape | Popup.CloseOnPressOutside)
|
: (Popup.CloseOnEscape | Popup.CloseOnPressOutside)
|
||||||
@@ -33,6 +47,8 @@ Dialog {
|
|||||||
border.width: 1
|
border.width: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Строки приходят из C++ уже отсортированными и сведёнными с локальными
|
||||||
|
// записями — здесь только показ.
|
||||||
readonly property var entries: seasons.backend.seasonalCatalog
|
readonly property var entries: seasons.backend.seasonalCatalog
|
||||||
|
|
||||||
readonly property var selectedEntry: {
|
readonly property var selectedEntry: {
|
||||||
@@ -63,6 +79,7 @@ Dialog {
|
|||||||
return String(entry[key])
|
return String(entry[key])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Свежий кэш отвечает без сети, поэтому дёргаем при каждом открытии.
|
||||||
onAboutToShow: seasons.backend.refreshSeasonalCatalog(false)
|
onAboutToShow: seasons.backend.refreshSeasonalCatalog(false)
|
||||||
|
|
||||||
header: Item {
|
header: Item {
|
||||||
@@ -84,6 +101,7 @@ Dialog {
|
|||||||
|
|
||||||
contentItem: Item {
|
contentItem: Item {
|
||||||
|
|
||||||
|
// ── Шапка таблицы ───────────────────────────────────────────────
|
||||||
Row {
|
Row {
|
||||||
id: tableHeader
|
id: tableHeader
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
@@ -121,6 +139,9 @@ Dialog {
|
|||||||
color: "#333333"
|
color: "#333333"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Сообщение вместо таблицы ────────────────────────────────────
|
||||||
|
// Пустой список и ошибка выглядят одинаково пустыми, поэтому причина
|
||||||
|
// показывается прямо на месте строк.
|
||||||
Text {
|
Text {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: parent.width - 80
|
width: parent.width - 80
|
||||||
@@ -136,6 +157,7 @@ Dialog {
|
|||||||
: seasons.backend.seasonalCatalogError)
|
: seasons.backend.seasonalCatalogError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Строки ──────────────────────────────────────────────────────
|
||||||
ListView {
|
ListView {
|
||||||
id: buildList
|
id: buildList
|
||||||
anchors.top: headerLine.bottom
|
anchors.top: headerLine.bottom
|
||||||
@@ -221,6 +243,8 @@ Dialog {
|
|||||||
color: "#333333"
|
color: "#333333"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Описание и размер выбранной сборки: они длинные и в таблицу не
|
||||||
|
// помещаются, а решение принимается по ним.
|
||||||
Column {
|
Column {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: 18
|
anchors.leftMargin: 18
|
||||||
@@ -290,6 +314,8 @@ Dialog {
|
|||||||
id: installButton
|
id: installButton
|
||||||
width: 150
|
width: 150
|
||||||
height: 36
|
height: 36
|
||||||
|
// Установка занимает и панель загрузки, и .minecraft целиком:
|
||||||
|
// пока лаунчер занят чем угодно, вторую начинать нельзя.
|
||||||
enabled: seasons.selectedEntry !== null && !seasons.backend.busy
|
enabled: seasons.selectedEntry !== null && !seasons.backend.busy
|
||||||
contentItem: Text {
|
contentItem: Text {
|
||||||
text: seasons.selectedEntry && seasons.selectedEntry.updateAvailable
|
text: seasons.selectedEntry && seasons.selectedEntry.updateAvailable
|
||||||
|
|||||||
@@ -4,16 +4,25 @@ import QtQuick
|
|||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
import QtQuick.Layouts 2.15
|
import QtQuick.Layouts 2.15
|
||||||
|
|
||||||
|
// Выбор версии Minecraft отдельным окном: слева категории, справа сами версии
|
||||||
|
// с поиском сверху.
|
||||||
|
//
|
||||||
|
// Раньше это был выпадающий список на всю тысячу версий: найти в нём бету 1.7
|
||||||
|
// можно было только поиском по точному номеру. Категории делят список на
|
||||||
|
// обозримые части, а поиск работает внутри выбранной.
|
||||||
Dialog {
|
Dialog {
|
||||||
id: picker
|
id: picker
|
||||||
|
|
||||||
required property var backend
|
required property var backend
|
||||||
|
|
||||||
|
// Версия, с которой окно открылось: по «Отмене» выбор к ней и возвращается.
|
||||||
property string selectedId: ""
|
property string selectedId: ""
|
||||||
property string category: "release"
|
property string category: "release"
|
||||||
property string filterText: ""
|
property string filterText: ""
|
||||||
property bool installedOnly: false
|
property bool installedOnly: false
|
||||||
|
|
||||||
|
// Выбранная версия подтверждена кнопкой или двойным щелчком. Имя не
|
||||||
|
// accepted(): такой сигнал у Dialog уже есть, и переопределить его нельзя.
|
||||||
signal versionChosen(string versionId)
|
signal versionChosen(string versionId)
|
||||||
|
|
||||||
modal: true
|
modal: true
|
||||||
@@ -37,6 +46,8 @@ Dialog {
|
|||||||
{ key: "other", title: Loc.t.version.filter.other }
|
{ key: "other", title: Loc.t.version.filter.other }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// Каталог приходит из C++ уже отсортированным (новые сверху), поэтому здесь
|
||||||
|
// только отбор — порядок не трогаем.
|
||||||
readonly property var visibleEntries: {
|
readonly property var visibleEntries: {
|
||||||
const query = picker.filterText.trim().toLowerCase()
|
const query = picker.filterText.trim().toLowerCase()
|
||||||
const source = picker.backend.versionCatalog
|
const source = picker.backend.versionCatalog
|
||||||
@@ -58,6 +69,7 @@ Dialog {
|
|||||||
picker.selectedId = versionId
|
picker.selectedId = versionId
|
||||||
picker.filterText = ""
|
picker.filterText = ""
|
||||||
searchField.text = ""
|
searchField.text = ""
|
||||||
|
// Открываемся на категории текущей версии, а не всегда на релизах.
|
||||||
picker.category = picker.categoryOf(versionId)
|
picker.category = picker.categoryOf(versionId)
|
||||||
picker.backend.refreshVersionCatalog()
|
picker.backend.refreshVersionCatalog()
|
||||||
picker.open()
|
picker.open()
|
||||||
@@ -105,6 +117,9 @@ Dialog {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Спрашиваем до удаления: версию придётся качать заново, а профили
|
||||||
|
// модлоадеров поверх неё — переустанавливать. Id запоминаем здесь:
|
||||||
|
// к моменту ответа строка под курсором может быть уже другой.
|
||||||
function askRemove(versionId) {
|
function askRemove(versionId) {
|
||||||
const info = picker.backend.versionRemovalInfo(versionId)
|
const info = picker.backend.versionRemovalInfo(versionId)
|
||||||
if (!info || info.installed !== true)
|
if (!info || info.installed !== true)
|
||||||
@@ -118,6 +133,8 @@ Dialog {
|
|||||||
|
|
||||||
function performRemove(versionId) {
|
function performRemove(versionId) {
|
||||||
picker.backend.removeVersion(versionId)
|
picker.backend.removeVersion(versionId)
|
||||||
|
// Профиль модлоадера был в каталоге только потому, что установлен:
|
||||||
|
// после удаления строка исчезает совсем, и выбор надо снять.
|
||||||
if (picker.selectedId === versionId && !picker.catalogHas(versionId))
|
if (picker.selectedId === versionId && !picker.catalogHas(versionId))
|
||||||
picker.selectedId = ""
|
picker.selectedId = ""
|
||||||
picker.revealSelected()
|
picker.revealSelected()
|
||||||
@@ -288,6 +305,7 @@ Dialog {
|
|||||||
contentItem: RowLayout {
|
contentItem: RowLayout {
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
|
// ── Категории ───────────────────────────────────────────────────
|
||||||
Rectangle {
|
Rectangle {
|
||||||
Layout.preferredWidth: 150
|
Layout.preferredWidth: 150
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
@@ -340,6 +358,7 @@ Dialog {
|
|||||||
color: "#333333"
|
color: "#333333"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Версии ──────────────────────────────────────────────────────
|
||||||
Item {
|
Item {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
@@ -474,6 +493,8 @@ Dialog {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Версия весит от десятков мегабайт, а галочка рядом —
|
||||||
|
// единственное место, где видно, что именно скачано.
|
||||||
Image {
|
Image {
|
||||||
visible: versionRow.modelData.installed
|
visible: versionRow.modelData.installed
|
||||||
source: "images/Trash.svg"
|
source: "images/Trash.svg"
|
||||||
@@ -510,6 +531,7 @@ Dialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Пустая категория, ничего не нашлось или манифест ещё не пришёл.
|
||||||
Text {
|
Text {
|
||||||
anchors.centerIn: versionList
|
anchors.centerIn: versionList
|
||||||
width: versionList.width - 20
|
width: versionList.width - 20
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Подготовка Linux-раннера Gitea Actions для сборки BiLauncher (Ubuntu 22.04).
|
|
||||||
#
|
|
||||||
# Qt (~/Qt/6.11.1/gcc_64 с WebEngine), CMake и Ninja (~/Qt/Tools) ставятся заранее
|
|
||||||
# через Qt Online Installer — скрипт их не трогает, а докачивает только то, чего Qt
|
|
||||||
# не даёт: компилятор, системные библиотеки для сборки и деплоя, Node.js (для
|
|
||||||
# actions/checkout), appimagetool и сам gitea-runner. Повторный запуск безопасен.
|
|
||||||
#
|
|
||||||
# Запуск от пользователя, которому принадлежит Qt (нужен sudo без пароля):
|
|
||||||
# ./setup-runner-linux.sh [токен регистрации]
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
TOKEN="${1:-}"
|
|
||||||
INSTANCE="${INSTANCE:-https://projects-live.galeonworx.com}"
|
|
||||||
RUNNER_NAME="${RUNNER_NAME:-linux-vm}"
|
|
||||||
RUNNER_VERSION="${RUNNER_VERSION:-4.1.0}"
|
|
||||||
QT_ROOT="${QT_ROOT:-$HOME/Qt/6.11.1/gcc_64}"
|
|
||||||
QT_TOOLS="${QT_TOOLS:-$HOME/Qt/Tools}"
|
|
||||||
RDIR="$HOME/act_runner"
|
|
||||||
|
|
||||||
[ -d "$QT_ROOT/lib/cmake/Qt6WebEngineQuick" ] || { echo "Нет Qt с WebEngine в $QT_ROOT" >&2; exit 1; }
|
|
||||||
|
|
||||||
# --- Компилятор и библиотеки ---------------------------------------------------
|
|
||||||
# libgl1-mesa-dev — заголовки OpenGL для Qt6::Gui; xcb-* и прочие — то, что
|
|
||||||
# Linux-деплой Qt и плагин xcb ищут при упаковке и запуске; libfuse2 — для
|
|
||||||
# запуска самого appimagetool (он тоже AppImage).
|
|
||||||
sudo apt-get update -q
|
|
||||||
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
|
|
||||||
build-essential patchelf file curl git xz-utils \
|
|
||||||
libgl1-mesa-dev libfuse2 libfontconfig1 libdbus-1-3 \
|
|
||||||
libxkbcommon-x11-0 libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 \
|
|
||||||
libxcb-render-util0 libxcb-shape0 libxcb-xinerama0 libxcb-xkb1 \
|
|
||||||
libnss3 libxcomposite1 libxdamage1 libxrandr2 libxtst6 libxkbfile1 libxshmfence1 libasound2
|
|
||||||
|
|
||||||
# --- Node.js LTS ---------------------------------------------------------------
|
|
||||||
if ! command -v node >/dev/null; then
|
|
||||||
NODE_VER=$(curl -fsSL https://nodejs.org/dist/index.json \
|
|
||||||
| python3 -c 'import json,sys; print(next(r["version"] for r in json.load(sys.stdin) if r["lts"]))')
|
|
||||||
curl -fsSL "https://nodejs.org/dist/$NODE_VER/node-$NODE_VER-linux-x64.tar.xz" -o /tmp/node.tar.xz
|
|
||||||
sudo rm -rf /opt/node && sudo mkdir -p /opt/node
|
|
||||||
sudo tar -xJf /tmp/node.tar.xz -C /opt/node --strip-components=1
|
|
||||||
sudo ln -sf /opt/node/bin/node /opt/node/bin/npm /opt/node/bin/npx /usr/local/bin/
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- appimagetool ----------------------------------------------------------------
|
|
||||||
if ! command -v appimagetool >/dev/null; then
|
|
||||||
sudo curl -fsSL -o /usr/local/bin/appimagetool \
|
|
||||||
https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
|
|
||||||
sudo chmod +x /usr/local/bin/appimagetool
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- gitea-runner ------------------------------------------------------------------
|
|
||||||
mkdir -p "$RDIR/work"
|
|
||||||
if [ ! -x "$RDIR/gitea-runner" ]; then
|
|
||||||
curl -fsSL -o "$RDIR/gitea-runner" \
|
|
||||||
"https://gitea.com/gitea/runner/releases/download/v$RUNNER_VERSION/gitea-runner-$RUNNER_VERSION-linux-amd64"
|
|
||||||
chmod +x "$RDIR/gitea-runner"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat > "$RDIR/config.yaml" <<EOF
|
|
||||||
log:
|
|
||||||
level: info
|
|
||||||
runner:
|
|
||||||
file: $RDIR/.runner
|
|
||||||
capacity: 1
|
|
||||||
timeout: 3h
|
|
||||||
fetch_timeout: 5s
|
|
||||||
fetch_interval: 2s
|
|
||||||
envs:
|
|
||||||
QT_ROOT: $QT_ROOT
|
|
||||||
QT_TOOLS: $QT_TOOLS
|
|
||||||
labels:
|
|
||||||
- "linux:host"
|
|
||||||
cache:
|
|
||||||
enabled: false
|
|
||||||
host:
|
|
||||||
workdir_parent: $RDIR/work
|
|
||||||
EOF
|
|
||||||
|
|
||||||
if [ -n "$TOKEN" ] && [ ! -f "$RDIR/.runner" ]; then
|
|
||||||
(cd "$RDIR" && ./gitea-runner register --no-interactive --instance "$INSTANCE" \
|
|
||||||
--token "$TOKEN" --name "$RUNNER_NAME" --labels "linux:host" --config config.yaml)
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- systemd: раннер работает от владельца Qt, а не от root ------------------------
|
|
||||||
sudo tee /etc/systemd/system/gitea-runner.service >/dev/null <<EOF
|
|
||||||
[Unit]
|
|
||||||
Description=Gitea Actions runner (BiLauncher)
|
|
||||||
After=network-online.target
|
|
||||||
Wants=network-online.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
User=$USER
|
|
||||||
WorkingDirectory=$RDIR
|
|
||||||
Environment=PATH=/usr/local/bin:/usr/bin:/bin
|
|
||||||
ExecStart=$RDIR/gitea-runner daemon --config $RDIR/config.yaml
|
|
||||||
Restart=always
|
|
||||||
RestartSec=10
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
sudo systemctl daemon-reload
|
|
||||||
sudo systemctl enable --now gitea-runner
|
|
||||||
echo "Готово: $(systemctl is-active gitea-runner)"
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
# Подготовка Windows-раннера Gitea Actions для сборки BiLauncher.
|
|
||||||
#
|
|
||||||
# Qt (C:\Qt\6.11.1\msvc2022_64 с WebEngine), CMake и Ninja (C:\Qt\Tools) ставятся
|
|
||||||
# заранее через Qt Online Installer — скрипт их не трогает, а докачивает только то,
|
|
||||||
# чего Qt не даёт: компилятор MSVC, git, Node.js (для actions/checkout), Inno Setup
|
|
||||||
# и сам gitea-runner. Повторный запуск безопасен: уже установленное пропускается.
|
|
||||||
#
|
|
||||||
# Запуск (PowerShell от администратора):
|
|
||||||
# powershell -ExecutionPolicy Bypass -File setup-runner-windows.ps1 [-Token <токен регистрации>]
|
|
||||||
|
|
||||||
param(
|
|
||||||
[string]$Token = "",
|
|
||||||
[string]$Instance = "https://projects-live.galeonworx.com",
|
|
||||||
[string]$RunnerName = "win-vm",
|
|
||||||
[string]$RunnerVersion = "4.1.0",
|
|
||||||
[string]$QtRoot = "C:\Qt\6.11.1\msvc2022_64",
|
|
||||||
[string]$QtTools = "C:\Qt\Tools"
|
|
||||||
)
|
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
|
||||||
$ProgressPreference = "SilentlyContinue" # иначе Invoke-WebRequest падает без консоли (по SSH)
|
|
||||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
||||||
|
|
||||||
$dl = "C:\ci-downloads"
|
|
||||||
New-Item -ItemType Directory -Force -Path $dl | Out-Null
|
|
||||||
|
|
||||||
function Fetch($url, $name) {
|
|
||||||
$out = Join-Path $dl $name
|
|
||||||
if (-not (Test-Path $out)) {
|
|
||||||
Write-Host "Скачиваю $url"
|
|
||||||
Invoke-WebRequest -UseBasicParsing -Uri $url -OutFile $out
|
|
||||||
}
|
|
||||||
return $out
|
|
||||||
}
|
|
||||||
|
|
||||||
function Run($exe, $argList) {
|
|
||||||
$p = Start-Process -FilePath $exe -ArgumentList $argList -Wait -PassThru -NoNewWindow
|
|
||||||
# 3010 — «успешно, нужна перезагрузка» у установщиков MSI и VS
|
|
||||||
if ($p.ExitCode -ne 0 -and $p.ExitCode -ne 3010) { throw "$exe завершился с кодом $($p.ExitCode)" }
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- Visual Studio 2022 Build Tools (MSVC x64 + Windows SDK) -----------------
|
|
||||||
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
|
|
||||||
$haveMsvc = (Test-Path $vswhere) -and
|
|
||||||
(& $vswhere -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath)
|
|
||||||
if (-not $haveMsvc) {
|
|
||||||
$vs = Fetch "https://aka.ms/vs/17/release/vs_BuildTools.exe" "vs_BuildTools.exe"
|
|
||||||
Write-Host "Ставлю VS 2022 Build Tools (20–40 минут)…"
|
|
||||||
Run $vs @("--quiet", "--wait", "--norestart", "--nocache",
|
|
||||||
"--add", "Microsoft.VisualStudio.Workload.VCTools", "--includeRecommended")
|
|
||||||
} else { Write-Host "MSVC уже установлен" }
|
|
||||||
|
|
||||||
# --- Git for Windows -----------------------------------------------------------
|
|
||||||
if (-not (Test-Path "C:\Program Files\Git\cmd\git.exe")) {
|
|
||||||
$rel = Invoke-RestMethod "https://api.github.com/repos/git-for-windows/git/releases/latest"
|
|
||||||
$asset = $rel.assets | Where-Object { $_.name -match '^Git-.*-64-bit\.exe$' } | Select-Object -First 1
|
|
||||||
$git = Fetch $asset.browser_download_url $asset.name
|
|
||||||
Run $git @("/VERYSILENT", "/NORESTART", "/NOCANCEL", "/SP-", "/COMPONENTS=gitlfs")
|
|
||||||
} else { Write-Host "Git уже установлен" }
|
|
||||||
|
|
||||||
# --- Node.js LTS (нужен JS-экшенам вроде actions/checkout) ---------------------
|
|
||||||
if (-not (Test-Path "C:\Program Files\nodejs\node.exe")) {
|
|
||||||
# Скобки вокруг Invoke-RestMethod обязательны: PowerShell 5.1 иначе отдаёт
|
|
||||||
# JSON-массив в конвейер одним объектом, и фильтр видит все версии сразу.
|
|
||||||
$lts = ((Invoke-RestMethod "https://nodejs.org/dist/index.json") | Where-Object { $_.lts } | Select-Object -First 1).version
|
|
||||||
$msi = Fetch "https://nodejs.org/dist/$lts/node-$lts-x64.msi" "node-$lts-x64.msi"
|
|
||||||
Run "msiexec.exe" @("/i", "`"$msi`"", "/qn", "/norestart")
|
|
||||||
} else { Write-Host "Node.js уже установлен" }
|
|
||||||
|
|
||||||
# --- Inno Setup ----------------------------------------------------------------
|
|
||||||
$iscc = Get-ChildItem "C:\Program Files*\Inno Setup*\ISCC.exe" -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
||||||
if (-not $iscc) {
|
|
||||||
# jrsoftware.org/download.php без браузера отдаёт HTML — берём файл из релизов на GitHub
|
|
||||||
$rel = Invoke-RestMethod "https://api.github.com/repos/jrsoftware/issrc/releases/latest"
|
|
||||||
$asset = $rel.assets | Where-Object { $_.name -match '^innosetup-[\d.]+(-x64)?\.exe$' } |
|
|
||||||
Sort-Object { $_.name -notmatch '-x64' } | Select-Object -First 1
|
|
||||||
$is = Fetch $asset.browser_download_url $asset.name
|
|
||||||
Run $is @("/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART", "/ALLUSERS")
|
|
||||||
$iscc = Get-ChildItem "C:\Program Files*\Inno Setup*\ISCC.exe" | Select-Object -First 1
|
|
||||||
} else { Write-Host "Inno Setup уже установлен" }
|
|
||||||
|
|
||||||
# --- Длинные пути: дерево WebEngine легко вылезает за 260 символов --------------
|
|
||||||
Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem -Name LongPathsEnabled -Value 1
|
|
||||||
& "C:\Program Files\Git\cmd\git.exe" config --system core.longpaths true
|
|
||||||
|
|
||||||
# --- gitea-runner ----------------------------------------------------------------
|
|
||||||
$rdir = "C:\act_runner"
|
|
||||||
New-Item -ItemType Directory -Force -Path $rdir, "C:\r" | Out-Null
|
|
||||||
$exe = Join-Path $rdir "gitea-runner.exe"
|
|
||||||
if (-not (Test-Path $exe)) {
|
|
||||||
$src = Fetch "https://gitea.com/gitea/runner/releases/download/v$RunnerVersion/gitea-runner-$RunnerVersion-windows-amd64.exe" "gitea-runner-$RunnerVersion.exe"
|
|
||||||
Copy-Item $src $exe
|
|
||||||
}
|
|
||||||
|
|
||||||
# Конфиг: host-режим, рабочая папка с коротким путём, пути к Qt через env.
|
|
||||||
$isccDir = Split-Path $iscc.FullName
|
|
||||||
$cfg = @"
|
|
||||||
log:
|
|
||||||
level: info
|
|
||||||
runner:
|
|
||||||
file: $($rdir -replace '\\','/')/.runner
|
|
||||||
capacity: 1
|
|
||||||
timeout: 3h
|
|
||||||
fetch_timeout: 5s
|
|
||||||
fetch_interval: 2s
|
|
||||||
envs:
|
|
||||||
QT_ROOT: '$QtRoot'
|
|
||||||
QT_TOOLS: '$QtTools'
|
|
||||||
ISCC_DIR: '$isccDir'
|
|
||||||
labels:
|
|
||||||
- "windows:host"
|
|
||||||
cache:
|
|
||||||
enabled: false
|
|
||||||
host:
|
|
||||||
workdir_parent: C:/r
|
|
||||||
"@
|
|
||||||
Set-Content -Path (Join-Path $rdir "config.yaml") -Value $cfg -Encoding UTF8
|
|
||||||
|
|
||||||
if ($Token -and -not (Test-Path (Join-Path $rdir ".runner"))) {
|
|
||||||
Push-Location $rdir
|
|
||||||
& $exe register --no-interactive --instance $Instance --token $Token `
|
|
||||||
--name $RunnerName --labels "windows:host" --config config.yaml
|
|
||||||
if ($LASTEXITCODE -ne 0) { throw "Регистрация раннера не удалась" }
|
|
||||||
Pop-Location
|
|
||||||
}
|
|
||||||
|
|
||||||
# Обёртка запуска: PATH дополняется git и node — задача планировщика может
|
|
||||||
# стартовать раньше, чем сессия получит обновлённый системный PATH.
|
|
||||||
$cmd = @"
|
|
||||||
@echo off
|
|
||||||
set PATH=C:\Program Files\Git\cmd;C:\Program Files\Git\usr\bin;C:\Program Files\nodejs;%PATH%
|
|
||||||
cd /d $rdir
|
|
||||||
gitea-runner.exe daemon --config config.yaml >> runner.log 2>&1
|
|
||||||
"@
|
|
||||||
Set-Content -Path (Join-Path $rdir "run-runner.cmd") -Value $cmd -Encoding ASCII
|
|
||||||
|
|
||||||
# Автозапуск при входе galeon: так задаче не нужен пароль учётной записи.
|
|
||||||
# Чтобы раннер поднимался и без входа, пересоздайте задачу с /sc onstart /rp *.
|
|
||||||
schtasks /create /f /tn "Gitea Runner" /sc onlogon /ru $env:USERNAME /it /rl highest `
|
|
||||||
/tr "powershell.exe -WindowStyle Hidden -NoProfile -Command $rdir\run-runner.cmd" | Out-Null
|
|
||||||
if (-not (Get-Process gitea-runner -ErrorAction SilentlyContinue)) { schtasks /run /tn "Gitea Runner" | Out-Null }
|
|
||||||
|
|
||||||
Write-Host "Готово. MSVC, git, node, Inno Setup и gitea-runner на месте."
|
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
"en": "Open mods folder"
|
"en": "Open mods folder"
|
||||||
},
|
},
|
||||||
"app.tooltip.seasonal": {
|
"app.tooltip.seasonal": {
|
||||||
"ru": "Сезонные сборки от команды Galeon'а",
|
"ru": "Сезонные сборки от команды Мельника",
|
||||||
"en": "Seasonal builds from Galeon team"
|
"en": "Seasonal builds from Galeon team"
|
||||||
},
|
},
|
||||||
"app.tooltip.settings": {
|
"app.tooltip.settings": {
|
||||||
@@ -156,8 +156,8 @@
|
|||||||
"en": "The Microsoft account owns the game but has no game profile yet. Sign in to the official launcher once and pick a nickname."
|
"en": "The Microsoft account owns the game but has no game profile yet. Sign in to the official launcher once and pick a nickname."
|
||||||
},
|
},
|
||||||
"auth.msa.error.noWebEngine": {
|
"auth.msa.error.noWebEngine": {
|
||||||
"ru": "Эта сборка лаунчера собрана без Qt WebEngine",
|
"ru": "Эта сборка лаунчера собрана без Qt WebEngine — показать окно входа Microsoft нечем",
|
||||||
"en": "This launcher build was made without Qt WebEngine"
|
"en": "This launcher build was made without Qt WebEngine — there is nothing to show the Microsoft sign-in window with"
|
||||||
},
|
},
|
||||||
"auth.msa.error.noXboxProfile": {
|
"auth.msa.error.noXboxProfile": {
|
||||||
"ru": "К аккаунту Microsoft не привязан профиль Xbox. Создайте его на xbox.com и повторите вход.",
|
"ru": "К аккаунту Microsoft не привязан профиль Xbox. Создайте его на xbox.com и повторите вход.",
|
||||||
@@ -196,8 +196,8 @@
|
|||||||
"en": "The Microsoft session has expired — sign in to the account again (%1)"
|
"en": "The Microsoft session has expired — sign in to the account again (%1)"
|
||||||
},
|
},
|
||||||
"auth.msa.error.windowUnavailable": {
|
"auth.msa.error.windowUnavailable": {
|
||||||
"ru": "Окно входа Microsoft недоступно",
|
"ru": "Окно входа Microsoft недоступно: сборка без Qt WebEngine",
|
||||||
"en": "The Microsoft sign-in window is unavailable"
|
"en": "The Microsoft sign-in window is unavailable: this build has no Qt WebEngine"
|
||||||
},
|
},
|
||||||
"auth.msa.error.xboxNoToken": {
|
"auth.msa.error.xboxNoToken": {
|
||||||
"ru": "Xbox Live не вернул токен",
|
"ru": "Xbox Live не вернул токен",
|
||||||
@@ -288,8 +288,8 @@
|
|||||||
"en": "Pick a version"
|
"en": "Pick a version"
|
||||||
},
|
},
|
||||||
"build.error.closeGameFilesMoving": {
|
"build.error.closeGameFilesMoving": {
|
||||||
"ru": "Файлы игры в процессе переноса, сначала закройте игру",
|
"ru": "Сначала закройте игру — её файлы сейчас переносятся",
|
||||||
"en": "Game files are being moved, close the game first"
|
"en": "Close the game first — its files are being moved right now"
|
||||||
},
|
},
|
||||||
"build.error.filesIncomplete": {
|
"build.error.filesIncomplete": {
|
||||||
"ru": "Файлы сборки установлены не полностью: %1\nПовторите установку сборки.",
|
"ru": "Файлы сборки установлены не полностью: %1\nПовторите установку сборки.",
|
||||||
@@ -328,8 +328,8 @@
|
|||||||
"en": "The build was not switched: %1"
|
"en": "The build was not switched: %1"
|
||||||
},
|
},
|
||||||
"build.error.switchFailedDirty": {
|
"build.error.switchFailedDirty": {
|
||||||
"ru": "Сборка не переключена: %1\n Повторите переключение.",
|
"ru": "Сборка не переключена: %1\nСодержимое .minecraft осталось разобранным — повторите переключение.",
|
||||||
"en": "The build was not switched: %1\n Switch again."
|
"en": "The build was not switched: %1\nThe contents of .minecraft are left half-applied — switch again."
|
||||||
},
|
},
|
||||||
"build.error.versionNotInstalled": {
|
"build.error.versionNotInstalled": {
|
||||||
"ru": "Версия «%1» из сборки «%2» не установлена в %3",
|
"ru": "Версия «%1» из сборки «%2» не установлена в %3",
|
||||||
@@ -340,8 +340,8 @@
|
|||||||
"en": "Build \"%1\" will be removed and cannot be recovered."
|
"en": "Build \"%1\" will be removed and cannot be recovered."
|
||||||
},
|
},
|
||||||
"build.hint.removingLast": {
|
"build.hint.removingLast": {
|
||||||
"ru": "Последняя сборка, файлы из корня игры не удаляются.",
|
"ru": "Это последняя сборка. Содержимое .minecraft останется на месте.",
|
||||||
"en": "Last build. The contents of .minecraft will stay."
|
"en": "This is the last build. The contents of .minecraft will stay where they are."
|
||||||
},
|
},
|
||||||
"build.label.active": {
|
"build.label.active": {
|
||||||
"ru": "активна",
|
"ru": "активна",
|
||||||
@@ -360,8 +360,8 @@
|
|||||||
"en": "Server address"
|
"en": "Server address"
|
||||||
},
|
},
|
||||||
"build.placeholder.name": {
|
"build.placeholder.name": {
|
||||||
"ru": "Введите наименование",
|
"ru": "как её видно в списке",
|
||||||
"en": "Write a name"
|
"en": "as it appears in the list"
|
||||||
},
|
},
|
||||||
"build.placeholder.serverAddress": {
|
"build.placeholder.serverAddress": {
|
||||||
"ru": "host:port (необязательно)",
|
"ru": "host:port (необязательно)",
|
||||||
@@ -384,8 +384,8 @@
|
|||||||
"en": "Build \"%1\": %2"
|
"en": "Build \"%1\": %2"
|
||||||
},
|
},
|
||||||
"build.status.ready": {
|
"build.status.ready": {
|
||||||
"ru": "Готова к запуску",
|
"ru": "Всё на месте, сборку можно запускать",
|
||||||
"en": "Ready to launch"
|
"en": "Everything is in place, the build can be launched"
|
||||||
},
|
},
|
||||||
"build.title.numbered": {
|
"build.title.numbered": {
|
||||||
"ru": "Сборка %1",
|
"ru": "Сборка %1",
|
||||||
@@ -396,8 +396,8 @@
|
|||||||
"en": "Remove the build?"
|
"en": "Remove the build?"
|
||||||
},
|
},
|
||||||
"build.warning.archiveGoesToo": {
|
"build.warning.archiveGoesToo": {
|
||||||
"ru": "Внимание, при удалении так же очищаются пользовательские сохранённые архивы.",
|
"ru": "Вместе с ней удалится её архив: моды, конфиги и миры этой сборки восстановить будет нельзя.",
|
||||||
"en": "Attention, after removing from the list all saved files will be deleted."
|
"en": "Its archive goes with it: the mods, configs and worlds of this build cannot be recovered."
|
||||||
},
|
},
|
||||||
"build.warning.archiveNotRemoved": {
|
"build.warning.archiveNotRemoved": {
|
||||||
"ru": "Сборка «%1» удалена, но её архив в %2 стереть не удалось",
|
"ru": "Сборка «%1» удалена, но её архив в %2 стереть не удалось",
|
||||||
@@ -1364,8 +1364,8 @@
|
|||||||
"en": "%1 — downloading"
|
"en": "%1 — downloading"
|
||||||
},
|
},
|
||||||
"settings.status.javaRuntimeNone": {
|
"settings.status.javaRuntimeNone": {
|
||||||
"ru": "не выбрана",
|
"ru": "не выбрана — искать в системе",
|
||||||
"en": "not selected"
|
"en": "not selected — search the system"
|
||||||
},
|
},
|
||||||
"settings.status.resolvedGameDir": {
|
"settings.status.resolvedGameDir": {
|
||||||
"ru": "Папка игры: %1",
|
"ru": "Папка игры: %1",
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
IDI_ICON1 ICON "icon.ico"
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
BiLauncher — сторонние компоненты и их лицензии
|
|
||||||
================================================
|
|
||||||
|
|
||||||
Сам BiLauncher распространяется по Apache License 2.0 (см. файл LICENSE).
|
|
||||||
В дистрибутив входят следующие сторонние компоненты.
|
|
||||||
|
|
||||||
|
|
||||||
1. Qt 6.11 (The Qt Company Ltd.)
|
|
||||||
--------------------------------
|
|
||||||
Модули: Qt Core, Gui, Network, Qml, Quick, Quick Controls 2, Svg, WebEngine,
|
|
||||||
WebChannel, Positioning и их плагины.
|
|
||||||
|
|
||||||
Используются по лицензии GNU Lesser General Public License v3 (LGPLv3).
|
|
||||||
Библиотеки Qt подключены динамически и лежат в дистрибутиве отдельными файлами:
|
|
||||||
пользователь вправе заменить их своей сборкой Qt той же версии.
|
|
||||||
|
|
||||||
Текст LGPLv3: https://www.gnu.org/licenses/lgpl-3.0.html
|
|
||||||
Исходный код Qt: https://download.qt.io/official_releases/qt/6.11/
|
|
||||||
https://code.qt.io/cgit/qt/
|
|
||||||
Сведения о лицензиях: https://doc.qt.io/qt-6/licensing.html
|
|
||||||
|
|
||||||
|
|
||||||
2. Qt WebEngine / Chromium
|
|
||||||
--------------------------
|
|
||||||
Qt WebEngine основан на проекте Chromium и включает множество сторонних
|
|
||||||
библиотек под лицензиями BSD, MIT, LGPL, MPL и другими. Полный перечень:
|
|
||||||
|
|
||||||
https://doc.qt.io/qt-6/qtwebengine-licensing.html
|
|
||||||
|
|
||||||
Исходный код Qt WebEngine: https://code.qt.io/cgit/qt/qtwebengine.git/
|
|
||||||
|
|
||||||
|
|
||||||
3. zlib 1.3.1 (только сборка для Linux)
|
|
||||||
---------------------------------------
|
|
||||||
Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
|
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
|
||||||
warranty. In no event will the authors be held liable for any damages
|
|
||||||
arising from the use of this software.
|
|
||||||
|
|
||||||
Permission is granted to anyone to use this software for any purpose,
|
|
||||||
including commercial applications, and to alter it and redistribute it
|
|
||||||
freely, subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must not
|
|
||||||
claim that you wrote the original software. If you use this software
|
|
||||||
in a product, an acknowledgment in the product documentation would be
|
|
||||||
appreciated but is not required.
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
misrepresented as being the original software.
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
Jean-loup Gailly Mark Adler
|
|
||||||
jloup@gzip.org madler@alumni.caltech.edu
|
|
||||||
|
|
||||||
|
|
||||||
4. Inno Setup (только установщик для Windows)
|
|
||||||
---------------------------------------------
|
|
||||||
Установщик для Windows собран с помощью Inno Setup.
|
|
||||||
Copyright (C) 1997-2026 Jordan Russell, Martijn Laan. https://jrsoftware.org/
|
|
||||||
Лицензия: https://jrsoftware.org/files/is/license.txt
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
; Установщик BiLauncher для Windows (Inno Setup 6).
|
|
||||||
;
|
|
||||||
; Собирается в CI после `cmake --install`:
|
|
||||||
; iscc /DAppVersion=1.0.0 /DSourceDir=C:\...\stage /DOutputDir=C:\...\dist packaging\windows\BiLauncher.iss
|
|
||||||
; SourceDir — префикс установки: bin\ с BiLauncher.exe и развёрнутым windeployqt Qt,
|
|
||||||
; share\doc\BiLauncher\ с лицензиями.
|
|
||||||
|
|
||||||
#ifndef AppVersion
|
|
||||||
#error Передайте версию: /DAppVersion=X.Y.Z
|
|
||||||
#endif
|
|
||||||
#ifndef SourceDir
|
|
||||||
#error Передайте префикс установки: /DSourceDir=...
|
|
||||||
#endif
|
|
||||||
#ifndef OutputDir
|
|
||||||
#define OutputDir "."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
[Setup]
|
|
||||||
; AppId не менять между версиями — по нему обновление находит прежнюю установку.
|
|
||||||
AppId={{6E0B5C1D-8F2A-4C7E-9B3D-2A1F4E5C7B90}
|
|
||||||
AppName=BiLauncher
|
|
||||||
AppVersion={#AppVersion}
|
|
||||||
AppVerName=BiLauncher {#AppVersion}
|
|
||||||
AppPublisher=GaleonDev
|
|
||||||
AppPublisherURL=https://projects-live.galeonworx.com/galeon/BiLauncher
|
|
||||||
AppSupportURL=https://projects-live.galeonworx.com/galeon/BiLauncher/issues
|
|
||||||
VersionInfoVersion={#AppVersion}
|
|
||||||
DefaultDirName={autopf}\BiLauncher
|
|
||||||
DefaultGroupName=BiLauncher
|
|
||||||
DisableProgramGroupPage=yes
|
|
||||||
LicenseFile={#SourceDir}\share\doc\BiLauncher\LICENSE
|
|
||||||
OutputDir={#OutputDir}
|
|
||||||
OutputBaseFilename=BiLauncher-{#AppVersion}-win64-setup
|
|
||||||
SetupIconFile=..\..\icons\icon.ico
|
|
||||||
UninstallDisplayIcon={app}\bin\BiLauncher.exe
|
|
||||||
Compression=lzma2/ultra64
|
|
||||||
SolidCompression=yes
|
|
||||||
LZMANumBlockThreads=4
|
|
||||||
ArchitecturesAllowed=x64compatible
|
|
||||||
ArchitecturesInstallIn64BitMode=x64compatible
|
|
||||||
PrivilegesRequiredOverridesAllowed=dialog
|
|
||||||
WizardStyle=modern
|
|
||||||
|
|
||||||
[Languages]
|
|
||||||
Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl"
|
|
||||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
|
||||||
|
|
||||||
[Tasks]
|
|
||||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
|
|
||||||
|
|
||||||
[Files]
|
|
||||||
Source: "{#SourceDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: "vc_redist.x64.exe"
|
|
||||||
#ifexist SourceDir + "\bin\vc_redist.x64.exe"
|
|
||||||
Source: "{#SourceDir}\bin\vc_redist.x64.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
|
|
||||||
#endif
|
|
||||||
|
|
||||||
[Icons]
|
|
||||||
Name: "{autoprograms}\BiLauncher"; Filename: "{app}\bin\BiLauncher.exe"
|
|
||||||
Name: "{autodesktop}\BiLauncher"; Filename: "{app}\bin\BiLauncher.exe"; Tasks: desktopicon
|
|
||||||
|
|
||||||
[Run]
|
|
||||||
#ifexist SourceDir + "\bin\vc_redist.x64.exe"
|
|
||||||
Filename: "{tmp}\vc_redist.x64.exe"; Parameters: "/install /quiet /norestart"; StatusMsg: "Установка Microsoft Visual C++ Runtime..."; Flags: waituntilterminated
|
|
||||||
#endif
|
|
||||||
Filename: "{app}\bin\BiLauncher.exe"; Description: "{cm:LaunchProgram,BiLauncher}"; Flags: nowait postinstall skipifsilent
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "zlibreference.h"
|
#include "zlibreference.h"
|
||||||
#include "localization.h"
|
#include "localization.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QProcessEnvironment>
|
#include <QProcessEnvironment>
|
||||||
|
|||||||