Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions src/main/core/mods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,15 @@ const MR_LOADER: Partial<Record<ServerType, string>> = {
export async function searchModrinth(id: string, query: string): Promise<ModrinthHit[]> {
const server = getServer(id)
if (!server) throw new Error('server-not-found')
const loader = MR_LOADER[server.type]
// Filter to the loaders this server can actually run. A single inner array is
// OR'd by Modrinth, so a plugin server matches the whole Bukkit family (incl.
// plugins tagged only `spigot`/`bukkit`); disjoint taxonomies then keep mods
// and plugins from mixing. Plugins are indexed as project_type "mod" on
// Modrinth, so we deliberately do NOT filter by project_type (it would drop
// every plugin) — the loader facet is the correct separator.
const loaders = searchLoaders(server.type)
const facets: string[][] = []
if (loader) facets.push([`categories:${loader}`])
if (loaders.length) facets.push(loaders.map((l) => `categories:${l}`))
if (server.mcVersion && server.mcVersion !== 'unknown') facets.push([`versions:${server.mcVersion}`])
const url =
`${MR}/search?limit=20&index=relevance&query=${encodeURIComponent(query)}` +
Expand Down Expand Up @@ -154,6 +160,26 @@ export function loadersFor(type: ServerType): string[] {
return single ? [single] : []
}

/** Mod loaders a hybrid (mohist/arclight) can run alongside Bukkit plugins. */
const HYBRID_MOD_LOADERS = ['forge']

/**
* Modrinth loaders to *search* for a server type. Unlike loadersFor (which drives
* the hash-based update check), this decides what browse results a user should
* see, so a hybrid unions the plugin family with its mod loaders — mohist should
* show both plugins and Forge mods. Because the loader taxonomies are disjoint
* (nothing is tagged both `paper` and `fabric`), filtering to these loaders is
* what keeps a Fabric server from listing plugins and vice-versa. Pure.
*/
export function searchLoaders(type: ServerType): string[] {
const isPlugin = PLUGIN_TYPES.includes(type)
const isModded = MODDED_TYPES.includes(type)
if (isPlugin && isModded) return [...new Set([...PLUGIN_LOADER_FAMILY, ...HYBRID_MOD_LOADERS])]
if (isPlugin) return PLUGIN_LOADER_FAMILY
const single = MR_LOADER[type]
return single ? [single] : []
}

function fileSha1(path: string): string {
return createHash('sha1').update(readFileSync(path)).digest('hex')
}
Expand Down
19 changes: 19 additions & 0 deletions src/main/smoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,25 @@ export async function runModUpdateSmoke(): Promise<void> {
if (modsMod.loadersFor('unknown').length !== 0) return fail('unknown type should not filter by loader')
console.log('MODUPDATE-SMOKE: loader family OK (plugin servers widen, modded/proxy stay single)')

// Browse-search loaders (#47): what the Modrinth tab filters by, so mods and
// plugins don't mix. Plugin servers = Bukkit family, modded = single loader,
// hybrid (mohist) = plugin family UNION its mod loaders (both must show),
// proxy = single, vanilla/unknown = unfiltered.
const sl = (t: Parameters<typeof modsMod.searchLoaders>[0]): string[] => modsMod.searchLoaders(t)
for (const l of ['paper', 'spigot', 'bukkit', 'purpur', 'folia']) {
if (!sl('paper').includes(l)) return fail(`paper browse should search ${l}`)
}
if (sl('fabric').join() !== 'fabric') return fail('fabric browse should search only fabric')
if (sl('forge').join() !== 'forge') return fail('forge browse should search only forge')
if (sl('velocity').join() !== 'velocity') return fail('velocity browse should search only velocity')
// hybrid must surface BOTH plugins and Forge mods
const moh = sl('mohist')
for (const l of ['paper', 'spigot', 'bukkit', 'forge']) {
if (!moh.includes(l)) return fail(`mohist (hybrid) browse should search ${l}, got ${moh.join()}`)
}
if (sl('vanilla').length !== 0) return fail('vanilla browse should not filter by loader')
console.log('MODUPDATE-SMOKE: browse-search loaders OK (plugin family, modded single, hybrid unions both)')

console.log('MODUPDATE-SMOKE: PASS')
app.exit(0)
} catch (e) {
Expand Down
Loading