mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
Merge pull request #9094 from horizon-rust/dezer/modrinth
🤖 Agent: desktop fmt/build/clippy -D warnings/tests 0 at this head; Modrinth's Java mods stay listed for Horizon instances with the existing Works/Partly/Doesn't run mark, and installs still check SHA-512 before writing.
This commit is contained in:
4 files changed
+106
-61
No files matched your search
+8
-6
@@ -81,12 +81,14 @@ start); the hedge places and its recipe crafts 4.
|
||||
|
||||
## The Mods page
|
||||
|
||||
The launcher's **Mods** page has three tabs: **Mods** and **Shader packs** search Horizon's registry (a Java
|
||||
instance's Mods tab searches Modrinth for its version), **Resource packs** searches Modrinth. Modrinth's Java mods and
|
||||
data packs aren't usable yet, so the Mods tab has no source switch and Data packs has no tab; the CLI still reaches
|
||||
them (`mods search --kind ...`). The Modpacks tab shows only while the sidebar's modpacks or its + button have it
|
||||
open. Resource packs and Modpacks have a search field (Enter searches), **Show everything** and the source: Modrinth or
|
||||
Horizon, with **CurseForge (coming soon)** beside it, disabled. Each result is an index row: its summary, author,
|
||||
The launcher's **Mods** page has the five kinds as tabs: **Mods**, **Modpacks**, **Resource packs**, **Shader packs**
|
||||
and **Data packs**, each with a search field (Enter searches). Mods, Modpacks and Resource packs pick their source:
|
||||
Horizon's registry or Modrinth, with **CurseForge (coming soon)** beside them, disabled. Mods start on Horizon's
|
||||
registry; **Shader packs** search it only (Horizon's own `.hshader` packs), **Data packs** search Modrinth only and
|
||||
install into the world picked under the search. A Java instance's tabs always search Modrinth for its version and
|
||||
loader, with the version and loader filters. A Horizon instance searching Modrinth's Java mods sees them all, each
|
||||
marked **Works**, **Partly** or **Doesn't run in Horizon** once its jar is checked; **Show everything** adds what was
|
||||
made for other Minecraft versions. Each result is an index row: its summary, author,
|
||||
downloads, source and licence, how well it runs (and why), **Page** (the project's page on its source) and
|
||||
**Install** (**Import** for a modpack). The Modpacks tab lists the imported packs first, with their coverage
|
||||
report, **Port** and **Play** ([modpacks.md](modpacks.md)). Installed packs are listed above the results with their version, source,
|
||||
|
||||
+10
-7
@@ -42,10 +42,13 @@ The opening, then Play ([clip](docs/opening.webm)):
|
||||
starts the game. With no install on the computer the Play page offers the download alone and the
|
||||
Minecraft folder row says none is needed. Without an owner,
|
||||
the Play page asks to sign in first. `horizon-launcher prepare --download`.
|
||||
- **Mods**: **Mods** and **Shader packs** search Horizon's own registry (a Java instance's mods
|
||||
come from Modrinth), **Resource packs** searches Modrinth, each marked Works, Partly or Doesn't
|
||||
run in Horizon; Modrinth's data packs aren't usable yet and have no tab. Install puts a file in the game folder only after its checksum matches, and a
|
||||
modpack (the sidebar's +) goes to the Modpacks page; installed packs show their source and checksum, with Update,
|
||||
- **Mods**: tabs for Mods, Modpacks, Resource packs, Shader packs and Data packs. Mods, Modpacks
|
||||
and Resource packs search Horizon's own registry or Modrinth (CurseForge support is coming soon);
|
||||
Shader packs search the registry, Data packs Modrinth (into the world picked there). A Java
|
||||
instance's files come from Modrinth for its version and loader; on a Horizon instance, Modrinth's
|
||||
Java mods are listed too, each marked Works, Partly or Doesn't run in Horizon. Install puts a file in
|
||||
the game folder only after its SHA-512 matches, and a
|
||||
modpack goes to the Modpacks page; installed packs show their source and checksum, with Update,
|
||||
**Update all** and Remove ([docs/mod-browser.md](../docs/mod-browser.md)).
|
||||
- **Modpacks**: import a Java modpack (a Modrinth `.mrpack`, a CurseForge zip, or a Prism,
|
||||
MultiMC or CurseForge instance folder) and see its coverage report: per mod, ported, partial,
|
||||
@@ -190,9 +193,9 @@ The opening, then Play ([clip](docs/opening.webm)):
|
||||
`datapacks/` under its row: what is there (and which the game has turned off), **Add data pack…**,
|
||||
and **Remove** (to the trash); a data pack `.zip` dropped on a world goes into it. The game turns
|
||||
a new one on when the world opens. From the command line: `horizon-launcher worlds
|
||||
datapack-list|datapack-add|datapack-remove <world> …`. `horizon-launcher mods search --kind datapack`
|
||||
finds them on Modrinth and `mods install <pack> --world <world>` installs one, saying what of it
|
||||
runs in Horizon.
|
||||
datapack-list|datapack-add|datapack-remove <world> …`. The Mods page's **Data packs**
|
||||
tab finds them on Modrinth and installs one into the world picked there (`mods search --kind
|
||||
datapack`, `mods install <pack> --world <world>`), saying what of it runs in Horizon.
|
||||
- **Packs**: Home lists the selected instance's resource packs and shader packs, each with a switch.
|
||||
The choice is the game's own: `resourcePacks` in options.txt (a pack turned on goes on top, as
|
||||
the game's Resource Packs screen does) and `pickedShaderPack` in `horizon-graphics.txt` (one shader
|
||||
|
||||
+55
-26
@@ -6,10 +6,14 @@
|
||||
//! instance).
|
||||
//!
|
||||
//! The mockup's tabs are its sources (Horizon, Modrinth, CurseForge soon); the launcher's page
|
||||
//! is by kind (mods and shader packs from Horizon's registry, resource packs and modpacks from
|
||||
//! Modrinth), each kind with its sources, so the tabs are the kinds, CurseForge after them as
|
||||
//! coming soon. Not in the mockup, kept in its patterns: Show everything, the source switch, the
|
||||
//! filters and the sort, which instance or world installs go to (under the search); the
|
||||
//! is by kind (mods, modpacks, resource packs, shader packs, data packs), each with its sources,
|
||||
//! so the tabs are the kinds and the sources are a switch under the search: Horizon's registry
|
||||
//! or Modrinth, CurseForge beside them as coming soon, on the kinds both serve (`switches`):
|
||||
//! shader packs are Horizon's registry's only, data packs Modrinth's only, and a Java
|
||||
//! instance's files always Modrinth's. Modrinth's Java mods are offered to a Horizon instance
|
||||
//! too, each marked Works, Partly or Doesn't run in Horizon. Not in the mockup, kept in its
|
||||
//! patterns: Show everything, the filters, which instance or world installs go to (under the
|
||||
//! search); the
|
||||
//! project's page, its rating and why it runs or not (in the project's card); adding a native mod
|
||||
//! from GitHub, the instance's installed list and its native build, imported modpacks and the
|
||||
//! install's progress (cards under the two).
|
||||
@@ -36,7 +40,9 @@ impl Launcher {
|
||||
&[("count", &m.results.len().to_string())],
|
||||
)
|
||||
.into()
|
||||
} else if m.source == SourceId::Modrinth {
|
||||
} else if m.source == SourceId::Modrinth
|
||||
&& matches!(m.kind, PackKind::ResourcePack | PackKind::Modpack)
|
||||
{
|
||||
tr("Search resource packs and modpacks").into()
|
||||
} else {
|
||||
tr("Search, then Enter").into()
|
||||
@@ -59,10 +65,7 @@ impl Launcher {
|
||||
.mb_0();
|
||||
let open = self.mods.kind;
|
||||
let mut tabs = div().flex().flex_none().items_center().gap(px(4.));
|
||||
for (kind, label, _) in KINDS
|
||||
.into_iter()
|
||||
.filter(|&(kind, ..)| SHOWN.contains(&kind) || kind == open)
|
||||
{
|
||||
for (kind, label, _) in KINDS {
|
||||
tabs = tabs.child(
|
||||
small_tab(
|
||||
SharedString::from(format!("mods-tab-{label}")),
|
||||
@@ -76,19 +79,6 @@ impl Launcher {
|
||||
})),
|
||||
);
|
||||
}
|
||||
// CurseForge: shown, inert, never searched, as in the mockup.
|
||||
tabs = tabs.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap(px(6.))
|
||||
.h(px(32.))
|
||||
.px(px(12.))
|
||||
.text_size(px(13.))
|
||||
.text_color(white(0.35))
|
||||
.child("CurseForge")
|
||||
.child(tr("soon").to_string()),
|
||||
);
|
||||
let header = div()
|
||||
.flex()
|
||||
.items_end()
|
||||
@@ -141,10 +131,9 @@ impl Launcher {
|
||||
})),
|
||||
)
|
||||
})
|
||||
.when(
|
||||
source_for(self.mods.kind) == SourceId::Modrinth && !java,
|
||||
|d| d.child(div().flex().child(self.mods_source_switch(cx))),
|
||||
)
|
||||
.when(switches(self.mods.kind) && !java, |d| {
|
||||
d.child(self.glass_source_switch(cx))
|
||||
})
|
||||
.children((!registry).then(|| self.mods_filters(cx)))
|
||||
.children(self.mods_target_line(cx));
|
||||
// The search, and the sort on its right.
|
||||
@@ -204,6 +193,46 @@ impl Launcher {
|
||||
)
|
||||
}
|
||||
|
||||
/// The source switch (`switches`): Horizon's registry or Modrinth as small tabs, CurseForge
|
||||
/// after them as coming soon, shown, inert, never searched, as in the mockup.
|
||||
fn glass_source_switch(&mut self, cx: &mut Context<Self>) -> Div {
|
||||
let t = self.theme;
|
||||
let current = self.mods.source;
|
||||
let mut row = div().flex().items_center().gap(px(4.));
|
||||
for (source, label) in SOURCES {
|
||||
row = row.child(
|
||||
small_tab(
|
||||
SharedString::from(format!("mods-source-{label}")),
|
||||
source == current,
|
||||
&t,
|
||||
)
|
||||
.child(tr(label).to_string())
|
||||
.on_click(cx.listener(move |this, _: &ClickEvent, _, cx| {
|
||||
if this.mods.source != source {
|
||||
this.mods.source = source;
|
||||
this.mods.browse.filters = Default::default();
|
||||
this.mods.browse.open = None;
|
||||
this.mods.picked = None;
|
||||
this.mods_search(0);
|
||||
}
|
||||
cx.notify();
|
||||
})),
|
||||
);
|
||||
}
|
||||
row.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap(px(6.))
|
||||
.h(px(32.))
|
||||
.px(px(12.))
|
||||
.text_size(px(13.))
|
||||
.text_color(white(0.35))
|
||||
.child("CurseForge")
|
||||
.child(tr("soon").to_string()),
|
||||
)
|
||||
}
|
||||
|
||||
/// The "Sort by" dropdown beside the search: as tall and as round as the search, white at
|
||||
/// 7 % like it; the choices on a glass popover under it, the chosen one ticked.
|
||||
fn glass_mods_sort(&mut self, cx: &mut Context<Self>) -> Div {
|
||||
|
||||
+33
-22
@@ -1,5 +1,7 @@
|
||||
//! The Mods page: search Horizon's own registry for mods and shader packs made for Horizon, or
|
||||
//! Modrinth for resource packs (a Java instance's mods too), see where each comes
|
||||
//! The Mods page: its tabs are the kinds (mods, modpacks, resource packs, shader packs, data
|
||||
//! packs). Search Horizon's own registry for what was made for Horizon, or Modrinth (CurseForge:
|
||||
//! coming soon) for Java mods, modpacks, resource packs and data packs (a Java instance's files
|
||||
//! always come from Modrinth, for its version), see where each comes
|
||||
//! from and how well it runs (a Java mod's jar is checked first; a Horizon mod says whether it is
|
||||
//! signed and what it may do), install it with its checksum checked, turn Horizon mods on and
|
||||
//! off, and update or remove what was installed (`horizon_launcher::browser`). Imported modpacks
|
||||
@@ -17,7 +19,7 @@ use java_instance::Target;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// The kinds, as the Mods page's tabs: name and icon. Only [`SHOWN`]'s have a tab.
|
||||
/// The kinds, as the Mods page's tabs: name and icon.
|
||||
const KINDS: [(PackKind, &str, &str); 5] = [
|
||||
(PackKind::Mod, "Mods", "box"),
|
||||
(PackKind::Modpack, "Modpacks", "archive"),
|
||||
@@ -25,15 +27,13 @@ const KINDS: [(PackKind, &str, &str); 5] = [
|
||||
(PackKind::Shader, "Shader packs", "zap"),
|
||||
(PackKind::DataPack, "Data packs", "notes"),
|
||||
];
|
||||
/// The kinds with a tab: Horizon's registry's, and Modrinth's resource packs. Modrinth's mods and
|
||||
/// data packs aren't usable yet; the Modpacks tab shows while the sidebar has it open.
|
||||
const SHOWN: [PackKind; 3] = [PackKind::Mod, PackKind::ResourcePack, PackKind::Shader];
|
||||
/// Java mods checked at once.
|
||||
const CHECKING: usize = 2;
|
||||
/// The sources to pick from on the Resource packs and Modpacks tabs; CurseForge is shown beside them as coming soon.
|
||||
const SOURCES: [(SourceId, &str); 2] = [
|
||||
(SourceId::Modrinth, "Modrinth"),
|
||||
/// The sources to pick from on the tabs that have both ([`switches`]); CurseForge is shown
|
||||
/// beside them as coming soon.
|
||||
pub(super) const SOURCES: [(SourceId, &str); 2] = [
|
||||
(SourceId::Horizon, "Horizon"),
|
||||
(SourceId::Modrinth, "Modrinth"),
|
||||
];
|
||||
const PAGE: usize = 20;
|
||||
|
||||
@@ -159,6 +159,7 @@ impl Mods {
|
||||
Ok("modpacks") => PackKind::Modpack,
|
||||
Ok("resourcepacks") => PackKind::ResourcePack,
|
||||
Ok("shaders") => PackKind::Shader,
|
||||
Ok("datapacks") => PackKind::DataPack,
|
||||
_ => PackKind::Mod,
|
||||
};
|
||||
Self {
|
||||
@@ -940,6 +941,10 @@ impl Launcher {
|
||||
if self.mods.kind != kind {
|
||||
self.mods.kind = kind;
|
||||
self.mods.source = source_for(kind);
|
||||
// A data pack goes into a world: one may have been made since.
|
||||
if kind == PackKind::DataPack {
|
||||
self.mods.read_worlds();
|
||||
}
|
||||
// Categories and loaders differ by kind.
|
||||
self.mods.browse.filters = Default::default();
|
||||
self.mods.browse.open = None;
|
||||
@@ -1021,11 +1026,7 @@ impl Launcher {
|
||||
);
|
||||
let this = cx.entity().downgrade();
|
||||
let open = self.mods.kind;
|
||||
let shown: Vec<_> = KINDS
|
||||
.into_iter()
|
||||
.filter(|&(kind, ..)| SHOWN.contains(&kind) || kind == open)
|
||||
.collect();
|
||||
let kinds = blocks::tabs("mods-kind", &shown, open, &t, {
|
||||
let kinds = blocks::tabs("mods-kind", &KINDS, open, &t, {
|
||||
let this = this.clone();
|
||||
move |kind, _, cx| {
|
||||
let _ = this.update(cx, |this, cx| {
|
||||
@@ -1052,11 +1053,11 @@ impl Launcher {
|
||||
this.mods_search(0);
|
||||
cx.notify();
|
||||
}));
|
||||
// Only the kinds Modrinth serves pick their source: CurseForge is coming soon there,
|
||||
// shown, inert, never searched (like the Microsoft account's "Coming soon").
|
||||
// A Java instance's mods and resource packs come from Modrinth, for its version.
|
||||
// The kinds both sources serve pick theirs: CurseForge is coming soon there, shown,
|
||||
// inert, never searched (like the Microsoft account's "Coming soon").
|
||||
// A Java instance's files come from Modrinth, for its version.
|
||||
let java = self.mods.java_for(self.mods.kind).is_some();
|
||||
let source_note = (source_for(self.mods.kind) == SourceId::Modrinth && !java)
|
||||
let source_note = (switches(self.mods.kind) && !java)
|
||||
.then(|| div().flex().child(self.mods_source_switch(cx)));
|
||||
// The registry lists only what was made for Horizon: no "everything", no Modrinth filters,
|
||||
// only its sort.
|
||||
@@ -1838,15 +1839,25 @@ impl Launcher {
|
||||
}
|
||||
}
|
||||
|
||||
/// Where a kind's tab searches first: Horizon's registry, but Modrinth for resource packs and
|
||||
/// modpacks.
|
||||
/// Where a kind's tab searches first: Horizon's registry for mods and shader packs, Modrinth for
|
||||
/// the rest (data packs are only there).
|
||||
fn source_for(kind: PackKind) -> SourceId {
|
||||
match kind {
|
||||
PackKind::ResourcePack | PackKind::Modpack => SourceId::Modrinth,
|
||||
_ => SourceId::Horizon,
|
||||
PackKind::Mod | PackKind::Shader => SourceId::Horizon,
|
||||
PackKind::ResourcePack | PackKind::Modpack | PackKind::DataPack => SourceId::Modrinth,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether a kind's tab picks its source: mods, modpacks and resource packs are on both Horizon's
|
||||
/// registry and Modrinth; Horizon's shader packs are on its registry only, data packs on Modrinth
|
||||
/// only.
|
||||
pub(super) fn switches(kind: PackKind) -> bool {
|
||||
matches!(
|
||||
kind,
|
||||
PackKind::Mod | PackKind::ResourcePack | PackKind::Modpack
|
||||
)
|
||||
}
|
||||
|
||||
impl Launcher {
|
||||
/// The source switch: Modrinth or Horizon's registry, CurseForge shown as coming soon and not
|
||||
/// clickable, like the Microsoft account's "Coming soon".
|
||||
|
||||
Reference in new issue
Block a user