diff --git a/src/hooks/useAppConfig.ts b/src/hooks/useAppConfig.ts index d698af3..4279706 100644 --- a/src/hooks/useAppConfig.ts +++ b/src/hooks/useAppConfig.ts @@ -1,7 +1,6 @@ import { useState, useEffect } from "react"; import { useLocalStorage } from "./useLocalStorage"; import { TauriService } from "../services/TauriService"; - export function useAppConfig() { const [username, setUsername] = useLocalStorage("lce-username", "Steve"); const [theme, setTheme] = useLocalStorage("lce-theme", "Modern"); @@ -15,12 +14,10 @@ export function useAppConfig() { const [profile, setProfile] = useLocalStorage("lce-profile", "legacy_evolved"); const [legacyMode, setLegacyMode] = useLocalStorage("lce-legacy-mode", false); const [hasCompletedSetup, setHasCompletedSetup] = useLocalStorage("lce-setup-completed", false); - const [isLoaded, setIsLoaded] = useState(false); const [linuxRunner, setLinuxRunner] = useState(); const [perfBoost, setPerfBoost] = useState(false); const [customEditions, setCustomEditions] = useState([]); - useEffect(() => { TauriService.loadConfig().then((config) => { if (config.username) setUsername(config.username); diff --git a/src/hooks/useAudioController.ts b/src/hooks/useAudioController.ts index 23cf783..f752ad0 100644 --- a/src/hooks/useAudioController.ts +++ b/src/hooks/useAudioController.ts @@ -61,7 +61,6 @@ export function useAudioController({ musicVol, sfxVol, showIntro, isGameRunning, const [splashIndex, setSplashIndex] = useState(-1); const musicPausedRef = useRef<{ at: number; track: number } | null>(null); const fadeIntervalRef = useRef(null); - const playSfx = useCallback((file: string) => { const a = new Audio(`/sounds/${file}`); a.volume = sfxVol / 100; @@ -71,7 +70,6 @@ export function useAudioController({ musicVol, sfxVol, showIntro, isGameRunning, const playPressSound = useCallback(() => playSfx("press.wav"), [playSfx]); const playBackSound = useCallback(() => playSfx("back.ogg"), [playSfx]); const playSplashSound = useCallback(() => playSfx("orb.ogg"), [playSfx]); - const fadeOut = useCallback((audio: HTMLAudioElement, duration: number = 500) => { return new Promise((resolve) => { if (fadeIntervalRef.current) clearInterval(fadeIntervalRef.current); @@ -132,16 +130,13 @@ export function useAudioController({ musicVol, sfxVol, showIntro, isGameRunning, useEffect(() => { if (showIntro) return; if (audioElement) return; - const audio = new Audio(TRACKS[currentTrack]); audio.volume = musicVol / 100; const handleEnded = () => setCurrentTrack((prev) => (prev + 1) % TRACKS.length); audio.addEventListener("ended", handleEnded); - const playPromise = audio.play(); if (playPromise !== undefined) { playPromise.catch(() => { - console.log("Autoplay prevented, waiting for user interaction"); const startMusic = () => { audio.play().catch(() => { }); document.removeEventListener("click", startMusic); diff --git a/src/hooks/useDiscordRPC.ts b/src/hooks/useDiscordRPC.ts index c18465a..58e1c84 100644 --- a/src/hooks/useDiscordRPC.ts +++ b/src/hooks/useDiscordRPC.ts @@ -1,6 +1,5 @@ import { useEffect } from "react"; import RpcService from "../services/RpcService"; - interface DiscordRPCProps { rpcEnabled: boolean; showIntro: boolean; @@ -29,7 +28,6 @@ export function useDiscordRPC({ useEffect(() => { const updateRPC = async () => { if (!rpcEnabled || showIntro || !username) return; - if (!isWindowVisible && !isGameRunning && downloadProgress === null) return; diff --git a/src/hooks/useGameManager.ts b/src/hooks/useGameManager.ts index be5135e..752f765 100644 --- a/src/hooks/useGameManager.ts +++ b/src/hooks/useGameManager.ts @@ -191,7 +191,7 @@ export function useGameManager({ const newEdition = { ...edition, id, - titleImage: "/images/minecraft_title_tucustom.png", + titleImage: "/images/MenuTitle.png", }; setCustomEditions([...customEditions, newEdition]); return id; diff --git a/src/hooks/useGamepad.ts b/src/hooks/useGamepad.ts index 6c6a196..1a990d5 100644 --- a/src/hooks/useGamepad.ts +++ b/src/hooks/useGamepad.ts @@ -1,5 +1,4 @@ import { useEffect, useRef, useState, useCallback } from 'react'; - export interface UseGamepadProps { playSfx: (file: string) => void; isWindowVisible: boolean; @@ -57,18 +56,15 @@ export const useGamepad = ({ playSfx, isWindowVisible }: UseGamepadProps) => { return typeof btn === "object" ? btn.value : (btn as any) ?? 0; }; const justPressed = (i: number) => btnVal(i) > 0.5 && !lastButtons.current[i]; - if (justPressed(1)) dispatchKey('Enter'); if (justPressed(2)) dispatchKey('Escape'); if (justPressed(4)) dispatchKey('Tab', true); if (justPressed(5)) dispatchKey('Tab'); - const newButtons: Record = {}; gp.buttons.forEach((btn, i) => { newButtons[i] = (typeof btn === "object" ? btn.value : btn) > 0.5; }); lastButtons.current = newButtons; - const deadzone = 0.5; const axisY = gp.axes[2] ?? 0; const prevY = lastAxes.current[2] ?? 0; @@ -76,7 +72,6 @@ export const useGamepad = ({ playSfx, isWindowVisible }: UseGamepadProps) => { dispatchKey(axisY < 0 ? 'ArrowDown' : 'ArrowUp'); } lastAxes.current[2] = axisY; - const axisX = gp.axes[1] ?? 0; const prevX = lastAxes.current[1] ?? 0; if (Math.abs(axisX) > deadzone && Math.abs(prevX) <= deadzone) { @@ -94,17 +89,16 @@ export const useGamepad = ({ playSfx, isWindowVisible }: UseGamepadProps) => { useEffect(() => { const handleConnect = () => setConnected(true); const handleDisconnect = () => { - const gamepads = navigator.getGamepads ? navigator.getGamepads() : []; - const hasGamepads = Array.from(gamepads).some(gp => gp !== null); - setConnected(hasGamepads); + const gamepads = navigator.getGamepads ? navigator.getGamepads() : []; + const hasGamepads = Array.from(gamepads).some(gp => gp !== null); + setConnected(hasGamepads); }; window.addEventListener("gamepadconnected", handleConnect); window.addEventListener("gamepaddisconnected", handleDisconnect); - const initialGamepads = navigator.getGamepads ? navigator.getGamepads() : []; if (Array.from(initialGamepads).some(gp => gp !== null)) { - setConnected(true); + setConnected(true); } return () => { diff --git a/src/hooks/useLocalStorage.ts b/src/hooks/useLocalStorage.ts index dfbd1db..d5d4f7f 100644 --- a/src/hooks/useLocalStorage.ts +++ b/src/hooks/useLocalStorage.ts @@ -1,5 +1,4 @@ import { useState, useCallback } from 'react'; - export function useLocalStorage(key: string, initialValue: T): [T, (value: T | ((val: T) => T)) => void] { const [storedValue, setStoredValue] = useState(() => { try { diff --git a/src/hooks/usePlatform.ts b/src/hooks/usePlatform.ts index aa1471b..fa3320a 100644 --- a/src/hooks/usePlatform.ts +++ b/src/hooks/usePlatform.ts @@ -1,17 +1,12 @@ import { useMemo } from 'react'; - - export function usePlatform() { const platform = useMemo(() => { if (typeof window === 'undefined') return { isLinux: false, isMac: false, isWindows: false }; - const ua = window.navigator.userAgent.toLowerCase(); const plat = window.navigator.platform.toLowerCase(); - const isLinux = plat.includes('linux') || ua.includes('linux'); const isMac = plat.includes('mac') || ua.includes('mac'); const isWindows = plat.includes('win') || ua.includes('win'); - return { isLinux, isMac, isWindows }; }, []); diff --git a/src/hooks/useSkinSync.ts b/src/hooks/useSkinSync.ts index 11bede1..a8713ac 100644 --- a/src/hooks/useSkinSync.ts +++ b/src/hooks/useSkinSync.ts @@ -17,12 +17,9 @@ export function useSkinSync({ profile, editions }: UseSkinSyncProps) { const [skinUrl, setSkinUrl] = useLocalStorage("lce-skin", "/images/Default.png"); const [skinIsSlim, setSkinIsSlim] = useLocalStorage("lce-skin-slim", false); const [skinBase64, setSkinBase64] = useState(null); - useEffect(() => { let cancelled = false; if (!skinUrl) return; - const edition = editions.find((e) => e.id === profile); - const supportsSlim = edition?.supportsSlimSkins ?? false; const img = new Image(); img.crossOrigin = "anonymous"; img.onload = async () => { @@ -38,7 +35,7 @@ export function useSkinSync({ profile, editions }: UseSkinSyncProps) { try { const res = await fetch(b64); const buf = await res.arrayBuffer(); - const animValue = (supportsSlim && skinIsSlim) ? (1 << 19) : 0; + const animValue = (skinIsSlim) ? (1 << 19) : 0; const pckBuf = PckService.serializePCK({ version: 2, endianness: "little", diff --git a/src/hooks/useUpdateCheck.ts b/src/hooks/useUpdateCheck.ts index 8a3447d..39a00bc 100644 --- a/src/hooks/useUpdateCheck.ts +++ b/src/hooks/useUpdateCheck.ts @@ -1,17 +1,13 @@ import { useState, useEffect, useCallback } from "react"; import pkg from "../../package.json"; - const CURRENT_VERSION = pkg.version; const REPO_URL = "https://api.github.com/repos/LCE-Hub/LCE-Emerald-Launcher/releases/latest"; - function isNewerVersion(latest: string, current: string): boolean { const latestParts = latest.split('.').map(Number); const currentParts = current.split('.').map(Number); - for (let i = 0; i < Math.max(latestParts.length, currentParts.length); i++) { const latestPart = latestParts[i] || 0; const currentPart = currentParts[i] || 0; - if (latestPart > currentPart) return true; if (latestPart < currentPart) return false; } @@ -21,15 +17,12 @@ function isNewerVersion(latest: string, current: string): boolean { export function useUpdateCheck() { const [updateMessage, setUpdateMessage] = useState(null); - const checkUpdates = useCallback(async () => { try { const response = await fetch(REPO_URL); if (!response.ok) return; - const data = await response.json(); const latestVersion = data.tag_name.replace(/^v/, ''); - if (isNewerVersion(latestVersion, CURRENT_VERSION)) { setUpdateMessage(`Version ${data.tag_name} is now available!`); } diff --git a/src/pages/App.tsx b/src/pages/App.tsx index 26cc858..33e2e62 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -29,7 +29,6 @@ import { } from "../context/LauncherContext"; import { TauriService } from "../services/TauriService"; import pkg from "../../package.json"; - export default function App() { const { showIntro, @@ -47,15 +46,12 @@ export default function App() { updateMessage, clearUpdateMessage, } = useUI(); - const config = useConfig(); const audio = useAudio(); const game = useGame(); const { skinUrl, setSkinUrl } = useSkin(); - const [showSetup, setShowSetup] = useState(true); const [displayIsDay, setDisplayIsDay] = useState(config.isDayTime); - useEffect(() => { setDisplayIsDay(config.isDayTime); }, [config.isDayTime]); @@ -65,7 +61,6 @@ export default function App() { ); const selectedVersionName = selectedEdition?.name || ""; const hasAnyInstall = game.installs.length > 0; - const titleImage = hasAnyInstall ? (selectedEdition?.titleImage || "/images/MenuTitle.png") : "/images/MenuTitle.png"; diff --git a/src/services/ArcService.ts b/src/services/ArcService.ts index 7fdceaf..56fb0f1 100644 --- a/src/services/ArcService.ts +++ b/src/services/ArcService.ts @@ -1,9 +1,7 @@ import { ArcEntry, ArcFile, LocFile, LocLanguage, LocString } from "../types/arc"; - export class ArcService { private static enc = new TextEncoder(); private static dec = new TextDecoder('utf-8'); - private static readUTF(view: DataView, off: number): { str: string; next: number } { const len = view.getUint16(off, false); const bytes = new Uint8Array(view.buffer, view.byteOffset + off + 2, len); @@ -22,12 +20,9 @@ export class ArcService { const view = new DataView(buffer); const raw = new Uint8Array(buffer); let off = 0; - const count = view.getInt32(off, false); off += 4; - if (count < 0 || count > 200000) throw new Error("Invalid file count"); - const entries: ArcEntry[] = []; for (let i = 0; i < count; i++) { const { str: rawName, next } = this.readUTF(view, off); @@ -36,7 +31,6 @@ export class ArcService { off += 4; const size = view.getInt32(off, false); off += 4; - let filename = rawName; let isCompressed = false; if (filename.charCodeAt(0) === 42) { @@ -69,10 +63,8 @@ export class ArcService { const view = new DataView(buffer); const out = new Uint8Array(buffer); let pos = 0; - view.setInt32(pos, arc.entries.length, false); pos += 4; - arc.entries.forEach((e, i) => { const nb = this.enc.encode((e.isCompressed ? "*" : "") + e.filename); view.setUint16(pos, nb.length, false); @@ -98,57 +90,53 @@ export class ArcService { const buf = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength); const view = new DataView(buf); let off = 0; - const version = view.getInt32(off, false); off += 4; const langCount = view.getInt32(off, false); off += 4; - const langMeta: { id: string, size: number }[] = []; for (let i = 0; i < langCount; i++) { - const { str: id, next } = this.readUTF(view, off); - off = next; - const size = view.getInt32(off, false); - off += 4; - langMeta.push({ id, size }); + const { str: id, next } = this.readUTF(view, off); + off = next; + const size = view.getInt32(off, false); + off += 4; + langMeta.push({ id, size }); } const languages: LocLanguage[] = []; for (let i = 0; i < langMeta.length; i++) { - const blobView = new DataView(buf, off, langMeta[i].size); - let boff = 0; - - const langVer = blobView.getInt32(boff, false); - boff += 4; - let isStatic = false; - if (langVer > 0) { - isStatic = blobView.getUint8(boff) !== 0; - boff += 1; + const blobView = new DataView(buf, off, langMeta[i].size); + let boff = 0; + const langVer = blobView.getInt32(boff, false); + boff += 4; + let isStatic = false; + if (langVer > 0) { + isStatic = blobView.getUint8(boff) !== 0; + boff += 1; + } + const { str: langId, next: n2 } = this.readUTF(blobView, boff); + boff = n2; + const total = blobView.getInt32(boff, false); + boff += 4; + const strings: LocString[] = []; + if (!isStatic) { + for (let j = 0; j < total; j++) { + const { str: key, next: nk } = this.readUTF(blobView, boff); + boff = nk; + const { str: val, next: nv } = this.readUTF(blobView, boff); + boff = nv; + strings.push({ key, value: val }); } - const { str: langId, next: n2 } = this.readUTF(blobView, boff); - boff = n2; - const total = blobView.getInt32(boff, false); - boff += 4; - - const strings: LocString[] = []; - if (!isStatic) { - for (let j = 0; j < total; j++) { - const { str: key, next: nk } = this.readUTF(blobView, boff); - boff = nk; - const { str: val, next: nv } = this.readUTF(blobView, boff); - boff = nv; - strings.push({ key, value: val }); - } - } else { - for (let j = 0; j < total; j++) { - const { str: val, next: nv } = this.readUTF(blobView, boff); - boff = nv; - strings.push({ value: val }); - } + } else { + for (let j = 0; j < total; j++) { + const { str: val, next: nv } = this.readUTF(blobView, boff); + boff = nv; + strings.push({ value: val }); } + } - languages.push({ id: langMeta[i].id, version: langVer, isStatic, langId, strings }); - off += langMeta[i].size; + languages.push({ id: langMeta[i].id, version: langVer, isStatic, langId, strings }); + off += langMeta[i].size; } return { version, languages }; @@ -156,53 +144,47 @@ export class ArcService { static serializeLOC(loc: LocFile): Uint8Array { const blobs = loc.languages.map(lang => { - const parts: Uint8Array[] = []; - - const vh = new Uint8Array(4); - new DataView(vh.buffer).setInt32(0, lang.version, false); - parts.push(vh); + const parts: Uint8Array[] = []; + const vh = new Uint8Array(4); + new DataView(vh.buffer).setInt32(0, lang.version, false); + parts.push(vh); + if (lang.version > 0) { + parts.push(new Uint8Array([lang.isStatic ? 1 : 0])); + } - if (lang.version > 0) { - parts.push(new Uint8Array([lang.isStatic ? 1 : 0])); + parts.push(this.writeUTF(lang.langId)); + const sc = new Uint8Array(4); + new DataView(sc.buffer).setInt32(0, lang.strings.length, false); + parts.push(sc); + lang.strings.forEach(s => { + if (!lang.isStatic && s.key) { + parts.push(this.writeUTF(s.key)); } + parts.push(this.writeUTF(s.value)); + }); - parts.push(this.writeUTF(lang.langId)); - - const sc = new Uint8Array(4); - new DataView(sc.buffer).setInt32(0, lang.strings.length, false); - parts.push(sc); - - lang.strings.forEach(s => { - if (!lang.isStatic && s.key) { - parts.push(this.writeUTF(s.key)); - } - parts.push(this.writeUTF(s.value)); - }); - - const total = parts.reduce((a, b) => a + b.length, 0); - const blob = new Uint8Array(total); - let p = 0; - parts.forEach(b => { - blob.set(b, p); - p += b.length; - }); - return blob; + const total = parts.reduce((a, b) => a + b.length, 0); + const blob = new Uint8Array(total); + let p = 0; + parts.forEach(b => { + blob.set(b, p); + p += b.length; + }); + return blob; }); const headerParts: Uint8Array[] = []; const vh = new Uint8Array(4); new DataView(vh.buffer).setInt32(0, loc.version, false); headerParts.push(vh); - const lc = new Uint8Array(4); new DataView(lc.buffer).setInt32(0, loc.languages.length, false); headerParts.push(lc); - loc.languages.forEach((lang, i) => { - headerParts.push(this.writeUTF(lang.id)); - const sz = new Uint8Array(4); - new DataView(sz.buffer).setInt32(0, blobs[i].length, false); - headerParts.push(sz); + headerParts.push(this.writeUTF(lang.id)); + const sz = new Uint8Array(4); + new DataView(sz.buffer).setInt32(0, blobs[i].length, false); + headerParts.push(sz); }); const allParts = [...headerParts, ...blobs]; @@ -210,8 +192,8 @@ export class ArcService { const out = new Uint8Array(total); let p = 0; allParts.forEach(b => { - out.set(b, p); - p += b.length; + out.set(b, p); + p += b.length; }); return out; } diff --git a/src/services/ColService.ts b/src/services/ColService.ts index d998410..5948ad8 100644 --- a/src/services/ColService.ts +++ b/src/services/ColService.ts @@ -1,5 +1,4 @@ import { ColFile, ColColor, ColWorldColor } from "../types/col"; - export class ColService { private static textDecoder = new TextDecoder("utf-8"); private static textEncoder = new TextEncoder(); diff --git a/src/services/GrfService.ts b/src/services/GrfService.ts index 057cc8b..634d7af 100644 --- a/src/services/GrfService.ts +++ b/src/services/GrfService.ts @@ -7,7 +7,6 @@ import { GrfHeader, GrfNode } from "../types/grf"; - export class GrfService { private static textDecoder = new TextDecoder("ascii"); private static textEncoder = new TextEncoder(); @@ -133,7 +132,7 @@ export class GrfService { let bodyView: DataView; let bodyOff = { p: 0 }; if (header.compressionLevel !== GrfCompressionLevel.None) { - view.getInt32(off.p, false); // decompressedSize + view.getInt32(off.p, false); //neo: this is decompressedSize off.p += 4; const compressedSize = view.getInt32(off.p, false); off.p += 4; diff --git a/src/services/OptionsService.ts b/src/services/OptionsService.ts index 84c3b9b..34b7f6b 100644 --- a/src/services/OptionsService.ts +++ b/src/services/OptionsService.ts @@ -1,11 +1,9 @@ import { OptionsFile } from "../types/options"; - export class OptionsService { 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 = { endianness, rawData diff --git a/src/services/RpcService.ts b/src/services/RpcService.ts index 2974f58..2e179f7 100644 --- a/src/services/RpcService.ts +++ b/src/services/RpcService.ts @@ -1,11 +1,9 @@ import { setActivity, start } from "tauri-plugin-drpc"; import { Activity, ActivityType, Assets, Timestamps, Button } from "tauri-plugin-drpc/activity"; - class RPC { private startTime: number = Date.now(); private initializationPromise: Promise | null = null; private initialized: boolean = false; - public async StartRPC() { if (this.initialized) return; if (sessionStorage.getItem('lce_rpc_started') === 'true') { @@ -38,16 +36,13 @@ class RPC { activity.setDetails(details); activity.setState(state); activity.setActivity(ActivityType.Playing); - const assets = new Assets(); assets.setLargeImage("logo"); assets.setLargeText("LCE Emerald Launcher"); assets.setSmallImage("app-icon"); assets.setSmallText(isPlaying ? "Playing" : "In Menus"); activity.setAssets(assets); - activity.setTimestamps(new Timestamps(this.startTime)); - activity.setButton([ new Button("Discord", "https://discord.gg/vD8akRU24f"), new Button("GitHub", "https://github.com/LCE-Hub/LCE-Emerald-Launcher") diff --git a/src/services/unused.ts b/src/services/unused.ts deleted file mode 100644 index 53a0e14..0000000 --- a/src/services/unused.ts +++ /dev/null @@ -1,2 +0,0 @@ -// empty :P -// what is this file lol ? - kay \ No newline at end of file diff --git a/src/types/unused.ts b/src/types/unused.ts deleted file mode 100644 index ada22b4..0000000 --- a/src/types/unused.ts +++ /dev/null @@ -1 +0,0 @@ -// empty :P \ No newline at end of file