- added statistics section
  for now launcher stores time spent in the game
- added Korean machine translation
- fixed an issue with analytics dialogue
- improved new launcher versions finder algorithm
This commit is contained in:
Observer KRypt0n_ 2021-11-11 12:20:27 +02:00
parent dbf8540946
commit 23d2a9a9f7
No known key found for this signature in database
GPG key ID: DC5D4EC1303465DA
24 changed files with 152 additions and 69 deletions

View file

@ -10,7 +10,7 @@
| Game version | Launcher version | Patch version |
| :---: | :---: | :---: |
| 2.2.0 | 1.4.0 | 2.2.0 stable ✅ |
| 2.2.0 | 1.4.1 | 2.2.0 stable ✅ |
Download from [Releases](https://notabug.org/nobody/an-anime-game-launcher/releases)
@ -89,14 +89,15 @@ npm start
* <s>Add installed packages deletion</s> *(1.2.0)*
* <s>Add voice packs support</s> (Thank @Maroxy for the developments in the previous versions) *(1.3.0)*
* <s>Color variants for progress bar's downloading text dependent on the background picture primary color</s> *(1.4.0)*
* <s>Playing statistics</s> *(1.4.1)*
* Make force launch button when the launcher's repository is unavailable
* Screenshots explorer
* Add vkBasalt support and "shaders library
* Add vkBasalt support and "shaders library" (the problem is, we don't have vkBasalt binaries, but the source code)
* Set default wine version to download so the wine install requirement is no longer needed
* Add Patch category in settings menu with
- Always participate in patches testing
- Applying anti login crash patch
- Remove patch
* Playing statistics
And don't forget to change the patch's URI when it will be changed

View file

@ -1,6 +1,6 @@
{
"name": "an-anime-game-linux-launcher",
"version": "1.4.0",
"version": "1.4.1",
"description": "An Anime Game Linux Launcher",
"author": "Nikita Podvirnyy <suimin.tu.mu.ga.mi@gmail.com>",
"contributors": [

View file

@ -23,6 +23,7 @@
<div class="menu-item" anchor="runners" i18id="WineVersion">Wine version</div>
<div class="menu-item" anchor="dxvks" i18id="DXVK">DXVK</div>
<div class="menu-item" anchor="environment" i18id="Environment">Environment</div>
<div class="menu-item" anchor="statistics" i18id="Statistics">Statistics</div>
</div>
<div class="settings">
@ -130,6 +131,16 @@
</div>
</div>
</div>
<div class="settings-item" id="statistics">
<h2 i18id="Statistics">Statistics</h2>
<div>
<span i18id="YouPlayedFor">You've played for</span>
<span id="play-hours"></span>
<span i18id="hours">hours</span>
</div>
</div>
</div>
</body>
</html>

View file

@ -16,6 +16,9 @@
"Value": "Wert",
"Add": "Hinzufügen",
"Delete": "Löschen",
"Statistics": "Statistics",
"YouPlayedFor": "You've played for",
"hours": "hours",
"Downloading": "wird Heruntergeladen",
"Unpack": "wird Entpackt",
"GameDownloaded": "Spiel würde erfolgreich heruntergeladen",

View file

@ -17,6 +17,9 @@
"Value": "Value",
"Add": "Add",
"Delete": "Delete",
"Statistics": "Statistics",
"YouPlayedFor": "You've played for",
"hours": "hours",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...",

View file

@ -16,6 +16,9 @@
"Value": "Value",
"Add": "Add",
"Delete": "Delete",
"Statistics": "Statistics",
"YouPlayedFor": "You've played for",
"hours": "hours",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",

View file

@ -16,6 +16,9 @@
"Value": "Value",
"Add": "Add",
"Delete": "Delete",
"Statistics": "Statistics",
"YouPlayedFor": "You've played for",
"hours": "hours",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",

View file

@ -16,6 +16,9 @@
"Value": "Value",
"Add": "Add",
"Delete": "Delete",
"Statistics": "Statistics",
"YouPlayedFor": "You've played for",
"hours": "hours",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",

View file

@ -16,6 +16,9 @@
"Value": "Value",
"Add": "Add",
"Delete": "Delete",
"Statistics": "Statistics",
"YouPlayedFor": "You've played for",
"hours": "hours",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",

View file

@ -17,6 +17,9 @@
"Value": "バリュー",
"Add": "加える",
"Delete": "削除",
"Statistics": "統計",
"YouPlayedFor": "あなたはのためにプレーしてきました",
"hours": "時間",
"Unpack": "開梱",
"GameDownloaded": "ゲームのインストールに成功しました",
"ApplyPatch": "パッチの適用...",

View file

@ -1,38 +1,41 @@
{
"Install": "Install",
"Update": "Update",
"Launch": "Launch",
"Runners": "Runners",
"Language": "Language",
"Voice": "Voice Pack",
"VoiceNotification": "This feature requires you to manually select the new voice pack in the game",
"AutoTheme": "Automatic theme switching",
"SettingsTitle": "Settings",
"GeneralSettings": "General",
"WineVersion": "Wine version",
"Environment": "Environment",
"EnvironmentalVariables": "Environmental variables",
"Name": "Name",
"Value": "Value",
"Add": "Add",
"Delete": "Delete",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again",
"TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk",
"AnalyticsTitle": "Yanfei's commission...",
"ParticipateInAnalytics": "Participate in anonymous data collection",
"AnalyticsText1": "To count the active user base for Linux, Yanfei would like to collect your IP address everytime the game updates",
"AnalyticsText2": "The IP address will be hashed for security purpose",
"AnalyticsShareCountry": "Share country",
"Participate": "Participate",
"Skip": "Skip",
"SkipAndDontAsk": "Skip and don't ask again",
"LauncherUpdateTitle": "Launcher update available: ",
"LauncherUpdateBody": "You can download a new version of the launcher from the project's repository at {uri.launcher}",
"TelemetryNotDisabled": "{placeholders.uppercase.company}'s telemetry servers don't disabled!"
"Install": "설치",
"Update": "업데이트",
"Launch": "발사",
"Runners": "주자",
"Language": "언어",
"Voice": "음성 팩",
"VoiceNotification": "이 기능을 사용하려면 게임에서 새 음성 팩을 수동으로 선택해야합니다",
"AutoTheme": "자동 테마 전환",
"SettingsTitle": "설정",
"GeneralSettings": "일반",
"WineVersion": "와인 버전",
"Environment": "환경",
"EnvironmentalVariables": "환경 변수",
"Name": "이름",
"Value": "가치",
"Add": "추가",
"Delete": "삭제",
"Statistics": "통계",
"YouPlayedFor": "당신은 위해 연주했습니다",
"hours": "시간",
"Downloading": "다운로드 중",
"Unpack": "풀기",
"GameDownloaded": "게임이 성공적으로 설치되었습니다",
"ApplyPatch": "패치 적용...",
"PatchRequired": "패치 필요",
"PatchRequiredHint": "이 게임 버전에는 안티 치트 패치가 없습니다. 며칠 기다렸다가 다시 시도하십시오",
"TestPatch": "테스트 패치 적용",
"TestPatchHint": "이 게임 버전에는 안티 치트 패치가 있지만 테스트 단계에 있습니다. 안정 될 때까지 며칠을 기다리거나 자신의 위험에 따라 적용 할 수 있습니다",
"AnalyticsTitle": "Yanfei 의위원회...",
"ParticipateInAnalytics": "익명 데이터 수집에 참여",
"AnalyticsText1": "리눅스에 대한 활성 사용자 기반을 계산하려면,Yanfei 는 게임 업데이트마다 IP 주소를 수집하고 싶습니다",
"AnalyticsText2": "IP 주소는 보안 목적으로 해시됩니다",
"AnalyticsShareCountry": "공유 국가",
"Participate": "참여",
"Skip": "건너 뛰기",
"SkipAndDontAsk": "건너 뛰고 다시 묻지 마십시오",
"LauncherUpdateTitle": "실행기 업데이트 가능: ",
"LauncherUpdateBody": "에서 프로젝트의 저장소에서 실행기의 새 버전을 다운로드 할 수 있습니다 {uri.launcher}",
"TelemetryNotDisabled": "{placeholders.uppercase.company} 의 원격 측정 서버가 비활성화되지 않음!"
}

View file

@ -16,6 +16,9 @@
"Value": "Value",
"Add": "Add",
"Delete": "Delete",
"Statistics": "Statistics",
"YouPlayedFor": "You've played for",
"hours": "hours",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",

View file

@ -16,6 +16,9 @@
"Value": "Значение",
"Add": "Добавить",
"Delete": "Удалить",
"Statistics": "Статистика",
"YouPlayedFor": "Вы играли",
"hours": "часов",
"Downloading": "Загрузка",
"Unpack": "Распаковка",
"GameDownloaded": "Игра была успешно установлена",

View file

@ -16,6 +16,9 @@
"Value": "Value",
"Add": "Add",
"Delete": "Delete",
"Statistics": "Statistics",
"YouPlayedFor": "You've played for",
"hours": "hours",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",

View file

@ -16,6 +16,9 @@
"Value": "Value",
"Add": "Add",
"Delete": "Delete",
"Statistics": "Statistics",
"YouPlayedFor": "You've played for",
"hours": "hours",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",

View file

@ -17,6 +17,9 @@
"Value": "Value",
"Add": "Add",
"Delete": "Delete",
"Statistics": "Statistics",
"YouPlayedFor": "You've played for",
"hours": "hours",
"Unpack": "开箱",
"GameDownloaded": "游戏安装成功",
"ApplyPatch": "应用补丁...",

View file

@ -17,6 +17,9 @@
"Value": "Value",
"Add": "Add",
"Delete": "Delete",
"Statistics": "Statistics",
"YouPlayedFor": "You've played for",
"hours": "hours",
"Unpack": "解壓縮中...",
"GameDownloaded": "遊戲安裝成功",
"ApplyPatch": "套用補丁...",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 349 KiB

After

Width:  |  Height:  |  Size: 348 KiB

View file

@ -1,6 +1,7 @@
const { ipcRenderer } = require('electron');
import $ from 'cash-dom';
import { LauncherLib } from './lib/LauncherLib';
import { LauncherUI } from './lib/LauncherUI';
@ -10,13 +11,18 @@ $(() => {
$('#participate').on('click', async () => {
await fetch(`https://an-anime-game-launcher.000webhostapp.com${ !$('#share-country').hasClass('checkbox-active') ? '/?hide-geo' : '' }`);
LauncherLib.updateConfig('analytics', LauncherLib.version);
// LauncherLib.version can break this property
// because analytics can be displayed even with the first
// launcher's run and then of course uninstalled game's version
// will be "null", which in analytics means that user don't
// want to see this dialog anymore
LauncherLib.updateConfig('analytics', (await LauncherLib.getData()).game.latest.version);
ipcRenderer.invoke('hide-analytics-participation');
});
$('#skip').on('click', () => {
LauncherLib.updateConfig('analytics', LauncherLib.version);
$('#skip').on('click', async () => {
LauncherLib.updateConfig('analytics', (await LauncherLib.getData()).game.latest.version);
ipcRenderer.invoke('hide-analytics-participation');
});

View file

@ -69,13 +69,14 @@ $(() => {
LauncherUI.updateLauncherState();
});
Tools.getGitTags(constants.uri.launcher).then (tags => {
if (tags.filter(entry => semver.gt(entry.tag, launcher_version)).length > 0)
Tools.getGitTags(constants.uri.launcher).then(tags => {
const latestVersion = tags[tags.length - 1].tag;
if (latestVersion && semver.gt(latestVersion, launcher_version))
{
ipcRenderer.send('notification', {
title: `${LauncherUI.i18n.translate('LauncherUpdateTitle')} (${launcher_version} -> ${tags[tags.length - 1].tag})`,
body: LauncherUI.i18n.translate('LauncherUpdateBody'),
timeoutType: 'never'
title: `${LauncherUI.i18n.translate('LauncherUpdateTitle')} (${launcher_version} -> ${latestVersion})`,
body: LauncherUI.i18n.translate('LauncherUpdateBody')
});
}
});
@ -117,21 +118,21 @@ $(() => {
if (LauncherUI.launcherState == 'game-launch-available')
{
console.log(`%c> Starting the game...`, 'font-size: 16px');
if (!await LauncherLib.isTelemetryDisabled())
{
console.log(`${constants.placeholders.uppercase.company}'s telemetry servers doesn't disabled!`);
ipcRenderer.send('notification', {
title: document.title,
body: LauncherUI.i18n.translate('TelemetryNotDisabled')
});
}
else
{
let wineExeutable = 'wine';
if (LauncherLib.getConfig('runner') !== null)
{
wineExeutable = path.join(
@ -139,27 +140,29 @@ $(() => {
LauncherLib.getConfig('runner.folder'),
LauncherLib.getConfig('runner.executable')
);
if (!fs.existsSync(wineExeutable))
{
wineExeutable = 'wine';
LauncherLib.updateConfig('runner', null);
}
}
console.log(`Wine executable: ${wineExeutable}`);
if (DiscordRPC.isActive())
{
DiscordRPC.setActivity({
details: 'In-Game',
largeImageKey: 'game',
largeImageText: 'An Anime Game Launcher',
startTimestamp: new Date().setDate(new Date().getDate())
startTimestamp: Date.now()
});
}
const startTime = Date.now();
exec(`${wineExeutable} launcher.bat`, {
cwd: constants.gameDir,
env: {
@ -169,9 +172,13 @@ $(() => {
}
}, (err: any, stdout: any, stderr: any) => {
console.log(`%c> Game closed`, 'font-size: 16px');
const playtime = Date.now() - startTime;
ipcRenderer.invoke('show-window');
LauncherLib.updateConfig('playtime', LauncherLib.getConfig('playtime') + Math.round(playtime / 1000));
if (DiscordRPC.isActive())
{
DiscordRPC.setActivity({
@ -180,12 +187,12 @@ $(() => {
largeImageText: 'An Anime Game Launcher'
});
}
console.log(err);
console.log(stdout);
console.log(stderr);
});
ipcRenderer.invoke('hide-window');
}
}

View file

@ -6,7 +6,6 @@ const fs = require('fs');
const path = require('path');
const os = require('os');
const { spawn, exec } = require('child_process');
const dns = require('dns');
const store = require('electron-store');
const https = require('follow-redirects').https;
@ -43,7 +42,9 @@ const config = new store ({
// FidelityFX Super Resolution
WINE_FULLSCREEN_FSR: '1',
WINE_FULLSCREEN_FSR_STRENGTH: '3'
}
},
playtime: 0 // Number of seconds user spent in game
}
});
@ -118,9 +119,10 @@ export class LauncherLib
response.on('data', (chunk: any) => data += chunk);
response.on('end', () => {
let jsondata: GIJSON = JSON.parse(data);
const jsonData: GIJSON = JSON.parse(data);
return jsondata.message === 'OK' ? resolve(jsondata.data) : reject(null);
return jsonData.message === 'OK' ?
resolve(jsonData.data) : reject(null);
});
}).on('error', (err: Error) => reject(err));
});
@ -216,7 +218,7 @@ export class LauncherLib
// WINEPREFIX='...../wineprefix' winetricks corefonts usetakefocus=n
public static async installPrefix (prefixpath: string, progress: (output: string, current: number, total: number) => void): Promise<void>
{
let installationSteps = [
const installationSteps = [
// corefonts
'Executing w_do_call corefonts',
'Executing load_corefonts',
@ -276,7 +278,7 @@ export class LauncherLib
// Delete zip file and assign patch directory.
fs.unlinkSync(path.join(constants.launcherDir, 'patch.zip'));
let patchDir = path.join(constants.launcherDir, 'gi-on-linux', pathInfo.version.replaceAll('.', ''));
const patchDir = path.join(constants.launcherDir, 'gi-on-linux', pathInfo.version.replaceAll('.', ''));
// Patch out the testing phase content from the shell files if active and make sure the shell files are executable.
exec(`cd ${patchDir} && sed -i '/^echo "If you would like to test this patch, modify this script and remove the line below this one."/,+5d' patch.sh`);

View file

@ -249,6 +249,7 @@ export class LauncherUI
sector.forEach(pixel => meanBrightness += pixel.color.r + pixel.color.g + pixel.color.b);
// TODO: convert RGB mean color to LAB to get real background brightness
meanBrightness /= sector.length * 3;
console.log(`Background's mean brightness is ${meanBrightness}`);

View file

@ -58,7 +58,7 @@ export class Tools
public static async getGitTags (uri: string): Promise<GitTag[]>
{
return new Promise(resolve => {
return new Promise((resolve, reject) => {
let git = spawn('git', ['ls-remote', '--tags', uri]),
tags: GitTag[] = [];
@ -77,6 +77,8 @@ export class Tools
});
});
git.stderr.on('data', (data: string) => reject(data));
git.on('close', () => resolve(tags));
});
}

View file

@ -132,6 +132,17 @@ $(() => {
td.last().find('span').text(value);
});
/**
* Statistics
*/
$('#play-hours').text((LauncherLib.getConfig('playtime') / 3600).toFixed(1).toString());
// Update this once per two minute
setInterval(() => {
$('#play-hours').text((LauncherLib.getConfig('playtime') / 3600).toFixed(1).toString());
}, 120 * 1000);
/**
* Wine versions manager
*/