Files
blitzkit/packages/scripts/src/core/vfs/steam.ts
T

98 lines
2.2 KiB
TypeScript
Raw Normal View History

2025-11-25 22:14:09 -06:00
import SteamUser, { EConnectionProtocol } from "steam-user";
2025-11-29 14:34:06 -06:00
import { AbstractVFS } from "./abstract";
2025-11-25 21:37:31 -06:00
2025-11-25 22:16:39 -06:00
interface SteamManifestFile {
chunks: {
sha: string;
crc: number;
offset: string;
cb_original: number;
cb_compressed: number;
2025-11-25 22:14:09 -06:00
}[];
2025-11-25 22:16:39 -06:00
filename: string;
size: string;
flags: number;
sha_filename: string;
sha_content: string;
linktarget: unknown;
}
interface SteamManifest {
files: SteamManifestFile[];
2025-11-25 22:20:46 -06:00
depot_id: number;
gid_manifest: string;
creation_time: number;
filenames_encrypted: boolean;
cb_disk_original: string;
cb_disk_compressed: string;
unique_chunks: number;
crc_encrypted: number;
crc_clear: number;
2025-11-25 22:14:09 -06:00
}
2025-11-25 21:37:31 -06:00
2025-11-29 14:34:06 -06:00
export class SteamVFS extends AbstractVFS {
2025-11-25 22:14:09 -06:00
private steam = new SteamUser({ protocol: EConnectionProtocol.TCP });
2025-11-25 22:16:39 -06:00
private manifest: Map<string, SteamManifestFile> = new Map();
2025-11-25 22:14:09 -06:00
constructor(
private username: string,
private password: string,
private app: number,
private depot: number
2025-11-29 14:34:06 -06:00
) {
super();
}
2025-11-25 22:14:09 -06:00
async init() {
this.steam.logOn({
accountName: this.username,
password: this.password,
2025-11-25 21:37:31 -06:00
});
2025-11-25 22:14:09 -06:00
await new Promise((resolve) => this.steam.once("loggedOn", resolve));
2025-11-25 21:37:31 -06:00
2025-11-25 22:14:09 -06:00
const productInfo = await this.steam.getProductInfo([this.app], []);
2025-11-25 22:16:39 -06:00
const manifest: SteamManifest = await new Promise((resolve) => {
2025-11-26 12:46:03 -06:00
// @ts-expect-error
2025-11-25 22:14:09 -06:00
this.steam.getManifest(
this.app,
this.depot,
productInfo.apps[this.app].appinfo.depots[this.depot].manifests.public
.gid,
"public",
2025-11-26 12:46:03 -06:00
// @ts-expect-error
2025-11-25 22:14:09 -06:00
(_, response) => {
resolve(response);
}
);
});
2025-11-25 22:16:39 -06:00
for (const file of manifest.files) {
2025-11-25 22:21:58 -06:00
const path = file.filename.replaceAll("\\", "/");
2025-11-25 22:20:46 -06:00
this.manifest.set(path, file);
2025-11-25 22:16:39 -06:00
}
2025-11-26 12:46:03 -06:00
return this;
}
2025-11-25 22:16:39 -06:00
2025-11-26 12:58:19 -06:00
has(path: string) {
2025-11-29 15:16:09 -06:00
return this.manifest.has(path);
2025-11-26 12:58:19 -06:00
}
2025-11-29 15:16:09 -06:00
async raw(path: string) {
2025-11-26 12:46:03 -06:00
const fileManifest = this.manifest.get(path)!;
const downloaded: { type: "complete"; file: Buffer } =
// @ts-expect-error
await this.steam.downloadFile(this.app, this.depot, fileManifest);
2025-11-29 15:16:09 -06:00
return new Uint8Array(downloaded.file);
2025-11-26 12:46:03 -06:00
}
2025-11-29 15:16:09 -06:00
paths() {
return Array.from(this.manifest.keys());
2025-11-26 12:58:19 -06:00
}
2025-11-26 12:46:03 -06:00
dispose() {
this.steam.logOff();
}
2025-11-25 21:37:31 -06:00
}