Launcher: panel accounts via authlib-injector, skin & cape editor
Microsoft sign-in is gone. Server accounts now receive Yggdrasil tokens from the panel and launch with authlib-injector pointed at the panel's auth server, so online-mode servers verify players against it. - Download authlib-injector from the panel mirror (fallback: official), SHA-256 verified and cached, with prefetched metadata - New Skin & cape settings tab: upload, arm style, reset, cape picker with front/back previews - Avatars render from the panel's head endpoint Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011ARcGWxLx21FwXJ3yfGriS
This commit is contained in:
18 files changed
+454
-208
No files matched your search
@@ -1,7 +1,7 @@
|
||||
// In-browser stand-in for the Rust backend, used by `npm run dev` outside
|
||||
// Tauri and for UI screenshots. Scenario via ?mock=setup|login|main.
|
||||
import { mockEmit } from './tauri';
|
||||
import type { Account, Bootstrap, Manifest, Settings } from './types';
|
||||
import type { Account, Bootstrap, Manifest, PlayerProfile, Settings } from './types';
|
||||
|
||||
const scenario = new URLSearchParams(location.search).get('mock') ?? 'main';
|
||||
|
||||
@@ -37,7 +37,7 @@ const manifest: Manifest = {
|
||||
api_version: 1,
|
||||
panel_version: '0.1.0',
|
||||
user: null,
|
||||
auth: { panel_accounts: true, registration: 'approval', microsoft: true, microsoft_client_id: 'demo', offline_local: true },
|
||||
auth: { panel_accounts: true, registration: 'approval', offline_local: true, yggdrasil_url: 'https://panel.scopenet.gg/api/yggdrasil' },
|
||||
branding: {
|
||||
name: 'SCOPENET',
|
||||
tagline: 'Your worlds, one click away.',
|
||||
@@ -76,6 +76,18 @@ const accounts: Account[] = scenario === 'main' || scenario === 'progress' ? [
|
||||
let active: string | null = accounts[0]?.id ?? null;
|
||||
|
||||
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
||||
|
||||
const profile: PlayerProfile = {
|
||||
uuid: 'b50ad385-829d-3141-a216-7e7d7539ba7f',
|
||||
name: 'Notch',
|
||||
skin_url: null,
|
||||
skin_model: 'classic',
|
||||
cape: null,
|
||||
available_capes: [
|
||||
{ id: 1, name: 'Founder', url: '' },
|
||||
{ id: 2, name: 'Season 4', url: '' },
|
||||
],
|
||||
};
|
||||
let running = false;
|
||||
|
||||
async function fakeLaunch(id: string) {
|
||||
@@ -134,11 +146,19 @@ export async function mockInvoke(cmd: string, args: Record<string, any>): Promis
|
||||
}
|
||||
case 'register_panel':
|
||||
return { account: null, pending: true };
|
||||
case 'ms_start':
|
||||
return { user_code: 'F7K2-QX9M', verification_uri: 'https://microsoft.com/link', expires_in: 900, interval: 5, message: '' };
|
||||
case 'ms_finish':
|
||||
await sleep(600_000);
|
||||
return null;
|
||||
case 'account_profile':
|
||||
case 'set_cape':
|
||||
case 'set_skin_model':
|
||||
if (cmd === 'set_cape') profile.cape = profile.available_capes.find((c) => c.id === args.capeId) ?? null;
|
||||
if (cmd === 'set_skin_model') profile.skin_model = args.model;
|
||||
return structuredClone(profile);
|
||||
case 'upload_skin':
|
||||
profile.skin_url = 'data:image/png;base64,' + args.data;
|
||||
profile.skin_model = args.model;
|
||||
return structuredClone(profile);
|
||||
case 'delete_skin':
|
||||
profile.skin_url = null;
|
||||
return structuredClone(profile);
|
||||
case 'select_account':
|
||||
active = args.id;
|
||||
return null;
|
||||
|
||||
@@ -39,6 +39,8 @@ export const app = $state({
|
||||
update: null as UpdateInfo | null,
|
||||
addAccount: false,
|
||||
instanceSettings: null as string | null,
|
||||
/** Bumped after a skin change so avatars reload. */
|
||||
skinVersion: 0,
|
||||
toasts: [] as { id: number; text: string; kind: 'ok' | 'error' | 'info' }[],
|
||||
});
|
||||
|
||||
|
||||
@@ -43,8 +43,7 @@ export interface Branding {
|
||||
export interface AuthConfig {
|
||||
panel_accounts: boolean;
|
||||
registration: 'closed' | 'open' | 'approval';
|
||||
microsoft: boolean;
|
||||
microsoft_client_id: string | null;
|
||||
yggdrasil_url: string | null;
|
||||
offline_local: boolean;
|
||||
}
|
||||
|
||||
@@ -57,7 +56,7 @@ export interface Manifest {
|
||||
user: { id: number; username: string; uuid: string; role: string; groups: string[] } | null;
|
||||
}
|
||||
|
||||
export interface Account { id: string; kind: 'panel' | 'microsoft' | 'offline'; username: string; uuid: string; panel_url: string | null; role: string | null }
|
||||
export interface Account { id: string; kind: 'panel' | 'offline'; username: string; uuid: string; panel_url: string | null; role: string | null }
|
||||
|
||||
export type Gc = 'default' | 'g1' | 'zgc';
|
||||
|
||||
@@ -108,5 +107,6 @@ export type ProgressEvent =
|
||||
| { type: 'log'; line: string };
|
||||
|
||||
export interface ServerStatus { online: boolean; version: string; players_online: number; players_max: number; sample: string[]; motd: string; favicon: string | null; latency_ms: number }
|
||||
export interface DeviceCode { user_code: string; verification_uri: string; expires_in: number; interval: number; message: string }
|
||||
export interface CapeInfo { id: number; name: string; url: string }
|
||||
export interface PlayerProfile { uuid: string; name: string; skin_url: string | null; skin_model: 'classic' | 'slim'; cape: CapeInfo | null; available_capes: CapeInfo[] }
|
||||
export interface UpdateInfo { version: string; notes: string; url: string; size: number }
|
||||
Reference in new issue
Block a user