2.0.0 beta 4

- made preparations to make discord rpc settings
- fixed game updating mechanism
- fixed `Patch.getPatchInfo()` method work
- added proper design for patch-related launcher states
- fixed progress bar displaying issues during pre-downloaded game unpacking
This commit is contained in:
Observer KRypt0n_ 2022-01-05 00:52:26 +02:00
parent 7ecab2f995
commit 6fb8852ef4
No known key found for this signature in database
GPG key ID: DC5D4EC1303465DA
23 changed files with 214 additions and 68 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

View file

@ -44,8 +44,15 @@ settings:
light: Hell
dark: Dunkel
discord: Discord RPC
dxvks: DXVK
# Discord RPC
discord:
title: Discord RPC
settings:
title: Discord RPC settings
items:
timer: Display spent time
in-launcher: In-launcher text
in-game: In-game text
# Verberssungen
enhancements:

View file

@ -44,8 +44,15 @@ settings:
light: Light
dark: Dark
discord: Discord RPC
dxvks: DXVK
# Discord RPC
discord:
title: Discord RPC
settings:
title: Discord RPC settings
items:
timer: Display spent time
in-launcher: In-launcher text
in-game: In-game text
# Enhancements
enhancements:

View file

@ -44,8 +44,15 @@ settings:
light: Светлая
dark: Тёмная
discord: Discord RPC
dxvks: DXVK
# Discord RPC
discord:
title: Discord RPC
settings:
title: Настройки Discord RPC
items:
timer: Отображать потраченное время
in-launcher: Текст в лаунчере
in-game: Текст в игре
# Улучшения
enhancements:

View file

@ -0,0 +1,35 @@
<script lang="ts">
import { _ } from 'svelte-i18n';
export let visible: boolean = false;
export let valuesChanged: (values: { game: string, launcher: string }) => void = () => {};
import Checkbox from './Checkbox.svelte';
</script>
<div style="display: {visible ? 'block' : 'none'}">
<h3>{$_('settings.general.items.discord.settings.title')}</h3>
<Checkbox lang="settings.general.items.discord.settings.items.timer" prop="discord.fields.timer" />
<table class="table" style="margin-top: 16px">
<tr>
<td>
<span>{$_('settings.general.items.discord.settings.items.in-launcher')}</span>
</td>
<td>
<input value="Preparing to launch" on:input={(value) => console.log(value)}>
</td>
</tr>
<tr>
<td>
<span>{$_('settings.general.items.discord.settings.items.in-game')}</span>
</td>
<td>
<input value="Playing the game">
</td>
</tr>
</table>
</div>

View file

@ -81,24 +81,19 @@ promisify(async () => {
* RPC settings
*/
fields: {
/**
* Launcher title
*/
title: 'An Anime Game Launcher',
/**
* Small messages after title
*/
state: {
/**
* Message showed when you're in game
*/
'in-launcher': 'Playing the game',
states: {
/**
* Message showed when you're in launcher
*/
'in-game': 'Preparing to launch'
'in-launcher': 'Preparing to launch',
/**
* Message showed when you're in game
*/
'in-game': 'Playing the game'
},
/**

View file

@ -4,6 +4,7 @@
@import "components/selectionBox"
@import "components/dropdownCheckboxes"
@import "components/selectionList"
@import "components/table"
@mixin themable($theme-name, $theme-map)
body[data-theme=#{$theme-name}]

View file

@ -0,0 +1,65 @@
@use "sass:map"
@mixin themable($theme-name, $theme-map)
body[data-theme=#{$theme-name}]
table.table
width: calc(100% - 24px)
margin-left: 12px
border-spacing: 0
$cell-height: 40px
$padding-v: 4px
$padding-h: 8px
tr
height: $cell-height
cursor: pointer
&:hover
background-color: map.get($theme-map, "background1")
td input
background-color: map.get($theme-map, "background1")
td:nth-of-type(1),
th:nth-of-type(1)
width: 40%
th,
td
border-bottom: 1px solid map.get($theme-map, "background1")
&:not(:last-child)
border-right: 1px solid map.get($theme-map, "background1")
td
span
display: block
width: calc(100% - 2 * $padding-h)
height: calc($cell-height - 2 * $padding-h)
margin: auto
input
display: block
width: calc(100% - 2 * $padding-h)
height: calc($cell-height - 2 * $padding-h)
color: map.get($theme-map, "text")
font-size: 15px
margin: auto
border: unset
outline: none
@import "../themes/light"
@import "../themes/dark"
@include themable(light, $light)
@include themable(dark, $dark)

View file

@ -15,6 +15,7 @@
import Checkbox from './components/Checkbox.svelte';
import SelectionBox from './components/SelectionBox.svelte';
import DropdownCheckboxes from './components/DropdownCheckboxes.svelte';
import DiscordSettings from './components/DiscordSettings.svelte';
import DXVKSelectionList from './components/DXVKSelectionList.svelte';
import RunnerSelectionList from './components/RunnerSelectionList.svelte';
import ShadersSelection from './components/ShadersSelection.svelte';
@ -110,9 +111,12 @@
let dxvkRecommendable = true,
runnersRecommendable = true,
discordRpcSettings = false,
fpsUnlockerAvailable = true,
voiceUpdateRequired = false;
Configs.get('discord.enabled').then((enabled) => discordRpcSettings = enabled as boolean);
// Auto theme switcher
Configs.get('theme').then((theme) => switchTheme(theme as string));
@ -169,7 +173,13 @@
valueChanged={switchTheme}
/>
<Checkbox lang="settings.general.items.discord" prop="discord.enabled" />
<Checkbox
lang="settings.general.items.discord.title"
prop="discord.enabled"
valueChanged={(value) => discordRpcSettings = value}
/>
<DiscordSettings visible={discordRpcSettings} />
</div>
<div class="settings-item" id="enhancements">

View file

@ -34,12 +34,12 @@ export default class Game
public static get current(): Promise<string|null>
{
return new Promise(async (resolve) => {
const persistentPath = `${await constants.paths.gameDataDir}/Persistent/ScriptVersion`;
// const persistentPath = `${await constants.paths.gameDataDir}/Persistent/ScriptVersion`;
const globalGameManagersPath = `${await constants.paths.gameDataDir}/globalgamemanagers`;
Neutralino.filesystem.readFile(persistentPath)
/*Neutralino.filesystem.readFile(persistentPath)
.then((version) => resolve(version))
.catch(() => {
.catch(() => {*/
Neutralino.filesystem.readBinaryFile(globalGameManagersPath)
.then((config: ArrayBuffer) => {
const buffer = new TextDecoder('ascii').decode(new Uint8Array(config));
@ -53,7 +53,7 @@ export default class Game
resolve(version !== null ? version[1] : null);
})
.catch(() => resolve(null));
});
// });
});
}

View file

@ -105,10 +105,7 @@ export default class Launcher
id: '901534333360304168',
// @ts-expect-error
details: discord.fields.title,
// @ts-expect-error
state: discord.fields.state[state],
details: discord.fields.states[state],
icon: {
// @ts-expect-error
@ -117,7 +114,7 @@ export default class Launcher
time: {
// @ts-expect-error
start: discord.fields.time ? Math.round(Date.now() / 1000) : 0
start: discord.fields.timer ? Math.round(Date.now() / 1000) : 0
}
});

View file

@ -192,21 +192,20 @@ export default class Patch
return new Promise(async (resolve, reject) => {
const patchUri = constants.uri.patch[source];
fetch(`${patchUri}/raw/master/${version.replaceAll('.', '')}/patch.sh`, this.fetchTimeout)
.then((patcherResponse) => {
fetch(`${patchUri}/raw/master/${version.replaceAll('.', '')}/README.txt`, this.fetchTimeout)
.then((readmeResponse) => {
// Return an error if patch's server is unavailable
if (patcherResponse.status === null)
if (readmeResponse.status === null)
reject(new Error(`${source} patch repository is unreachable`));
// If [version]/patch.sh file doesn't exist - it means
// If [version]/README.txt file doesn't exist - it means
// that patch repo has no [version]
else if (patcherResponse.status === 404)
else if (readmeResponse.status === 404)
resolve(null);
// Otherwise it should be [preparation], [testing] or [stable]
else
{
fetch(`${patchUri}/raw/master/${version.replaceAll('.', '')}/patch_files/unityplayer_patch.vcdiff`, this.fetchTimeout)
.then((response) => {
// Return an error if patch's server is unavailable
@ -228,46 +227,53 @@ export default class Patch
// Otherwise it's [testing] or [stable]
else
{
patcherResponse.body(this.fetchTimeout)
.then((response) => {
fetch(`${patchUri}/raw/master/${version.replaceAll('.', '')}/patch.sh`, this.fetchTimeout)
.then((patcherResponse) => {
// Return an error if patch's server is unavailable
if (response === '')
if (patcherResponse.status === null)
reject(new Error(`${source} patch repository is unreachable`));
// Otherwise - let's prepare [testing] or [stable] output
else
{
// If this line is commented - then it's [stable] version
// Otherwise it's [testing]
const stableMark = '#echo "If you would like to test this patch, modify this script and remove the line below this one."';
else patcherResponse.body(this.fetchTimeout)
.then((response) => {
// Return an error if patch's server is unavailable
if (response === '')
reject(new Error(`${source} patch repository is unreachable`));
let patchInfo: PatchInfo = {
version: version,
state: response.includes(stableMark) ? 'stable' : 'testing',
applied: false,
source: source
};
// Otherwise - let's prepare [testing] or [stable] output
else
{
// If this line is commented - then it's [stable] version
// Otherwise it's [testing]
const stableMark = '#echo "If you would like to test this patch, modify this script and remove the line below this one."';
const originalPlayer = /if \[ "\${sum}" != "([a-z0-9]{32})" \]; then/mg.exec(response);
let patchInfo: PatchInfo = {
version: version,
state: response.includes(stableMark) ? 'stable' : 'testing',
applied: false,
source: source
};
// If we could get original UnityPlayer.dll hash - then we can
// compare it with actual UnityPlayer.dll hash and say whether the patch
// was applied or not
if (originalPlayer !== null)
{
constants.paths.gameDir.then((gameDir) => {
Neutralino.filesystem.readBinaryFile(`${gameDir}/UnityPlayer.dll`)
.then((currPlayer: ArrayBuffer) => {
patchInfo.applied = md5(currPlayer) != originalPlayer[1];
const originalPlayer = /if \[ "\${sum}" != "([a-z0-9]{32})" \]; then/mg.exec(response);
resolve(patchInfo);
})
.catch(() => resolve(patchInfo));
});
}
// If we could get original UnityPlayer.dll hash - then we can
// compare it with actual UnityPlayer.dll hash and say whether the patch
// was applied or not
if (originalPlayer !== null)
{
constants.paths.gameDir.then((gameDir) => {
Neutralino.filesystem.readBinaryFile(`${gameDir}/UnityPlayer.dll`)
.then((currPlayer: ArrayBuffer) => {
patchInfo.applied = md5(currPlayer) != originalPlayer[1];
else resolve(patchInfo);
}
resolve(patchInfo);
})
.catch(() => resolve(patchInfo));
});
}
else resolve(patchInfo);
}
});
});
}
});

View file

@ -152,14 +152,20 @@ export default class State
case 'test-patch-available':
this.launchButton.textContent = 'Apply test patch';
this.launchButton.classList.add('button-blue');
this.launchButton.setAttribute('aria-label', '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');
break;
case 'patch-unavailable':
// TODO: some warning message
this.launchButton.textContent = 'Patch unavailable';
this.launchButton.classList.add('button-blue');
this.launchButton.setAttribute('disabled', '');
this.launchButton.setAttribute('aria-label', 'This game version has no anti-cheat patch. Please, wait a few days before there will be a test or stable version');
break;
}
}
@ -293,13 +299,19 @@ export default class State
{
const patch = await Patch.latest;
if (!patch.applied)
// If the latest game version is, for example, 2.3.0
// and the patch is 2.4.0 preparation, it means that
// 2.4.0 will be released soon, but since it's still not released
// we shouldn't show something about it to user and just let him play the game
if (gameLatest.game.latest.version === patch.version && !patch.applied)
{
state = patch.state == 'preparation' ?
'patch-unavailable' : (patch.state == 'testing' ?
'test-patch-available' : 'patch-available');
}
// Patch is more important than game pre-downloading
// because otherwise we will not be able to play the game
else if (gameLatest.pre_download_game && !await Game.isUpdatePredownloaded())
state = 'game-pre-installation-available';

View file

@ -45,6 +45,8 @@ export default (launcher: Launcher): Promise<void> => {
showPercents: true,
showTotals: true
});
launcher.progressBar?.show();
});
stream?.unpackProgress((current: number, total: number, difference: number) => {

View file

@ -71,6 +71,8 @@ export default (launcher: Launcher): Promise<void> => {
showPercents: true,
showTotals: true
});
launcher.progressBar?.show();
});
stream?.unpackProgress((current: number, total: number, difference: number) => {