You've already forked AstralRinth
forked from didirus/AstralRinth
Merge commit '175b90be5a42e5bfd3289ffdfbf7b201404f82a8' into beta
This commit is contained in:
@@ -27,6 +27,7 @@ hashlink.workspace = true
|
||||
png.workspace = true
|
||||
bytemuck.workspace = true
|
||||
rgb.workspace = true
|
||||
phf.workspace = true
|
||||
|
||||
chrono = { workspace = true, features = ["serde"] }
|
||||
daedalus.workspace = true
|
||||
|
||||
@@ -5,6 +5,8 @@ use crate::state::attached_world_data::AttachedWorldData;
|
||||
use crate::state::{
|
||||
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::{
|
||||
ServerGameProfile, ServerPlayers, ServerStatus, ServerVersion,
|
||||
};
|
||||
@@ -835,7 +837,7 @@ mod servers_data {
|
||||
|
||||
pub async fn get_profile_protocol_version(
|
||||
profile: &str,
|
||||
) -> Result<Option<i32>> {
|
||||
) -> Result<Option<ProtocolVersion>> {
|
||||
let mut profile = super::profile::get(profile).await?.ok_or_else(|| {
|
||||
ErrorKind::UnmanagedProfileError(format!(
|
||||
"Could not find profile {profile}"
|
||||
@@ -846,7 +848,12 @@ pub async fn get_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?;
|
||||
@@ -854,7 +861,7 @@ pub async fn get_profile_protocol_version(
|
||||
.versions
|
||||
.iter()
|
||||
.position(|it| it.id == profile.game_version)
|
||||
.ok_or(crate::ErrorKind::LauncherError(format!(
|
||||
.ok_or(ErrorKind::LauncherError(format!(
|
||||
"Invalid game version: {}",
|
||||
profile.game_version
|
||||
)))?;
|
||||
@@ -890,16 +897,19 @@ pub async fn get_profile_protocol_version(
|
||||
profile.protocol_version = version;
|
||||
profile.upsert(&state.pool).await?;
|
||||
}
|
||||
Ok(version)
|
||||
Ok(version.map(ProtocolVersion::modern))
|
||||
}
|
||||
|
||||
pub async fn get_server_status(
|
||||
address: &str,
|
||||
protocol_version: Option<i32>,
|
||||
protocol_version: Option<ProtocolVersion>,
|
||||
) -> Result<ServerStatus> {
|
||||
let (original_host, original_port) = parse_server_address(address)?;
|
||||
let (host, port) =
|
||||
resolve_server_address(original_host, original_port).await?;
|
||||
tracing::debug!(
|
||||
"Pinging {address} with protocol version {protocol_version:?}"
|
||||
);
|
||||
server_ping::get_server_status(
|
||||
&(&host as &str, port),
|
||||
(original_host, original_port),
|
||||
|
||||
@@ -422,7 +422,7 @@ pub async fn install_minecraft(
|
||||
|
||||
pub async fn read_protocol_version_from_jar(
|
||||
path: PathBuf,
|
||||
) -> crate::Result<Option<i32>> {
|
||||
) -> crate::Result<Option<u32>> {
|
||||
let zip = async_zip::tokio::read::fs::ZipFileReader::new(path).await?;
|
||||
let Some(entry_index) = zip
|
||||
.file()
|
||||
@@ -435,7 +435,7 @@ pub async fn read_protocol_version_from_jar(
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct VersionData {
|
||||
protocol_version: Option<i32>,
|
||||
protocol_version: Option<u32>,
|
||||
}
|
||||
|
||||
let mut data = vec![];
|
||||
|
||||
@@ -32,7 +32,7 @@ pub struct Profile {
|
||||
pub icon_path: Option<String>,
|
||||
|
||||
pub game_version: String,
|
||||
pub protocol_version: Option<i32>,
|
||||
pub protocol_version: Option<u32>,
|
||||
pub loader: ModLoader,
|
||||
pub loader_version: Option<String>,
|
||||
|
||||
@@ -320,7 +320,7 @@ impl TryFrom<ProfileQueryResult> for Profile {
|
||||
name: x.name,
|
||||
icon_path: x.icon_path,
|
||||
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_version: x.mod_loader_version,
|
||||
groups: serde_json::from_value(x.groups).unwrap_or_default(),
|
||||
|
||||
@@ -4,4 +4,5 @@ pub mod io;
|
||||
pub mod jre;
|
||||
pub mod platform;
|
||||
pub mod utils; // [AR] Feature
|
||||
pub mod protocol_version;
|
||||
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::error::Result;
|
||||
use crate::util::protocol_version::ProtocolVersion;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::value::RawValue;
|
||||
use std::time::Duration;
|
||||
@@ -42,16 +43,23 @@ pub struct ServerGameProfile {
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub struct ServerVersion {
|
||||
pub name: String,
|
||||
pub protocol: i32,
|
||||
pub protocol: u32,
|
||||
#[serde(skip_deserializing)]
|
||||
pub legacy: bool,
|
||||
}
|
||||
|
||||
pub async fn get_server_status(
|
||||
address: &impl ToSocketAddrs,
|
||||
original_address: (&str, u16),
|
||||
protocol_version: Option<i32>,
|
||||
protocol_version: Option<ProtocolVersion>,
|
||||
) -> Result<ServerStatus> {
|
||||
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(
|
||||
format!("Ping of {}:{} timed out", original_address.0, original_address.1)
|
||||
).into())
|
||||
@@ -68,7 +76,7 @@ mod modern {
|
||||
pub async fn status(
|
||||
address: &impl ToSocketAddrs,
|
||||
original_address: (&str, u16),
|
||||
protocol_version: Option<i32>,
|
||||
protocol_version: Option<u32>,
|
||||
) -> crate::Result<ServerStatus> {
|
||||
let mut stream = TcpStream::connect(address).await?;
|
||||
handshake(&mut stream, original_address, protocol_version).await?;
|
||||
@@ -80,10 +88,10 @@ mod modern {
|
||||
async fn handshake(
|
||||
stream: &mut TcpStream,
|
||||
original_address: (&str, u16),
|
||||
protocol_version: Option<i32>,
|
||||
protocol_version: Option<u32>,
|
||||
) -> crate::Result<()> {
|
||||
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 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
**Client:** `%PROJECT_CLIENT_SIDE%` \
|
||||
**Server:** `%PROJECT_SERVER_SIDE%`
|
||||
@@ -1,3 +1,5 @@
|
||||
## Misuse of Slug
|
||||
## Misuse of custom URL
|
||||
|
||||
Per section 5.2 of %RULES% must accurately represent your project.
|
||||
We ask that you ensure your project's %PROJECT_SLUG_FLINK% accurately represents your project.
|
||||
Your current slug of `%PROJECT_SLUG%` may not accurately match your project's Name or contain excess information.
|
||||
A mismatched URL may make it more difficult for users to find your content. Abbreviations or similar are fine to use if applicable. If your preferred URL is not available, and you cannot find a matching public project, let us know in this moderation thread when you resubmit your project, and our moderation team may be able to free it up for your project.
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
## Private Use
|
||||
|
||||
Under normal circumstances, your project would be rejected due to the issues listed above.
|
||||
However, since your project is not intended for for public use, these requirements will be waived and your project will be unlisted. This means it will remain accessible through a direct link without appearing in public search results, allowing you to share it privately.
|
||||
However, since your project is not intended for public use, these requirements will be waived and your project will be unlisted. This means it will remain accessible through a direct link without appearing in public search results, allowing you to share it privately.
|
||||
If you're okay with this, or submitted your project to be unlisted already, than no further action is necessary.
|
||||
If you would like to publish your project publicly, please address all moderation concerns before resubmitting this project.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
## Unsupported Project
|
||||
|
||||
Unfortunately, Modrinth does not currently support the upload of %INVALID_TYPE%.
|
||||
|
||||
If you would like to publish this project in the future and help Modrinth grow, consider creating an [issue](https://github.com/modrinth/code/issues) suggesting support for this type of content.
|
||||
|
||||
We appreciate your understanding and look forward to hosting your other creations.
|
||||
@@ -31,7 +31,9 @@ const categories: Stage = {
|
||||
weight: 701,
|
||||
suggestedStatus: 'flagged',
|
||||
severity: 'low',
|
||||
shouldShow: (project) => project.categories.includes('optimization'),
|
||||
shouldShow: (project) =>
|
||||
project.categories.includes('optimization') ||
|
||||
project.additional_categories.includes('optimization'),
|
||||
message: async () =>
|
||||
(await import('../messages/categories/inaccurate.md?raw')).default +
|
||||
(await import('../messages/categories/optimization_misused.md?raw')).default,
|
||||
|
||||
@@ -25,6 +25,7 @@ const gallery: Stage = {
|
||||
weight: 901,
|
||||
suggestedStatus: 'flagged',
|
||||
severity: 'low',
|
||||
shouldShow: (project) => project.gallery && project.gallery.length > 0,
|
||||
message: async () => (await import('../messages/gallery/not-relevant.md?raw')).default,
|
||||
} as ButtonAction,
|
||||
],
|
||||
|
||||
@@ -7,7 +7,8 @@ const sideTypes: Stage = {
|
||||
id: 'environment',
|
||||
icon: GlobeIcon,
|
||||
guidance_url: 'https://modrinth.com/legal/rules#miscellaneous',
|
||||
navigate: '/settings#side-types',
|
||||
navigate: '/settings',
|
||||
text: async () => (await import('../messages/checklist-text/side_types.md?raw')).default,
|
||||
actions: [
|
||||
{
|
||||
id: 'side_types_inaccurate_modpack',
|
||||
|
||||
@@ -150,7 +150,24 @@ const versions: Stage = {
|
||||
severity: `medium`,
|
||||
weight: 1004,
|
||||
message: async () => (await import('../messages/versions/broken_version.md?raw')).default,
|
||||
},
|
||||
} as ButtonAction,
|
||||
{
|
||||
id: 'unsupported_project_type',
|
||||
type: 'button',
|
||||
label: `Unsupported`,
|
||||
suggestedStatus: `rejected`,
|
||||
severity: `medium`,
|
||||
weight: 1005,
|
||||
message: async () =>
|
||||
(await import('../messages/versions/unsupported_project.md?raw')).default,
|
||||
relevantExtraInput: [
|
||||
{
|
||||
label: 'Project Type',
|
||||
required: true,
|
||||
variable: 'INVALID_TYPE',
|
||||
},
|
||||
],
|
||||
} as ButtonAction,
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -317,6 +317,11 @@ export function flattenProjectVariables(project: Project): Record<string, string
|
||||
vars[`PROJECT_PERMANENT_LINK`] = `https://modrinth.com/project/${project.id}`
|
||||
vars[`PROJECT_SETTINGS_LINK`] = `https://modrinth.com/project/${project.id}/settings`
|
||||
vars[`PROJECT_SETTINGS_FLINK`] = `[Settings](https://modrinth.com/project/${project.id}/settings)`
|
||||
vars[`PROJECT_TITLE_FLINK`] = `[Name](https://modrinth.com/project/${project.id}/settings)`
|
||||
vars[`PROJECT_SLUG_FLINK`] = `[URL](https://modrinth.com/project/${project.id}/settings)`
|
||||
vars[`PROJECT_SUMMARY_FLINK`] = `[Summary](https://modrinth.com/project/${project.id}/settings)`
|
||||
vars[`PROJECT_ENVIRONMENT_FLINK`] =
|
||||
`[Environment Information](https://modrinth.com/project/${project.id}/settings)`
|
||||
vars[`PROJECT_TAGS_LINK`] = `https://modrinth.com/project/${project.id}/settings/tags`
|
||||
vars[`PROJECT_TAGS_FLINK`] = `[Tags](https://modrinth.com/project/${project.id}/settings/tags)`
|
||||
vars[`PROJECT_DESCRIPTION_LINK`] =
|
||||
|
||||
Reference in New Issue
Block a user