feat(oneclient): Debug Info (#418)

This commit is contained in:
Jacob 2025-12-04 07:54:23 +00:00 • committed by GitHub
parent cb8caf60e8
commit e1f8dac5a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 510 additions and 49 deletions

132
Cargo.lock generated
View file

@ -855,7 +855,7 @@ dependencies = [
"num-traits",
"serde",
"wasm-bindgen",
"windows-link",
"windows-link 0.1.1",
]
[[package]]
@ -1959,6 +1959,16 @@ dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "gethostname"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
dependencies = [
"rustix 1.0.3",
"windows-link 0.2.1",
]
[[package]]
name = "getrandom"
version = "0.1.16"
@ -3026,6 +3036,18 @@ dependencies = [
"memoffset",
]
[[package]]
name = "nix"
version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
dependencies = [
"bitflags 2.6.0",
"cfg-if",
"cfg_aliases 0.2.1",
"libc",
]
[[package]]
name = "nodrop"
version = "0.1.14"
@ -3261,6 +3283,16 @@ dependencies = [
"objc2-foundation 0.3.1",
]
[[package]]
name = "objc2-core-location"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac0f75792558aa9d618443bbb5db7426a7a0b6fddf96903f86ef9ad02e135740"
dependencies = [
"objc2 0.6.1",
"objc2-foundation 0.3.1",
]
[[package]]
name = "objc2-encode"
version = "4.1.0"
@ -3357,6 +3389,7 @@ checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5"
dependencies = [
"bitflags 2.6.0",
"objc2 0.6.1",
"objc2-core-foundation",
"objc2-foundation 0.3.1",
]
@ -3367,8 +3400,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed"
dependencies = [
"bitflags 2.6.0",
"block2 0.6.1",
"objc2 0.6.1",
"objc2-cloud-kit",
"objc2-core-data",
"objc2-core-foundation",
"objc2-core-graphics",
"objc2-core-image",
"objc2-core-location",
"objc2-foundation 0.3.1",
"objc2-quartz-core 0.3.1",
"objc2-user-notifications",
]
[[package]]
name = "objc2-user-notifications"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a3f5ec77a81d9e0c5a0b32159b0cb143d7086165e79708351e02bf37dfc65cd"
dependencies = [
"objc2 0.6.1",
"objc2-foundation 0.3.1",
]
@ -3421,6 +3472,7 @@ dependencies = [
"tauri-plugin-deep-link",
"tauri-plugin-dialog",
"tauri-plugin-fs",
"tauri-plugin-os",
"tauri-plugin-single-instance",
"tauri-plugin-updater",
"tauri-plugin-window-state",
@ -3478,6 +3530,7 @@ dependencies = [
"specta",
"sysinfo",
"tauri",
"tauri-plugin-os",
"taurpc",
"thiserror 2.0.12",
"tokio",
@ -3535,6 +3588,7 @@ dependencies = [
"tauri-plugin-deep-link",
"tauri-plugin-dialog",
"tauri-plugin-opener",
"tauri-plugin-os",
"tauri-plugin-single-instance",
"tauri-plugin-updater",
"tauri-plugin-window-state",
@ -3623,6 +3677,22 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "os_info"
version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c39b5918402d564846d5aba164c09a66cc88d232179dfd3e3c619a25a268392"
dependencies = [
"android_system_properties",
"log",
"nix 0.30.1",
"objc2 0.6.1",
"objc2-foundation 0.3.1",
"objc2-ui-kit",
"serde",
"windows-sys 0.61.2",
]
[[package]]
name = "os_pipe"
version = "1.2.1"
@ -5759,6 +5829,15 @@ dependencies = [
"futures-core",
]
[[package]]
name = "sys-locale"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
dependencies = [
"libc",
]
[[package]]
name = "sysinfo"
version = "0.34.2"
@ -6114,6 +6193,24 @@ dependencies = [
"zbus",
]
[[package]]
name = "tauri-plugin-os"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "424f19432397850c2ddd42aa58078630c15287bbce3866eb1d90e7dbee680637"
dependencies = [
"gethostname 1.1.0",
"log",
"os_info",
"serde",
"serde_json",
"serialize-to-javascript",
"sys-locale",
"tauri",
"tauri-plugin",
"thiserror 2.0.12",
]
[[package]]
name = "tauri-plugin-single-instance"
version = "2.2.3"
@ -7315,7 +7412,7 @@ dependencies = [
"windows-collections",
"windows-core 0.61.0",
"windows-future",
"windows-link",
"windows-link 0.1.1",
"windows-numerics",
]
@ -7357,7 +7454,7 @@ checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
dependencies = [
"windows-implement 0.60.0",
"windows-interface 0.59.1",
"windows-link",
"windows-link 0.1.1",
"windows-result 0.3.2",
"windows-strings 0.4.0",
]
@ -7369,7 +7466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
dependencies = [
"windows-core 0.61.0",
"windows-link",
"windows-link 0.1.1",
]
[[package]]
@ -7422,6 +7519,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-numerics"
version = "0.2.0"
@ -7429,7 +7532,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
dependencies = [
"windows-core 0.61.0",
"windows-link",
"windows-link 0.1.1",
]
[[package]]
@ -7449,7 +7552,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad1da3e436dc7653dfdf3da67332e22bff09bb0e28b0239e1624499c7830842e"
dependencies = [
"windows-link",
"windows-link 0.1.1",
"windows-result 0.3.2",
"windows-strings 0.4.0",
]
@ -7478,7 +7581,7 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
dependencies = [
"windows-link",
"windows-link 0.1.1",
]
[[package]]
@ -7497,7 +7600,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
dependencies = [
"windows-link",
"windows-link 0.1.1",
]
[[package]]
@ -7536,6 +7639,15 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link 0.2.1",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
@ -7860,7 +7972,7 @@ version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12"
dependencies = [
"gethostname",
"gethostname 0.4.3",
"rustix 0.38.44",
"x11rb-protocol",
]
@ -7918,7 +8030,7 @@ dependencies = [
"futures-core",
"futures-lite",
"hex",
"nix",
"nix 0.29.0",
"ordered-stream",
"serde",
"serde_repr",

View file

@ -49,6 +49,7 @@ tauri-plugin-clipboard-manager = { version = "=2.2.2" }
tauri-plugin-deep-link = { version = "=2.2.1" }
tauri-plugin-dialog = { version = "=2.2.1" }
tauri-plugin-fs = { version = "=2.2.1" }
tauri-plugin-os = { version = "=2.2.1" }
tauri-plugin-single-instance = { version = "=2.2.3" }
tauri-plugin-updater = { version = "=2.7.1" }
tauri-plugin-window-state = { version = "=2.2.2" }

View file

@ -37,6 +37,7 @@ tauri-plugin-updater = { workspace = true }
tauri-plugin-clipboard-manager = { workspace = true }
tauri-plugin-dialog = { workspace = true }
tauri-plugin-fs = { workspace = true }
tauri-plugin-os = { workspace = true }
tauri-plugin-deep-link = { workspace = true }
# code gen

View file

@ -1,3 +1,20 @@
use std::process::Command;
use std::time::{SystemTime, UNIX_EPOCH};
fn main() {
let output = Command::new("git")
.args(&["rev-parse", "HEAD"])
.output()
.unwrap();
let git_hash = String::from_utf8(output.stdout).unwrap();
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
let start = SystemTime::now();
let timestamp = start
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_secs();
println!("cargo:rustc-env=BUILD_TIMESTAMP={}", timestamp);
tauri_build::build();
}

View file

@ -36,6 +36,8 @@
"fs:allow-download-read",
"fs:allow-download-write",
"fs:allow-data-read-recursive",
"fs:allow-data-write-recursive"
"fs:allow-data-write-recursive",
"os:default"
]
}

View file

@ -4,16 +4,12 @@ use onelauncher_core::api::cluster::dao::ClusterId;
use onelauncher_core::api::packages::modpack::data::ModpackArchive;
use onelauncher_core::entity::clusters;
use onelauncher_core::error::LauncherResult;
use tauri::Runtime;
use crate::oneclient::bundles::BundlesManager;
use crate::oneclient::clusters::{OnlineClusterManifest, get_data_storage_versions};
#[taurpc::procedures(path = "oneclient", export_to = "../frontend/src/bindings.gen.ts")]
pub trait OneClientApi {
#[taurpc(alias = "openDevTools")]
async fn open_dev_tools<R: Runtime>(webview_window: tauri::WebviewWindow<R>);
#[taurpc(alias = "getClustersGroupedByMajor")]
async fn get_clusters_grouped_by_major() -> LauncherResult<HashMap<u32, Vec<clusters::Model>>>;
@ -29,11 +25,6 @@ pub struct OneClientApiImpl;
#[taurpc::resolvers]
impl OneClientApi for OneClientApiImpl {
async fn open_dev_tools<R: Runtime>(self, webview_window: tauri::WebviewWindow<R>) {
#[cfg(feature = "devtools")]
webview_window.open_devtools();
}
async fn get_clusters_grouped_by_major(
self,
) -> LauncherResult<HashMap<u32, Vec<clusters::Model>>> {

View file

@ -234,7 +234,7 @@ gallery: string[] }
export type SettingProfileModel = { name: string; java_id: number | null; res: Resolution | null; force_fullscreen: boolean | null; mem_max: number | null; launch_args: string | null; launch_env: string | null; hook_pre: string | null; hook_wrapper: string | null; hook_post: string | null; os_extra: SettingsOsExtra | null }
export type Settings = { global_game_settings: SettingProfileModel; allow_parallel_running_clusters: boolean; enable_gamemode: boolean; discord_enabled: boolean; seen_onboarding: boolean; mod_list_use_grid: boolean; slow_mod_bulk_downloading: boolean; max_concurrent_requests: number; settings_version: number; native_window_frame: boolean; show_tanstack_dev_tools: boolean }
export type Settings = { global_game_settings: SettingProfileModel; allow_parallel_running_clusters: boolean; enable_gamemode: boolean; discord_enabled: boolean; seen_onboarding: boolean; mod_list_use_grid: boolean; parallel_mod_downloading: boolean; max_concurrent_requests: number; settings_version: number; native_window_frame: boolean; show_tanstack_dev_tools: boolean }
export type SettingsOsExtra = Record<string, never>
@ -301,9 +301,17 @@ export type VersionType =
*/
"old_beta"
const ARGS_MAP = { 'folders':'{"fromCluster":["folder_name"],"openCluster":["folder_name"]}', 'core':'{"getLogs":["id"],"getClusters":[],"removeUser":["uuid"],"getRunningProcesses":[],"searchPackages":["provider","query"],"getMultiplePackages":["provider","slugs"],"removeCluster":["id"],"readSettings":[],"getProfileOrDefault":["name"],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"changeSkin":["access_token","skin_url","skin_variant"],"isClusterRunning":["cluster_id"],"getScreenshots":["id"],"launchCluster":["id","uuid"],"uploadSkinBytes":["access_token","skin_data","image_format","skin_variant"],"updateClusterById":["id","request"],"updateClusterProfile":["name","profile"],"openMsaLogin":[],"open":["input"],"createSettingsProfile":["name"],"getUser":["uuid"],"installModpack":["modpack","cluster_id"],"getGameVersions":[],"removeCape":["access_token"],"getUsers":[],"getPackage":["provider","slug"],"downloadExternalPackage":["package","cluster_id","force","skip_compatibility"],"getRunningProcessesByClusterId":["cluster_id"],"createCluster":["options"],"setDefaultUser":["uuid"],"writeSettings":["setting"],"changeCape":["access_token","cape_uuid"],"fetchLoggedInProfile":["access_token"],"fetchMinecraftProfile":["uuid"],"convertUsernameUUID":["username_uuid"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"getClusterById":["id"],"getWorlds":["id"],"getGlobalProfile":[],"getDefaultUser":["fallback"],"getUsersFromAuthor":["provider","author"],"getLoadersForVersion":["mc_version"],"getLogByName":["id","name"],"getPackageBody":["provider","body"],"killProcess":["pid"]}', 'events':'{"process":["event"],"ingress":["event"],"message":["event"]}', 'oneclient':'{"getBundlesFor":["cluster_id"],"getClustersGroupedByMajor":[],"openDevTools":[],"getVersions":[]}' }
export type Router = { 'folders': { fromCluster: (folderName: string) => Promise<string>,
openCluster: (folderName: string) => Promise<null> },
const ARGS_MAP = { 'folders':'{"fromCluster":["folder_name"],"openCluster":["folder_name"]}', 'oneclient':'{"getBundlesFor":["cluster_id"],"getVersions":[],"getClustersGroupedByMajor":[]}', 'core':'{"fetchLoggedInProfile":["access_token"],"getMultiplePackages":["provider","slugs"],"getProfileOrDefault":["name"],"getGameVersions":[],"removeCape":["access_token"],"removeCluster":["id"],"getLoadersForVersion":["mc_version"],"getScreenshots":["id"],"getLogByName":["id","name"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"createCluster":["options"],"getPackageBody":["provider","body"],"fetchMinecraftProfile":["uuid"],"killProcess":["pid"],"getUsers":[],"getDefaultUser":["fallback"],"getRunningProcessesByClusterId":["cluster_id"],"convertUsernameUUID":["username_uuid"],"launchCluster":["id","uuid"],"updateClusterById":["id","request"],"changeCape":["access_token","cape_uuid"],"getWorlds":["id"],"getPackage":["provider","slug"],"updateClusterProfile":["name","profile"],"downloadExternalPackage":["package","cluster_id","force","skip_compatibility"],"readSettings":[],"searchPackages":["provider","query"],"getGlobalProfile":[],"createSettingsProfile":["name"],"getUser":["uuid"],"getRunningProcesses":[],"installModpack":["modpack","cluster_id"],"changeSkin":["access_token","skin_url","skin_variant"],"open":["input"],"openMsaLogin":[],"getClusters":[],"isClusterRunning":["cluster_id"],"getLogs":["id"],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"removeUser":["uuid"],"getUsersFromAuthor":["provider","author"],"uploadSkinBytes":["access_token","skin_data","image_format","skin_variant"],"setDefaultUser":["uuid"],"writeSettings":["setting"],"getClusterById":["id"]}', 'events':'{"message":["event"],"ingress":["event"],"process":["event"]}', 'debug':'{"getVersion":[],"getType":[],"getArch":[],"getLocale":[],"getBuildTimestamp":[],"openDevTools":[],"getCommitHash":[],"isInDev":[],"getFamily":[],"getPlatform":[]}' }
export type Router = { 'debug': { openDevTools: () => Promise<void>,
isInDev: () => Promise<boolean>,
getPlatform: () => Promise<string>,
getArch: () => Promise<string>,
getFamily: () => Promise<string>,
getLocale: () => Promise<string | null>,
getType: () => Promise<string>,
getVersion: () => Promise<string>,
getCommitHash: () => Promise<string>,
getBuildTimestamp: () => Promise<string> },
'core': { getClusters: () => Promise<ClusterModel[]>,
getClusterById: (id: number) => Promise<ClusterModel | null>,
removeCluster: (id: number) => Promise<null>,
@ -349,13 +357,14 @@ changeCape: (accessToken: string, capeUuid: string) => Promise<MojangFullPlayerP
removeCape: (accessToken: string) => Promise<MojangFullPlayerProfile>,
convertUsernameUUID: (usernameUuid: string) => Promise<MowojangProfile>,
open: (input: string) => Promise<null> },
'oneclient': { getClustersGroupedByMajor: () => Promise<Partial<{ [key in number]: ClusterModel[] }>>,
getBundlesFor: (clusterId: number) => Promise<ModpackArchive[]>,
getVersions: () => Promise<OnlineClusterManifest> },
'events': { ingress: (event: IngressPayload) => Promise<void>,
message: (event: MessagePayload) => Promise<void>,
process: (event: ProcessPayload) => Promise<void> },
'oneclient': { openDevTools: () => Promise<void>,
getClustersGroupedByMajor: () => Promise<Partial<{ [key in number]: ClusterModel[] }>>,
getBundlesFor: (clusterId: number) => Promise<ModpackArchive[]>,
getVersions: () => Promise<OnlineClusterManifest> } };
'folders': { fromCluster: (folderName: string) => Promise<string>,
openCluster: (folderName: string) => Promise<null> } };
export type { InferCommandOutput }

View file

@ -1,4 +1,5 @@
import type { ExternalPackage, ManagedVersionDependency, ModpackFile, Provider } from '@/bindings.gen';
import { useSettings } from '@/hooks/useSettings';
import { bindings } from '@/main';
import { useCommandMut } from '@onelauncher/common';
import { Button } from '@onelauncher/common/components';
@ -7,7 +8,6 @@ import { useEffect, useImperativeHandle, useState } from 'react';
import { DialogTrigger } from 'react-aria-components';
import { getModMetaDataName } from './Bundle';
import { Overlay } from './overlay';
import { useSettings } from '@/hooks/useSettings';
export interface DownloadModsRef {
openDownloadDialog: (nextPath?: string) => void;
@ -129,12 +129,11 @@ function DownloadingMods({ mods, setOpen, nextPath }: { mods: ModDataArray; setO
});
const { setting } = useSettings();
let useSlowDownloading = setting('slow_mod_bulk_downloading');
let useParallelModDownloading = setting('parallel_mod_downloading');
useEffect(() => {
const downloadAll = async () => {
if (useSlowDownloading)
if (useParallelModDownloading)
for (const mod of mods) {
setModName(mod.name);
try {
@ -153,7 +152,6 @@ function DownloadingMods({ mods, setOpen, nextPath }: { mods: ModDataArray; setO
setDownloadedMods(prev => prev + 1);
}
});
};
downloadAll();

View file

@ -9,6 +9,7 @@ import { Window } from '@tauri-apps/api/window';
import { MinusIcon, Settings02Icon, SquareIcon, XCloseIcon } from '@untitled-theme/icons-react';
import { twMerge } from 'tailwind-merge';
import { AccountAvatar } from './AccountAvatar';
import { Overlay, SuperSecretDevOptions } from './overlay';
import { AccountPopup } from './overlay/AccountPopup';
export function Navbar() {
@ -21,8 +22,16 @@ export function Navbar() {
return (
<nav className="flex flex-row items-center justify-between h-20 px-12 z-40" data-tauri-drag-region="true">
<div className="flex flex-1 pointer-events-none">
<LauncherLogo height={47} width={230} />
<div className="flex flex-1">
<Overlay.Trigger>
<NavbarButton className="w-[230px] h-[47px] focus:outline-none focus:ring-0" color="none">
<LauncherLogo height={47} width={230} />
</NavbarButton>
<Overlay>
<SuperSecretDevOptions />
</Overlay>
</Overlay.Trigger>
</div>
<div className="flex flex-1 items-center justify-center pointer-events-none gap-6">

View file

@ -0,0 +1,123 @@
import { bindings } from '@/main';
import { Button } from '@onelauncher/common/components';
import { writeText } from '@tauri-apps/plugin-clipboard-manager';
import { useEffect, useState } from 'react';
import { Overlay } from './Overlay';
export type DebugInfoArray = Array<{ title: string; value: string }>;
export interface DebugInfoData {
inDev: boolean;
platform: string;
arch: string;
family: string;
locale: string;
type: string;
version: string;
commitHash: string;
buildTimestamp: string;
}
export function useDebugInfo(): DebugInfoArray {
const [devInfo, setDevInfo] = useState<DebugInfoData>({
inDev: false,
platform: 'UNKNOWN',
arch: 'UNKNOWN',
family: 'UNKNOWN',
locale: 'UNKNOWN',
type: 'UNKNOWN',
version: 'UNKNOWN',
commitHash: 'UNKNOWN',
buildTimestamp: 'UNKNOWN',
});
useEffect(() => {
const fetchDevInfo = async () => {
const [
inDev,
platform,
arch,
family,
locale,
type,
version,
commitHash,
buildTimestamp,
] = await Promise.all([
bindings.debug.isInDev(),
bindings.debug.getPlatform(),
bindings.debug.getArch(),
bindings.debug.getFamily(),
bindings.debug.getLocale(),
bindings.debug.getType(),
bindings.debug.getVersion(),
bindings.debug.getCommitHash(),
bindings.debug.getBuildTimestamp(),
]);
setDevInfo({
inDev,
platform,
arch,
family,
locale: locale ?? 'UNKNOWN',
type,
version,
commitHash,
buildTimestamp,
});
};
void fetchDevInfo();
}, []);
return [
{ title: 'inDev', value: devInfo.inDev ? 'yes' : 'no' },
{ title: 'Platform', value: devInfo.platform },
{ title: 'Arch', value: devInfo.arch },
{ title: 'Family', value: devInfo.family },
{ title: 'Locale', value: devInfo.locale },
{ title: 'Type', value: devInfo.type },
{ title: 'Version', value: devInfo.version },
{ title: 'Commit Hash', value: devInfo.commitHash },
{ title: 'Build Timestamp', value: devInfo.buildTimestamp },
];
}
export function copyDebugInfo(debugInfo: DebugInfoArray) {
const timestamp = Math.floor(new Date().getTime() / 1000);
const lines = [`**Data exported at:** <t:${timestamp}> (\`${timestamp}\`)`, ...debugInfo.map((lineData) => {
if (lineData.title === 'Build Timestamp')
return `**${lineData.title}:** <t:${lineData.value}> (\`${lineData.value}\`)`;
return `**${lineData.title}:** \`${lineData.value}\``;
})];
writeText(lines.join('\n'));
}
export function DebugInfo() {
const debugInfo = useDebugInfo();
return (
<Overlay.Dialog>
<Overlay.Title>Debug Info</Overlay.Title>
<RawDebugInfo debugInfo={debugInfo} />
</Overlay.Dialog>
);
}
export function RawDebugInfo({ debugInfo }: { debugInfo: DebugInfoArray }) {
const copy = () => copyDebugInfo(debugInfo);
return (
<>
<div>
{debugInfo.map((lineData) => {
let line = '';
if (lineData.title === 'Build Timestamp')
line = `${lineData.title}: ${new Date(Number(lineData.value) * 1000)}`;
else line = `${lineData.title}: ${lineData.value}`;
return <p key={lineData.title}>{line}</p>;
})}
</div>
<Button onPress={copy}>Copy Data</Button>
</>
);
}

View file

@ -0,0 +1,61 @@
import { useSettings } from '@/hooks/useSettings';
import { bindings } from '@/main';
import { Button } from '@onelauncher/common/components';
import { Link } from '@tanstack/react-router';
import { dataDir, join } from '@tauri-apps/api/path';
import { BatteryEmptyIcon, Code02Icon, FolderIcon, LinkExternal01Icon, Truck01Icon } from '@untitled-theme/icons-react';
import { useEffect, useState } from 'react';
import SettingsRow from '../SettingsRow';
import SettingsSwitch from '../SettingSwitch';
import { RawDebugInfo, useDebugInfo } from './DebugInfo';
import { Overlay } from './Overlay';
export function SuperSecretDevOptions() {
const { createSetting } = useSettings();
const debugInfo = useDebugInfo();
const [launcherDir, setLauncherDir] = useState('');
useEffect(() => {
(async () => {
setLauncherDir(await join(await dataDir(), 'OneClient'));
})();
}, []);
const openLauncherDir = () => bindings.core.open(launcherDir);
return (
<Overlay.Dialog>
<Overlay.Title>Super Secret Dev Options</Overlay.Title>
<div>
<SettingsRow description="Enable The Tanstack Dev Tools" icon={<Code02Icon />} title="Tanstack Dev Tools">
<SettingsSwitch setting={createSetting('show_tanstack_dev_tools')} />
</SettingsRow>
<SettingsRow description="Open Dev Tools" icon={<Code02Icon />} title="Open Dev Tools">
<Button onPress={bindings.debug.openDevTools} size="normal">Open</Button>
</SettingsRow>
<SettingsRow description="Use Parallel Mod Downloading for speed. This can create some issues sometimes" icon={<BatteryEmptyIcon />} title="Use Parallel Mod Downloading">
<SettingsSwitch setting={createSetting('parallel_mod_downloading')} />
</SettingsRow>
<SettingsRow description="Skip Onboarding" icon={<Truck01Icon />} title="Skip Onboarding">
<Link to="/onboarding/finished">
<Button size="normal">Skip</Button>
</Link>
</SettingsRow>
<SettingsRow description={launcherDir} icon={<FolderIcon />} title="Launcher Folder">
<Button onClick={openLauncherDir} size="normal">
<LinkExternal01Icon />
{' '}
Open
</Button>
</SettingsRow>
</div>
<RawDebugInfo debugInfo={debugInfo} />
</Overlay.Dialog>
);
}

View file

@ -1,10 +1,12 @@
export * from './AccountPopup';
export * from './AddAccountModal';
export * from './BundleModListModal';
export * from './DebugInfo';
export * from './ImportSkinModal';
export * from './NoAccountPopup';
export * from './Overlay';
export * from './Popup';
export * from './RemoveAccountModal';
export * from './RemoveSkinCapeModal';
export * from './SuperSecretDevOptions';
export * from './Toasts';

View file

@ -1,10 +1,11 @@
import { DebugInfo, Overlay } from '@/components/overlay';
import SettingsRow from '@/components/SettingsRow';
import SettingsSwitch from '@/components/SettingSwitch';
import { useSettings } from '@/hooks/useSettings';
import { bindings } from '@/main';
import { Button } from '@onelauncher/common/components';
import { createFileRoute, Link } from '@tanstack/react-router';
import { BatteryEmptyIcon, BatteryFullIcon, Code02Icon, Truck01Icon } from '@untitled-theme/icons-react';
import { BatteryEmptyIcon, BatteryFullIcon, Code02Icon, FileHeart02Icon, Truck01Icon } from '@untitled-theme/icons-react';
import Sidebar from './route';
export const Route = createFileRoute('/app/settings/developer')({
@ -19,6 +20,20 @@ function RouteComponent() {
<div className="h-full">
<h1 className="text-xl">Developer Options</h1>
<SettingsRow
description="Open Debug Info"
icon={<FileHeart02Icon />}
title="Open Debug Info"
>
<Overlay.Trigger>
<Button size="normal">Open</Button>
<Overlay>
<DebugInfo />
</Overlay>
</Overlay.Trigger>
</SettingsRow>
<SettingsRow.Header>Dev Tools</SettingsRow.Header>
<SettingsRow
description="Enable The Tanstack Dev Tools"
@ -32,7 +47,7 @@ function RouteComponent() {
icon={<Code02Icon />}
title="Open Dev Tools"
>
<Button onPress={bindings.oneclient.openDevTools} size="normal">Open</Button>
<Button onPress={bindings.debug.openDevTools} size="normal">Open</Button>
</SettingsRow>
<SettingsRow.Header>Onboarding</SettingsRow.Header>
@ -60,14 +75,9 @@ function RouteComponent() {
<SettingsSwitch setting={createSetting('mod_list_use_grid')} />
</SettingsRow>
<SettingsRow.Header>Mod Downloading</SettingsRow.Header>
<SettingsRow
description="Slow is sometimes better. This is more consistent but takes longer then someone having a god dam CHILD???"
icon={<BatteryEmptyIcon />}
title="Use Slow Mod Bulk Downloading"
>
<SettingsSwitch setting={createSetting('slow_mod_bulk_downloading')} />
<SettingsRow description="Use Parallel Mod Downloading for speed. This can create some issues sometimes" icon={<BatteryEmptyIcon />} title="Use Parallel Mod Downloading">
<SettingsSwitch setting={createSetting('parallel_mod_downloading')} />
</SettingsRow>
</div>

View file

@ -21,7 +21,7 @@ function RouteComponent() {
useEffect(() => {
(async () => {
setLauncherDir(await join(await dataDir(), 'OneLauncher'));
setLauncherDir(await join(await dataDir(), 'OneClient'));
})();
}, []);

View file

@ -3,6 +3,7 @@ import type { PropsWithChildren } from 'react';
import LauncherLogo from '@/assets/logos/oneclient.svg?react';
import { LoaderSuspense, NavbarButton } from '@/components';
import { GameBackground } from '@/components/GameBackground';
import { Overlay, SuperSecretDevOptions } from '@/components/overlay';
import { Stepper } from '@/components/Stepper';
import { bindings } from '@/main';
import { useCommandSuspense } from '@onelauncher/common';
@ -13,6 +14,7 @@ import { Window } from '@tauri-apps/api/window';
import { MinusIcon, SquareIcon, XCloseIcon } from '@untitled-theme/icons-react';
import { motion } from 'motion/react';
import { useEffect } from 'react';
import { Button as AriaButton } from 'react-aria-components';
import { MouseParallax } from 'react-just-parallax';
export const Route = createFileRoute('/onboarding')({
@ -164,7 +166,15 @@ function AppShell({
<div className={`min-w-64 ${isFirstStep ? 'bg-page' : ''} border-r border-component-border flex flex-col`}>
<div className="p-6">
<div className="flex items-center gap-2">
<LauncherLogo className="w-52 h-12" />
<Overlay.Trigger>
<AriaButton className="w-52 h-12 focus:outline-none focus:ring-0">
<LauncherLogo className="w-52 h-12" />
</AriaButton>
<Overlay>
<SuperSecretDevOptions />
</Overlay>
</Overlay.Trigger>
</div>
</div>

View file

@ -38,6 +38,7 @@ tauri-plugin-clipboard-manager = { workspace = true }
tauri-plugin-dialog = { workspace = true }
tauri-plugin-deep-link = { workspace = true }
tauri-plugin-opener = { workspace = true }
tauri-plugin-os = { workspace = true }
# code gen
taurpc = { workspace = true }

View file

@ -1,3 +1,20 @@
use std::process::Command;
use std::time::{SystemTime, UNIX_EPOCH};
fn main() {
let output = Command::new("git")
.args(&["rev-parse", "HEAD"])
.output()
.unwrap();
let git_hash = String::from_utf8(output.stdout).unwrap();
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
let start = SystemTime::now();
let timestamp = start
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_secs();
println!("cargo:rustc-env=BUILD_TIMESTAMP={}", timestamp);
tauri_build::build();
}

View file

@ -44,6 +44,8 @@
]
},
"opener:allow-open-url",
"opener:default"
"opener:default",
"os:default"
]
}

View file

@ -98,6 +98,7 @@ sanitize-filename = { workspace = true }
# features[tauri]
tauri = { workspace = true, optional = true }
tauri-plugin-os = { workspace = true }
taurpc = { workspace = true, optional = true }
# features[specta]

View file

@ -0,0 +1,89 @@
use tauri::Runtime;
use tauri_plugin_os::{arch, family, locale, platform, type_, version};
use crate::error::LauncherResult;
#[taurpc::procedures(path = "debug")]
pub trait TauriLauncherDebugApi {
#[taurpc(alias = "openDevTools")]
async fn open_dev_tools<R: Runtime>(webview_window: tauri::WebviewWindow<R>);
#[taurpc(alias = "isInDev")]
async fn is_in_dev() -> bool;
#[taurpc(alias = "getPlatform")]
async fn get_platform() -> String;
#[taurpc(alias = "getArch")]
async fn get_arch() -> String;
#[taurpc(alias = "getFamily")]
async fn get_family() -> String;
#[taurpc(alias = "getLocale")]
async fn get_locale() -> Option<String>;
#[taurpc(alias = "getType")]
async fn get_type() -> String;
#[taurpc(alias = "getVersion")]
async fn get_version() -> String;
#[taurpc(alias = "getCommitHash")]
async fn get_commit_hash() -> LauncherResult<String>;
#[taurpc(alias = "getBuildTimestamp")]
async fn get_build_timestamp() -> LauncherResult<String>;
}
#[taurpc::ipc_type]
pub struct TauriLauncherDebugApiImpl;
#[taurpc::resolvers]
impl TauriLauncherDebugApi for TauriLauncherDebugApiImpl {
async fn open_dev_tools<R: Runtime>(self, webview_window: tauri::WebviewWindow<R>) {
webview_window.open_devtools();
}
async fn is_in_dev(self) -> bool {
tauri::is_dev()
}
async fn get_platform(self) -> String {
platform().to_string()
}
async fn get_arch(self) -> String {
arch().to_string()
}
async fn get_family(self) -> String {
family().to_string()
}
async fn get_locale(self) -> Option<String> {
locale()
}
async fn get_type(self) -> String {
type_().to_string()
}
async fn get_version(self) -> String {
version().to_string()
}
async fn get_commit_hash(self) -> LauncherResult<String> {
if tauri::is_dev() {
let hash = std::env::var("GIT_HASH").map_err(anyhow::Error::from)?;
Ok(hash)
} else {
Ok("null".to_string())
}
}
async fn get_build_timestamp(self) -> LauncherResult<String> {
let timestamp = std::env::var("BUILD_TIMESTAMP").map_err(anyhow::Error::from)?;
Ok(timestamp)
}
}

View file

@ -7,6 +7,9 @@ pub use commands::*;
mod folders;
pub use folders::*;
mod debug;
pub use debug::*;
pub trait TauRPCLauncherExt {
fn use_launcher_api(self) -> Self;
}
@ -16,5 +19,6 @@ impl<R: tauri::Runtime> TauRPCLauncherExt for taurpc::Router<R> {
self.merge(TauriLauncherApiImpl.into_handler())
.merge(TauriLauncherEventApiImpl.into_handler())
.merge(TauriLauncherFoldersApiImpl.into_handler())
.merge(TauriLauncherDebugApiImpl.into_handler())
}
}

View file

@ -16,7 +16,7 @@ pub struct Settings {
pub discord_enabled: bool,
pub seen_onboarding: bool,
pub mod_list_use_grid: bool,
pub slow_mod_bulk_downloading: bool,
pub parallel_mod_downloading: bool,
pub max_concurrent_requests: usize,
pub settings_version: u32,
pub native_window_frame: bool,
@ -33,7 +33,7 @@ impl Default for Settings {
discord_enabled: false,
seen_onboarding: false,
mod_list_use_grid: true,
slow_mod_bulk_downloading: false,
parallel_mod_downloading: true,
enable_gamemode: false,
max_concurrent_requests: 25,
settings_version: 1,

View file

@ -26,6 +26,7 @@ export const buttonVariants = tv({
ghost: [
'hover:bg-ghost-overlay-hover pressed:bg-ghost-overlay-pressed checked:selected:bg-ghost-overlay-pressed pending:bg-ghost-overlay-pressed',
],
none: [],
},
size: {
normal: 'py-1.5 px-3',