summaryrefslogtreecommitdiff
path: root/src/SMAPI.Toolkit/Serialization/Models/Manifest.cs
blob: 010106026729cd3989b297fc3e3c66c0e24188ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json;
using StardewModdingAPI.Toolkit.Serialization.Converters;

namespace StardewModdingAPI.Toolkit.Serialization.Models
{
    /// <summary>A manifest which describes a mod for SMAPI.</summary>
    public class Manifest : IManifest
    {
        /*********
        ** Accessors
        *********/
        /// <summary>The mod name.</summary>
        public string Name { get; }

        /// <summary>A brief description of the mod.</summary>
        public string Description { get; }

        /// <summary>The mod author's name.</summary>
        public string Author { get; }

        /// <summary>The mod version.</summary>
        public ISemanticVersion Version { get; }

        /// <summary>The minimum SMAPI version required by this mod, if any.</summary>
        public ISemanticVersion? MinimumApiVersion { get; }

        /// <summary>The name of the DLL in the directory that has the <c>Entry</c> method. Mutually exclusive with <see cref="ContentPackFor"/>.</summary>
        public string? EntryDll { get; }

        /// <summary>The mod which will read this as a content pack. Mutually exclusive with <see cref="Manifest.EntryDll"/>.</summary>
        [JsonConverter(typeof(ManifestContentPackForConverter))]
        public IManifestContentPackFor? ContentPackFor { get; }

        /// <summary>The other mods that must be loaded before this mod.</summary>
        [JsonConverter(typeof(ManifestDependencyArrayConverter))]
        public IManifestDependency[] Dependencies { get; }

        /// <summary>The namespaced mod IDs to query for updates (like <c>Nexus:541</c>).</summary>
        public string[] UpdateKeys { get; private set; }

        /// <summary>The unique mod ID.</summary>
        public string UniqueID { get; }

        /// <summary>Any manifest fields which didn't match a valid field.</summary>
        [JsonExtensionData]
        public IDictionary<string, object> ExtraFields { get; set; } = new Dictionary<string, object>();


        /*********
        ** Public methods
        *********/
        /// <summary>Construct an instance for a transitional content pack.</summary>
        /// <param name="uniqueID">The unique mod ID.</param>
        /// <param name="name">The mod name.</param>
        /// <param name="author">The mod author's name.</param>
        /// <param name="description">A brief description of the mod.</param>
        /// <param name="version">The mod version.</param>
        /// <param name="contentPackFor">The modID which will read this as a content pack.</param>
        public Manifest(string uniqueID, string name, string author, string description, ISemanticVersion version, string? contentPackFor = null)
            : this(
                uniqueId: uniqueID,
                name: name,
                author: author,
                description: description,
                version: version,
                minimumApiVersion: null,
                entryDll: null,
                contentPackFor: contentPackFor != null
                    ? new ManifestContentPackFor(contentPackFor, null)
                    : null,
                dependencies: null,
                updateKeys: null
            )
        { }

        /// <summary>Construct an instance for a transitional content pack.</summary>
        /// <param name="uniqueId">The unique mod ID.</param>
        /// <param name="name">The mod name.</param>
        /// <param name="author">The mod author's name.</param>
        /// <param name="description">A brief description of the mod.</param>
        /// <param name="version">The mod version.</param>
        /// <param name="minimumApiVersion">The minimum SMAPI version required by this mod, if any.</param>
        /// <param name="entryDll">The name of the DLL in the directory that has the <c>Entry</c> method. Mutually exclusive with <see cref="ContentPackFor"/>.</param>
        /// <param name="contentPackFor">The modID which will read this as a content pack.</param>
        /// <param name="dependencies">The other mods that must be loaded before this mod.</param>
        /// <param name="updateKeys">The namespaced mod IDs to query for updates (like <c>Nexus:541</c>).</param>
        [JsonConstructor]
        public Manifest(string uniqueId, string name, string author, string description, ISemanticVersion version, ISemanticVersion? minimumApiVersion, string? entryDll, IManifestContentPackFor? contentPackFor, IManifestDependency[]? dependencies, string[]? updateKeys)
        {
            this.UniqueID = this.NormalizeWhitespace(uniqueId);
            this.Name = this.NormalizeWhitespace(name);
            this.Author = this.NormalizeWhitespace(author);
            this.Description = this.NormalizeWhitespace(description);
            this.Version = version;
            this.MinimumApiVersion = minimumApiVersion;
            this.EntryDll = this.NormalizeWhitespace(entryDll);
            this.ContentPackFor = contentPackFor;
            this.Dependencies = dependencies ?? Array.Empty<IManifestDependency>();
            this.UpdateKeys = updateKeys ?? Array.Empty<string>();
        }

        /// <summary>Override the update keys loaded from the mod info.</summary>
        /// <param name="updateKeys">The new update keys to set.</param>
        internal void OverrideUpdateKeys(params string[] updateKeys)
        {
            this.UpdateKeys = updateKeys;
        }


        /*********
        ** Private methods
        *********/
        /// <summary>Normalize whitespace in a raw string.</summary>
        /// <param name="input">The input to strip.</param>
#if NET5_0_OR_GREATER
        [return: NotNullIfNotNull("input")]
#endif
        private string? NormalizeWhitespace(string? input)
        {
            return input
                ?.Trim()
                .Replace("\r", "")
                .Replace("\n", "");
        }
    }
}