Skip to content

Commit

Permalink
Merge branch 'develop' into stable
Browse files Browse the repository at this point in the history
  • Loading branch information
Pathoschild committed Nov 5, 2024
2 parents 6a1eb71 + 2769248 commit 4daed27
Show file tree
Hide file tree
Showing 16 changed files with 35 additions and 254 deletions.
2 changes: 1 addition & 1 deletion build/common.targets
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ repo. It imports the other MSBuild files as needed.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!--set general build properties -->
<Version>4.1.3</Version>
<Version>4.1.4</Version>
<Product>SMAPI</Product>
<LangVersion>latest</LangVersion>
<AssemblySearchPaths>$(AssemblySearchPaths);{GAC}</AssemblySearchPaths>
Expand Down
21 changes: 17 additions & 4 deletions docs/release-notes.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
[README](README.md)

# Release notes
## 4.1.4
Released 05 November 2024 for Stardew Valley 1.6.10 or later.

* For players:
* Fixed a wide variety of mod errors and crashes after SMAPI 4.1.0 in some specific cases (e.g. Content Patcher "unable to find constructor" errors).

* For mod authors:
* Removed the new private assembly references feature. This may be revisited in a future update once the dust settles on 1.6.9.
* Fixed error propagating edits to `Data/ChairTiles`.

## 4.1.3
Released 04 November 2024 for Stardew Valley 1.6.10 or later.

* Improved compatibility rewriters for Stardew Valley 1.6.9+.
* For players:
* Improved compatibility rewriters for Stardew Valley 1.6.9+.

## 4.1.2
Released 04 November 2024 for Stardew Valley 1.6.10 or later.

* Updated for Stardew Valley 1.6.10.
* Fixed various issues with custom maps loaded from `.tmx` files in Stardew Valley 1.6.9.
* For players:
* Updated for Stardew Valley 1.6.10.
* Fixed various issues with custom maps loaded from `.tmx` files in Stardew Valley 1.6.9.

## 4.1.1
Released 04 November 2024 for Stardew Valley 1.6.9 or later.

* Fixed crash when loading saves containing a custom spouse room loaded from a `.tmx` file.
* For players:
* Fixed crash when loading saves containing a custom spouse room loaded from a `.tmx` file.

## 4.1.0
Released 04 November 2024 for Stardew Valley 1.6.9 or later. See [release highlights](https://www.patreon.com/posts/115304143).
Expand Down
4 changes: 2 additions & 2 deletions src/SMAPI.Mods.ConsoleCommands/manifest.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"Name": "Console Commands",
"Author": "SMAPI",
"Version": "4.1.3",
"Version": "4.1.4",
"Description": "Adds SMAPI console commands that let you manipulate the game.",
"UniqueID": "SMAPI.ConsoleCommands",
"EntryDll": "ConsoleCommands.dll",
"MinimumApiVersion": "4.1.3"
"MinimumApiVersion": "4.1.4"
}
4 changes: 2 additions & 2 deletions src/SMAPI.Mods.SaveBackup/manifest.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"Name": "Save Backup",
"Author": "SMAPI",
"Version": "4.1.3",
"Version": "4.1.4",
"Description": "Automatically backs up all your saves once per day into its folder.",
"UniqueID": "SMAPI.SaveBackup",
"EntryDll": "SaveBackup.dll",
"MinimumApiVersion": "4.1.3"
"MinimumApiVersion": "4.1.4"
}
1 change: 0 additions & 1 deletion src/SMAPI.Tests/Core/ModResolverTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,6 @@ private Manifest GetManifest(string? id = null, string? name = null, string? ver
minimumApiVersion: minimumApiVersion != null ? new SemanticVersion(minimumApiVersion) : null,
minimumGameVersion: minimumGameVersion != null ? new SemanticVersion(minimumGameVersion) : null,
dependencies: dependencies ?? Array.Empty<IManifestDependency>(),
privateAssemblies: Array.Empty<IManifestPrivateAssembly>(),
updateKeys: Array.Empty<string>()
);
}
Expand Down
3 changes: 0 additions & 3 deletions src/SMAPI.Toolkit.CoreInterfaces/IManifest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ public interface IManifest
/// <summary>The other mods that must be loaded before this mod.</summary>
IManifestDependency[] Dependencies { get; }

/// <summary>The assemblies in the mod folder which should only be referenced by this mod. These will be ignored when another mod tries to use assemblies with the same names.</summary>
IManifestPrivateAssembly[] PrivateAssemblies { get; }

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

Expand Down
11 changes: 0 additions & 11 deletions src/SMAPI.Toolkit.CoreInterfaces/IManifestPrivateAssembly.cs

This file was deleted.

39 changes: 0 additions & 39 deletions src/SMAPI.Toolkit/Framework/ManifestValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,45 +99,6 @@ public static bool TryValidateFields(IManifest manifest, out string error)
}
}

// validate private assemblies format
if (!hasDll)
{
if (manifest.PrivateAssemblies.Length > 0)
{
error = $"manifest includes {nameof(IManifest.PrivateAssemblies)}, which isn't valid for a content pack.";
return false;
}
}
else
{
foreach (IManifestPrivateAssembly? assembly in manifest.PrivateAssemblies)
{
if (assembly is null)
{
error = $"manifest has a null entry under {nameof(IManifest.PrivateAssemblies)}.";
return false;
}

if (string.IsNullOrWhiteSpace(assembly.Name))
{
error = $"manifest has a {nameof(IManifest.PrivateAssemblies)} entry with no {nameof(IManifestPrivateAssembly.Name)} field.";
return false;
}

if (assembly.Name.Contains('/') || assembly.Name.Contains('\\') || assembly.Name.Contains(".dll"))
{
error = $"manifest has a {nameof(IManifest.PrivateAssemblies)} entry with an invalid {nameof(IManifestPrivateAssembly.Name)} field (must be the assembly name without the file path, extension, or metadata).";
return false;
}

if (assembly.Name is "0Harmony" or "MonoGame.Framework" or "StardewModdingAPI" or "Stardew Valley" or "StardewValley.GameData")
{
error = $"manifest has a {nameof(IManifest.PrivateAssemblies)} entry with an invalid {nameof(IManifestPrivateAssembly.Name)} field (the '{assembly.Name}' assembly can't be private).";
return false;
}
}
}

error = "";
return true;
}
Expand Down

This file was deleted.

9 changes: 1 addition & 8 deletions src/SMAPI.Toolkit/Serialization/Models/Manifest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ public class Manifest : IManifest
[JsonConverter(typeof(ManifestDependencyArrayConverter))]
public IManifestDependency[] Dependencies { get; }

/// <inheritdoc />
[JsonConverter(typeof(ManifestPrivateAssemblyArrayConverter))]
public IManifestPrivateAssembly[] PrivateAssemblies { get; }

/// <inheritdoc />
public string[] UpdateKeys { get; private set; }

Expand Down Expand Up @@ -80,7 +76,6 @@ public Manifest(string uniqueID, string name, string author, string description,
contentPackFor: contentPackFor != null
? new ManifestContentPackFor(contentPackFor, null)
: null,
privateAssemblies: null,
dependencies: null,
updateKeys: null
)
Expand All @@ -97,10 +92,9 @@ public Manifest(string uniqueID, string name, string author, string description,
/// <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="privateAssemblies">The names of assemblies that should be private to this mod. These assemblies will not be directly accessible by other mods and will be ignored when a mod tries to use an assembly with the same name in a public manner.</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, ISemanticVersion? minimumGameVersion, string? entryDll, IManifestContentPackFor? contentPackFor, IManifestDependency[]? dependencies, IManifestPrivateAssembly[]? privateAssemblies, string[]? updateKeys)
public Manifest(string uniqueId, string name, string author, string description, ISemanticVersion version, ISemanticVersion? minimumApiVersion, ISemanticVersion? minimumGameVersion, string? entryDll, IManifestContentPackFor? contentPackFor, IManifestDependency[]? dependencies, string[]? updateKeys)
{
this.UniqueID = this.NormalizeField(uniqueId);
this.Name = this.NormalizeField(name, replaceSquareBrackets: true);
Expand All @@ -112,7 +106,6 @@ public Manifest(string uniqueId, string name, string author, string description,
this.EntryDll = this.NormalizeField(entryDll);
this.ContentPackFor = contentPackFor;
this.Dependencies = dependencies ?? Array.Empty<IManifestDependency>();
this.PrivateAssemblies = privateAssemblies ?? Array.Empty<IManifestPrivateAssembly>();
this.UpdateKeys = updateKeys ?? Array.Empty<string>();
}

Expand Down
27 changes: 0 additions & 27 deletions src/SMAPI.Toolkit/Serialization/Models/ManifestPrivateAssembly.cs

This file was deleted.

2 changes: 1 addition & 1 deletion src/SMAPI/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ internal static class EarlyConstants
internal static int? LogScreenId { get; set; }

/// <summary>SMAPI's current raw semantic version.</summary>
internal static string RawApiVersion = "4.1.3";
internal static string RawApiVersion = "4.1.4";
}

/// <summary>Contains SMAPI's constants and assumptions.</summary>
Expand Down
33 changes: 7 additions & 26 deletions src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,37 +106,22 @@ public AssemblyLoader(Platform targetPlatform, IMonitor monitor, bool paranoidMo
/// <param name="mod">The mod for which the assembly is being loaded.</param>
/// <param name="assemblyFile">The assembly file.</param>
/// <param name="assumeCompatible">Assume the mod is compatible, even if incompatible code is detected.</param>
/// <param name="assemblyLoadContext">The assembly load context with which to load assemblies for the current mod.</param>
/// <returns>Returns the rewrite metadata for the preprocessed assembly.</returns>
/// <exception cref="IncompatibleInstructionException">An incompatible CIL instruction was found while rewriting the assembly.</exception>
public Assembly Load(IModMetadata mod, FileInfo assemblyFile, bool assumeCompatible, ModAssemblyLoadContext assemblyLoadContext)
public Assembly Load(IModMetadata mod, FileInfo assemblyFile, bool assumeCompatible)
{
// get referenced local assemblies
AssemblyParseResult[] assemblies;
{
HashSet<string> visitedAssemblyNames = new( // don't try loading assemblies that are already loaded
from assembly in AppDomain.CurrentDomain.GetAssemblies()
let name = assembly.GetName().Name
where
name != null
&& (
!assemblyLoadContext.IsPrivateAssembly(name)
&& assemblyLoadContext.IsLoadedPublicAssembly(name)
)
where name != null
select name
);
assemblies = this.GetReferencedLocalAssemblies(assemblyFile, visitedAssemblyNames, this.AssemblyDefinitionResolver).ToArray();
}

// validate private assemblies
foreach (IManifestPrivateAssembly entry in mod.Manifest.PrivateAssemblies)
{
string assemblyName = entry.Name;

if (!entry.UsedDynamically && assemblies.All(a => a.Definition?.Name.Name != assemblyName))
this.Monitor.Log($" Mod '{mod.DisplayName}' refers to private assembly '{assemblyName}' in its manifest, but doesn't use it. This is a bug that should be reported to that mod's author.", LogLevel.Warn);
}

// validate load
if (!assemblies.Any() || assemblies[0].Status == AssemblyLoadStatus.Failed)
{
Expand Down Expand Up @@ -174,27 +159,23 @@ select name
}

// load assembly
bool loadAsPrivate = assemblyLoadContext.IsPrivateAssembly(assembly.Definition.Name.Name);
if (changed)
{
if (!oneAssembly)
this.Monitor.Log($" Loading{(loadAsPrivate ? " private" : "")} assembly '{assembly.File.Name}' (rewritten)...");
this.Monitor.Log($" Loading assembly '{assembly.File.Name}' (rewritten)...");

// load assembly
using MemoryStream outAssemblyStream = new();
using MemoryStream outSymbolStream = new();
assembly.Definition.Write(outAssemblyStream, new WriterParameters { WriteSymbols = true, SymbolStream = outSymbolStream, SymbolWriterProvider = this.SymbolWriterProvider });
outAssemblyStream.Position = 0;
outSymbolStream.Position = 0;
lastAssembly = assemblyLoadContext.LoadFromStream(outAssemblyStream, outSymbolStream);
assemblyLoadContext.OnLoadedAssembly(lastAssembly);
byte[] bytes = outAssemblyStream.ToArray();
lastAssembly = Assembly.Load(bytes, outSymbolStream.ToArray());
}
else
{
if (!oneAssembly)
this.Monitor.Log($" Loading{(loadAsPrivate ? " private" : "")} assembly '{assembly.File.Name}'...");
lastAssembly = assemblyLoadContext.LoadFromAssemblyPath(assembly.File.FullName);
assemblyLoadContext.OnLoadedAssembly(lastAssembly);
this.Monitor.Log($" Loading assembly '{assembly.File.Name}'...");
lastAssembly = Assembly.UnsafeLoadFrom(assembly.File.FullName);
}

// track loaded assembly for definition resolution
Expand Down
Loading

0 comments on commit 4daed27

Please sign in to comment.