Legacy ping support (#4062)
* Detection of protocol versions before 18w47b * Refactor old_protocol_versions into protocol_version * Ping servers closer to how a client of an instance's version would ping a server * Allow pinging legacy servers from a modern profile in the same way a modern client would * Ping 1.4.2 through 1.5.2 like a Vanilla client in those versions would when in such an instance
This commit is contained in:
parent
13103b4950
commit
175b90be5a
44
Cargo.lock
generated
44
Cargo.lock
generated
@ -5731,6 +5731,17 @@ dependencies = [
|
|||||||
"phf_shared 0.11.3",
|
"phf_shared 0.11.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7"
|
||||||
|
dependencies = [
|
||||||
|
"phf_macros 0.12.1",
|
||||||
|
"phf_shared 0.12.1",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_codegen"
|
name = "phf_codegen"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@ -5781,6 +5792,16 @@ dependencies = [
|
|||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_generator"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2cbb1126afed61dd6368748dae63b1ee7dc480191c6262a3b4ff1e29d86a6c5b"
|
||||||
|
dependencies = [
|
||||||
|
"fastrand 2.3.0",
|
||||||
|
"phf_shared 0.12.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_macros"
|
name = "phf_macros"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
@ -5808,6 +5829,19 @@ dependencies = [
|
|||||||
"syn 2.0.101",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_macros"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d713258393a82f091ead52047ca779d37e5766226d009de21696c4e667044368"
|
||||||
|
dependencies = [
|
||||||
|
"phf_generator 0.12.1",
|
||||||
|
"phf_shared 0.12.1",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.101",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_shared"
|
name = "phf_shared"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@ -5835,6 +5869,15 @@ dependencies = [
|
|||||||
"siphasher 1.0.1",
|
"siphasher 1.0.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_shared"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981"
|
||||||
|
dependencies = [
|
||||||
|
"siphasher 1.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "1.1.10"
|
version = "1.1.10"
|
||||||
@ -8946,6 +8989,7 @@ dependencies = [
|
|||||||
"notify-debouncer-mini",
|
"notify-debouncer-mini",
|
||||||
"p256",
|
"p256",
|
||||||
"paste",
|
"paste",
|
||||||
|
"phf 0.12.1",
|
||||||
"png",
|
"png",
|
||||||
"quartz_nbt",
|
"quartz_nbt",
|
||||||
"quick-xml 0.37.5",
|
"quick-xml 0.37.5",
|
||||||
|
|||||||
@ -99,6 +99,7 @@ notify = { version = "8.0.0", default-features = false }
|
|||||||
notify-debouncer-mini = { version = "0.6.0", default-features = false }
|
notify-debouncer-mini = { version = "0.6.0", default-features = false }
|
||||||
p256 = "0.13.2"
|
p256 = "0.13.2"
|
||||||
paste = "1.0.15"
|
paste = "1.0.15"
|
||||||
|
phf = { version = "0.12.1", features = ["macros"] }
|
||||||
png = "0.17.16"
|
png = "0.17.16"
|
||||||
prometheus = "0.14.0"
|
prometheus = "0.14.0"
|
||||||
quartz_nbt = "0.2.9"
|
quartz_nbt = "0.2.9"
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {
|
import {
|
||||||
|
type ProtocolVersion,
|
||||||
type ServerWorld,
|
type ServerWorld,
|
||||||
type ServerData,
|
type ServerData,
|
||||||
type WorldWithProfile,
|
type WorldWithProfile,
|
||||||
@ -33,7 +34,7 @@ const theme = useTheming()
|
|||||||
|
|
||||||
const jumpBackInItems = ref<JumpBackInItem[]>([])
|
const jumpBackInItems = ref<JumpBackInItem[]>([])
|
||||||
const serverData = ref<Record<string, ServerData>>({})
|
const serverData = ref<Record<string, ServerData>>({})
|
||||||
const protocolVersions = ref<Record<string, number | null>>({})
|
const protocolVersions = ref<Record<string, ProtocolVersion | null>>({})
|
||||||
|
|
||||||
const MIN_JUMP_BACK_IN = 3
|
const MIN_JUMP_BACK_IN = 3
|
||||||
const MAX_JUMP_BACK_IN = 6
|
const MAX_JUMP_BACK_IN = 6
|
||||||
@ -121,11 +122,8 @@ async function populateJumpBackIn() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// fetch each server's data
|
servers.forEach(({ instancePath, address }) =>
|
||||||
Promise.all(
|
refreshServerData(serverData.value[address], protocolVersions.value[instancePath], address),
|
||||||
servers.map(({ instancePath, address }) =>
|
|
||||||
refreshServerData(serverData.value[address], protocolVersions.value[instancePath], address),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,8 +148,8 @@ async function populateJumpBackIn() {
|
|||||||
.slice(0, MAX_JUMP_BACK_IN)
|
.slice(0, MAX_JUMP_BACK_IN)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refreshServer(address: string, instancePath: string) {
|
function refreshServer(address: string, instancePath: string) {
|
||||||
await refreshServerData(serverData.value[address], protocolVersions.value[instancePath], address)
|
refreshServerData(serverData.value[address], protocolVersions.value[instancePath], address)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function joinWorld(world: WorldWithProfile) {
|
async function joinWorld(world: WorldWithProfile) {
|
||||||
|
|||||||
@ -1,7 +1,14 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import type { ServerStatus, ServerWorld, SingleplayerWorld, World } from '@/helpers/worlds.ts'
|
import type {
|
||||||
import { set_world_display_status, getWorldIdentifier } from '@/helpers/worlds.ts'
|
ProtocolVersion,
|
||||||
|
ServerStatus,
|
||||||
|
ServerWorld,
|
||||||
|
SingleplayerWorld,
|
||||||
|
World,
|
||||||
|
set_world_display_status,
|
||||||
|
getWorldIdentifier,
|
||||||
|
} from '@/helpers/worlds.ts'
|
||||||
import { formatNumber, getPingLevel } from '@modrinth/utils'
|
import { formatNumber, getPingLevel } from '@modrinth/utils'
|
||||||
import {
|
import {
|
||||||
useRelativeTime,
|
useRelativeTime,
|
||||||
@ -55,7 +62,7 @@ const props = withDefaults(
|
|||||||
playingWorld?: boolean
|
playingWorld?: boolean
|
||||||
startingInstance?: boolean
|
startingInstance?: boolean
|
||||||
supportsQuickPlay?: boolean
|
supportsQuickPlay?: boolean
|
||||||
currentProtocol?: number | null
|
currentProtocol?: ProtocolVersion | null
|
||||||
highlighted?: boolean
|
highlighted?: boolean
|
||||||
|
|
||||||
// Server only
|
// Server only
|
||||||
@ -102,7 +109,8 @@ const serverIncompatible = computed(
|
|||||||
!!props.serverStatus &&
|
!!props.serverStatus &&
|
||||||
!!props.serverStatus.version?.protocol &&
|
!!props.serverStatus.version?.protocol &&
|
||||||
!!props.currentProtocol &&
|
!!props.currentProtocol &&
|
||||||
props.serverStatus.version.protocol !== props.currentProtocol,
|
(props.serverStatus.version.protocol !== props.currentProtocol.version ||
|
||||||
|
props.serverStatus.version.legacy !== props.currentProtocol.legacy),
|
||||||
)
|
)
|
||||||
|
|
||||||
const locked = computed(() => props.world.type === 'singleplayer' && props.world.locked)
|
const locked = computed(() => props.world.type === 'singleplayer' && props.world.locked)
|
||||||
|
|||||||
@ -51,6 +51,7 @@ export type ServerStatus = {
|
|||||||
version?: {
|
version?: {
|
||||||
name: string
|
name: string
|
||||||
protocol: number
|
protocol: number
|
||||||
|
legacy: boolean
|
||||||
}
|
}
|
||||||
favicon?: string
|
favicon?: string
|
||||||
enforces_secure_chat: boolean
|
enforces_secure_chat: boolean
|
||||||
@ -70,11 +71,17 @@ export interface Chat {
|
|||||||
|
|
||||||
export type ServerData = {
|
export type ServerData = {
|
||||||
refreshing: boolean
|
refreshing: boolean
|
||||||
|
lastSuccessfulRefresh?: number
|
||||||
status?: ServerStatus
|
status?: ServerStatus
|
||||||
rawMotd?: string | Chat
|
rawMotd?: string | Chat
|
||||||
renderedMotd?: string
|
renderedMotd?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ProtocolVersion = {
|
||||||
|
version: number
|
||||||
|
legacy: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export async function get_recent_worlds(
|
export async function get_recent_worlds(
|
||||||
limit: number,
|
limit: number,
|
||||||
displayStatuses?: DisplayStatus[],
|
displayStatuses?: DisplayStatus[],
|
||||||
@ -156,13 +163,13 @@ export async function remove_server_from_profile(path: string, index: number): P
|
|||||||
return await invoke('plugin:worlds|remove_server_from_profile', { path, index })
|
return await invoke('plugin:worlds|remove_server_from_profile', { path, index })
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get_profile_protocol_version(path: string): Promise<number | null> {
|
export async function get_profile_protocol_version(path: string): Promise<ProtocolVersion | null> {
|
||||||
return await invoke('plugin:worlds|get_profile_protocol_version', { path })
|
return await invoke('plugin:worlds|get_profile_protocol_version', { path })
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get_server_status(
|
export async function get_server_status(
|
||||||
address: string,
|
address: string,
|
||||||
protocolVersion: number | null = null,
|
protocolVersion: ProtocolVersion | null = null,
|
||||||
): Promise<ServerStatus> {
|
): Promise<ServerStatus> {
|
||||||
return await invoke('plugin:worlds|get_server_status', { address, protocolVersion })
|
return await invoke('plugin:worlds|get_server_status', { address, protocolVersion })
|
||||||
}
|
}
|
||||||
@ -206,30 +213,39 @@ export function isServerWorld(world: World): world is ServerWorld {
|
|||||||
|
|
||||||
export async function refreshServerData(
|
export async function refreshServerData(
|
||||||
serverData: ServerData,
|
serverData: ServerData,
|
||||||
protocolVersion: number | null,
|
protocolVersion: ProtocolVersion | null,
|
||||||
address: string,
|
address: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const refreshTime = Date.now()
|
||||||
serverData.refreshing = true
|
serverData.refreshing = true
|
||||||
await get_server_status(address, protocolVersion)
|
await get_server_status(address, protocolVersion)
|
||||||
.then((status) => {
|
.then((status) => {
|
||||||
|
if (serverData.lastSuccessfulRefresh && serverData.lastSuccessfulRefresh > refreshTime) {
|
||||||
|
// Don't update if there was a more recent successful refresh
|
||||||
|
return
|
||||||
|
}
|
||||||
|
serverData.lastSuccessfulRefresh = Date.now()
|
||||||
serverData.status = status
|
serverData.status = status
|
||||||
if (status.description) {
|
if (status.description) {
|
||||||
serverData.rawMotd = status.description
|
serverData.rawMotd = status.description
|
||||||
serverData.renderedMotd = autoToHTML(status.description)
|
serverData.renderedMotd = autoToHTML(status.description)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
|
||||||
console.error(`Refreshing addr: ${address}`, err)
|
|
||||||
})
|
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
serverData.refreshing = false
|
serverData.refreshing = false
|
||||||
})
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(`Refreshing addr ${address}`, protocolVersion, err)
|
||||||
|
if (!protocolVersion?.legacy) {
|
||||||
|
refreshServerData(serverData, { version: 74, legacy: true }, address)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function refreshServers(
|
export function refreshServers(
|
||||||
worlds: World[],
|
worlds: World[],
|
||||||
serverData: Record<string, ServerData>,
|
serverData: Record<string, ServerData>,
|
||||||
protocolVersion: number | null,
|
protocolVersion: ProtocolVersion | null,
|
||||||
) {
|
) {
|
||||||
const servers = worlds.filter(isServerWorld)
|
const servers = worlds.filter(isServerWorld)
|
||||||
servers.forEach((server) => {
|
servers.forEach((server) => {
|
||||||
@ -243,10 +259,8 @@ export async function refreshServers(
|
|||||||
})
|
})
|
||||||
|
|
||||||
// noinspection ES6MissingAwait - handled with .then by refreshServerData already
|
// noinspection ES6MissingAwait - handled with .then by refreshServerData already
|
||||||
Promise.all(
|
Object.keys(serverData).forEach((address) =>
|
||||||
Object.keys(serverData).map((address) =>
|
refreshServerData(serverData[address], protocolVersion, address),
|
||||||
refreshServerData(serverData[address], protocolVersion, address),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -134,6 +134,7 @@ import {
|
|||||||
} from '@modrinth/ui'
|
} from '@modrinth/ui'
|
||||||
import { PlusIcon, SpinnerIcon, UpdatedIcon, SearchIcon, XIcon } from '@modrinth/assets'
|
import { PlusIcon, SpinnerIcon, UpdatedIcon, SearchIcon, XIcon } from '@modrinth/assets'
|
||||||
import {
|
import {
|
||||||
|
type ProtocolVersion,
|
||||||
type SingleplayerWorld,
|
type SingleplayerWorld,
|
||||||
type World,
|
type World,
|
||||||
type ServerWorld,
|
type ServerWorld,
|
||||||
@ -210,7 +211,9 @@ const worldPlaying = ref<World>()
|
|||||||
const worlds = ref<World[]>([])
|
const worlds = ref<World[]>([])
|
||||||
const serverData = ref<Record<string, ServerData>>({})
|
const serverData = ref<Record<string, ServerData>>({})
|
||||||
|
|
||||||
const protocolVersion = ref<number | null>(await get_profile_protocol_version(instance.value.path))
|
const protocolVersion = ref<ProtocolVersion | null>(
|
||||||
|
await get_profile_protocol_version(instance.value.path),
|
||||||
|
)
|
||||||
|
|
||||||
const unlistenProfile = await profile_listener(async (e: ProfileEvent) => {
|
const unlistenProfile = await profile_listener(async (e: ProfileEvent) => {
|
||||||
if (e.profile_path_id !== instance.value.path) return
|
if (e.profile_path_id !== instance.value.path) return
|
||||||
@ -246,7 +249,7 @@ async function refreshAllWorlds() {
|
|||||||
worlds.value = await refreshWorlds(instance.value.path).finally(
|
worlds.value = await refreshWorlds(instance.value.path).finally(
|
||||||
() => (refreshingAll.value = false),
|
() => (refreshingAll.value = false),
|
||||||
)
|
)
|
||||||
await refreshServers(worlds.value, serverData.value, protocolVersion.value)
|
refreshServers(worlds.value, serverData.value, protocolVersion.value)
|
||||||
|
|
||||||
const hasNoWorlds = worlds.value.length === 0
|
const hasNoWorlds = worlds.value.length === 0
|
||||||
|
|
||||||
|
|||||||
@ -5,8 +5,8 @@ use tauri::{AppHandle, Manager, Runtime};
|
|||||||
use theseus::prelude::ProcessMetadata;
|
use theseus::prelude::ProcessMetadata;
|
||||||
use theseus::profile::{QuickPlayType, get_full_path};
|
use theseus::profile::{QuickPlayType, get_full_path};
|
||||||
use theseus::worlds::{
|
use theseus::worlds::{
|
||||||
DisplayStatus, ServerPackStatus, ServerStatus, World, WorldType,
|
DisplayStatus, ProtocolVersion, ServerPackStatus, ServerStatus, World,
|
||||||
WorldWithProfile,
|
WorldType, WorldWithProfile,
|
||||||
};
|
};
|
||||||
use theseus::{profile, worlds};
|
use theseus::{profile, worlds};
|
||||||
|
|
||||||
@ -183,14 +183,16 @@ pub async fn remove_server_from_profile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_profile_protocol_version(path: &str) -> Result<Option<i32>> {
|
pub async fn get_profile_protocol_version(
|
||||||
|
path: &str,
|
||||||
|
) -> Result<Option<ProtocolVersion>> {
|
||||||
Ok(worlds::get_profile_protocol_version(path).await?)
|
Ok(worlds::get_profile_protocol_version(path).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_server_status(
|
pub async fn get_server_status(
|
||||||
address: &str,
|
address: &str,
|
||||||
protocol_version: Option<i32>,
|
protocol_version: Option<ProtocolVersion>,
|
||||||
) -> Result<ServerStatus> {
|
) -> Result<ServerStatus> {
|
||||||
Ok(worlds::get_server_status(address, protocol_version).await?)
|
Ok(worlds::get_server_status(address, protocol_version).await?)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,6 +27,7 @@ hashlink.workspace = true
|
|||||||
png.workspace = true
|
png.workspace = true
|
||||||
bytemuck.workspace = true
|
bytemuck.workspace = true
|
||||||
rgb.workspace = true
|
rgb.workspace = true
|
||||||
|
phf.workspace = true
|
||||||
|
|
||||||
chrono = { workspace = true, features = ["serde"] }
|
chrono = { workspace = true, features = ["serde"] }
|
||||||
daedalus.workspace = true
|
daedalus.workspace = true
|
||||||
|
|||||||
@ -5,6 +5,8 @@ use crate::state::attached_world_data::AttachedWorldData;
|
|||||||
use crate::state::{
|
use crate::state::{
|
||||||
Profile, ProfileInstallStage, attached_world_data, server_join_log,
|
Profile, ProfileInstallStage, attached_world_data, server_join_log,
|
||||||
};
|
};
|
||||||
|
use crate::util::protocol_version::OLD_PROTOCOL_VERSIONS;
|
||||||
|
pub use crate::util::protocol_version::ProtocolVersion;
|
||||||
pub use crate::util::server_ping::{
|
pub use crate::util::server_ping::{
|
||||||
ServerGameProfile, ServerPlayers, ServerStatus, ServerVersion,
|
ServerGameProfile, ServerPlayers, ServerStatus, ServerVersion,
|
||||||
};
|
};
|
||||||
@ -835,7 +837,7 @@ mod servers_data {
|
|||||||
|
|
||||||
pub async fn get_profile_protocol_version(
|
pub async fn get_profile_protocol_version(
|
||||||
profile: &str,
|
profile: &str,
|
||||||
) -> Result<Option<i32>> {
|
) -> Result<Option<ProtocolVersion>> {
|
||||||
let mut profile = super::profile::get(profile).await?.ok_or_else(|| {
|
let mut profile = super::profile::get(profile).await?.ok_or_else(|| {
|
||||||
ErrorKind::UnmanagedProfileError(format!(
|
ErrorKind::UnmanagedProfileError(format!(
|
||||||
"Could not find profile {profile}"
|
"Could not find profile {profile}"
|
||||||
@ -846,7 +848,12 @@ pub async fn get_profile_protocol_version(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(protocol_version) = profile.protocol_version {
|
if let Some(protocol_version) = profile.protocol_version {
|
||||||
return Ok(Some(protocol_version));
|
return Ok(Some(ProtocolVersion::modern(protocol_version)));
|
||||||
|
}
|
||||||
|
if let Some(protocol_version) =
|
||||||
|
OLD_PROTOCOL_VERSIONS.get(&profile.game_version)
|
||||||
|
{
|
||||||
|
return Ok(Some(*protocol_version));
|
||||||
}
|
}
|
||||||
|
|
||||||
let minecraft = crate::api::metadata::get_minecraft_versions().await?;
|
let minecraft = crate::api::metadata::get_minecraft_versions().await?;
|
||||||
@ -854,7 +861,7 @@ pub async fn get_profile_protocol_version(
|
|||||||
.versions
|
.versions
|
||||||
.iter()
|
.iter()
|
||||||
.position(|it| it.id == profile.game_version)
|
.position(|it| it.id == profile.game_version)
|
||||||
.ok_or(crate::ErrorKind::LauncherError(format!(
|
.ok_or(ErrorKind::LauncherError(format!(
|
||||||
"Invalid game version: {}",
|
"Invalid game version: {}",
|
||||||
profile.game_version
|
profile.game_version
|
||||||
)))?;
|
)))?;
|
||||||
@ -890,16 +897,19 @@ pub async fn get_profile_protocol_version(
|
|||||||
profile.protocol_version = version;
|
profile.protocol_version = version;
|
||||||
profile.upsert(&state.pool).await?;
|
profile.upsert(&state.pool).await?;
|
||||||
}
|
}
|
||||||
Ok(version)
|
Ok(version.map(ProtocolVersion::modern))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_server_status(
|
pub async fn get_server_status(
|
||||||
address: &str,
|
address: &str,
|
||||||
protocol_version: Option<i32>,
|
protocol_version: Option<ProtocolVersion>,
|
||||||
) -> Result<ServerStatus> {
|
) -> Result<ServerStatus> {
|
||||||
let (original_host, original_port) = parse_server_address(address)?;
|
let (original_host, original_port) = parse_server_address(address)?;
|
||||||
let (host, port) =
|
let (host, port) =
|
||||||
resolve_server_address(original_host, original_port).await?;
|
resolve_server_address(original_host, original_port).await?;
|
||||||
|
tracing::debug!(
|
||||||
|
"Pinging {address} with protocol version {protocol_version:?}"
|
||||||
|
);
|
||||||
server_ping::get_server_status(
|
server_ping::get_server_status(
|
||||||
&(&host as &str, port),
|
&(&host as &str, port),
|
||||||
(original_host, original_port),
|
(original_host, original_port),
|
||||||
|
|||||||
@ -419,7 +419,7 @@ pub async fn install_minecraft(
|
|||||||
|
|
||||||
pub async fn read_protocol_version_from_jar(
|
pub async fn read_protocol_version_from_jar(
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
) -> crate::Result<Option<i32>> {
|
) -> crate::Result<Option<u32>> {
|
||||||
let zip = async_zip::tokio::read::fs::ZipFileReader::new(path).await?;
|
let zip = async_zip::tokio::read::fs::ZipFileReader::new(path).await?;
|
||||||
let Some(entry_index) = zip
|
let Some(entry_index) = zip
|
||||||
.file()
|
.file()
|
||||||
@ -432,7 +432,7 @@ pub async fn read_protocol_version_from_jar(
|
|||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
struct VersionData {
|
struct VersionData {
|
||||||
protocol_version: Option<i32>,
|
protocol_version: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut data = vec![];
|
let mut data = vec![];
|
||||||
|
|||||||
@ -32,7 +32,7 @@ pub struct Profile {
|
|||||||
pub icon_path: Option<String>,
|
pub icon_path: Option<String>,
|
||||||
|
|
||||||
pub game_version: String,
|
pub game_version: String,
|
||||||
pub protocol_version: Option<i32>,
|
pub protocol_version: Option<u32>,
|
||||||
pub loader: ModLoader,
|
pub loader: ModLoader,
|
||||||
pub loader_version: Option<String>,
|
pub loader_version: Option<String>,
|
||||||
|
|
||||||
@ -320,7 +320,7 @@ impl TryFrom<ProfileQueryResult> for Profile {
|
|||||||
name: x.name,
|
name: x.name,
|
||||||
icon_path: x.icon_path,
|
icon_path: x.icon_path,
|
||||||
game_version: x.game_version,
|
game_version: x.game_version,
|
||||||
protocol_version: x.protocol_version.map(|x| x as i32),
|
protocol_version: x.protocol_version.map(|x| x as u32),
|
||||||
loader: ModLoader::from_string(&x.mod_loader),
|
loader: ModLoader::from_string(&x.mod_loader),
|
||||||
loader_version: x.mod_loader_version,
|
loader_version: x.mod_loader_version,
|
||||||
groups: serde_json::from_value(x.groups).unwrap_or_default(),
|
groups: serde_json::from_value(x.groups).unwrap_or_default(),
|
||||||
|
|||||||
@ -3,4 +3,5 @@ pub mod fetch;
|
|||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod jre;
|
pub mod jre;
|
||||||
pub mod platform;
|
pub mod platform;
|
||||||
|
pub mod protocol_version;
|
||||||
pub mod server_ping;
|
pub mod server_ping;
|
||||||
|
|||||||
478
packages/app-lib/src/util/protocol_version.rs
Normal file
478
packages/app-lib/src/util/protocol_version.rs
Normal file
@ -0,0 +1,478 @@
|
|||||||
|
use phf::phf_map;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug, Copy, Clone)]
|
||||||
|
pub struct ProtocolVersion {
|
||||||
|
pub version: u32,
|
||||||
|
pub legacy: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProtocolVersion {
|
||||||
|
pub const fn modern(version: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
version,
|
||||||
|
legacy: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn legacy(version: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
version,
|
||||||
|
legacy: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The map of protocol versions from before version.json was added. For newer versions, the
|
||||||
|
/// protocol version can just be read from version.json.
|
||||||
|
pub const OLD_PROTOCOL_VERSIONS: phf::Map<&str, ProtocolVersion> = phf_map! {
|
||||||
|
// April fools versions
|
||||||
|
"1.RV-Pre1" => ProtocolVersion::modern(108),
|
||||||
|
"15w14a" => ProtocolVersion::modern(48),
|
||||||
|
"2point0_purple" => ProtocolVersion::legacy(92),
|
||||||
|
"2point0_red" => ProtocolVersion::legacy(91),
|
||||||
|
"2point0_blue" => ProtocolVersion::legacy(90),
|
||||||
|
|
||||||
|
// Normal versions
|
||||||
|
"18w47a" => ProtocolVersion::modern(446),
|
||||||
|
"18w46a" => ProtocolVersion::modern(445),
|
||||||
|
"18w45a" => ProtocolVersion::modern(444),
|
||||||
|
"18w44a" => ProtocolVersion::modern(443),
|
||||||
|
"18w43c" => ProtocolVersion::modern(442),
|
||||||
|
"18w43b" => ProtocolVersion::modern(441),
|
||||||
|
"18w43a" => ProtocolVersion::modern(440),
|
||||||
|
"1.13.2" => ProtocolVersion::modern(404),
|
||||||
|
"1.13.2-pre2" => ProtocolVersion::modern(403),
|
||||||
|
"1.13.2-pre1" => ProtocolVersion::modern(402),
|
||||||
|
"1.13.1" => ProtocolVersion::modern(401),
|
||||||
|
"1.13.1-pre2" => ProtocolVersion::modern(400),
|
||||||
|
"1.13.1-pre1" => ProtocolVersion::modern(399),
|
||||||
|
"18w33a" => ProtocolVersion::modern(398),
|
||||||
|
"18w32a" => ProtocolVersion::modern(397),
|
||||||
|
"18w31a" => ProtocolVersion::modern(396),
|
||||||
|
"18w30b" => ProtocolVersion::modern(395),
|
||||||
|
"18w30a" => ProtocolVersion::modern(394),
|
||||||
|
"1.13" => ProtocolVersion::modern(393),
|
||||||
|
"1.13-pre10" => ProtocolVersion::modern(392),
|
||||||
|
"1.13-pre9" => ProtocolVersion::modern(391),
|
||||||
|
"1.13-pre8" => ProtocolVersion::modern(390),
|
||||||
|
"1.13-pre7" => ProtocolVersion::modern(389),
|
||||||
|
"1.13-pre6" => ProtocolVersion::modern(388),
|
||||||
|
"1.13-pre5" => ProtocolVersion::modern(387),
|
||||||
|
"1.13-pre4" => ProtocolVersion::modern(386),
|
||||||
|
"1.13-pre3" => ProtocolVersion::modern(385),
|
||||||
|
"1.13-pre2" => ProtocolVersion::modern(384),
|
||||||
|
"1.13-pre1" => ProtocolVersion::modern(383),
|
||||||
|
"18w22c" => ProtocolVersion::modern(382),
|
||||||
|
"18w22b" => ProtocolVersion::modern(381),
|
||||||
|
"18w22a" => ProtocolVersion::modern(380),
|
||||||
|
"18w21b" => ProtocolVersion::modern(379),
|
||||||
|
"18w21a" => ProtocolVersion::modern(378),
|
||||||
|
"18w20c" => ProtocolVersion::modern(377),
|
||||||
|
"18w20b" => ProtocolVersion::modern(376),
|
||||||
|
"18w20a" => ProtocolVersion::modern(375),
|
||||||
|
"18w19b" => ProtocolVersion::modern(374),
|
||||||
|
"18w19a" => ProtocolVersion::modern(373),
|
||||||
|
"18w16a" => ProtocolVersion::modern(372),
|
||||||
|
"18w15a" => ProtocolVersion::modern(371),
|
||||||
|
"18w14b" => ProtocolVersion::modern(370),
|
||||||
|
"18w14a" => ProtocolVersion::modern(369),
|
||||||
|
"18w11a" => ProtocolVersion::modern(368),
|
||||||
|
"18w10d" => ProtocolVersion::modern(367),
|
||||||
|
"18w10c" => ProtocolVersion::modern(366),
|
||||||
|
"18w10b" => ProtocolVersion::modern(365),
|
||||||
|
"18w10a" => ProtocolVersion::modern(364),
|
||||||
|
"18w09a" => ProtocolVersion::modern(363),
|
||||||
|
"18w08b" => ProtocolVersion::modern(362),
|
||||||
|
"18w08a" => ProtocolVersion::modern(361),
|
||||||
|
"18w07c" => ProtocolVersion::modern(360),
|
||||||
|
"18w07b" => ProtocolVersion::modern(359),
|
||||||
|
"18w07a" => ProtocolVersion::modern(358),
|
||||||
|
"18w06a" => ProtocolVersion::modern(357),
|
||||||
|
"18w05a" => ProtocolVersion::modern(356),
|
||||||
|
"18w03b" => ProtocolVersion::modern(355),
|
||||||
|
"18w03a" => ProtocolVersion::modern(354),
|
||||||
|
"18w02a" => ProtocolVersion::modern(353),
|
||||||
|
"18w01a" => ProtocolVersion::modern(352),
|
||||||
|
"17w50a" => ProtocolVersion::modern(351),
|
||||||
|
"17w49b" => ProtocolVersion::modern(350),
|
||||||
|
"17w49a" => ProtocolVersion::modern(349),
|
||||||
|
"17w48a" => ProtocolVersion::modern(348),
|
||||||
|
"17w47b" => ProtocolVersion::modern(347),
|
||||||
|
"17w47a" => ProtocolVersion::modern(346),
|
||||||
|
"17w46a" => ProtocolVersion::modern(345),
|
||||||
|
"17w45b" => ProtocolVersion::modern(344),
|
||||||
|
"17w45a" => ProtocolVersion::modern(343),
|
||||||
|
"17w43b" => ProtocolVersion::modern(342),
|
||||||
|
"17w43a" => ProtocolVersion::modern(341),
|
||||||
|
"1.12.2" => ProtocolVersion::modern(340),
|
||||||
|
"1.21.2-pre2" => ProtocolVersion::modern(339),
|
||||||
|
"1.21.2-pre1" => ProtocolVersion::modern(339),
|
||||||
|
"1.12.1" => ProtocolVersion::modern(338),
|
||||||
|
"1.12.1-pre1" => ProtocolVersion::modern(337),
|
||||||
|
"17w31a" => ProtocolVersion::modern(336),
|
||||||
|
"1.12" => ProtocolVersion::modern(335),
|
||||||
|
"1.12-pre7" => ProtocolVersion::modern(334),
|
||||||
|
"1.12-pre6" => ProtocolVersion::modern(333),
|
||||||
|
"1.12-pre5" => ProtocolVersion::modern(332),
|
||||||
|
"1.12-pre4" => ProtocolVersion::modern(331),
|
||||||
|
"1.12-pre3" => ProtocolVersion::modern(330),
|
||||||
|
"1.12-pre2" => ProtocolVersion::modern(329),
|
||||||
|
"1.12-pre1" => ProtocolVersion::modern(328),
|
||||||
|
"17w18b" => ProtocolVersion::modern(327),
|
||||||
|
"17w18a" => ProtocolVersion::modern(326),
|
||||||
|
"17w17b" => ProtocolVersion::modern(325),
|
||||||
|
"17w17a" => ProtocolVersion::modern(324),
|
||||||
|
"17w16b" => ProtocolVersion::modern(323),
|
||||||
|
"17w16a" => ProtocolVersion::modern(322),
|
||||||
|
"17w15a" => ProtocolVersion::modern(321),
|
||||||
|
"17w14a" => ProtocolVersion::modern(320),
|
||||||
|
"17w13b" => ProtocolVersion::modern(319),
|
||||||
|
"17w13a" => ProtocolVersion::modern(318),
|
||||||
|
"17w06a" => ProtocolVersion::modern(317),
|
||||||
|
"1.11.2" => ProtocolVersion::modern(316),
|
||||||
|
"1.11.1" => ProtocolVersion::modern(316),
|
||||||
|
"16w50a" => ProtocolVersion::modern(316),
|
||||||
|
"1.11" => ProtocolVersion::modern(315),
|
||||||
|
"1.11-pre1" => ProtocolVersion::modern(314),
|
||||||
|
"16w44a" => ProtocolVersion::modern(313),
|
||||||
|
"16w43a" => ProtocolVersion::modern(313),
|
||||||
|
"16w42a" => ProtocolVersion::modern(312),
|
||||||
|
"16w41a" => ProtocolVersion::modern(311),
|
||||||
|
"16w40a" => ProtocolVersion::modern(310),
|
||||||
|
"16w39c" => ProtocolVersion::modern(309),
|
||||||
|
"16w39b" => ProtocolVersion::modern(308),
|
||||||
|
"16w39a" => ProtocolVersion::modern(307),
|
||||||
|
"16w38a" => ProtocolVersion::modern(306),
|
||||||
|
"16w36a" => ProtocolVersion::modern(305),
|
||||||
|
"16w35a" => ProtocolVersion::modern(304),
|
||||||
|
"16w33a" => ProtocolVersion::modern(303),
|
||||||
|
"16w32b" => ProtocolVersion::modern(302),
|
||||||
|
"16w32a" => ProtocolVersion::modern(301),
|
||||||
|
"1.10.2" => ProtocolVersion::modern(210),
|
||||||
|
"1.10.1" => ProtocolVersion::modern(210),
|
||||||
|
"1.10" => ProtocolVersion::modern(210),
|
||||||
|
"1.10-pre2" => ProtocolVersion::modern(205),
|
||||||
|
"1.10-pre1" => ProtocolVersion::modern(204),
|
||||||
|
"16w21b" => ProtocolVersion::modern(203),
|
||||||
|
"16w21a" => ProtocolVersion::modern(202),
|
||||||
|
"16w20a" => ProtocolVersion::modern(201),
|
||||||
|
"1.9.4" => ProtocolVersion::modern(110),
|
||||||
|
"1.9.3" => ProtocolVersion::modern(110),
|
||||||
|
"1.9.3-pre3" => ProtocolVersion::modern(110),
|
||||||
|
"1.9.3-pre2" => ProtocolVersion::modern(110),
|
||||||
|
"1.9.3-pre1" => ProtocolVersion::modern(109),
|
||||||
|
"16w15b" => ProtocolVersion::modern(109),
|
||||||
|
"16w15a" => ProtocolVersion::modern(109),
|
||||||
|
"16w14a" => ProtocolVersion::modern(109),
|
||||||
|
"1.9.2" => ProtocolVersion::modern(109),
|
||||||
|
"1.9.1" => ProtocolVersion::modern(108),
|
||||||
|
"1.9.1-pre3" => ProtocolVersion::modern(108),
|
||||||
|
"1.9.1-pre2" => ProtocolVersion::modern(108),
|
||||||
|
"1.9.1-pre1" => ProtocolVersion::modern(107),
|
||||||
|
"1.9" => ProtocolVersion::modern(107),
|
||||||
|
"1.9-pre4" => ProtocolVersion::modern(106),
|
||||||
|
"1.9-pre3" => ProtocolVersion::modern(105),
|
||||||
|
"1.9-pre2" => ProtocolVersion::modern(104),
|
||||||
|
"1.9-pre1" => ProtocolVersion::modern(103),
|
||||||
|
"16w07b" => ProtocolVersion::modern(102),
|
||||||
|
"16w07a" => ProtocolVersion::modern(101),
|
||||||
|
"16w06a" => ProtocolVersion::modern(100),
|
||||||
|
"16w05b" => ProtocolVersion::modern(99),
|
||||||
|
"16w05a" => ProtocolVersion::modern(98),
|
||||||
|
"16w04a" => ProtocolVersion::modern(97),
|
||||||
|
"16w03a" => ProtocolVersion::modern(96),
|
||||||
|
"16w02a" => ProtocolVersion::modern(95),
|
||||||
|
"15w51b" => ProtocolVersion::modern(94),
|
||||||
|
"15w51a" => ProtocolVersion::modern(93),
|
||||||
|
"15w50a" => ProtocolVersion::modern(92),
|
||||||
|
"15w49b" => ProtocolVersion::modern(91),
|
||||||
|
"15w49a" => ProtocolVersion::modern(90),
|
||||||
|
"15w47c" => ProtocolVersion::modern(89),
|
||||||
|
"15w47b" => ProtocolVersion::modern(88),
|
||||||
|
"15w47a" => ProtocolVersion::modern(87),
|
||||||
|
"15w46a" => ProtocolVersion::modern(86),
|
||||||
|
"15w45a" => ProtocolVersion::modern(85),
|
||||||
|
"15w44b" => ProtocolVersion::modern(84),
|
||||||
|
"15w44a" => ProtocolVersion::modern(83),
|
||||||
|
"15w43c" => ProtocolVersion::modern(82),
|
||||||
|
"15w43b" => ProtocolVersion::modern(81),
|
||||||
|
"15w43a" => ProtocolVersion::modern(80),
|
||||||
|
"15w42a" => ProtocolVersion::modern(79),
|
||||||
|
"15w41b" => ProtocolVersion::modern(78),
|
||||||
|
"15w41a" => ProtocolVersion::modern(77),
|
||||||
|
"15w40b" => ProtocolVersion::modern(76),
|
||||||
|
"15w40a" => ProtocolVersion::modern(75),
|
||||||
|
"15w39c" => ProtocolVersion::modern(74),
|
||||||
|
"15w39b" => ProtocolVersion::modern(74),
|
||||||
|
"15w39a" => ProtocolVersion::modern(74),
|
||||||
|
"15w38b" => ProtocolVersion::modern(73),
|
||||||
|
"15w38a" => ProtocolVersion::modern(72),
|
||||||
|
"15w37a" => ProtocolVersion::modern(71),
|
||||||
|
"15w36d" => ProtocolVersion::modern(70),
|
||||||
|
"15w36c" => ProtocolVersion::modern(69),
|
||||||
|
"15w36b" => ProtocolVersion::modern(68),
|
||||||
|
"15w36a" => ProtocolVersion::modern(67),
|
||||||
|
"15w35e" => ProtocolVersion::modern(66),
|
||||||
|
"15w35d" => ProtocolVersion::modern(65),
|
||||||
|
"15w35c" => ProtocolVersion::modern(64),
|
||||||
|
"15w35b" => ProtocolVersion::modern(63),
|
||||||
|
"15w35a" => ProtocolVersion::modern(62),
|
||||||
|
"15w34d" => ProtocolVersion::modern(61),
|
||||||
|
"15w34c" => ProtocolVersion::modern(60),
|
||||||
|
"15w34b" => ProtocolVersion::modern(59),
|
||||||
|
"15w34a" => ProtocolVersion::modern(58),
|
||||||
|
"15w33c" => ProtocolVersion::modern(57),
|
||||||
|
"15w33b" => ProtocolVersion::modern(56),
|
||||||
|
"15w33a" => ProtocolVersion::modern(55),
|
||||||
|
"15w32c" => ProtocolVersion::modern(54),
|
||||||
|
"15w32b" => ProtocolVersion::modern(53),
|
||||||
|
"15w32a" => ProtocolVersion::modern(52),
|
||||||
|
"15w31c" => ProtocolVersion::modern(51),
|
||||||
|
"15w31b" => ProtocolVersion::modern(50),
|
||||||
|
"15w31a" => ProtocolVersion::modern(49),
|
||||||
|
"1.8.9" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.8" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.7" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.6" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.5" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.4" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.3" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.2" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.2-pre7" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.2-pre6" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.2-pre5" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.2-pre4" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.2-pre3" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.2-pre2" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.2-pre1" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.1" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.1-pre5" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.1-pre4" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.1-pre3" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.1-pre2" => ProtocolVersion::modern(47),
|
||||||
|
"1.8.1-pre1" => ProtocolVersion::modern(47),
|
||||||
|
"1.8" => ProtocolVersion::modern(47),
|
||||||
|
"1.8-pre3" => ProtocolVersion::modern(46),
|
||||||
|
"1.8-pre2" => ProtocolVersion::modern(45),
|
||||||
|
"1.8-pre1" => ProtocolVersion::modern(44),
|
||||||
|
"14w34d" => ProtocolVersion::modern(43),
|
||||||
|
"14w34c" => ProtocolVersion::modern(42),
|
||||||
|
"14w34b" => ProtocolVersion::modern(41),
|
||||||
|
"14w34a" => ProtocolVersion::modern(40),
|
||||||
|
"14w33c" => ProtocolVersion::modern(39),
|
||||||
|
"14w33b" => ProtocolVersion::modern(38),
|
||||||
|
"14w33a" => ProtocolVersion::modern(37),
|
||||||
|
"14w32d" => ProtocolVersion::modern(36),
|
||||||
|
"14w32c" => ProtocolVersion::modern(35),
|
||||||
|
"14w32b" => ProtocolVersion::modern(34),
|
||||||
|
"14w32a" => ProtocolVersion::modern(33),
|
||||||
|
"14w31a" => ProtocolVersion::modern(32),
|
||||||
|
"14w30c" => ProtocolVersion::modern(31),
|
||||||
|
"14w30b" => ProtocolVersion::modern(30),
|
||||||
|
"14w30a" => ProtocolVersion::modern(30),
|
||||||
|
"14w29b" => ProtocolVersion::modern(29),
|
||||||
|
"14w29a" => ProtocolVersion::modern(29),
|
||||||
|
"14w28b" => ProtocolVersion::modern(28),
|
||||||
|
"14w28a" => ProtocolVersion::modern(27),
|
||||||
|
"14w27b" => ProtocolVersion::modern(26),
|
||||||
|
"14w27a" => ProtocolVersion::modern(26),
|
||||||
|
"14w26c" => ProtocolVersion::modern(25),
|
||||||
|
"14w26b" => ProtocolVersion::modern(24),
|
||||||
|
"14w26a" => ProtocolVersion::modern(23),
|
||||||
|
"14w25b" => ProtocolVersion::modern(22),
|
||||||
|
"14w25a" => ProtocolVersion::modern(21),
|
||||||
|
"14w21b" => ProtocolVersion::modern(20),
|
||||||
|
"14w21a" => ProtocolVersion::modern(19),
|
||||||
|
"14w20b" => ProtocolVersion::modern(18),
|
||||||
|
"14w20a" => ProtocolVersion::modern(18),
|
||||||
|
"14w19a" => ProtocolVersion::modern(17),
|
||||||
|
"14w18b" => ProtocolVersion::modern(16),
|
||||||
|
"14w18a" => ProtocolVersion::modern(16),
|
||||||
|
"14w17a" => ProtocolVersion::modern(15),
|
||||||
|
"14w11b" => ProtocolVersion::modern(14),
|
||||||
|
"14w11a" => ProtocolVersion::modern(14),
|
||||||
|
"14w10c" => ProtocolVersion::modern(13),
|
||||||
|
"14w10b" => ProtocolVersion::modern(13),
|
||||||
|
"14w10a" => ProtocolVersion::modern(13),
|
||||||
|
"14w08a" => ProtocolVersion::modern(12),
|
||||||
|
"14w07a" => ProtocolVersion::modern(11),
|
||||||
|
"14w06b" => ProtocolVersion::modern(10),
|
||||||
|
"14w06a" => ProtocolVersion::modern(10),
|
||||||
|
"14w05b" => ProtocolVersion::modern(9),
|
||||||
|
"14w05a" => ProtocolVersion::modern(9),
|
||||||
|
"14w04b" => ProtocolVersion::modern(8),
|
||||||
|
"14w04a" => ProtocolVersion::modern(7),
|
||||||
|
"14w03b" => ProtocolVersion::modern(6),
|
||||||
|
"14w03a" => ProtocolVersion::modern(6),
|
||||||
|
"14w02c" => ProtocolVersion::modern(5),
|
||||||
|
"14w02b" => ProtocolVersion::modern(5),
|
||||||
|
"14w02a" => ProtocolVersion::modern(5),
|
||||||
|
"1.7.10" => ProtocolVersion::modern(5),
|
||||||
|
"1.7.10-pre4" => ProtocolVersion::modern(5),
|
||||||
|
"1.7.10-pre3" => ProtocolVersion::modern(5),
|
||||||
|
"1.7.10-pre2" => ProtocolVersion::modern(5),
|
||||||
|
"1.7.10-pre1" => ProtocolVersion::modern(5),
|
||||||
|
"1.7.9" => ProtocolVersion::modern(5),
|
||||||
|
"1.7.8" => ProtocolVersion::modern(5),
|
||||||
|
"1.7.7" => ProtocolVersion::modern(5),
|
||||||
|
"1.7.6" => ProtocolVersion::modern(5),
|
||||||
|
"1.7.6-pre2" => ProtocolVersion::modern(5),
|
||||||
|
"1.7.6-pre1" => ProtocolVersion::modern(5),
|
||||||
|
"1.7.5" => ProtocolVersion::modern(4),
|
||||||
|
"1.7.4" => ProtocolVersion::modern(4),
|
||||||
|
"1.7.3" => ProtocolVersion::modern(4),
|
||||||
|
"13w49a" => ProtocolVersion::modern(4),
|
||||||
|
"13w48b" => ProtocolVersion::modern(4),
|
||||||
|
"13w48a" => ProtocolVersion::modern(4),
|
||||||
|
"13w47e" => ProtocolVersion::modern(4),
|
||||||
|
"13w47d" => ProtocolVersion::modern(4),
|
||||||
|
"13w47c" => ProtocolVersion::modern(4),
|
||||||
|
"13w47b" => ProtocolVersion::modern(4),
|
||||||
|
"13w47a" => ProtocolVersion::modern(4),
|
||||||
|
"1.7.2" => ProtocolVersion::modern(4),
|
||||||
|
"1.7.1" => ProtocolVersion::modern(3),
|
||||||
|
"1.7" => ProtocolVersion::modern(3),
|
||||||
|
"13w43a" => ProtocolVersion::modern(2),
|
||||||
|
"13w42b" => ProtocolVersion::modern(1),
|
||||||
|
"13w42a" => ProtocolVersion::modern(1),
|
||||||
|
"13w41b" => ProtocolVersion::modern(0),
|
||||||
|
"13w41a" => ProtocolVersion::modern(0),
|
||||||
|
"13w39b" => ProtocolVersion::legacy(80),
|
||||||
|
"13w39a" => ProtocolVersion::legacy(80),
|
||||||
|
"13w38c" => ProtocolVersion::legacy(79),
|
||||||
|
"13w38b" => ProtocolVersion::legacy(79),
|
||||||
|
"13w38a" => ProtocolVersion::legacy(79),
|
||||||
|
"1.6.4" => ProtocolVersion::legacy(78),
|
||||||
|
"1.6.3" => ProtocolVersion::legacy(77),
|
||||||
|
"13w37b" => ProtocolVersion::legacy(76),
|
||||||
|
"13w37a" => ProtocolVersion::legacy(76),
|
||||||
|
"13w36b" => ProtocolVersion::legacy(75),
|
||||||
|
"13w36a" => ProtocolVersion::legacy(75),
|
||||||
|
"1.6.2" => ProtocolVersion::legacy(74),
|
||||||
|
"1.6.1" => ProtocolVersion::legacy(73),
|
||||||
|
"1.6" => ProtocolVersion::legacy(72),
|
||||||
|
"13w26a" => ProtocolVersion::legacy(72),
|
||||||
|
"13w25c" => ProtocolVersion::legacy(71),
|
||||||
|
"13w25b" => ProtocolVersion::legacy(71),
|
||||||
|
"13w25a" => ProtocolVersion::legacy(71),
|
||||||
|
"13w24b" => ProtocolVersion::legacy(70),
|
||||||
|
"13w24a" => ProtocolVersion::legacy(69),
|
||||||
|
"13w23b" => ProtocolVersion::legacy(68),
|
||||||
|
"13w23a" => ProtocolVersion::legacy(67),
|
||||||
|
"13w22a" => ProtocolVersion::legacy(67),
|
||||||
|
"13w21b" => ProtocolVersion::legacy(67),
|
||||||
|
"13w21a" => ProtocolVersion::legacy(67),
|
||||||
|
"13w19a" => ProtocolVersion::legacy(66),
|
||||||
|
"13w18c" => ProtocolVersion::legacy(65),
|
||||||
|
"13w18b" => ProtocolVersion::legacy(65),
|
||||||
|
"13w18a" => ProtocolVersion::legacy(65),
|
||||||
|
"13w17a" => ProtocolVersion::legacy(64),
|
||||||
|
"13w16b" => ProtocolVersion::legacy(63),
|
||||||
|
"13w16a" => ProtocolVersion::legacy(62),
|
||||||
|
"1.5.2" => ProtocolVersion::legacy(61),
|
||||||
|
"1.5.1" => ProtocolVersion::legacy(60),
|
||||||
|
"13w12~" => ProtocolVersion::legacy(60),
|
||||||
|
"13w11a" => ProtocolVersion::legacy(60),
|
||||||
|
"1.5" => ProtocolVersion::legacy(60),
|
||||||
|
"13w10b" => ProtocolVersion::legacy(60),
|
||||||
|
"13w10a" => ProtocolVersion::legacy(60),
|
||||||
|
"13w09c" => ProtocolVersion::legacy(60),
|
||||||
|
"13w09b" => ProtocolVersion::legacy(59),
|
||||||
|
"13w09a" => ProtocolVersion::legacy(59),
|
||||||
|
"13w07a" => ProtocolVersion::legacy(58),
|
||||||
|
"13w06a" => ProtocolVersion::legacy(58),
|
||||||
|
"13w05b" => ProtocolVersion::legacy(56),
|
||||||
|
"13w05a" => ProtocolVersion::legacy(56),
|
||||||
|
"13w04a" => ProtocolVersion::legacy(55),
|
||||||
|
"13w03a" => ProtocolVersion::legacy(54),
|
||||||
|
"13w02b" => ProtocolVersion::legacy(53),
|
||||||
|
"13w02a" => ProtocolVersion::legacy(53),
|
||||||
|
"13w01b" => ProtocolVersion::legacy(52),
|
||||||
|
"13w01a" => ProtocolVersion::legacy(52),
|
||||||
|
"1.4.7" => ProtocolVersion::legacy(51),
|
||||||
|
"1.4.6" => ProtocolVersion::legacy(51),
|
||||||
|
"12w50b" => ProtocolVersion::legacy(51),
|
||||||
|
"12w50a" => ProtocolVersion::legacy(51),
|
||||||
|
"12w49a" => ProtocolVersion::legacy(50),
|
||||||
|
"1.4.5" => ProtocolVersion::legacy(49),
|
||||||
|
"1.4.4" => ProtocolVersion::legacy(49),
|
||||||
|
"1.4.3" => ProtocolVersion::legacy(48),
|
||||||
|
"1.4.2" => ProtocolVersion::legacy(47),
|
||||||
|
"1.4.1" => ProtocolVersion::legacy(47),
|
||||||
|
"1.4" => ProtocolVersion::legacy(47),
|
||||||
|
"12w42b" => ProtocolVersion::legacy(47),
|
||||||
|
"12w42a" => ProtocolVersion::legacy(46),
|
||||||
|
"12w41b" => ProtocolVersion::legacy(46),
|
||||||
|
"12w41a" => ProtocolVersion::legacy(46),
|
||||||
|
"12w40b" => ProtocolVersion::legacy(45),
|
||||||
|
"12w40a" => ProtocolVersion::legacy(44),
|
||||||
|
"12w39b" => ProtocolVersion::legacy(43),
|
||||||
|
"12w39a" => ProtocolVersion::legacy(43),
|
||||||
|
"12w38b" => ProtocolVersion::legacy(43),
|
||||||
|
"12w38a" => ProtocolVersion::legacy(43),
|
||||||
|
"12w37a" => ProtocolVersion::legacy(42),
|
||||||
|
"12w36a" => ProtocolVersion::legacy(42),
|
||||||
|
"12w34b" => ProtocolVersion::legacy(42),
|
||||||
|
"12w34a" => ProtocolVersion::legacy(41),
|
||||||
|
"12w32a" => ProtocolVersion::legacy(40),
|
||||||
|
"1.3.2" => ProtocolVersion::legacy(39),
|
||||||
|
"1.3.1" => ProtocolVersion::legacy(39),
|
||||||
|
"1.3" => ProtocolVersion::legacy(39),
|
||||||
|
"12w30e" => ProtocolVersion::legacy(39),
|
||||||
|
"12w30d" => ProtocolVersion::legacy(39),
|
||||||
|
"12w30c" => ProtocolVersion::legacy(39),
|
||||||
|
"12w30b" => ProtocolVersion::legacy(38),
|
||||||
|
"12w30a" => ProtocolVersion::legacy(38),
|
||||||
|
"12w27a" => ProtocolVersion::legacy(38),
|
||||||
|
"12w26a" => ProtocolVersion::legacy(37),
|
||||||
|
"12w25a" => ProtocolVersion::legacy(37),
|
||||||
|
"12w24a" => ProtocolVersion::legacy(36),
|
||||||
|
"12w23b" => ProtocolVersion::legacy(35),
|
||||||
|
"12w23a" => ProtocolVersion::legacy(35),
|
||||||
|
"12w22a" => ProtocolVersion::legacy(34),
|
||||||
|
"12w21b" => ProtocolVersion::legacy(33),
|
||||||
|
"12w21a" => ProtocolVersion::legacy(33),
|
||||||
|
"12w19a" => ProtocolVersion::legacy(32),
|
||||||
|
"12w18a" => ProtocolVersion::legacy(32),
|
||||||
|
"12w17a" => ProtocolVersion::legacy(31),
|
||||||
|
"12w16a" => ProtocolVersion::legacy(30),
|
||||||
|
"12w15a" => ProtocolVersion::legacy(29),
|
||||||
|
"1.2.5" => ProtocolVersion::legacy(29),
|
||||||
|
"1.2.4" => ProtocolVersion::legacy(29),
|
||||||
|
"1.2.3" => ProtocolVersion::legacy(28),
|
||||||
|
"1.2.2" => ProtocolVersion::legacy(28),
|
||||||
|
"1.2.1" => ProtocolVersion::legacy(28),
|
||||||
|
"1.2" => ProtocolVersion::legacy(28),
|
||||||
|
"12w08a" => ProtocolVersion::legacy(28),
|
||||||
|
"12w07b" => ProtocolVersion::legacy(27),
|
||||||
|
"12w07a" => ProtocolVersion::legacy(27),
|
||||||
|
"12w06a" => ProtocolVersion::legacy(25),
|
||||||
|
"12w05b" => ProtocolVersion::legacy(24),
|
||||||
|
"12w05a" => ProtocolVersion::legacy(24),
|
||||||
|
"12w04a" => ProtocolVersion::legacy(24),
|
||||||
|
"12w03a" => ProtocolVersion::legacy(24),
|
||||||
|
"1.1" => ProtocolVersion::legacy(23),
|
||||||
|
"12w01a" => ProtocolVersion::legacy(23),
|
||||||
|
"11w50a" => ProtocolVersion::legacy(22),
|
||||||
|
"11w49a" => ProtocolVersion::legacy(22),
|
||||||
|
"11w48a" => ProtocolVersion::legacy(22),
|
||||||
|
"11w47a" => ProtocolVersion::legacy(22),
|
||||||
|
"1.0.1" => ProtocolVersion::legacy(22),
|
||||||
|
"1.0.0" => ProtocolVersion::legacy(22),
|
||||||
|
"1.0.0-rc2-1" => ProtocolVersion::legacy(22),
|
||||||
|
"1.0.0-rc2-2" => ProtocolVersion::legacy(22),
|
||||||
|
"1.0.0-rc2-3" => ProtocolVersion::legacy(22),
|
||||||
|
"1.0.0-rc1" => ProtocolVersion::legacy(22),
|
||||||
|
"b1.9-pre6" => ProtocolVersion::legacy(22),
|
||||||
|
"b1.9-pre5" => ProtocolVersion::legacy(21),
|
||||||
|
"b1.9-pre4" => ProtocolVersion::legacy(20),
|
||||||
|
"b1.9-pre3" => ProtocolVersion::legacy(19),
|
||||||
|
"b1.9-pre2" => ProtocolVersion::legacy(19),
|
||||||
|
"b1.9-pre1" => ProtocolVersion::legacy(18),
|
||||||
|
"b1.8.1" => ProtocolVersion::legacy(17),
|
||||||
|
"b1.8" => ProtocolVersion::legacy(17),
|
||||||
|
"b1.8-pre2" => ProtocolVersion::legacy(16),
|
||||||
|
"b1.8-pre1-1" => ProtocolVersion::legacy(15),
|
||||||
|
"b1.8-pre1-2" => ProtocolVersion::legacy(15),
|
||||||
|
};
|
||||||
@ -1,5 +1,6 @@
|
|||||||
use crate::ErrorKind;
|
use crate::ErrorKind;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
use crate::util::protocol_version::ProtocolVersion;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::value::RawValue;
|
use serde_json::value::RawValue;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -42,16 +43,23 @@ pub struct ServerGameProfile {
|
|||||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||||
pub struct ServerVersion {
|
pub struct ServerVersion {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub protocol: i32,
|
pub protocol: u32,
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
pub legacy: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_server_status(
|
pub async fn get_server_status(
|
||||||
address: &impl ToSocketAddrs,
|
address: &impl ToSocketAddrs,
|
||||||
original_address: (&str, u16),
|
original_address: (&str, u16),
|
||||||
protocol_version: Option<i32>,
|
protocol_version: Option<ProtocolVersion>,
|
||||||
) -> Result<ServerStatus> {
|
) -> Result<ServerStatus> {
|
||||||
select! {
|
select! {
|
||||||
res = modern::status(address, original_address, protocol_version) => res,
|
res = async {
|
||||||
|
match protocol_version {
|
||||||
|
Some(ProtocolVersion { legacy: true, version }) => legacy::status(address, original_address, Some(version as u8)).await,
|
||||||
|
protocol => modern::status(address, original_address, protocol.map(|v| v.version)).await,
|
||||||
|
}
|
||||||
|
} => res,
|
||||||
_ = tokio::time::sleep(Duration::from_secs(30)) => Err(ErrorKind::OtherError(
|
_ = tokio::time::sleep(Duration::from_secs(30)) => Err(ErrorKind::OtherError(
|
||||||
format!("Ping of {}:{} timed out", original_address.0, original_address.1)
|
format!("Ping of {}:{} timed out", original_address.0, original_address.1)
|
||||||
).into())
|
).into())
|
||||||
@ -68,7 +76,7 @@ mod modern {
|
|||||||
pub async fn status(
|
pub async fn status(
|
||||||
address: &impl ToSocketAddrs,
|
address: &impl ToSocketAddrs,
|
||||||
original_address: (&str, u16),
|
original_address: (&str, u16),
|
||||||
protocol_version: Option<i32>,
|
protocol_version: Option<u32>,
|
||||||
) -> crate::Result<ServerStatus> {
|
) -> crate::Result<ServerStatus> {
|
||||||
let mut stream = TcpStream::connect(address).await?;
|
let mut stream = TcpStream::connect(address).await?;
|
||||||
handshake(&mut stream, original_address, protocol_version).await?;
|
handshake(&mut stream, original_address, protocol_version).await?;
|
||||||
@ -80,10 +88,10 @@ mod modern {
|
|||||||
async fn handshake(
|
async fn handshake(
|
||||||
stream: &mut TcpStream,
|
stream: &mut TcpStream,
|
||||||
original_address: (&str, u16),
|
original_address: (&str, u16),
|
||||||
protocol_version: Option<i32>,
|
protocol_version: Option<u32>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let (host, port) = original_address;
|
let (host, port) = original_address;
|
||||||
let protocol_version = protocol_version.unwrap_or(-1);
|
let protocol_version = protocol_version.map_or(-1, |x| x as i32);
|
||||||
|
|
||||||
const PACKET_ID: i32 = 0;
|
const PACKET_ID: i32 = 0;
|
||||||
const NEXT_STATE: i32 = 1;
|
const NEXT_STATE: i32 = 1;
|
||||||
@ -221,3 +229,95 @@ mod modern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod legacy {
|
||||||
|
use super::ServerStatus;
|
||||||
|
use crate::worlds::{ServerPlayers, ServerVersion};
|
||||||
|
use crate::{Error, ErrorKind};
|
||||||
|
use serde_json::value::to_raw_value;
|
||||||
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
use tokio::net::{TcpStream, ToSocketAddrs};
|
||||||
|
|
||||||
|
pub async fn status(
|
||||||
|
address: &impl ToSocketAddrs,
|
||||||
|
original_address: (&str, u16),
|
||||||
|
protocol_version: Option<u8>,
|
||||||
|
) -> crate::Result<ServerStatus> {
|
||||||
|
let protocol_version = protocol_version.unwrap_or(74);
|
||||||
|
|
||||||
|
let mut packet = vec![0xfe];
|
||||||
|
if protocol_version >= 47 {
|
||||||
|
packet.push(0x01);
|
||||||
|
}
|
||||||
|
if protocol_version >= 73 {
|
||||||
|
packet.push(0xfa);
|
||||||
|
write_legacy(&mut packet, "MC|PingHost");
|
||||||
|
|
||||||
|
let (host, port) = original_address;
|
||||||
|
let len_index = packet.len();
|
||||||
|
packet.push(protocol_version);
|
||||||
|
write_legacy(&mut packet, host);
|
||||||
|
packet.extend_from_slice(&(port as u32).to_be_bytes());
|
||||||
|
packet.splice(
|
||||||
|
len_index..len_index,
|
||||||
|
((packet.len() - len_index) as u16).to_be_bytes(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut stream = TcpStream::connect(address).await?;
|
||||||
|
stream.write_all(&packet).await?;
|
||||||
|
stream.flush().await?;
|
||||||
|
|
||||||
|
let packet_id = stream.read_u8().await?;
|
||||||
|
if packet_id != 0xff {
|
||||||
|
return Err(Error::from(ErrorKind::InputError(
|
||||||
|
"Unexpected legacy status response".to_string(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let data_length = stream.read_u16().await?;
|
||||||
|
let mut data = vec![0u8; data_length as usize * 2];
|
||||||
|
stream.read_exact(&mut data).await?;
|
||||||
|
|
||||||
|
drop(stream);
|
||||||
|
|
||||||
|
let data = String::from_utf16_lossy(
|
||||||
|
&data
|
||||||
|
.chunks_exact(2)
|
||||||
|
.map(|a| u16::from_be_bytes([a[0], a[1]]))
|
||||||
|
.collect::<Vec<u16>>(),
|
||||||
|
);
|
||||||
|
let mut ancient_server = false;
|
||||||
|
let mut parts = data.split('\0');
|
||||||
|
if parts.next() != Some("§1") {
|
||||||
|
ancient_server = true;
|
||||||
|
parts = data.split('§');
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ServerStatus {
|
||||||
|
version: (!ancient_server).then(|| ServerVersion {
|
||||||
|
protocol: parts
|
||||||
|
.next()
|
||||||
|
.and_then(|x| x.parse().ok())
|
||||||
|
.unwrap_or(0),
|
||||||
|
name: parts.next().unwrap_or("").to_owned(),
|
||||||
|
legacy: true,
|
||||||
|
}),
|
||||||
|
description: parts.next().and_then(|x| to_raw_value(x).ok()),
|
||||||
|
players: Some(ServerPlayers {
|
||||||
|
online: parts.next().and_then(|x| x.parse().ok()).unwrap_or(-1),
|
||||||
|
max: parts.next().and_then(|x| x.parse().ok()).unwrap_or(-1),
|
||||||
|
sample: vec![],
|
||||||
|
}),
|
||||||
|
favicon: None,
|
||||||
|
enforces_secure_chat: false,
|
||||||
|
ping: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_legacy(out: &mut Vec<u8>, text: &str) {
|
||||||
|
let encoded = text.encode_utf16().collect::<Vec<_>>();
|
||||||
|
out.extend_from_slice(&(encoded.len() as u16).to_be_bytes());
|
||||||
|
out.extend(encoded.into_iter().flat_map(u16::to_be_bytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user