ForgeModMetadata refactoring

This commit is contained in:
Kir_Antipov 2022-11-25 01:35:27 +03:00
parent 9570097d5b
commit 2fc40453de
5 changed files with 137 additions and 67 deletions

View file

@ -193,21 +193,9 @@ Can be automatically retrieved from the config file of your mod:
- `mods.toml` (Forge) - `mods.toml` (Forge)
- Custom `mc-publish` field *(recommended)*: - Custom `mc-publish` field:
```toml ```toml
[custom.mc-publish] [mc-publish]
modrinth="AANobbMI"
```
- Custom `projects` field:
```toml
[custom.projects]
modrinth="AANobbMI"
```
- `projects` field:
```toml
[projects]
modrinth="AANobbMI" modrinth="AANobbMI"
``` ```
@ -311,21 +299,9 @@ Can be automatically retrieved from the config file of your mod:
- `mods.toml` (Forge) - `mods.toml` (Forge)
- Custom `mc-publish` field *(recommended)*: - Custom `mc-publish` field:
```toml ```toml
[custom.mc-publish] [mc-publish]
curseforge=394468
```
- Custom `projects` field:
```toml
[custom.projects]
curseforge=394468
```
- `projects` field:
```toml
[projects]
curseforge=394468 curseforge=394468
``` ```
@ -617,7 +593,7 @@ Can be automatically retrieved from the config file of your mod:
versionRange="0.3.0" versionRange="0.3.0"
ordering="NONE" ordering="NONE"
side="BOTH" side="BOTH"
[dependencies.mod-id.custom.mc-publish] [dependencies.mod-id.mc-publish]
ignore=false # `mc-publish` will ignore this dependency, if `ignore` is set to true ignore=false # `mc-publish` will ignore this dependency, if `ignore` is set to true
modrinth="included-dependency-forge" # Modrinth's project slug modrinth="included-dependency-forge" # Modrinth's project slug
curseforge="included-dependency-forge" # CurseForge's project slug curseforge="included-dependency-forge" # CurseForge's project slug

View file

@ -0,0 +1,44 @@
// https://forge.gemwire.uk/wiki/Mods.toml
type ForgeModConfig = {
// Non-Mod-Specific Properties
modLoader: string;
loaderVersion: string;
license: string;
showAsResourcePack?: boolean;
properties?: Record<string, unknown>;
issueTrackerURL?: string;
// Mod Properties
mods: {
modId: string;
namespace?: string;
version?: string;
displayName?: string;
description?: string;
logoFile?: string;
logoBlur?: boolean;
updateJSONURL?: string;
modproperties?: Record<string, unknown>;
credits?: string;
authors?: string;
displayURL?: string;
displayTest?: "MATCH_VERSION" | "IGNORE_SERVER_VERSION" | "IGNORE_ALL_VERSION" | "NONE";
}[];
// Dependency Configurations
dependencies?: Record<string, ({
modId: string;
mandatory: boolean;
incompatible?: boolean;
embedded?: boolean;
versionRange?: string;
ordering?: "BEFORE" | "AFTER" | "NONE";
side?: "CLIENT" | "SERVER" | "BOTH";
} & Record<string, any>)[]>;
} & Record<string, any>;
namespace ForgeModConfig {
export const FILENAME = "META-INF/mods.toml";
}
export default ForgeModConfig;

View file

@ -1,18 +1,21 @@
import ModMetadata from "../../metadata/mod-metadata"; import ModMetadata from "../mod-metadata";
import toml from "toml"; import toml from "toml";
import ZippedModMetadataReader from "../../metadata/zipped-mod-metadata-reader"; import ZippedModMetadataReader from "../zipped-mod-metadata-reader";
import ForgeModMetadata from "./forge-mod-metadata"; import ForgeModMetadata from "./forge-mod-metadata";
import ForgeModConfig from "./forge-mod-config";
export default class ForgeModMetadataReader extends ZippedModMetadataReader { class ForgeModMetadataReader extends ZippedModMetadataReader<ForgeModConfig> {
constructor() { constructor() {
super("META-INF/mods.toml"); super(ForgeModConfig.FILENAME);
} }
protected loadConfig(buffer: Buffer): Record<string, unknown> { protected loadConfig(buffer: Buffer): ForgeModConfig {
return toml.parse(buffer.toString("utf8")); return toml.parse(buffer.toString("utf8"));
} }
protected createMetadataFromConfig(config: Record<string, unknown>): ModMetadata { protected createMetadataFromConfig(config: ForgeModConfig): ModMetadata {
return new ForgeModMetadata(config); return new ForgeModMetadata(config);
} }
} }
export default ForgeModMetadataReader;

View file

@ -1,29 +1,74 @@
import ModConfig from "../../metadata/mod-config"; import action from "../../../package.json";
import ModConfigDependency from "../../metadata/mod-config-dependency"; import Dependency from "../dependency";
import Dependency from "../../metadata/dependency"; import DependencyKind from "../dependency-kind";
import DependencyKind from "../../metadata/dependency-kind"; import ForgeModConfig from "./forge-mod-config";
import ModMetadata from "../mod-metadata";
import PublisherTarget from "../../publishing/publisher-target";
const ignoredByDefault = ["minecraft", "java", "forge"]; type ForgeDependency = ForgeModConfig["dependencies"][string][number];
function createDependency(body: any): Dependency {
return new ModConfigDependency({ function getDependencies(config: ForgeModConfig): Dependency[] {
ignore: ignoredByDefault.includes(body.modId), return Object
...body, .values(config.dependencies || {})
id: body.modId, .filter(x => Array.isArray(x))
version: body.versionRange, .flatMap(x => x)
kind: body.incompatible && DependencyKind.Breaks || body.embedded && DependencyKind.Includes || body.mandatory && DependencyKind.Depends || DependencyKind.Recommends .map(parseDependency)
}); .filter((x, i, self) => self.findIndex(y => x.id === y.id && x.kind === y.kind) === i);
} }
export default class ForgeModMetadata extends ModConfig { function parseDependency(body: ForgeDependency): Dependency {
public readonly id: string; const id = body.modId;
public readonly name: string; const kind = body.incompatible && DependencyKind.Breaks || body.embedded && DependencyKind.Includes || body.mandatory && DependencyKind.Depends || DependencyKind.Recommends;
public readonly version: string; const version = body.versionRange;
public readonly loaders: string[]; const ignore = body[action.name]?.ignore ?? body.custom?.[action.name]?.ignore ?? body.ignore ?? isDependencyIgnoredByDefault(id);
public readonly dependencies: Dependency[]; const aliases = new Map<PublisherTarget, string>();
for (const target of PublisherTarget.getValues()) {
const targetName = PublisherTarget.toString(target).toLowerCase();
const alias = body[action.name]?.[targetName] ?? body.custom?.[action.name]?.[targetName];
if (alias) {
aliases.set(target, String(alias));
}
}
constructor(config: Record<string, unknown>) { return Dependency.create({ id, kind, version, ignore, aliases });
super(config); }
const mods = Array.isArray(this.config.mods) && <any[]>this.config.mods || [];
const ignoredByDefault = [
"minecraft",
"java",
"forge",
];
function isDependencyIgnoredByDefault(id: string): boolean {
return ignoredByDefault.includes(id);
}
function getProjects(config: ForgeModConfig): Map<PublisherTarget, string> {
const projects = new Map();
for (const target of PublisherTarget.getValues()) {
const targetName = PublisherTarget.toString(target).toLowerCase();
const projectId = config[action.name]?.[targetName]
?? config.custom?.[action.name]?.[targetName]
?? config.projects?.[targetName]
?? config.custom?.projects?.[targetName];
if (projectId) {
projects.set(target, String(projectId));
}
}
return projects;
}
class ForgeModMetadata implements ModMetadata {
readonly id: string;
readonly name: string;
readonly version: string;
readonly loaders: string[];
readonly dependencies: Dependency[];
private readonly _projects: Map<PublisherTarget, string>;
constructor(config: ForgeModConfig) {
const mods = Array.isArray(config.mods) && config.mods || [];
const mod = mods[0]; const mod = mods[0];
if (!mod) { if (!mod) {
throw new Error("At least one mod should be specified"); throw new Error("At least one mod should be specified");
@ -33,11 +78,14 @@ export default class ForgeModMetadata extends ModConfig {
this.name = mod.displayName || this.id; this.name = mod.displayName || this.id;
this.version = mod.version || "*"; this.version = mod.version || "*";
this.loaders = ["forge"]; this.loaders = ["forge"];
this.dependencies = Object this.dependencies = getDependencies(config);
.values(this.config.dependencies || {})
.filter(Array.isArray) this._projects = getProjects(config);
.flatMap(x => x) }
.map(createDependency)
.filter((x, i, self) => self.findIndex(y => x.id === y.id && x.kind === y.kind) === i); getProjectId(project: PublisherTarget): string | undefined {
return this._projects.get(project);
} }
} }
export default ForgeModMetadata;

View file

@ -13,7 +13,7 @@ license="MIT"
Example mod Example mod
''' '''
[projects] [mc-publish]
modrinth="AANobbMI" modrinth="AANobbMI"
[custom.projects] [custom.projects]
curseforge=394468 curseforge=394468
@ -46,13 +46,12 @@ license="MIT"
versionRange="0.2.0" versionRange="0.2.0"
ordering="NONE" ordering="NONE"
side="BOTH" side="BOTH"
[dependencies.example-mod.projects] [dependencies.example-mod.mc-publish]
modrinth="AAAA" modrinth="AAAA"
[dependencies.example-mod.custom.projects]
curseforge=42 curseforge=42
ignore=true
[dependencies.example-mod.custom.mc-publish] [dependencies.example-mod.custom.mc-publish]
github="v0.2.0" github="v0.2.0"
ignore=true
[[dependencies.example-mod]] [[dependencies.example-mod]]