Add explicit client/server side field to manifest
Bake each file's "side" (client / server / both) into manifest.json at build time so both the launcher and the server filter deterministically and offline. This replaces the launcher's previous "download everything" default and lets the server short-circuit its runtime Modrinth lookup when a file already has an authoritative tag. Schema: - ManifestFile.Side: "client" | "server" | "both" (null = "both" for backward compat with manifests pre-dating this field) - Files marked "both" omit the field entirely to keep the JSON tight Code changes: - launcher Manifest.cs + ManifestSyncService: filter out "server" files in both the prune+download path and FindMissingFiles - server Manifest.cs + ManifestSync: drop "client" files outright; only fall back to the existing runtime Modrinth lookup for files with no explicit side (legacy/un-tagged mods stay protected) - server LockedMod: side field propagates into manifest at build time - scripts/Build-Pack.ps1: propagate side from lockfile to manifest - scripts/Bootstrap-Sides.ps1: one-off populator; queries Modrinth's client_side/server_side per project, conservatively marks restricted only when one side is "unsupported", leaves ambiguous cases as "both" - pack/pack.lock.json: bootstrap-populated sides (3 client, 5 server, rest both); CurseForge mods default to "both" pending manual review; version bumped 0.9.3 -> 0.10.0 since clients must re-sync Compatibility: - Old launcher + new manifest: ignores unknown "side", downloads all - New launcher + old manifest: side null -> "both", installs all - Old server + new manifest: same -- runtime Modrinth lookup still works - New server + old manifest: side null -> runtime lookup, same behaviour
This commit is contained in:
@@ -66,6 +66,7 @@ public sealed class ManifestSyncService
|
||||
var missing = new System.Collections.Generic.List<ManifestFile>();
|
||||
foreach (var file in manifest.Files)
|
||||
{
|
||||
if (IsServerOnly(file)) continue; // never expected on disk client-side
|
||||
var dest = Path.Combine(installDir, file.Path);
|
||||
if (!File.Exists(dest)) missing.Add(file);
|
||||
}
|
||||
@@ -113,6 +114,19 @@ public sealed class ManifestSyncService
|
||||
$"Pack: {manifest.Name ?? "modpack"} v{manifest.Version ?? "?"} (local: {local?.Version ?? "none"})"
|
||||
));
|
||||
|
||||
// Drop server-only files before computing wanted/download sets. Doing
|
||||
// it once here means the rest of the sync (prune + download) doesn't
|
||||
// need to know about sides. Unknown/missing/'both' = include on client.
|
||||
var serverOnlyCount = manifest.Files.Count(f => IsServerOnly(f));
|
||||
if (serverOnlyCount > 0)
|
||||
{
|
||||
manifest.Files = manifest.Files.Where(f => !IsServerOnly(f)).ToList();
|
||||
progress.Report(new ProgressReport(
|
||||
ProgressKind.Log,
|
||||
$"Skipping {serverOnlyCount} server-only file(s) declared in manifest."
|
||||
));
|
||||
}
|
||||
|
||||
var wantedPaths = new HashSet<string>(
|
||||
manifest.Files.Select(f => NormalizePath(f.Path)),
|
||||
StringComparer.OrdinalIgnoreCase
|
||||
@@ -249,4 +263,12 @@ public sealed class ManifestSyncService
|
||||
}
|
||||
|
||||
private static string NormalizePath(string p) => p.Replace('\\', '/').TrimStart('/');
|
||||
|
||||
/// <summary>
|
||||
/// True if this manifest file is tagged as server-only and therefore
|
||||
/// should not be installed on the client. Unknown/null/'both' = false
|
||||
/// (always include) so manifests pre-dating the field still install.
|
||||
/// </summary>
|
||||
private static bool IsServerOnly(ManifestFile f)
|
||||
=> string.Equals(f.Side, "server", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user