import { invoke } from '@tauri-apps/api/core' import type { TerracottaState } from '@/helpers/terracotta' export type MultiplayerProvider = 'terracotta' | 'hongshi' export type HongshiStatus = | 'unsupported' | 'idle' | 'waiting_for_port' | 'downloading' | 'selecting_node' | 'starting' | 'open' | 'closed' | 'error' export type HongshiErrorType = | 'unsupported' | 'node_list' | 'node_unavailable' | 'invalid_port' | 'install' | 'kernel_start' | 'kernel_exit' | 'status_file' | 'unknown' export interface HongshiNode { name: string address: string latency_ms: number | null reachable: boolean cached: boolean } export interface DetectedLanPort { instance_id: string instance_name: string process_id: string port: number detected_at: string } export interface HongshiState { supported: boolean status: HongshiStatus local_port: number | null node: HongshiNode | null public_address: string | null created_at: string | null last_exit_code: number | null error_type: HongshiErrorType | null error_message: string | null bound_instance_id: string | null port_changed: boolean binary_installed: boolean download_progress: number | null } export interface ProviderCapabilities { provider: MultiplayerProvider supported: boolean can_host: boolean can_join: boolean requires_local_port: boolean unsupported_reason: string | null } export interface MultiplayerState { active_provider: MultiplayerProvider | null providers: ProviderCapabilities[] terracotta: TerracottaState hongshi: HongshiState } export function storedMultiplayerProvider(value: string | null): MultiplayerProvider { return value === 'hongshi' ? 'hongshi' : 'terracotta' } export function validLocalPort(value: string): number | null { if (!/^\d+$/.test(value)) return null const port = Number(value) return Number.isInteger(port) && port >= 1 && port <= 65535 ? port : null } export function selectedDetectedInstance(current: string, ports: DetectedLanPort[]): string { if (current !== 'manual' && ports.some((entry) => entry.instance_id === current)) { return current } return ports.length === 1 ? ports[0].instance_id : 'manual' } export function selectedNodePreference(current: string, nodes: HongshiNode[]): string { return current === 'auto' || nodes.some((node) => node.name === current) ? current : 'auto' } const command = (name: string) => `plugin:multiplayer|${name}` export const multiplayer = { getState: () => invoke(command('multiplayer_get_state')), getNodes: (forceRefresh = false) => invoke(command('multiplayer_get_nodes'), { forceRefresh }), getDetectedPorts: () => invoke(command('multiplayer_get_detected_ports')), downloadHongshi: () => invoke(command('multiplayer_download_hongshi')), switchProvider: (provider: MultiplayerProvider) => invoke(command('multiplayer_switch_provider'), { provider }), prepareTerracotta: () => invoke(command('multiplayer_prepare_terracotta')), hostTerracotta: (playerName: string) => invoke(command('multiplayer_host'), { request: { provider: 'terracotta', player_name: playerName.trim(), room_code: null, }, }), joinTerracotta: (playerName: string, roomCode: string) => invoke(command('multiplayer_join'), { request: { provider: 'terracotta', player_name: playerName.trim(), room_code: roomCode.trim(), }, }), hostHongshi: (localPort: number, nodeName: string | null, instanceId: string | null) => invoke(command('multiplayer_host'), { request: { provider: 'hongshi', local_port: localPort, node_name: nodeName, instance_id: instanceId, }, }), stop: () => invoke(command('multiplayer_stop')), reset: () => invoke(command('multiplayer_reset')), getPlayerName: () => invoke(command('multiplayer_get_player_name')), openHongshiLogs: () => invoke(command('multiplayer_open_hongshi_logs')), }