mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 20:19:49 +02:00
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f355cb9f76 | ||
|
|
e42576b005 | ||
|
|
f68198475e | ||
|
|
896ae20dce | ||
|
|
b8fdc5424d | ||
|
|
204c3eacc1 | ||
|
|
4d0f21e10b | ||
|
|
d3202e8607 | ||
|
|
a438eb704f |
No files matched your search
@@ -2,7 +2,6 @@ name: Website
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: production
|
|
||||||
|
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 4 * * *"
|
- cron: "0 4 * * *"
|
||||||
@@ -34,14 +33,40 @@ on:
|
|||||||
- preview
|
- preview
|
||||||
- opentest
|
- opentest
|
||||||
|
|
||||||
|
client_provider:
|
||||||
|
description: Client provider
|
||||||
|
|
||||||
|
type: choice
|
||||||
|
required: true
|
||||||
|
default: steam
|
||||||
|
|
||||||
|
options:
|
||||||
|
- steam
|
||||||
|
- zip
|
||||||
|
- wgpkg
|
||||||
|
|
||||||
|
client_source:
|
||||||
|
description: Client source
|
||||||
|
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
default: 444200/windows
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ inputs.environment || github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
# client
|
||||||
|
STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }}
|
||||||
|
STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }}
|
||||||
|
CLIENT_PROVIDER: ${{ inputs.client_provider || 'steam' }}
|
||||||
|
CLIENT_SOURCE: ${{ inputs.client_source || '444200/windows' }}
|
||||||
|
CLIENT_DIR: ../../temp/game
|
||||||
|
|
||||||
# blitzkit
|
# blitzkit
|
||||||
PUBLIC_ENVIRONMENT: ${{ inputs.environment || 'production' }}
|
PUBLIC_ENVIRONMENT: ${{ inputs.environment || 'production' }}
|
||||||
PUBLIC_PROMOTE_OPENTEST: false
|
PUBLIC_PROMOTE_OPENTEST: false
|
||||||
@@ -52,7 +77,6 @@ env:
|
|||||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||||
GAME_DIR: ../../temp/game
|
|
||||||
|
|
||||||
# google
|
# google
|
||||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||||
@@ -60,12 +84,6 @@ env:
|
|||||||
# wargaming
|
# wargaming
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||||
|
|
||||||
# steam
|
|
||||||
STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }}
|
|
||||||
STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }}
|
|
||||||
STEAM_APP: 444200
|
|
||||||
STEAM_OS: windows
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build website
|
name: Build website
|
||||||
@@ -73,7 +91,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
chunk: [default, api]
|
chunk: [default, api]
|
||||||
|
|
||||||
@@ -96,44 +114,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GH_TOKEN }}
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
- name: Configure pages
|
- name: Setup CLIs
|
||||||
uses: actions/configure-pages@v6
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y aria2 libarchive-tools
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: bun install
|
run: bun install
|
||||||
|
|
||||||
- name: Setup DepotDownloader
|
- name: Download Client
|
||||||
run: |
|
run: bun run download-client
|
||||||
REPO_USER="SteamRE"
|
|
||||||
REPO_NAME="DepotDownloader"
|
|
||||||
TEMP="temp"
|
|
||||||
|
|
||||||
OUT="$TEMP/$REPO_NAME"
|
|
||||||
ZIP="$TEMP/$REPO_NAME.zip"
|
|
||||||
|
|
||||||
URL=$(
|
|
||||||
curl -s "https://api.github.com/repos/$REPO_USER/$REPO_NAME/releases/latest" \
|
|
||||||
| jq -r '.assets[]
|
|
||||||
| select(.name | contains("linux-x64"))
|
|
||||||
| .browser_download_url' \
|
|
||||||
| head -n 1
|
|
||||||
)
|
|
||||||
|
|
||||||
mkdir -p "$TEMP"
|
|
||||||
curl -L "$URL" -o "$ZIP"
|
|
||||||
unzip -p "$ZIP" "$REPO_NAME" > "$OUT"
|
|
||||||
rm "$ZIP"
|
|
||||||
|
|
||||||
chmod +x "$OUT"
|
|
||||||
|
|
||||||
- name: Download game
|
|
||||||
run: |
|
|
||||||
TEMP="temp"
|
|
||||||
|
|
||||||
DEPOT_DOWNLOADER="$TEMP/DepotDownloader"
|
|
||||||
GAME="$TEMP/game"
|
|
||||||
|
|
||||||
$DEPOT_DOWNLOADER -os $STEAM_OS -app $STEAM_APP -username $STEAM_USERNAME -password $STEAM_PASSWORD -dir $GAME -max-downloads 256
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: bun run --bun build
|
run: bun run --bun build
|
||||||
@@ -149,6 +139,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Trigger deployment
|
- name: Trigger deployment
|
||||||
|
|
||||||
|
if: ${{ github.ref == 'refs/heads/production' }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
TOKEN: ${{ secrets.GH_NODE_DEPLOY_TOKEN }}
|
TOKEN: ${{ secrets.GH_NODE_DEPLOY_TOKEN }}
|
||||||
CHUNK: ${{ matrix.chunk }}
|
CHUNK: ${{ matrix.chunk }}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# BlitzKit 1.31.1
|
||||||
|
|
||||||
|
This update adds capabilities to release BlitzKit OpenTest and Preview.
|
||||||
+3
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "blitzkit",
|
"name": "blitzkit",
|
||||||
"version": "1.31.0",
|
"version": "1.31.1",
|
||||||
"license": "BlitzKit License",
|
"license": "BlitzKit License",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -8,7 +8,8 @@
|
|||||||
"build": "cd packages/website && bun run build",
|
"build": "cd packages/website && bun run build",
|
||||||
"discover-ids": "cd packages/scripts && bun run discover-ids",
|
"discover-ids": "cd packages/scripts && bun run discover-ids",
|
||||||
"build-protos": "cd packages/scripts && bun run build-protos",
|
"build-protos": "cd packages/scripts && bun run build-protos",
|
||||||
"record-performance": "cd packages/scripts && bun run record-performance"
|
"record-performance": "cd packages/scripts && bun run record-performance",
|
||||||
|
"download-client": "cd packages/scripts && bun run download-client"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"hp": "{value}од",
|
"hp": "{value}од",
|
||||||
"x": "x{value}",
|
"x": "x{value}",
|
||||||
"percentage": "{value}%",
|
"percentage": "{value}%",
|
||||||
"deg_s": "{value}°/c",
|
"deg_s": "{value}град/c",
|
||||||
"plus": "+{value}"
|
"plus": "+{value}"
|
||||||
},
|
},
|
||||||
"gun_types": {
|
"gun_types": {
|
||||||
@@ -37,8 +37,8 @@
|
|||||||
"d_1": "Вчора"
|
"d_1": "Вчора"
|
||||||
},
|
},
|
||||||
"branches": {
|
"branches": {
|
||||||
"beta": "Бета",
|
"beta": "Beta",
|
||||||
"development": "Розробка",
|
"development": "Development",
|
||||||
"opentest": "Відкритий тест",
|
"opentest": "Відкритий тест",
|
||||||
"preview": "Preview",
|
"preview": "Preview",
|
||||||
"production": "Production"
|
"production": "Production"
|
||||||
@@ -340,8 +340,8 @@
|
|||||||
},
|
},
|
||||||
"mixer": {
|
"mixer": {
|
||||||
"name": "Mixer",
|
"name": "Mixer",
|
||||||
"button": "Змішувати та поєднувати",
|
"button": "Mix and match",
|
||||||
"description": "Змішані танкові модулі",
|
"description": "Mix tank modules",
|
||||||
"seo_description": "Mix and match hulls, turrets, and guns of tanks in World of Tanks Blitz",
|
"seo_description": "Mix and match hulls, turrets, and guns of tanks in World of Tanks Blitz",
|
||||||
"screenshot": "Знімок екрану",
|
"screenshot": "Знімок екрану",
|
||||||
"randomize": "Рандомізувати"
|
"randomize": "Рандомізувати"
|
||||||
@@ -501,11 +501,11 @@
|
|||||||
"tech_tree": {
|
"tech_tree": {
|
||||||
"title": "Звичайний",
|
"title": "Звичайний",
|
||||||
"battle": "1 бій",
|
"battle": "1 бій",
|
||||||
"battles": "{count} битви",
|
"battles": "{count} battles",
|
||||||
"route": "Route {index} of {count}"
|
"route": "Route {index} of {count}"
|
||||||
},
|
},
|
||||||
"game_modes": {
|
"game_modes": {
|
||||||
"title": "Здібності ігрового режиму"
|
"title": "Game mode abilities"
|
||||||
},
|
},
|
||||||
"review": {
|
"review": {
|
||||||
"title": "Review videos",
|
"title": "Review videos",
|
||||||
@@ -626,7 +626,7 @@
|
|||||||
"camouflageShootingStill": "Нерухомо",
|
"camouflageShootingStill": "Нерухомо",
|
||||||
"camouflageShootingMoving": "У русі",
|
"camouflageShootingMoving": "У русі",
|
||||||
"camouflageCaughtOnFire": "Caught on fire",
|
"camouflageCaughtOnFire": "Caught on fire",
|
||||||
"width": "Ширина",
|
"width": "Width",
|
||||||
"height": "Height",
|
"height": "Height",
|
||||||
"length": "Length",
|
"length": "Length",
|
||||||
"volume": "Volume",
|
"volume": "Volume",
|
||||||
@@ -740,7 +740,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"gallery": {
|
"gallery": {
|
||||||
"name": "Галерея",
|
"name": "Gallery",
|
||||||
"button": "Browse all",
|
"button": "Browse all",
|
||||||
"description": "Blitz player avatars",
|
"description": "Blitz player avatars",
|
||||||
"seo_description": "Усі World of Tanks Blitz аватари гравців",
|
"seo_description": "Усі World of Tanks Blitz аватари гравців",
|
||||||
@@ -843,7 +843,7 @@
|
|||||||
"breakdown": {
|
"breakdown": {
|
||||||
"name": "Breakdown",
|
"name": "Breakdown",
|
||||||
"options": {
|
"options": {
|
||||||
"width": "Ширина",
|
"width": "Width",
|
||||||
"height": "Height",
|
"height": "Height",
|
||||||
"showTotal": "Show total",
|
"showTotal": "Show total",
|
||||||
"listGap": "List gap",
|
"listGap": "List gap",
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"discover-ids": "bun src/discoverIds/index.ts",
|
"discover-ids": "bun src/discoverIds/index.ts",
|
||||||
"build-protos": "bun src/protos.ts",
|
"build-protos": "bun src/protos.ts",
|
||||||
"record-performance": "bun src/recordPerformance/index.ts"
|
"record-performance": "bun src/recordPerformance/index.ts",
|
||||||
|
"download-client": "bun src/downloadClient/index.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzkit/closed": "workspace:*",
|
"@blitzkit/closed": "workspace:*",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { exit } from "node:process";
|
|||||||
import { GitObjectStorage } from "../core/blitzkit/gitObjectStorage";
|
import { GitObjectStorage } from "../core/blitzkit/gitObjectStorage";
|
||||||
import { IdArray } from "../core/blitzkit/idArray";
|
import { IdArray } from "../core/blitzkit/idArray";
|
||||||
import { CHUNK_COUNT, MAX_DRY_STREAK, MAX_IDS_PER_CALL } from "./constants";
|
import { CHUNK_COUNT, MAX_DRY_STREAK, MAX_IDS_PER_CALL } from "./constants";
|
||||||
import { sleep, withinTimeLimit } from "./time";
|
import { atMaxRate } from "./time";
|
||||||
import { IdsManifest, QuickInfo, RegionDescriptor } from "./types";
|
import { IdsManifest, QuickInfo, RegionDescriptor } from "./types";
|
||||||
|
|
||||||
const storage = await new GitObjectStorage(
|
const storage = await new GitObjectStorage(
|
||||||
@@ -30,18 +30,16 @@ for (let i = 0; i < manifest.chunks; i++) {
|
|||||||
|
|
||||||
console.log(`Found ${manifest.chunks} pre-existing chunks`);
|
console.log(`Found ${manifest.chunks} pre-existing chunks`);
|
||||||
|
|
||||||
manifest.chunks = CHUNK_COUNT;
|
|
||||||
|
|
||||||
let chunks: IdArray[] = [];
|
let chunks: IdArray[] = [];
|
||||||
|
|
||||||
if (discoveredChunks.length === manifest.chunks) {
|
if (manifest.chunks === CHUNK_COUNT) {
|
||||||
console.log("Pre-existing chunking is consistent, passing as-is...");
|
console.log("Pre-existing chunking is consistent, passing as-is...");
|
||||||
|
|
||||||
chunks = discoveredChunks as IdArray[];
|
chunks = discoveredChunks as IdArray[];
|
||||||
} else {
|
} else {
|
||||||
console.log("Pre-existing chunking is not consistent, re-chunking...");
|
console.log("Pre-existing chunking is not consistent, re-chunking...");
|
||||||
|
|
||||||
chunks = Array.from({ length: manifest.chunks }).map(() => new IdArray());
|
chunks = Array.from({ length: CHUNK_COUNT }).map(() => new IdArray());
|
||||||
|
|
||||||
for (let i = 0; i < discoveredChunks.length; i++) {
|
for (let i = 0; i < discoveredChunks.length; i++) {
|
||||||
const ids = discoveredChunks[i];
|
const ids = discoveredChunks[i];
|
||||||
@@ -49,7 +47,7 @@ if (discoveredChunks.length === manifest.chunks) {
|
|||||||
|
|
||||||
for (let j = 0; j < size; j++) {
|
for (let j = 0; j < size; j++) {
|
||||||
const id = ids!.get(j);
|
const id = ids!.get(j);
|
||||||
const chunk = chunks[id % manifest.chunks];
|
const chunk = chunks[id % CHUNK_COUNT];
|
||||||
|
|
||||||
chunk.push(id);
|
chunk.push(id);
|
||||||
}
|
}
|
||||||
@@ -60,6 +58,9 @@ if (discoveredChunks.length === manifest.chunks) {
|
|||||||
console.log("Sorting chunks...");
|
console.log("Sorting chunks...");
|
||||||
|
|
||||||
for (let i = 0; i < chunks.length; i++) chunks[i].sort();
|
for (let i = 0; i < chunks.length; i++) chunks[i].sort();
|
||||||
|
|
||||||
|
manifest.chunks = CHUNK_COUNT;
|
||||||
|
manifest.last_verified = manifest.last_verified % CHUNK_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
const regions: RegionDescriptor[] = [
|
const regions: RegionDescriptor[] = [
|
||||||
@@ -116,7 +117,6 @@ async function save() {
|
|||||||
manifest.total_count = totalFound;
|
manifest.total_count = totalFound;
|
||||||
|
|
||||||
await storage.write("manifest.json", JSON.stringify(manifest, null, 2));
|
await storage.write("manifest.json", JSON.stringify(manifest, null, 2));
|
||||||
|
|
||||||
await storage.commit();
|
await storage.commit();
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
@@ -129,15 +129,18 @@ async function save() {
|
|||||||
process.on("SIGINT", save);
|
process.on("SIGINT", save);
|
||||||
process.on("SIGTERM", save);
|
process.on("SIGTERM", save);
|
||||||
|
|
||||||
const queue: { region: RegionDescriptor; url: string; size: number }[] = [];
|
|
||||||
const applicationId = import.meta.env.PUBLIC_WARGAMING_APPLICATION_ID;
|
const applicationId = import.meta.env.PUBLIC_WARGAMING_APPLICATION_ID;
|
||||||
const fields = "account_id%2C-account_id";
|
const fields = "account_id%2C-account_id";
|
||||||
let regionI = 0;
|
let regionI = 0;
|
||||||
|
|
||||||
function fillQueue() {
|
console.log("Starting discovery loop...");
|
||||||
if (queue.length >= 1) return;
|
|
||||||
|
atMaxRate(async ({ _break: break1 }) => {
|
||||||
|
if (regions.length === 0) {
|
||||||
|
console.log("All regions exhausted, exiting discovery loop...");
|
||||||
|
return break1();
|
||||||
|
}
|
||||||
|
|
||||||
while (regions.length > 0) {
|
|
||||||
regionI = (regionI + 1) % regions.length;
|
regionI = (regionI + 1) % regions.length;
|
||||||
const region = regions[regionI];
|
const region = regions[regionI];
|
||||||
|
|
||||||
@@ -146,7 +149,8 @@ function fillQueue() {
|
|||||||
`Removing region ${region.domain} removed due to ${region.dry_streak} dry streak...`,
|
`Removing region ${region.domain} removed due to ${region.dry_streak} dry streak...`,
|
||||||
);
|
);
|
||||||
regions.splice(regionI, 1);
|
regions.splice(regionI, 1);
|
||||||
continue;
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const id0 = region.seed;
|
const id0 = region.seed;
|
||||||
@@ -162,8 +166,7 @@ function fillQueue() {
|
|||||||
fields
|
fields
|
||||||
}&account_id=${accountIds}`;
|
}&account_id=${accountIds}`;
|
||||||
|
|
||||||
queue.push({ region, url, size: idRange.length });
|
atMaxRate(async ({ _break: break2 }) => {
|
||||||
|
|
||||||
if (idRange.length < MAX_IDS_PER_CALL) {
|
if (idRange.length < MAX_IDS_PER_CALL) {
|
||||||
console.log(
|
console.log(
|
||||||
`Removing region ${region.domain} removed due to ID range exhaustion...`,
|
`Removing region ${region.domain} removed due to ID range exhaustion...`,
|
||||||
@@ -171,31 +174,12 @@ function fillQueue() {
|
|||||||
regions.splice(regionI, 1);
|
regions.splice(regionI, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
const response = await fetch(url);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Starting discovery loop...");
|
|
||||||
|
|
||||||
while (withinTimeLimit() && regions.length > 0) {
|
|
||||||
await sleep();
|
|
||||||
|
|
||||||
fillQueue();
|
|
||||||
|
|
||||||
if (queue.length === 0) {
|
|
||||||
console.log("Queue empty, ending discovery loop...");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const request = queue.shift()!;
|
|
||||||
const response = await fetch(request.url);
|
|
||||||
const data = (await response.json()) as QuickInfo;
|
const data = (await response.json()) as QuickInfo;
|
||||||
|
|
||||||
if (data.status !== "ok") {
|
if (data.status !== "ok") {
|
||||||
console.warn("Failed API call; pushing back into queue...");
|
console.warn("Failed API call; trying again...");
|
||||||
queue.push(request);
|
return;
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let foundIds = 0;
|
let foundIds = 0;
|
||||||
@@ -215,30 +199,14 @@ while (withinTimeLimit() && regions.length > 0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (foundIds === 0) {
|
if (foundIds === 0) {
|
||||||
request.region.dry_streak += request.size;
|
region.dry_streak += idRange.length;
|
||||||
} else {
|
} else {
|
||||||
request.region.dry_streak = 0;
|
region.dry_streak = 0;
|
||||||
// console.log(`Found ${foundIds} ids in ${request.region.domain}`);
|
// console.log(`Found ${foundIds} ids in ${request.region.domain}`);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// console.log("Starting verification loop...");
|
break2();
|
||||||
|
});
|
||||||
// while (withinTimeLimit()) {
|
});
|
||||||
// const verificationIndex = (manifest.last_verified + 1) % manifest.chunks;
|
|
||||||
// manifest.last_verified = verificationIndex;
|
|
||||||
// const chunk = chunks[verificationIndex];
|
|
||||||
// const size = chunk.size();
|
|
||||||
|
|
||||||
// let i0 = 0;
|
|
||||||
// while (withinTimeLimit() && i0 < size) {
|
|
||||||
// await sleep();
|
|
||||||
|
|
||||||
// const i1 = Math.min(i0 + MAX_IDS_PER_CALL - 1, size - 1);
|
|
||||||
// const indices = range(i0, i1 + 1);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// console.log(`Verification complete for chunk ${verificationIndex}`);
|
|
||||||
// }
|
|
||||||
|
|
||||||
await save();
|
await save();
|
||||||
@@ -9,6 +9,37 @@ export function withinTimeLimit() {
|
|||||||
return performance.now() < t1;
|
return performance.now() < t1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sleep() {
|
export function sleep(t: number) {
|
||||||
return new Promise((resolve) => setTimeout(resolve, 1000 / API_RATE));
|
return new Promise((resolve) => setTimeout(resolve, t));
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MethodContext {
|
||||||
|
_break(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastT = 0;
|
||||||
|
const maxDelta = 1000 / API_RATE;
|
||||||
|
const DELTA_BUFFER = 0;
|
||||||
|
export async function atMaxRate(method: (context: MethodContext) => void) {
|
||||||
|
let isBroken = false;
|
||||||
|
|
||||||
|
const context: MethodContext = {
|
||||||
|
_break() {
|
||||||
|
isBroken = true;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
while (!isBroken) {
|
||||||
|
if (!withinTimeLimit()) break;
|
||||||
|
|
||||||
|
const t = performance.now();
|
||||||
|
const delta = t - lastT;
|
||||||
|
|
||||||
|
if (delta < maxDelta) {
|
||||||
|
await sleep(maxDelta - delta + DELTA_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
method(context);
|
||||||
|
lastT = t;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// dava engine has a lot of tiny files, this is faster
|
||||||
|
export const DEPOT_DOWNLOADER_MAX_DOWNLOADS = 256;
|
||||||
|
export const DEPOT_DOWNLOADER_OUTPUT = "../../temp/depotdownloader";
|
||||||
|
export const DEPOT_DOWNLOADER_EXECUTABLE = `${DEPOT_DOWNLOADER_OUTPUT}/DepotDownloader`;
|
||||||
|
|
||||||
|
export const ARIA2_OUTPUT = "../../temp/aria2";
|
||||||
|
export const ARIA2_EXECUTABLE = `${ARIA2_OUTPUT}/aria2c`;
|
||||||
|
|
||||||
|
export const WGPKG_DIR = "../../temp/wgpkgs";
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
import { assertSecret } from "@blitzkit/core";
|
||||||
|
import { $ } from "bun";
|
||||||
|
import { mkdir, rm } from "node:fs/promises";
|
||||||
|
import {
|
||||||
|
DEPOT_DOWNLOADER_EXECUTABLE,
|
||||||
|
DEPOT_DOWNLOADER_MAX_DOWNLOADS,
|
||||||
|
DEPOT_DOWNLOADER_OUTPUT,
|
||||||
|
WGPKG_DIR,
|
||||||
|
} from "./constants";
|
||||||
|
import { QuickGitHubRelease } from "./types";
|
||||||
|
|
||||||
|
const provider = assertSecret(import.meta.env.CLIENT_PROVIDER);
|
||||||
|
const source = assertSecret(import.meta.env.CLIENT_SOURCE);
|
||||||
|
const dir = assertSecret(import.meta.env.CLIENT_DIR);
|
||||||
|
|
||||||
|
await rm(dir, { recursive: true, force: true });
|
||||||
|
await mkdir(dir, { recursive: true });
|
||||||
|
|
||||||
|
if (provider === "steam") {
|
||||||
|
const [id, platform] = source.split("/");
|
||||||
|
|
||||||
|
console.log("Downloading Depot Downloader...");
|
||||||
|
|
||||||
|
const releases = await fetch(
|
||||||
|
"https://api.github.com/repos/SteamRE/DepotDownloader/releases/latest",
|
||||||
|
).then((response) => response.json() as Promise<QuickGitHubRelease>);
|
||||||
|
const asset = releases.assets.find((asset) =>
|
||||||
|
asset.name.includes("linux-x64"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!asset) {
|
||||||
|
throw new Error("No linux-x64 asset found for Steam DepotDownloader");
|
||||||
|
}
|
||||||
|
|
||||||
|
await rm(DEPOT_DOWNLOADER_OUTPUT, { recursive: true, force: true });
|
||||||
|
|
||||||
|
await $`curl -L "${asset.browser_download_url}" -o "${DEPOT_DOWNLOADER_OUTPUT}.zip"`;
|
||||||
|
await $`unzip "${DEPOT_DOWNLOADER_OUTPUT}.zip" -d "${DEPOT_DOWNLOADER_OUTPUT}"`;
|
||||||
|
await $`chmod +x "${DEPOT_DOWNLOADER_EXECUTABLE}"`;
|
||||||
|
|
||||||
|
console.log("Downloading client...");
|
||||||
|
|
||||||
|
const username = assertSecret(import.meta.env.STEAM_USERNAME);
|
||||||
|
const password = assertSecret(import.meta.env.STEAM_PASSWORD);
|
||||||
|
|
||||||
|
await $`${DEPOT_DOWNLOADER_EXECUTABLE} -os ${
|
||||||
|
platform
|
||||||
|
} -app ${id} -username ${username} -password ${
|
||||||
|
password
|
||||||
|
} -dir ${dir} -max-downloads ${DEPOT_DOWNLOADER_MAX_DOWNLOADS}`;
|
||||||
|
} else if (provider === "zip") {
|
||||||
|
const url = assertSecret(import.meta.env.CLIENT_SOURCE);
|
||||||
|
|
||||||
|
console.log("Downloading and extracting zipped client...");
|
||||||
|
|
||||||
|
await mkdir(dir, { recursive: true });
|
||||||
|
await $`curl -L "${url}" | bsdtar -xf- --strip-components=1 -C ${dir}`;
|
||||||
|
} else if (provider === "wgpkg") {
|
||||||
|
let index = 1;
|
||||||
|
const urls: string[] = [];
|
||||||
|
|
||||||
|
console.log("Discovering packages...");
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const url = `${source}.${index.toString().padStart(3, "0")}`;
|
||||||
|
const response = await fetch(url);
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
|
urls.push(url);
|
||||||
|
} else if (response.status === 404) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
throw new Error(`Wargaming response error status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Downloading ${urls.length} packages...`);
|
||||||
|
|
||||||
|
await rm(WGPKG_DIR, { recursive: true });
|
||||||
|
|
||||||
|
const inputContent = urls
|
||||||
|
.map((url) => {
|
||||||
|
const name = url.split("/").pop()!;
|
||||||
|
return `${url}\n out=${name}\n dir=${WGPKG_DIR}`;
|
||||||
|
})
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
await $`echo ${inputContent} | aria2c -j ${urls.length} -x 2 -s 2 -i -`;
|
||||||
|
|
||||||
|
const firstChunk = `${WGPKG_DIR}/${urls[0].split("/").pop()!}`;
|
||||||
|
await $`7z x "${firstChunk}" -o${dir} -y`;
|
||||||
|
|
||||||
|
await rm(WGPKG_DIR, { recursive: true });
|
||||||
|
} else {
|
||||||
|
throw new Error(`Unknown provider: ${provider}`);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export interface QuickGitHubRelease {
|
||||||
|
assets: Asset[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Asset {
|
||||||
|
name: string;
|
||||||
|
browser_download_url: string;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { assertSecret } from "@blitzkit/core";
|
import { assertSecret } from "@blitzkit/core";
|
||||||
import { LocalVFS } from "@blitzkit/core/src/blitzkit/vfs/local";
|
import { LocalVFS } from "@blitzkit/core/src/blitzkit/vfs/local";
|
||||||
|
|
||||||
export const vfs = new LocalVFS(assertSecret(import.meta.env.GAME_DIR));
|
export const vfs = new LocalVFS(assertSecret(import.meta.env.CLIENT_DIR));
|
||||||
Reference in new issue
Block a user