feat: add cafeberry logo

This commit is contained in:
neoapps-dev 2026-08-16 03:03:42 +03:00
parent 89b422ba6c
commit 7a2650bd48
12 changed files with 194 additions and 126 deletions

View file

@ -27,7 +27,7 @@ pub fn launch_bridge(
let intent_class = env.find_class("android/content/Intent")?;
let intent = env.new_object(
intent_class,
"(Landroid/content/Context;Ljava/lang/Class;)V",
"(Landroid/content/Context;Ljava/lang/Class;)V", //neo: i hate smali so much
&[(&activity).into(), (&bridge_class).into()],
)?;

View file

@ -429,7 +429,7 @@ fn build_empty_chunk_nbt(chunk_x: i32, chunk_z: i32) -> Vec<u8> {
out.extend_from_slice(&0i64.to_be_bytes());
out.extend_from_slice(b"\x01\x00\x10TerrainPopulated\x01");
out.extend_from_slice(b"\x09\x00\x08Entities\x0a\x00\x00\x00\x00");
out.extend_from_slice(b"\x09\x00\x0cTileEntities\x0a\x00\x00\x00\x00");
out.extend_from_slice(b"\x09\x00\x0cTileEntities\x0a\x00\x00\x00\x00"); //neo: someone send help
out.push(0x00);
out.push(0x00);
out

View file

@ -731,6 +731,7 @@ fn game_exited_ok(log: &str) -> bool {
.rev()
.take(3)
.any(|line| line.contains("AppPolicyGetProcessTerminationMethod"))
//neo: TODO: investigate what Windows outputs for success to prevent false detection lol
}
fn handle_game_exit(

View file

@ -1285,6 +1285,7 @@ static MODERN_DIRECT_MAP: once_cell::sync::Lazy<HashMap<&'static str, LegacyBloc
"lava_cauldron",
LegacyBlockState { id: 118, data: 0 },
);
//neo: m.insert("help", neo {thisis: verytiring});
m
});

View file

@ -21,7 +21,7 @@ pub enum NbtValue {
#[derive(Debug, Clone, Default, PartialEq)]
pub struct NbtCompound {
pub name: String,
pub tags: Vec<(String, NbtValue)>,
pub tags: Vec<(String, NbtValue)>, //neo: if you came here asking about this, dont. please. dont ask why im storing a tuple in a vec. or why im manually resizing a vec.
}
impl NbtCompound {

View file

@ -1,3 +1,5 @@
//neo: TODO: Intel macOS support
use tauri::AppHandle;
#[cfg(target_os = "macos")]
use std::io::Write;

View file

@ -15,7 +15,7 @@ pub async fn add_to_steam(
let (exe_str, launch_options, start_dir) = if in_flatpak {
(
"/usr/bin/flatpak".to_string(),
format!("run io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher \"{}\"", instance_id),
format!("run io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher \"{}\"", instance_id), //neo: yes i'm hardcoding it lmfao
std::env::var("HOME").unwrap_or_default(),
)
} else {

View file

@ -30,6 +30,6 @@ pub async fn start_lce_auth(app: tauri::AppHandle) -> Result<String, String> {
#[cfg(not(target_os = "android"))]
{
let _ = app;
Err("LCE Online auth is only supported on Android".into())
Err("LCE Online auth is only supported on Android".into()) //neo: erm, rust-side only. its supported on desktop on the typescript side.
}
}

View file

@ -3,7 +3,7 @@ use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::TcpListener;
use tokio_util::sync::CancellationToken;
use tauri::{AppHandle, Emitter};
const REGISTRY_URL: &str = "https://raw.githubusercontent.com/LCE-Hub/LCE-Workshop/refs/heads/main";
const REGISTRY_URL: &str = "https://raw.githubusercontent.com/LCE-Hub/LCE-Workshop/refs/heads/main"; //neo: more hardcoding!
static CLIENT: Lazy<reqwest::Client> = Lazy::new(|| reqwest::Client::new());
pub struct Guard {
cancel: Option<CancellationToken>,
@ -34,7 +34,7 @@ pub async fn start(app: AppHandle) -> CancellationToken {
}
async fn serve(app: AppHandle, cancel: CancellationToken) {
let listener = match TcpListener::bind("127.0.0.1:5582").await {
let listener = match TcpListener::bind("127.0.0.1:5582").await { //neo: dont say a word about this weird port.
Ok(l) => l,
Err(e) => {
let _ = app.emit("backend-error", format!("Workshop server failed to bind: {e}"));

View file

@ -1,14 +1,17 @@
import { OptionsFile } from "../types/options";
export class OptionsService {
public static readOptions(buffer: ArrayBuffer, endianness: "little" | "big" = "little"): OptionsFile {
public static readOptions(
buffer: ArrayBuffer,
endianness: "little" | "big" = "little",
): OptionsFile {
const rawData = new Uint8Array(buffer).slice();
const view = new DataView(buffer);
const little = endianness === "little";
const opt: Partial<OptionsFile> = {
endianness,
rawData
rawData,
};
//neo: someone save me from these values
opt.musicVolume = view.getUint8(0x01);
opt.soundVolume = view.getUint8(0x02);
opt.gameSensitivity = view.getUint8(0x03);
@ -24,7 +27,7 @@ export class OptionsService {
opt.verticalSplitscreen = (val06 & (1 << 8)) !== 0;
opt.splitscreenGamertags = (val06 & (1 << 9)) !== 0;
opt.hints = (val06 & (1 << 10)) !== 0;
opt.autosaveTimer = (val06 >> 11) & 0xF;
opt.autosaveTimer = (val06 >> 11) & 0xf;
opt.inGameTooltips = (val06 & (1 << 15)) !== 0;
const val54 = view.getUint32(0x54, little);
opt.renderClouds = (val54 & (1 << 0)) !== 0;
@ -45,46 +48,46 @@ export class OptionsService {
opt.displaySaveIcon = (val54 & (1 << 29)) !== 0;
opt.flyingViewRolling = (val54 & (1 << 30)) === 0;
opt.showGlideGhostPath = (val54 & (1 << 31)) !== 0;
opt.chosenSkin = view.getUint32(0x4C, little);
opt.playerCape = view.getUint32(0x5C, little);
opt.chosenSkin = view.getUint32(0x4c, little);
opt.playerCape = view.getUint32(0x5c, little);
opt.favoriteSkins = [];
for (let i = 0; i < 10; i++) {
opt.favoriteSkins.push(view.getUint32(0x60 + i * 4, little));
}
opt.actions = {
jump: view.getUint8(0xA4),
use: view.getUint8(0xA5),
action: view.getUint8(0xA6),
cycleHeldItemLeft: view.getUint8(0xA7),
cycleHeldItemRight: view.getUint8(0xA8),
inventory: view.getUint8(0xA9),
drop: view.getUint8(0xAA),
sneakDismount: view.getUint8(0xAB),
crafting: view.getUint8(0xAC),
changeCameraMode: view.getUint8(0xAD),
flyLeft: view.getUint8(0xAE),
flyRight: view.getUint8(0xAF),
flyUp: view.getUint8(0xB0),
flyDown: view.getUint8(0xB1),
sprint: view.getUint8(0xB2),
pickBlock: view.getUint8(0xB3),
previousPlayer: view.getUint8(0xB4),
nextPlayer: view.getUint8(0xB5),
spectateNoise: view.getUint8(0xB6),
cancelSpectating: view.getUint8(0xB7),
confirmReady: view.getUint8(0xB8),
vote: view.getUint8(0xB9),
restartSection: view.getUint8(0xBA),
restartRace: view.getUint8(0xBB),
lookBehind: view.getUint8(0xBC)
jump: view.getUint8(0xa4),
use: view.getUint8(0xa5),
action: view.getUint8(0xa6),
cycleHeldItemLeft: view.getUint8(0xa7),
cycleHeldItemRight: view.getUint8(0xa8),
inventory: view.getUint8(0xa9),
drop: view.getUint8(0xaa),
sneakDismount: view.getUint8(0xab),
crafting: view.getUint8(0xac),
changeCameraMode: view.getUint8(0xad),
flyLeft: view.getUint8(0xae),
flyRight: view.getUint8(0xaf),
flyUp: view.getUint8(0xb0),
flyDown: view.getUint8(0xb1),
sprint: view.getUint8(0xb2),
pickBlock: view.getUint8(0xb3),
previousPlayer: view.getUint8(0xb4),
nextPlayer: view.getUint8(0xb5),
spectateNoise: view.getUint8(0xb6),
cancelSpectating: view.getUint8(0xb7),
confirmReady: view.getUint8(0xb8),
vote: view.getUint8(0xb9),
restartSection: view.getUint8(0xba),
restartRace: view.getUint8(0xbb),
lookBehind: view.getUint8(0xbc),
};
return opt as OptionsFile;
}
public static serializeOptions(opt: OptionsFile): ArrayBuffer {
const minSize = 0xBC + 1;
const minSize = 0xbc + 1;
const buffer = new Uint8Array(Math.max(opt.rawData.length, minSize));
buffer.set(opt.rawData);
const view = new DataView(buffer.buffer);
@ -97,69 +100,69 @@ export class OptionsService {
view.setUint8(0x51, opt.interfaceOpacity);
let val06 = view.getUint16(0x06, little);
val06 = (val06 & ~0x3) | (opt.difficulty & 0x3);
val06 = (val06 & ~(1 << 2)) | (opt.viewBobbing ? (1 << 2) : 0);
val06 = (val06 & ~(1 << 3)) | (opt.inGameGamertags ? (1 << 3) : 0);
val06 = (val06 & ~(1 << 6)) | (opt.invertLook ? (1 << 6) : 0);
val06 = (val06 & ~(1 << 7)) | (opt.southpaw ? (1 << 7) : 0);
val06 = (val06 & ~(1 << 8)) | (opt.verticalSplitscreen ? (1 << 8) : 0);
val06 = (val06 & ~(1 << 9)) | (opt.splitscreenGamertags ? (1 << 9) : 0);
val06 = (val06 & ~(1 << 10)) | (opt.hints ? (1 << 10) : 0);
val06 = (val06 & ~(0xF << 11)) | ((opt.autosaveTimer & 0xF) << 11);
val06 = (val06 & ~(1 << 15)) | (opt.inGameTooltips ? (1 << 15) : 0);
val06 = (val06 & ~(1 << 2)) | (opt.viewBobbing ? 1 << 2 : 0);
val06 = (val06 & ~(1 << 3)) | (opt.inGameGamertags ? 1 << 3 : 0);
val06 = (val06 & ~(1 << 6)) | (opt.invertLook ? 1 << 6 : 0);
val06 = (val06 & ~(1 << 7)) | (opt.southpaw ? 1 << 7 : 0);
val06 = (val06 & ~(1 << 8)) | (opt.verticalSplitscreen ? 1 << 8 : 0);
val06 = (val06 & ~(1 << 9)) | (opt.splitscreenGamertags ? 1 << 9 : 0);
val06 = (val06 & ~(1 << 10)) | (opt.hints ? 1 << 10 : 0);
val06 = (val06 & ~(0xf << 11)) | ((opt.autosaveTimer & 0xf) << 11);
val06 = (val06 & ~(1 << 15)) | (opt.inGameTooltips ? 1 << 15 : 0);
view.setUint16(0x06, val06, little);
let val54 = view.getUint32(0x54, little);
val54 = (val54 & ~(1 << 0)) | (opt.renderClouds ? (1 << 0) : 0);
val54 = (val54 & ~(1 << 7)) | (opt.displayHud ? (1 << 7) : 0);
val54 = (val54 & ~(1 << 8)) | (opt.displayHand ? (1 << 8) : 0);
val54 = (val54 & ~(1 << 9)) | (opt.customSkinAnimation ? (1 << 9) : 0);
val54 = (val54 & ~(1 << 10)) | (opt.deathMessages ? (1 << 10) : 0);
val54 = (val54 & ~(1 << 0)) | (opt.renderClouds ? 1 << 0 : 0);
val54 = (val54 & ~(1 << 7)) | (opt.displayHud ? 1 << 7 : 0);
val54 = (val54 & ~(1 << 8)) | (opt.displayHand ? 1 << 8 : 0);
val54 = (val54 & ~(1 << 9)) | (opt.customSkinAnimation ? 1 << 9 : 0);
val54 = (val54 & ~(1 << 10)) | (opt.deathMessages ? 1 << 10 : 0);
val54 = (val54 & ~(0x3 << 11)) | ((opt.hudSize & 0x3) << 11);
val54 = (val54 & ~(0x3 << 13)) | ((opt.hudSizeSplitscreen & 0x3) << 13);
val54 = (val54 & ~(1 << 15)) | (opt.animatedCharacter ? (1 << 15) : 0);
val54 = (val54 & ~(1 << 18)) | (opt.classicCrafting ? (1 << 18) : 0);
val54 = (val54 & ~(1 << 19)) | (opt.caveSounds ? (1 << 19) : 0);
val54 = (val54 & ~(1 << 20)) | (opt.gameChat ? (1 << 20) : 0);
val54 = (val54 & ~(1 << 21)) | (opt.minecartSounds ? (1 << 21) : 0);
val54 = (val54 & ~(1 << 22)) | (opt.showGlideGhost ? (1 << 22) : 0);
val54 = (val54 & ~(1 << 26)) | (opt.autoJump ? (1 << 26) : 0);
val54 = (val54 & ~(1 << 28)) | (opt.displayGameMessages ? (1 << 28) : 0);
val54 = (val54 & ~(1 << 29)) | (opt.displaySaveIcon ? (1 << 29) : 0);
val54 = (val54 & ~(1 << 30)) | (!opt.flyingViewRolling ? (1 << 30) : 0);
val54 = (val54 & ~(1 << 31)) | (opt.showGlideGhostPath ? (1 << 31) : 0);
val54 = (val54 & ~(1 << 15)) | (opt.animatedCharacter ? 1 << 15 : 0);
val54 = (val54 & ~(1 << 18)) | (opt.classicCrafting ? 1 << 18 : 0);
val54 = (val54 & ~(1 << 19)) | (opt.caveSounds ? 1 << 19 : 0);
val54 = (val54 & ~(1 << 20)) | (opt.gameChat ? 1 << 20 : 0);
val54 = (val54 & ~(1 << 21)) | (opt.minecartSounds ? 1 << 21 : 0);
val54 = (val54 & ~(1 << 22)) | (opt.showGlideGhost ? 1 << 22 : 0);
val54 = (val54 & ~(1 << 26)) | (opt.autoJump ? 1 << 26 : 0);
val54 = (val54 & ~(1 << 28)) | (opt.displayGameMessages ? 1 << 28 : 0);
val54 = (val54 & ~(1 << 29)) | (opt.displaySaveIcon ? 1 << 29 : 0);
val54 = (val54 & ~(1 << 30)) | (!opt.flyingViewRolling ? 1 << 30 : 0);
val54 = (val54 & ~(1 << 31)) | (opt.showGlideGhostPath ? 1 << 31 : 0);
view.setUint32(0x54, val54, little);
view.setUint32(0x4C, opt.chosenSkin, little);
view.setUint32(0x5C, opt.playerCape, little);
view.setUint32(0x4c, opt.chosenSkin, little);
view.setUint32(0x5c, opt.playerCape, little);
for (let i = 0; i < 10; i++) {
if (opt.favoriteSkins[i] !== undefined) {
view.setUint32(0x60 + i * 4, opt.favoriteSkins[i], little);
}
}
view.setUint8(0xA4, opt.actions.jump);
view.setUint8(0xA5, opt.actions.use);
view.setUint8(0xA6, opt.actions.action);
view.setUint8(0xA7, opt.actions.cycleHeldItemLeft);
view.setUint8(0xA8, opt.actions.cycleHeldItemRight);
view.setUint8(0xA9, opt.actions.inventory);
view.setUint8(0xAA, opt.actions.drop);
view.setUint8(0xAB, opt.actions.sneakDismount);
view.setUint8(0xAC, opt.actions.crafting);
view.setUint8(0xAD, opt.actions.changeCameraMode);
view.setUint8(0xAE, opt.actions.flyLeft);
view.setUint8(0xAF, opt.actions.flyRight);
view.setUint8(0xB0, opt.actions.flyUp);
view.setUint8(0xB1, opt.actions.flyDown);
view.setUint8(0xB2, opt.actions.sprint);
view.setUint8(0xB3, opt.actions.pickBlock);
view.setUint8(0xB4, opt.actions.previousPlayer);
view.setUint8(0xB5, opt.actions.nextPlayer);
view.setUint8(0xB6, opt.actions.spectateNoise);
view.setUint8(0xB7, opt.actions.cancelSpectating);
view.setUint8(0xB8, opt.actions.confirmReady);
view.setUint8(0xB9, opt.actions.vote);
view.setUint8(0xBA, opt.actions.restartSection);
view.setUint8(0xBB, opt.actions.restartRace);
view.setUint8(0xBC, opt.actions.lookBehind);
view.setUint8(0xa4, opt.actions.jump);
view.setUint8(0xa5, opt.actions.use);
view.setUint8(0xa6, opt.actions.action);
view.setUint8(0xa7, opt.actions.cycleHeldItemLeft);
view.setUint8(0xa8, opt.actions.cycleHeldItemRight);
view.setUint8(0xa9, opt.actions.inventory);
view.setUint8(0xaa, opt.actions.drop);
view.setUint8(0xab, opt.actions.sneakDismount);
view.setUint8(0xac, opt.actions.crafting);
view.setUint8(0xad, opt.actions.changeCameraMode);
view.setUint8(0xae, opt.actions.flyLeft);
view.setUint8(0xaf, opt.actions.flyRight);
view.setUint8(0xb0, opt.actions.flyUp);
view.setUint8(0xb1, opt.actions.flyDown);
view.setUint8(0xb2, opt.actions.sprint);
view.setUint8(0xb3, opt.actions.pickBlock);
view.setUint8(0xb4, opt.actions.previousPlayer);
view.setUint8(0xb5, opt.actions.nextPlayer);
view.setUint8(0xb6, opt.actions.spectateNoise);
view.setUint8(0xb7, opt.actions.cancelSpectating);
view.setUint8(0xb8, opt.actions.confirmReady);
view.setUint8(0xb9, opt.actions.vote);
view.setUint8(0xba, opt.actions.restartSection);
view.setUint8(0xbb, opt.actions.restartRace);
view.setUint8(0xbc, opt.actions.lookBehind);
return buffer.buffer;
}
}

View file

@ -17,7 +17,12 @@ export interface SwfImage {
}
export class SwfService {
static parse(buffer: Uint8Array): { version: number; compressed: boolean; frameHeader: Uint8Array; tags: SwfTag[] } {
static parse(buffer: Uint8Array): {
version: number;
compressed: boolean;
frameHeader: Uint8Array;
tags: SwfTag[];
} {
if (buffer.length < 8) throw new Error("Invalid SWF: file too small");
const sig = String.fromCharCode(buffer[0], buffer[1], buffer[2]);
const version = buffer[3];
@ -48,7 +53,11 @@ export class SwfService {
const code = tagHeader >> 6;
let length = tagHeader & 0x3f;
if (length === 0x3f) {
length = data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24);
length =
data[offset] |
(data[offset + 1] << 8) |
(data[offset + 2] << 16) |
(data[offset + 3] << 24);
offset += 4;
}
const tagData = data.slice(offset, offset + length);
@ -60,7 +69,12 @@ export class SwfService {
return { version, compressed: sig === "CWS", frameHeader, tags };
}
static serialize(version: number, compressed: boolean, frameHeader: Uint8Array, tags: SwfTag[]): Uint8Array {
static serialize(
version: number,
compressed: boolean,
frameHeader: Uint8Array,
tags: SwfTag[],
): Uint8Array {
const payloads: Uint8Array[] = [frameHeader];
let bodyLength = frameHeader.length;
@ -89,7 +103,9 @@ export class SwfService {
}
const fileLength = 8 + uncompressedBody.length;
const finalBody = compressed ? pako.deflate(uncompressedBody) : uncompressedBody;
const finalBody = compressed
? pako.deflate(uncompressedBody)
: uncompressedBody;
const result = new Uint8Array(8 + finalBody.length);
result.set(new TextEncoder().encode(compressed ? "CWS" : "FWS"), 0);
result[3] = version;
@ -125,15 +141,32 @@ export class SwfService {
const charId = tag.data[0] | (tag.data[1] << 8);
const imgData = tag.data.slice(2);
const fixed = this.fixJpeg(imgData, tag.code === 6 ? jpegTables : null);
images.push({ id: charId, type: "jpeg", data: fixed, name: nameMap[charId] });
images.push({
id: charId,
type: "jpeg",
data: fixed,
name: nameMap[charId],
});
} else if (tag.code === 35) {
const charId = tag.data[0] | (tag.data[1] << 8);
const alphaOffset = tag.data[2] | (tag.data[3] << 8) | (tag.data[4] << 16) | (tag.data[5] << 24);
const alphaOffset =
tag.data[2] |
(tag.data[3] << 8) |
(tag.data[4] << 16) |
(tag.data[5] << 24);
const imgData = tag.data.slice(6, 6 + alphaOffset);
const alphaRaw = tag.data.slice(6 + alphaOffset);
let alpha = undefined;
try { alpha = pako.inflate(alphaRaw); } catch (e) { }
images.push({ id: charId, type: "jpeg", data: this.fixJpeg(imgData), alphaData: alpha, name: nameMap[charId] });
try {
alpha = pako.inflate(alphaRaw);
} catch (e) {}
images.push({
id: charId,
type: "jpeg",
data: this.fixJpeg(imgData),
alphaData: alpha,
name: nameMap[charId],
});
} else if (tag.code === 20 || tag.code === 36) {
const charId = tag.data[0] | (tag.data[1] << 8);
const format = tag.data[2];
@ -144,20 +177,23 @@ export class SwfService {
images.push({
id: charId,
type: "lossless",
type: "lossless", //neo: aka PNG
data: raw,
width,
height,
format,
hasAlpha,
name: nameMap[charId]
name: nameMap[charId],
});
}
}
return images;
}
private static fixJpeg(data: Uint8Array, jtt: Uint8Array | null = null): Uint8Array {
private static fixJpeg(
data: Uint8Array,
jtt: Uint8Array | null = null,
): Uint8Array {
let combined = data;
if (jtt && jtt.length > 0) {
let tLen = jtt.length;
@ -172,7 +208,8 @@ export class SwfService {
}
static async decodeLosslessToRGBA(img: SwfImage): Promise<Uint8Array> {
if (img.type !== "lossless" || !img.width || !img.height) return new Uint8Array(0);
if (img.type !== "lossless" || !img.width || !img.height)
return new Uint8Array(0);
const decoded = pako.inflate(img.data);
const rgba = new Uint8Array(img.width * img.height * 4);
if (img.format === 3) {
@ -189,7 +226,7 @@ export class SwfService {
a > 0 ? Math.min(255, (r_pm * 255) / a) : 0,
a > 0 ? Math.min(255, (g_pm * 255) / a) : 0,
a > 0 ? Math.min(255, (b_pm * 255) / a) : 0,
a
a,
]);
} else {
palette.push([decoded[ptr++], decoded[ptr++], decoded[ptr++], 255]);
@ -211,7 +248,9 @@ export class SwfService {
const rowStride = Math.ceil((img.width * 2) / 4) * 4;
for (let y = 0; y < img.height; y++) {
for (let x = 0; x < img.width; x++) {
const p = decoded[y * rowStride + x * 2] | (decoded[y * rowStride + x * 2 + 1] << 8);
const p =
decoded[y * rowStride + x * 2] |
(decoded[y * rowStride + x * 2 + 1] << 8);
const r = ((p >> 10) & 0x1f) << 3;
const g = ((p >> 5) & 0x1f) << 3;
const b = (p & 0x1f) << 3;
@ -248,9 +287,20 @@ export class SwfService {
return rgba;
}
static updateImageTag(tags: SwfTag[], charId: number, newData: Uint8Array, type: SwfImage["type"]): SwfTag[] {
return tags.map(tag => {
if (tag.code === 6 || tag.code === 21 || tag.code === 35 || tag.code === 20 || tag.code === 36) {
static updateImageTag(
tags: SwfTag[],
charId: number,
newData: Uint8Array,
type: SwfImage["type"],
): SwfTag[] {
return tags.map((tag) => {
if (
tag.code === 6 ||
tag.code === 21 ||
tag.code === 35 ||
tag.code === 20 ||
tag.code === 36
) {
const id = tag.data[0] | (tag.data[1] << 8);
if (id === charId) {
let payload: Uint8Array;

View file

@ -64,7 +64,7 @@ export interface Runner {
id: string;
name: string;
path: string;
type: "wine" | "proton";
type: "wine" | "proton"; //neo: i beg you please use Proton dont use WINE, WineD3D sickens me
}
export interface MacOSSetupProgress {
@ -196,15 +196,25 @@ export class TauriService {
return invoke("workshop_list_installed");
}
static onDownloadProgress(callback: (data: { instanceId: string; percent: number }) => void) {
return listen<{ instanceId: string; percent: number }>("download-progress", (event) =>
callback(event.payload),
static onDownloadProgress(
callback: (data: { instanceId: string; percent: number }) => void,
) {
return listen<{ instanceId: string; percent: number }>(
"download-progress",
(event) => callback(event.payload),
);
}
static onWorkshopProgress(callback: (data: { packageId: string; percent: number }) => void) {
return listen<{ instanceId: string; percent: number }>("workshop-progress", (event) =>
callback({ packageId: event.payload.instanceId, percent: event.payload.percent }),
static onWorkshopProgress(
callback: (data: { packageId: string; percent: number }) => void,
) {
return listen<{ instanceId: string; percent: number }>(
"workshop-progress",
(event) =>
callback({
packageId: event.payload.instanceId,
percent: event.payload.percent,
}),
);
}
@ -221,21 +231,15 @@ export class TauriService {
}
static onBackendError(callback: (message: string) => void) {
return listen<string>("backend-error", (event) =>
callback(event.payload),
);
return listen<string>("backend-error", (event) => callback(event.payload));
}
static onGameLog(callback: (log: string) => void) {
return listen<string>("game-log", (event) =>
callback(event.payload),
);
return listen<string>("game-log", (event) => callback(event.payload));
}
static onDownloadRetry(callback: (attempt: number) => void) {
return listen<number>("download-retry", (event) =>
callback(event.payload),
);
return listen<number>("download-retry", (event) => callback(event.payload));
}
static async openUrl(url: string): Promise<void> {
@ -391,7 +395,9 @@ export class TauriService {
return invoke("get_instance_path", { instanceId });
}
static async getInstanceArgsSchema(instanceId: string): Promise<string | null> {
static async getInstanceArgsSchema(
instanceId: string,
): Promise<string | null> {
return invoke("get_instance_args_schema", { instanceId });
}
@ -439,7 +445,12 @@ export class TauriService {
branch: string,
dlcFolder: string,
): Promise<void> {
return invoke("download_dlc_files", { instanceId, repoUrl, branch, dlcFolder });
return invoke("download_dlc_files", {
instanceId,
repoUrl,
branch,
dlcFolder,
});
}
static async importWorld(