Merge branch 'create-toolkit' into develop
This commit is contained in:
commit
b6cda8f0d3
|
@ -25,7 +25,7 @@
|
|||
|
||||
<!-- add common references -->
|
||||
<ItemGroup>
|
||||
<Reference Condition="'$(OS)' == 'Windows_NT'" Include="System.Management" />
|
||||
<Reference Condition="'$(OS)' == 'Windows_NT' AND '$(MSBuildProjectName)' != 'StardewModdingAPI.Toolkit'" Include="System.Management" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- add game references-->
|
||||
|
@ -111,6 +111,10 @@
|
|||
<Copy SourceFiles="$(TargetDir)\$(TargetName).pdb" DestinationFolder="$(GamePath)\Mods\$(AssemblyName)" Condition="Exists('$(TargetDir)\$(TargetName).pdb')" />
|
||||
<Copy SourceFiles="$(TargetDir)\manifest.json" DestinationFolder="$(GamePath)\Mods\$(AssemblyName)" />
|
||||
</Target>
|
||||
<Target Name="CopyToolkit" Condition="'$(MSBuildProjectName)' == 'StardewModdingAPI.Toolkit' AND '$(Configuration)' == 'Debug'" AfterTargets="PostBuildEvent">
|
||||
<Copy SourceFiles="$(TargetDir)\$(TargetName).dll" DestinationFolder="$(GamePath)" />
|
||||
<Copy SourceFiles="$(TargetDir)\$(TargetName).pdb" DestinationFolder="$(GamePath)" />
|
||||
</Target>
|
||||
|
||||
<!-- launch SMAPI on debug -->
|
||||
<PropertyGroup Condition="$(Configuration) == 'Debug'">
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
-->
|
||||
<Target Name="AfterBuild">
|
||||
<PropertyGroup>
|
||||
<CompiledSmapiPath>$(SolutionDir)\..\bin\$(Configuration)\SMAPI</CompiledSmapiPath>
|
||||
<CompiledRootPath>$(SolutionDir)\..\bin\$(Configuration)</CompiledRootPath>
|
||||
<CompiledSmapiPath>$(CompiledRootPath)\SMAPI</CompiledSmapiPath>
|
||||
<CompiledToolkitPath>$(CompiledRootPath)\SMAPI.Toolkit\net4.5</CompiledToolkitPath>
|
||||
<PackagePath>$(SolutionDir)\..\bin\Packaged</PackagePath>
|
||||
<PackageInternalPath>$(PackagePath)\internal</PackageInternalPath>
|
||||
</PropertyGroup>
|
||||
|
@ -35,6 +37,8 @@
|
|||
<Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\System.Numerics.dll" DestinationFolder="$(PackageInternalPath)\Mono" />
|
||||
<Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\System.Runtime.Caching.dll" DestinationFolder="$(PackageInternalPath)\Mono" />
|
||||
<Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\steam_appid.txt" DestinationFolder="$(PackageInternalPath)\Mono" />
|
||||
<Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="$(CompiledToolkitPath)\StardewModdingAPI.Toolkit.dll" DestinationFolder="$(PackageInternalPath)\Mono" />
|
||||
<Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="$(CompiledToolkitPath)\StardewModdingAPI.Toolkit.pdb" DestinationFolder="$(PackageInternalPath)\Mono" />
|
||||
<Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="@(CompiledMods)" DestinationFolder="$(PackageInternalPath)\Mono\Mods\%(RecursiveDir)" />
|
||||
|
||||
<!-- copy SMAPI files for Windows -->
|
||||
|
@ -46,6 +50,8 @@
|
|||
<Copy Condition="$(OS) == 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\StardewModdingAPI.config.json" DestinationFolder="$(PackageInternalPath)\Windows" />
|
||||
<Copy Condition="$(OS) == 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\StardewModdingAPI.metadata.json" DestinationFolder="$(PackageInternalPath)\Windows" />
|
||||
<Copy Condition="$(OS) == 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\steam_appid.txt" DestinationFolder="$(PackageInternalPath)\Windows" />
|
||||
<Copy Condition="$(OS) == 'Windows_NT'" SourceFiles="$(CompiledToolkitPath)\StardewModdingAPI.Toolkit.dll" DestinationFolder="$(PackageInternalPath)\Windows" />
|
||||
<Copy Condition="$(OS) == 'Windows_NT'" SourceFiles="$(CompiledToolkitPath)\StardewModdingAPI.Toolkit.pdb" DestinationFolder="$(PackageInternalPath)\Windows" />
|
||||
<Copy Condition="$(OS) == 'Windows_NT'" SourceFiles="@(CompiledMods)" DestinationFolder="$(PackageInternalPath)\Windows\Mods\%(RecursiveDir)" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
|
@ -152,7 +152,7 @@ namespace StardewModdingApi.Installer
|
|||
** Get platform & set window title
|
||||
****/
|
||||
Platform platform = EnvironmentUtility.DetectPlatform();
|
||||
Console.Title = $"SMAPI {new SemanticVersionImpl(this.GetType().Assembly.GetName().Version)} installer on {platform} {EnvironmentUtility.GetFriendlyPlatformName(platform)}";
|
||||
Console.Title = $"SMAPI {this.GetDisplayVersion(this.GetType().Assembly.GetName().Version)} installer on {platform} {EnvironmentUtility.GetFriendlyPlatformName(platform)}";
|
||||
Console.WriteLine();
|
||||
|
||||
#if SMAPI_FOR_WINDOWS
|
||||
|
@ -421,6 +421,16 @@ namespace StardewModdingApi.Installer
|
|||
/*********
|
||||
** Private methods
|
||||
*********/
|
||||
/// <summary>Get the display text for an assembly version.</summary>
|
||||
/// <param name="version">The assembly version.</param>
|
||||
private string GetDisplayVersion(Version version)
|
||||
{
|
||||
string str = $"{version.Major}.{version.Minor}";
|
||||
if (version.Build != 0)
|
||||
str += $".{version.Build}";
|
||||
return str;
|
||||
}
|
||||
|
||||
/// <summary>Get the value of a key in the Windows registry.</summary>
|
||||
/// <param name="key">The full path of the registry key relative to HKLM.</param>
|
||||
/// <param name="name">The name of the value.</param>
|
||||
|
|
|
@ -16,6 +16,5 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)Models\ModSeachModel.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ConsoleWriting\MonitorColorScheme.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Platform.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)SemanticVersionImpl.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web.Script.Serialization;
|
||||
using StardewModdingAPI.Internal;
|
||||
using StardewModdingAPI.Toolkit;
|
||||
|
||||
namespace StardewModdingAPI.ModBuildConfig.Framework
|
||||
{
|
||||
|
@ -132,9 +132,9 @@ namespace StardewModdingAPI.ModBuildConfig.Framework
|
|||
int minor = versionFields.ContainsKey("MinorVersion") ? (int)versionFields["MinorVersion"] : 0;
|
||||
int patch = versionFields.ContainsKey("PatchVersion") ? (int)versionFields["PatchVersion"] : 0;
|
||||
string tag = versionFields.ContainsKey("Build") ? (string)versionFields["Build"] : null;
|
||||
return new SemanticVersionImpl(major, minor, patch, tag).ToString();
|
||||
return new SemanticVersion(major, minor, patch, tag).ToString();
|
||||
}
|
||||
return new SemanticVersionImpl(versionObj.ToString()).ToString(); // SMAPI 2.0+
|
||||
return new SemanticVersion(versionObj.ToString()).ToString(); // SMAPI 2.0+
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -55,6 +55,12 @@
|
|||
<ItemGroup>
|
||||
<Content Include="assets\nuget-icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\StardewModdingAPI.Toolkit\StardewModdingAPI.Toolkit.csproj">
|
||||
<Project>{ea5cfd2e-9453-4d29-b80f-8e0ea23f4ac6}</Project>
|
||||
<Name>StardewModdingAPI.Toolkit</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="..\SMAPI.Internal\SMAPI.Internal.projitems" Label="Shared" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\..\build\common.targets" />
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\NUnit.3.10.1\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.10.1\build\NUnit.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
|
@ -56,7 +56,7 @@
|
|||
<Compile Include="..\..\build\GlobalAssemblyInfo.cs">
|
||||
<Link>Properties\GlobalAssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Core\PathUtilitiesTests.cs" />
|
||||
<Compile Include="Toolkit\PathUtilitiesTests.cs" />
|
||||
<Compile Include="Utilities\SemanticVersionTests.cs" />
|
||||
<Compile Include="Utilities\SDateTests.cs" />
|
||||
<Compile Include="Core\TranslationTests.cs" />
|
||||
|
@ -73,6 +73,10 @@
|
|||
<Project>{f1a573b0-f436-472c-ae29-0b91ea6b9f8f}</Project>
|
||||
<Name>StardewModdingAPI</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\StardewModdingAPI.Toolkit\StardewModdingAPI.Toolkit.csproj">
|
||||
<Project>{ea5cfd2e-9453-4d29-b80f-8e0ea23f4ac6}</Project>
|
||||
<Name>StardewModdingAPI.Toolkit</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using NUnit.Framework;
|
||||
using StardewModdingAPI.Framework.Utilities;
|
||||
using StardewModdingAPI.Toolkit.Utilities;
|
||||
|
||||
namespace StardewModdingAPI.Tests.Core
|
||||
namespace StardewModdingAPI.Tests.Toolkit
|
||||
{
|
||||
/// <summary>Unit tests for <see cref="PathUtilities"/>.</summary>
|
||||
[TestFixture]
|
|
@ -5,7 +5,7 @@ using System.Text.RegularExpressions;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using StardewModdingAPI.Internal;
|
||||
using StardewModdingAPI.Toolkit;
|
||||
using StardewModdingAPI.Web.Framework.Clients.GitHub;
|
||||
using StardewModdingAPI.Web.ViewModels;
|
||||
|
||||
|
@ -105,7 +105,7 @@ namespace StardewModdingAPI.Web.Controllers
|
|||
foreach (GitAsset asset in release.Assets)
|
||||
{
|
||||
Match match = Regex.Match(asset.FileName, @"SMAPI-(?<version>[\d\.]+(?:-.+)?)-installer(?<forDevs>-for-developers)?.zip");
|
||||
if (!match.Success || !SemanticVersionImpl.TryParse(match.Groups["version"].Value, out SemanticVersionImpl version))
|
||||
if (!match.Success || !SemanticVersion.TryParse(match.Groups["version"].Value, out ISemanticVersion version))
|
||||
continue;
|
||||
bool isBeta = version.Tag != null;
|
||||
bool isForDevs = match.Groups["forDevs"].Success;
|
||||
|
@ -127,7 +127,7 @@ namespace StardewModdingAPI.Web.Controllers
|
|||
public GitAsset Asset { get; }
|
||||
|
||||
/// <summary>The SMAPI version.</summary>
|
||||
public SemanticVersionImpl Version { get; }
|
||||
public ISemanticVersion Version { get; }
|
||||
|
||||
/// <summary>Whether this is a beta download.</summary>
|
||||
public bool IsBeta { get; }
|
||||
|
@ -145,7 +145,7 @@ namespace StardewModdingAPI.Web.Controllers
|
|||
/// <param name="version">The SMAPI version.</param>
|
||||
/// <param name="isBeta">Whether this is a beta download.</param>
|
||||
/// <param name="isForDevs">Whether this is a 'for developers' download.</param>
|
||||
public ReleaseVersion(GitRelease release, GitAsset asset, SemanticVersionImpl version, bool isBeta, bool isForDevs)
|
||||
public ReleaseVersion(GitRelease release, GitAsset asset, ISemanticVersion version, bool isBeta, bool isForDevs)
|
||||
{
|
||||
this.Release = release;
|
||||
this.Asset = asset;
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using StardewModdingAPI.Internal;
|
||||
using StardewModdingAPI.Toolkit;
|
||||
using StardewModdingAPI.Web.Framework.LogParsing.Models;
|
||||
|
||||
namespace StardewModdingAPI.Web.Framework.LogParsing
|
||||
|
@ -31,7 +31,7 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
|
|||
|
||||
/// <summary>A regex pattern matching an entry in SMAPI's mod list.</summary>
|
||||
/// <remarks>The author name and description are optional.</remarks>
|
||||
private readonly Regex ModListEntryPattern = new Regex(@"^ (?<name>.+?) (?<version>" + SemanticVersionImpl.UnboundedVersionPattern + @")(?: by (?<author>[^\|]+))?(?: \| (?<description>.+))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private readonly Regex ModListEntryPattern = new Regex(@"^ (?<name>.+?) (?<version>" + SemanticVersion.UnboundedVersionPattern + @")(?: by (?<author>[^\|]+))?(?: \| (?<description>.+))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
/// <summary>A regex pattern matching the start of SMAPI's content pack list.</summary>
|
||||
private readonly Regex ContentPackListStartPattern = new Regex(@"^Loaded \d+ content packs:$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using Microsoft.AspNetCore.Routing.Constraints;
|
||||
using StardewModdingAPI.Internal;
|
||||
using StardewModdingAPI.Toolkit;
|
||||
|
||||
namespace StardewModdingAPI.Web.Framework
|
||||
{
|
||||
|
@ -11,6 +11,6 @@ namespace StardewModdingAPI.Web.Framework
|
|||
*********/
|
||||
/// <summary>Construct an instance.</summary>
|
||||
public VersionConstraint()
|
||||
: base(SemanticVersionImpl.Regex) { }
|
||||
: base(SemanticVersion.Regex) { }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,11 +17,14 @@
|
|||
<PackageReference Include="Microsoft.AspNetCore.Rewrite" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.1" />
|
||||
<PackageReference Include="Pathoschild.Http.FluentClient" Version="3.1.0" />
|
||||
<PackageReference Include="Pathoschild.Http.FluentClient" Version="3.2.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.1" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\SMAPI.Internal\SMAPI.Internal.projitems" Label="Shared" />
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\StardewModdingAPI.Toolkit\StardewModdingAPI.Toolkit.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -60,6 +60,8 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "StardewModdingAPI.Internal"
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StardewModdingAPI.Mods.SaveBackup", "SMAPI.Mods.SaveBackup\StardewModdingAPI.Mods.SaveBackup.csproj", "{E272EB5D-8C57-417E-8E60-C1079D3F53C4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StardewModdingAPI.Toolkit", "StardewModdingAPI.Toolkit\StardewModdingAPI.Toolkit.csproj", "{EA5CFD2E-9453-4D29-B80F-8E0EA23F4AC6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||
SMAPI.Internal\SMAPI.Internal.projitems*{443ddf81-6aaf-420a-a610-3459f37e5575}*SharedItemsImports = 4
|
||||
|
@ -68,46 +70,50 @@ Global
|
|||
SMAPI.Internal\SMAPI.Internal.projitems*{f1a573b0-f436-472c-ae29-0b91ea6b9f8f}*SharedItemsImports = 4
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x86 = Release|x86
|
||||
Debug|Default = Debug|Default
|
||||
Release|Default = Release|Default
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{28480467-1A48-46A7-99F8-236D95225359}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{28480467-1A48-46A7-99F8-236D95225359}.Debug|x86.Build.0 = Debug|x86
|
||||
{28480467-1A48-46A7-99F8-236D95225359}.Release|x86.ActiveCfg = Release|x86
|
||||
{28480467-1A48-46A7-99F8-236D95225359}.Release|x86.Build.0 = Release|x86
|
||||
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Debug|x86.Build.0 = Debug|x86
|
||||
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Release|x86.ActiveCfg = Release|x86
|
||||
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Release|x86.Build.0 = Release|x86
|
||||
{443DDF81-6AAF-420A-A610-3459F37E5575}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{443DDF81-6AAF-420A-A610-3459F37E5575}.Debug|x86.Build.0 = Debug|x86
|
||||
{443DDF81-6AAF-420A-A610-3459F37E5575}.Release|x86.ActiveCfg = Release|x86
|
||||
{443DDF81-6AAF-420A-A610-3459F37E5575}.Release|x86.Build.0 = Release|x86
|
||||
{36CCB19E-92EB-48C7-9615-98EEFD45109B}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{36CCB19E-92EB-48C7-9615-98EEFD45109B}.Debug|x86.Build.0 = Debug|x86
|
||||
{36CCB19E-92EB-48C7-9615-98EEFD45109B}.Release|x86.ActiveCfg = Release|x86
|
||||
{36CCB19E-92EB-48C7-9615-98EEFD45109B}.Release|x86.Build.0 = Release|x86
|
||||
{A308F679-51A3-4006-92D5-BAEC7EBD01A1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A308F679-51A3-4006-92D5-BAEC7EBD01A1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A308F679-51A3-4006-92D5-BAEC7EBD01A1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A308F679-51A3-4006-92D5-BAEC7EBD01A1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{EA4F1E80-743F-4A1D-9757-AE66904A196A}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{EA4F1E80-743F-4A1D-9757-AE66904A196A}.Debug|x86.Build.0 = Debug|x86
|
||||
{EA4F1E80-743F-4A1D-9757-AE66904A196A}.Release|x86.ActiveCfg = Release|x86
|
||||
{EA4F1E80-743F-4A1D-9757-AE66904A196A}.Release|x86.Build.0 = Release|x86
|
||||
{80AD8528-AA49-4731-B4A6-C691845815A1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{80AD8528-AA49-4731-B4A6-C691845815A1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{80AD8528-AA49-4731-B4A6-C691845815A1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{80AD8528-AA49-4731-B4A6-C691845815A1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0CF97929-B0D0-4D73-B7BF-4FF7191035F9}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0CF97929-B0D0-4D73-B7BF-4FF7191035F9}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0CF97929-B0D0-4D73-B7BF-4FF7191035F9}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0CF97929-B0D0-4D73-B7BF-4FF7191035F9}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E272EB5D-8C57-417E-8E60-C1079D3F53C4}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{E272EB5D-8C57-417E-8E60-C1079D3F53C4}.Debug|x86.Build.0 = Debug|x86
|
||||
{E272EB5D-8C57-417E-8E60-C1079D3F53C4}.Release|x86.ActiveCfg = Release|x86
|
||||
{E272EB5D-8C57-417E-8E60-C1079D3F53C4}.Release|x86.Build.0 = Release|x86
|
||||
{28480467-1A48-46A7-99F8-236D95225359}.Debug|Default.ActiveCfg = Debug|x86
|
||||
{28480467-1A48-46A7-99F8-236D95225359}.Debug|Default.Build.0 = Debug|x86
|
||||
{28480467-1A48-46A7-99F8-236D95225359}.Release|Default.ActiveCfg = Release|x86
|
||||
{28480467-1A48-46A7-99F8-236D95225359}.Release|Default.Build.0 = Release|x86
|
||||
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Debug|Default.ActiveCfg = Debug|x86
|
||||
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Debug|Default.Build.0 = Debug|x86
|
||||
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Release|Default.ActiveCfg = Release|x86
|
||||
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Release|Default.Build.0 = Release|x86
|
||||
{443DDF81-6AAF-420A-A610-3459F37E5575}.Debug|Default.ActiveCfg = Debug|x86
|
||||
{443DDF81-6AAF-420A-A610-3459F37E5575}.Debug|Default.Build.0 = Debug|x86
|
||||
{443DDF81-6AAF-420A-A610-3459F37E5575}.Release|Default.ActiveCfg = Release|x86
|
||||
{443DDF81-6AAF-420A-A610-3459F37E5575}.Release|Default.Build.0 = Release|x86
|
||||
{36CCB19E-92EB-48C7-9615-98EEFD45109B}.Debug|Default.ActiveCfg = Debug|x86
|
||||
{36CCB19E-92EB-48C7-9615-98EEFD45109B}.Debug|Default.Build.0 = Debug|x86
|
||||
{36CCB19E-92EB-48C7-9615-98EEFD45109B}.Release|Default.ActiveCfg = Release|x86
|
||||
{36CCB19E-92EB-48C7-9615-98EEFD45109B}.Release|Default.Build.0 = Release|x86
|
||||
{A308F679-51A3-4006-92D5-BAEC7EBD01A1}.Debug|Default.ActiveCfg = Debug|Any CPU
|
||||
{A308F679-51A3-4006-92D5-BAEC7EBD01A1}.Debug|Default.Build.0 = Debug|Any CPU
|
||||
{A308F679-51A3-4006-92D5-BAEC7EBD01A1}.Release|Default.ActiveCfg = Release|Any CPU
|
||||
{A308F679-51A3-4006-92D5-BAEC7EBD01A1}.Release|Default.Build.0 = Release|Any CPU
|
||||
{EA4F1E80-743F-4A1D-9757-AE66904A196A}.Debug|Default.ActiveCfg = Debug|x86
|
||||
{EA4F1E80-743F-4A1D-9757-AE66904A196A}.Debug|Default.Build.0 = Debug|x86
|
||||
{EA4F1E80-743F-4A1D-9757-AE66904A196A}.Release|Default.ActiveCfg = Release|x86
|
||||
{EA4F1E80-743F-4A1D-9757-AE66904A196A}.Release|Default.Build.0 = Release|x86
|
||||
{80AD8528-AA49-4731-B4A6-C691845815A1}.Debug|Default.ActiveCfg = Debug|Any CPU
|
||||
{80AD8528-AA49-4731-B4A6-C691845815A1}.Debug|Default.Build.0 = Debug|Any CPU
|
||||
{80AD8528-AA49-4731-B4A6-C691845815A1}.Release|Default.ActiveCfg = Release|Any CPU
|
||||
{80AD8528-AA49-4731-B4A6-C691845815A1}.Release|Default.Build.0 = Release|Any CPU
|
||||
{0CF97929-B0D0-4D73-B7BF-4FF7191035F9}.Debug|Default.ActiveCfg = Debug|Any CPU
|
||||
{0CF97929-B0D0-4D73-B7BF-4FF7191035F9}.Debug|Default.Build.0 = Debug|Any CPU
|
||||
{0CF97929-B0D0-4D73-B7BF-4FF7191035F9}.Release|Default.ActiveCfg = Release|Any CPU
|
||||
{0CF97929-B0D0-4D73-B7BF-4FF7191035F9}.Release|Default.Build.0 = Release|Any CPU
|
||||
{E272EB5D-8C57-417E-8E60-C1079D3F53C4}.Debug|Default.ActiveCfg = Debug|x86
|
||||
{E272EB5D-8C57-417E-8E60-C1079D3F53C4}.Debug|Default.Build.0 = Debug|x86
|
||||
{E272EB5D-8C57-417E-8E60-C1079D3F53C4}.Release|Default.ActiveCfg = Release|x86
|
||||
{E272EB5D-8C57-417E-8E60-C1079D3F53C4}.Release|Default.Build.0 = Release|x86
|
||||
{EA5CFD2E-9453-4D29-B80F-8E0EA23F4AC6}.Debug|Default.ActiveCfg = Debug|Any CPU
|
||||
{EA5CFD2E-9453-4D29-B80F-8E0EA23F4AC6}.Debug|Default.Build.0 = Debug|Any CPU
|
||||
{EA5CFD2E-9453-4D29-B80F-8E0EA23F4AC6}.Release|Default.ActiveCfg = Release|Any CPU
|
||||
{EA5CFD2E-9453-4D29-B80F-8E0EA23F4AC6}.Release|Default.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -4,8 +4,8 @@ using System.Diagnostics.Contracts;
|
|||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using StardewModdingAPI.Framework.Reflection;
|
||||
using StardewModdingAPI.Framework.Utilities;
|
||||
using StardewModdingAPI.Internal;
|
||||
using StardewModdingAPI.Toolkit.Utilities;
|
||||
using StardewValley;
|
||||
|
||||
namespace StardewModdingAPI.Framework.Content
|
||||
|
|
|
@ -8,8 +8,8 @@ using Microsoft.Xna.Framework.Content;
|
|||
using StardewModdingAPI.Framework.Content;
|
||||
using StardewModdingAPI.Framework.ContentManagers;
|
||||
using StardewModdingAPI.Framework.Reflection;
|
||||
using StardewModdingAPI.Framework.Utilities;
|
||||
using StardewModdingAPI.Metadata;
|
||||
using StardewModdingAPI.Toolkit.Utilities;
|
||||
using StardewValley;
|
||||
|
||||
namespace StardewModdingAPI.Framework
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.IO;
|
|||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using StardewModdingAPI.Framework.Serialisation;
|
||||
using StardewModdingAPI.Framework.Utilities;
|
||||
using StardewModdingAPI.Toolkit.Utilities;
|
||||
using xTile;
|
||||
|
||||
namespace StardewModdingAPI.Framework
|
||||
|
|
|
@ -9,7 +9,7 @@ using Microsoft.Xna.Framework.Content;
|
|||
using Microsoft.Xna.Framework.Graphics;
|
||||
using StardewModdingAPI.Framework.ContentManagers;
|
||||
using StardewModdingAPI.Framework.Exceptions;
|
||||
using StardewModdingAPI.Framework.Utilities;
|
||||
using StardewModdingAPI.Toolkit.Utilities;
|
||||
using StardewValley;
|
||||
using xTile;
|
||||
using xTile.Format;
|
||||
|
|
|
@ -6,7 +6,7 @@ using StardewModdingAPI.Events;
|
|||
using StardewModdingAPI.Framework.Input;
|
||||
using StardewModdingAPI.Framework.Models;
|
||||
using StardewModdingAPI.Framework.Serialisation;
|
||||
using StardewModdingAPI.Framework.Utilities;
|
||||
using StardewModdingAPI.Toolkit.Utilities;
|
||||
|
||||
namespace StardewModdingAPI.Framework.ModHelpers
|
||||
{
|
||||
|
|
|
@ -7,7 +7,7 @@ using StardewModdingAPI.Framework.Exceptions;
|
|||
using StardewModdingAPI.Framework.ModData;
|
||||
using StardewModdingAPI.Framework.Models;
|
||||
using StardewModdingAPI.Framework.Serialisation;
|
||||
using StardewModdingAPI.Framework.Utilities;
|
||||
using StardewModdingAPI.Toolkit.Utilities;
|
||||
|
||||
namespace StardewModdingAPI.Framework.ModLoading
|
||||
{
|
||||
|
|
|
@ -25,9 +25,9 @@ using StardewModdingAPI.Framework.ModHelpers;
|
|||
using StardewModdingAPI.Framework.ModLoading;
|
||||
using StardewModdingAPI.Framework.Reflection;
|
||||
using StardewModdingAPI.Framework.Serialisation;
|
||||
using StardewModdingAPI.Framework.Utilities;
|
||||
using StardewModdingAPI.Internal;
|
||||
using StardewModdingAPI.Internal.Models;
|
||||
using StardewModdingAPI.Toolkit.Utilities;
|
||||
using StardewValley;
|
||||
using Monitor = StardewModdingAPI.Framework.Monitor;
|
||||
using SObject = StardewValley.Object;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using StardewModdingAPI.Internal;
|
||||
|
||||
namespace StardewModdingAPI
|
||||
{
|
||||
|
@ -11,7 +10,7 @@ namespace StardewModdingAPI
|
|||
** Properties
|
||||
*********/
|
||||
/// <summary>The underlying semantic version implementation.</summary>
|
||||
private readonly SemanticVersionImpl Version;
|
||||
private readonly Toolkit.ISemanticVersion Version;
|
||||
|
||||
|
||||
/*********
|
||||
|
@ -40,20 +39,20 @@ namespace StardewModdingAPI
|
|||
/// <param name="build">An optional build tag.</param>
|
||||
[JsonConstructor]
|
||||
public SemanticVersion(int majorVersion, int minorVersion, int patchVersion, string build = null)
|
||||
: this(new SemanticVersionImpl(majorVersion, minorVersion, patchVersion, build)) { }
|
||||
: this(new Toolkit.SemanticVersion(majorVersion, minorVersion, patchVersion, build)) { }
|
||||
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="version">The semantic version string.</param>
|
||||
/// <exception cref="ArgumentNullException">The <paramref name="version"/> is null.</exception>
|
||||
/// <exception cref="FormatException">The <paramref name="version"/> is not a valid semantic version.</exception>
|
||||
public SemanticVersion(string version)
|
||||
: this(new SemanticVersionImpl(version)) { }
|
||||
: this(new Toolkit.SemanticVersion(version)) { }
|
||||
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="version">The assembly version.</param>
|
||||
/// <exception cref="ArgumentNullException">The <paramref name="version"/> is null.</exception>
|
||||
public SemanticVersion(Version version)
|
||||
: this(new SemanticVersionImpl(version)) { }
|
||||
: this(new Toolkit.SemanticVersion(version)) { }
|
||||
|
||||
/// <summary>Whether this is a pre-release version.</summary>
|
||||
public bool IsPrerelease()
|
||||
|
@ -67,7 +66,8 @@ namespace StardewModdingAPI
|
|||
/// <remarks>The implementation is defined by Semantic Version 2.0 (http://semver.org/).</remarks>
|
||||
public int CompareTo(ISemanticVersion other)
|
||||
{
|
||||
return this.Version.CompareTo(other.MajorVersion, other.MinorVersion, other.PatchVersion, other.Build);
|
||||
Toolkit.ISemanticVersion toolkitOther = new Toolkit.SemanticVersion(other.MajorVersion, other.MinorVersion, other.PatchVersion, other.Build);
|
||||
return this.Version.CompareTo(toolkitOther);
|
||||
}
|
||||
|
||||
/// <summary>Get whether this version is older than the specified version.</summary>
|
||||
|
@ -137,7 +137,7 @@ namespace StardewModdingAPI
|
|||
/// <returns>Returns whether parsing the version succeeded.</returns>
|
||||
internal static bool TryParse(string version, out ISemanticVersion parsed)
|
||||
{
|
||||
if (SemanticVersionImpl.TryParse(version, out SemanticVersionImpl versionImpl))
|
||||
if (Toolkit.SemanticVersion.TryParse(version, out Toolkit.ISemanticVersion versionImpl))
|
||||
{
|
||||
parsed = new SemanticVersion(versionImpl);
|
||||
return true;
|
||||
|
@ -153,7 +153,7 @@ namespace StardewModdingAPI
|
|||
*********/
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="version">The underlying semantic version implementation.</param>
|
||||
private SemanticVersion(SemanticVersionImpl version)
|
||||
private SemanticVersion(Toolkit.ISemanticVersion version)
|
||||
{
|
||||
this.Version = version;
|
||||
}
|
||||
|
|
|
@ -176,7 +176,6 @@
|
|||
<Compile Include="Framework\StateTracking\LocationTracker.cs" />
|
||||
<Compile Include="Framework\StateTracking\PlayerTracker.cs" />
|
||||
<Compile Include="Framework\Utilities\ContextHash.cs" />
|
||||
<Compile Include="Framework\Utilities\PathUtilities.cs" />
|
||||
<Compile Include="IContentPack.cs" />
|
||||
<Compile Include="IManifestContentPackFor.cs" />
|
||||
<Compile Include="IMultiplayerHelper.cs" />
|
||||
|
@ -333,6 +332,12 @@
|
|||
<ItemGroup>
|
||||
<Analyzer Include="..\SMAPI.ModBuildConfig.Analyzer\bin\netstandard1.3\StardewModdingAPI.ModBuildConfig.Analyzer.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\StardewModdingAPI.Toolkit\StardewModdingAPI.Toolkit.csproj">
|
||||
<Project>{ea5cfd2e-9453-4d29-b80f-8e0ea23f4ac6}</Project>
|
||||
<Name>StardewModdingAPI.Toolkit</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="..\SMAPI.Internal\SMAPI.Internal.projitems" Label="Shared" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\..\build\common.targets" />
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using HtmlAgilityPack;
|
||||
using Pathoschild.Http.Client;
|
||||
|
||||
namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
|
||||
{
|
||||
/// <summary>An HTTP client for fetching mod metadata from the wiki compatibility list.</summary>
|
||||
public class WikiCompatibilityClient : IDisposable
|
||||
{
|
||||
/*********
|
||||
** Properties
|
||||
*********/
|
||||
/// <summary>The underlying HTTP client.</summary>
|
||||
private readonly IClient Client;
|
||||
|
||||
|
||||
/*********
|
||||
** Public methods
|
||||
*********/
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="userAgent">The user agent for the wiki API.</param>
|
||||
/// <param name="baseUrl">The base URL for the wiki API.</param>
|
||||
public WikiCompatibilityClient(string userAgent, string baseUrl = "https://stardewvalleywiki.com/mediawiki/api.php")
|
||||
{
|
||||
this.Client = new FluentClient(baseUrl).SetUserAgent(userAgent);
|
||||
}
|
||||
|
||||
/// <summary>Fetch mod compatibility entries.</summary>
|
||||
public async Task<WikiCompatibilityEntry[]> FetchAsync()
|
||||
{
|
||||
// fetch HTML
|
||||
ResponseModel response = await this.Client
|
||||
.GetAsync("")
|
||||
.WithArguments(new
|
||||
{
|
||||
action = "parse",
|
||||
page = "Modding:SMAPI_compatibility",
|
||||
format = "json"
|
||||
})
|
||||
.As<ResponseModel>();
|
||||
string html = response.Parse.Text["*"];
|
||||
|
||||
// parse HTML
|
||||
var doc = new HtmlDocument();
|
||||
doc.LoadHtml(html);
|
||||
|
||||
// find mod entries
|
||||
HtmlNodeCollection modNodes = doc.DocumentNode.SelectNodes("table[@id='mod-list']//tr[@class='mod']");
|
||||
if (modNodes == null)
|
||||
throw new InvalidOperationException("Can't parse wiki compatibility list, no mods found.");
|
||||
|
||||
// parse
|
||||
return this.ParseEntries(modNodes).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Client?.Dispose();
|
||||
}
|
||||
|
||||
|
||||
/*********
|
||||
** Private methods
|
||||
*********/
|
||||
/// <summary>Parse valid mod compatibility entries.</summary>
|
||||
/// <param name="nodes">The HTML compatibility entries.</param>
|
||||
private IEnumerable<WikiCompatibilityEntry> ParseEntries(IEnumerable<HtmlNode> nodes)
|
||||
{
|
||||
foreach (HtmlNode node in nodes)
|
||||
{
|
||||
// parse status
|
||||
WikiCompatibilityStatus status;
|
||||
{
|
||||
string rawStatus = node.GetAttributeValue("data-status", null);
|
||||
if (rawStatus == null)
|
||||
continue; // not a mod node?
|
||||
if (!Enum.TryParse(rawStatus, true, out status))
|
||||
throw new InvalidOperationException($"Unknown status '{rawStatus}' when parsing compatibility list.");
|
||||
}
|
||||
|
||||
// parse unofficial version
|
||||
ISemanticVersion unofficialVersion = null;
|
||||
{
|
||||
string rawUnofficialVersion = node.GetAttributeValue("data-unofficial-version", null);
|
||||
SemanticVersion.TryParse(rawUnofficialVersion, out unofficialVersion);
|
||||
}
|
||||
|
||||
// parse other fields
|
||||
string name = node.Descendants("td").FirstOrDefault()?.InnerText?.Trim();
|
||||
string summary = node.Descendants("td").FirstOrDefault(p => p.GetAttributeValue("class", null) == "summary")?.InnerText.Trim();
|
||||
string[] ids = this.GetAttribute(node, "data-id")?.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(p => p.Trim()).ToArray() ?? new string[0];
|
||||
int? nexusID = this.GetNullableIntAttribute(node, "data-nexus-id");
|
||||
int? chucklefishID = this.GetNullableIntAttribute(node, "data-chucklefish-id");
|
||||
string githubRepo = this.GetAttribute(node, "data-github");
|
||||
string customSourceUrl = this.GetAttribute(node, "data-custom-source");
|
||||
string customUrl = this.GetAttribute(node, "data-custom-url");
|
||||
|
||||
// yield model
|
||||
yield return new WikiCompatibilityEntry
|
||||
{
|
||||
ID = ids,
|
||||
Name = name,
|
||||
Status = status,
|
||||
NexusID = nexusID,
|
||||
ChucklefishID = chucklefishID,
|
||||
GitHubRepo = githubRepo,
|
||||
CustomSourceUrl = customSourceUrl,
|
||||
CustomUrl = customUrl,
|
||||
UnofficialVersion = unofficialVersion,
|
||||
Summary = summary
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Get a nullable integer attribute value.</summary>
|
||||
/// <param name="node">The HTML node.</param>
|
||||
/// <param name="attributeName">The attribute name.</param>
|
||||
private int? GetNullableIntAttribute(HtmlNode node, string attributeName)
|
||||
{
|
||||
string raw = this.GetAttribute(node, attributeName);
|
||||
if (raw != null && int.TryParse(raw, out int value))
|
||||
return value;
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Get a strings attribute value.</summary>
|
||||
/// <param name="node">The HTML node.</param>
|
||||
/// <param name="attributeName">The attribute name.</param>
|
||||
private string GetAttribute(HtmlNode node, string attributeName)
|
||||
{
|
||||
string raw = node.GetAttributeValue(attributeName, null);
|
||||
if (raw != null)
|
||||
raw = HtmlEntity.DeEntitize(raw);
|
||||
return raw;
|
||||
}
|
||||
|
||||
/// <summary>The response model for the MediaWiki parse API.</summary>
|
||||
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Local")]
|
||||
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")]
|
||||
private class ResponseModel
|
||||
{
|
||||
/// <summary>The parse API results.</summary>
|
||||
public ResponseParseModel Parse { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>The inner response model for the MediaWiki parse API.</summary>
|
||||
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Local")]
|
||||
[SuppressMessage("ReSharper", "CollectionNeverUpdated.Local")]
|
||||
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")]
|
||||
private class ResponseParseModel
|
||||
{
|
||||
/// <summary>The parsed text.</summary>
|
||||
public IDictionary<string, string> Text { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
|
||||
{
|
||||
/// <summary>An entry in the mod compatibility list.</summary>
|
||||
public class WikiCompatibilityEntry
|
||||
{
|
||||
/// <summary>The mod's unique ID. A mod may have multiple current IDs in rare cases (e.g. due to parallel releases or unofficial updates).</summary>
|
||||
public string[] ID { get; set; }
|
||||
|
||||
/// <summary>The mod's display name.</summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>The mod ID on Nexus.</summary>
|
||||
public int? NexusID { get; set; }
|
||||
|
||||
/// <summary>The mod ID in the Chucklefish mod repo.</summary>
|
||||
public int? ChucklefishID { get; set; }
|
||||
|
||||
/// <summary>The GitHub repository in the form 'owner/repo'.</summary>
|
||||
public string GitHubRepo { get; set; }
|
||||
|
||||
/// <summary>The URL to a non-GitHub source repo.</summary>
|
||||
public string CustomSourceUrl { get; set; }
|
||||
|
||||
/// <summary>The custom mod page URL (if applicable).</summary>
|
||||
public string CustomUrl { get; set; }
|
||||
|
||||
/// <summary>The version of the latest unofficial update, if applicable.</summary>
|
||||
public ISemanticVersion UnofficialVersion { get; set; }
|
||||
|
||||
/// <summary>The compatibility status.</summary>
|
||||
public WikiCompatibilityStatus Status { get; set; }
|
||||
|
||||
/// <summary>The human-readable summary of the compatibility status or workaround, without HTML formatitng.</summary>
|
||||
public string Summary { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki
|
||||
{
|
||||
/// <summary>The compatibility status for a mod.</summary>
|
||||
public enum WikiCompatibilityStatus
|
||||
{
|
||||
/// <summary>The mod is compatible.</summary>
|
||||
Ok = 0,
|
||||
|
||||
/// <summary>The mod is compatible if you use an optional official download.</summary>
|
||||
Optional = 1,
|
||||
|
||||
/// <summary>The mod is compatible if you use an unofficial update.</summary>
|
||||
Unofficial = 2,
|
||||
|
||||
/// <summary>The mod isn't compatible, but the player can fix it or there's a good alternative.</summary>
|
||||
Workaround = 3,
|
||||
|
||||
/// <summary>The mod isn't compatible.</summary>
|
||||
Broken = 4,
|
||||
|
||||
/// <summary>The mod is no longer maintained by the author, and an unofficial update or continuation is unlikely.</summary>
|
||||
Abandoned = 5,
|
||||
|
||||
/// <summary>The mod is no longer needed and should be removed.</summary>
|
||||
Obsolete = 6
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
|
||||
namespace StardewModdingAPI.Toolkit
|
||||
{
|
||||
/// <summary>A semantic version with an optional release tag.</summary>
|
||||
public interface ISemanticVersion : IComparable<ISemanticVersion>, IEquatable<ISemanticVersion>
|
||||
{
|
||||
/*********
|
||||
** Accessors
|
||||
*********/
|
||||
/// <summary>The major version incremented for major API changes.</summary>
|
||||
int Major { get; }
|
||||
|
||||
/// <summary>The minor version incremented for backwards-compatible changes.</summary>
|
||||
int Minor { get; }
|
||||
|
||||
/// <summary>The patch version for backwards-compatible bug fixes.</summary>
|
||||
int Patch { get; }
|
||||
|
||||
/// <summary>An optional prerelease tag.</summary>
|
||||
string Tag { get; }
|
||||
|
||||
|
||||
/*********
|
||||
** Accessors
|
||||
*********/
|
||||
/// <summary>Whether this is a pre-release version.</summary>
|
||||
bool IsPrerelease();
|
||||
|
||||
/// <summary>Get whether this version is older than the specified version.</summary>
|
||||
/// <param name="other">The version to compare with this instance.</param>
|
||||
bool IsOlderThan(ISemanticVersion other);
|
||||
|
||||
/// <summary>Get whether this version is newer than the specified version.</summary>
|
||||
/// <param name="other">The version to compare with this instance.</param>
|
||||
bool IsNewerThan(ISemanticVersion other);
|
||||
|
||||
/// <summary>Get whether this version is between two specified versions (inclusively).</summary>
|
||||
/// <param name="min">The minimum version.</param>
|
||||
/// <param name="max">The maximum version.</param>
|
||||
bool IsBetween(ISemanticVersion min, ISemanticVersion max);
|
||||
|
||||
/// <summary>Get a string representation of the version.</summary>
|
||||
string ToString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
using System.Threading.Tasks;
|
||||
using StardewModdingAPI.Toolkit.Framework.Clients.Wiki;
|
||||
|
||||
namespace StardewModdingAPI.Toolkit
|
||||
{
|
||||
/// <summary>A convenience wrapper for the various tools.</summary>
|
||||
public class ModToolkit
|
||||
{
|
||||
/*********
|
||||
** Properties
|
||||
*********/
|
||||
/// <summary>The default HTTP user agent for the toolkit.</summary>
|
||||
private readonly string UserAgent;
|
||||
|
||||
|
||||
/*********
|
||||
** Public methods
|
||||
*********/
|
||||
/// <summary>Construct an instance.</summary>
|
||||
public ModToolkit()
|
||||
{
|
||||
ISemanticVersion version = new SemanticVersion(this.GetType().Assembly.GetName().Version);
|
||||
this.UserAgent = $"SMAPI Mod Handler Toolkit/{version}";
|
||||
}
|
||||
|
||||
/// <summary>Extract mod metadata from the wiki compatibility list.</summary>
|
||||
public async Task<WikiCompatibilityEntry[]> GetWikiCompatibilityListAsync()
|
||||
{
|
||||
var client = new WikiCompatibilityClient(this.UserAgent);
|
||||
return await client.FetchAsync();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: AssemblyTitle("SMAPI.Toolkit")]
|
||||
[assembly: AssemblyDescription("A library which encapsulates mod-handling logic for mod managers and tools. Not intended for use by mods.")]
|
||||
[assembly: AssemblyProduct("SMAPI Toolkit")]
|
||||
[assembly: AssemblyVersion("0.1.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.0")]
|
||||
[assembly: InternalsVisibleTo("StardewModdingAPI")]
|
||||
[assembly: InternalsVisibleTo("StardewModdingAPI.Web")]
|
|
@ -1,12 +1,29 @@
|
|||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace StardewModdingAPI.Internal
|
||||
namespace StardewModdingAPI.Toolkit
|
||||
{
|
||||
/// <summary>A low-level implementation of a semantic version with an optional release tag.</summary>
|
||||
/// <summary>A semantic version with an optional release tag.</summary>
|
||||
/// <remarks>The implementation is defined by Semantic Version 2.0 (http://semver.org/).</remarks>
|
||||
internal class SemanticVersionImpl : IComparable<SemanticVersionImpl>
|
||||
public class SemanticVersion : ISemanticVersion
|
||||
{
|
||||
/*********
|
||||
** Properties
|
||||
*********/
|
||||
/// <summary>A regex pattern matching a version within a larger string.</summary>
|
||||
internal const string UnboundedVersionPattern = @"(?>(?<major>0|[1-9]\d*))\.(?>(?<minor>0|[1-9]\d*))(?>(?:\.(?<patch>0|[1-9]\d*))?)(?:-(?<prerelease>(?>[a-z0-9]+[\-\.]?)+))?";
|
||||
|
||||
/// <summary>A regular expression matching a semantic version string.</summary>
|
||||
/// <remarks>
|
||||
/// This pattern is derived from the BNF documentation in the <a href="https://github.com/mojombo/semver">semver repo</a>,
|
||||
/// with three important deviations intended to support Stardew Valley mod conventions:
|
||||
/// - allows short-form "x.y" versions;
|
||||
/// - allows hyphens in prerelease tags as synonyms for dots (like "-unofficial-update.3");
|
||||
/// - doesn't allow '+build' suffixes.
|
||||
/// </remarks>
|
||||
internal static readonly Regex Regex = new Regex($@"^{SemanticVersion.UnboundedVersionPattern}$", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
|
||||
|
||||
|
||||
/*********
|
||||
** Accessors
|
||||
*********/
|
||||
|
@ -22,18 +39,6 @@ namespace StardewModdingAPI.Internal
|
|||
/// <summary>An optional prerelease tag.</summary>
|
||||
public string Tag { get; }
|
||||
|
||||
/// <summary>A regex pattern matching a version within a larger string.</summary>
|
||||
internal const string UnboundedVersionPattern = @"(?>(?<major>0|[1-9]\d*))\.(?>(?<minor>0|[1-9]\d*))(?>(?:\.(?<patch>0|[1-9]\d*))?)(?:-(?<prerelease>(?>[a-z0-9]+[\-\.]?)+))?";
|
||||
|
||||
/// <summary>A regular expression matching a semantic version string.</summary>
|
||||
/// <remarks>
|
||||
/// This pattern is derived from the BNF documentation in the <a href="https://github.com/mojombo/semver">semver repo</a>,
|
||||
/// with three important deviations intended to support Stardew Valley mod conventions:
|
||||
/// - allows short-form "x.y" versions;
|
||||
/// - allows hyphens in prerelease tags as synonyms for dots (like "-unofficial-update.3");
|
||||
/// - doesn't allow '+build' suffixes.
|
||||
/// </remarks>
|
||||
internal static readonly Regex Regex = new Regex($@"^{SemanticVersionImpl.UnboundedVersionPattern}$", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
|
||||
|
||||
/*********
|
||||
** Public methods
|
||||
|
@ -41,9 +46,9 @@ namespace StardewModdingAPI.Internal
|
|||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="major">The major version incremented for major API changes.</param>
|
||||
/// <param name="minor">The minor version incremented for backwards-compatible changes.</param>
|
||||
/// <param name="patch">The patch version for backwards-compatible bug fixes.</param>
|
||||
/// <param name="patch">The patch version for backwards-compatible fixes.</param>
|
||||
/// <param name="tag">An optional prerelease tag.</param>
|
||||
public SemanticVersionImpl(int major, int minor, int patch, string tag = null)
|
||||
public SemanticVersion(int major, int minor, int patch, string tag = null)
|
||||
{
|
||||
this.Major = major;
|
||||
this.Minor = minor;
|
||||
|
@ -54,7 +59,7 @@ namespace StardewModdingAPI.Internal
|
|||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="version">The assembly version.</param>
|
||||
/// <exception cref="ArgumentNullException">The <paramref name="version"/> is null.</exception>
|
||||
public SemanticVersionImpl(Version version)
|
||||
public SemanticVersion(Version version)
|
||||
{
|
||||
if (version == null)
|
||||
throw new ArgumentNullException(nameof(version), "The input version can't be null.");
|
||||
|
@ -68,12 +73,12 @@ namespace StardewModdingAPI.Internal
|
|||
/// <param name="version">The semantic version string.</param>
|
||||
/// <exception cref="ArgumentNullException">The <paramref name="version"/> is null.</exception>
|
||||
/// <exception cref="FormatException">The <paramref name="version"/> is not a valid semantic version.</exception>
|
||||
public SemanticVersionImpl(string version)
|
||||
public SemanticVersion(string version)
|
||||
{
|
||||
// parse
|
||||
if (version == null)
|
||||
throw new ArgumentNullException(nameof(version), "The input version string can't be null.");
|
||||
var match = SemanticVersionImpl.Regex.Match(version.Trim());
|
||||
var match = SemanticVersion.Regex.Match(version.Trim());
|
||||
if (!match.Success)
|
||||
throw new FormatException($"The input '{version}' isn't a valid semantic version.");
|
||||
|
||||
|
@ -87,20 +92,100 @@ namespace StardewModdingAPI.Internal
|
|||
/// <summary>Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version.</summary>
|
||||
/// <param name="other">The version to compare with this instance.</param>
|
||||
/// <exception cref="ArgumentNullException">The <paramref name="other"/> value is null.</exception>
|
||||
public int CompareTo(SemanticVersionImpl other)
|
||||
public int CompareTo(ISemanticVersion other)
|
||||
{
|
||||
if (other == null)
|
||||
throw new ArgumentNullException(nameof(other));
|
||||
return this.CompareTo(other.Major, other.Minor, other.Patch, other.Tag);
|
||||
}
|
||||
|
||||
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
|
||||
/// <returns>true if the current object is equal to the <paramref name="other" /> parameter; otherwise, false.</returns>
|
||||
/// <param name="other">An object to compare with this object.</param>
|
||||
public bool Equals(ISemanticVersion other)
|
||||
{
|
||||
return other != null && this.CompareTo(other) == 0;
|
||||
}
|
||||
|
||||
/// <summary>Whether this is a pre-release version.</summary>
|
||||
public bool IsPrerelease()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(this.Tag);
|
||||
}
|
||||
|
||||
/// <summary>Get whether this version is older than the specified version.</summary>
|
||||
/// <param name="other">The version to compare with this instance.</param>
|
||||
public bool IsOlderThan(ISemanticVersion other)
|
||||
{
|
||||
return this.CompareTo(other) < 0;
|
||||
}
|
||||
|
||||
/// <summary>Get whether this version is newer than the specified version.</summary>
|
||||
/// <param name="other">The version to compare with this instance.</param>
|
||||
public bool IsNewerThan(ISemanticVersion other)
|
||||
{
|
||||
return this.CompareTo(other) > 0;
|
||||
}
|
||||
|
||||
/// <summary>Get whether this version is between two specified versions (inclusively).</summary>
|
||||
/// <param name="min">The minimum version.</param>
|
||||
/// <param name="max">The maximum version.</param>
|
||||
public bool IsBetween(ISemanticVersion min, ISemanticVersion max)
|
||||
{
|
||||
return this.CompareTo(min) >= 0 && this.CompareTo(max) <= 0;
|
||||
}
|
||||
|
||||
/// <summary>Get a string representation of the version.</summary>
|
||||
public override string ToString()
|
||||
{
|
||||
// version
|
||||
string result = this.Patch != 0
|
||||
? $"{this.Major}.{this.Minor}.{this.Patch}"
|
||||
: $"{this.Major}.{this.Minor}";
|
||||
|
||||
// tag
|
||||
string tag = this.Tag;
|
||||
if (tag != null)
|
||||
result += $"-{tag}";
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>Parse a version string without throwing an exception if it fails.</summary>
|
||||
/// <param name="version">The version string.</param>
|
||||
/// <param name="parsed">The parsed representation.</param>
|
||||
/// <returns>Returns whether parsing the version succeeded.</returns>
|
||||
public static bool TryParse(string version, out ISemanticVersion parsed)
|
||||
{
|
||||
try
|
||||
{
|
||||
parsed = new SemanticVersion(version);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
parsed = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********
|
||||
** Private methods
|
||||
*********/
|
||||
/// <summary>Get a normalised build tag.</summary>
|
||||
/// <param name="tag">The tag to normalise.</param>
|
||||
private string GetNormalisedTag(string tag)
|
||||
{
|
||||
tag = tag?.Trim();
|
||||
return !string.IsNullOrWhiteSpace(tag) ? tag : null;
|
||||
}
|
||||
|
||||
/// <summary>Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version.</summary>
|
||||
/// <param name="otherMajor">The major version to compare with this instance.</param>
|
||||
/// <param name="otherMinor">The minor version to compare with this instance.</param>
|
||||
/// <param name="otherPatch">The patch version to compare with this instance.</param>
|
||||
/// <param name="otherTag">The prerelease tag to compare with this instance.</param>
|
||||
public int CompareTo(int otherMajor, int otherMinor, int otherPatch, string otherTag)
|
||||
private int CompareTo(int otherMajor, int otherMinor, int otherPatch, string otherTag)
|
||||
{
|
||||
const int same = 0;
|
||||
const int curNewer = 1;
|
||||
|
@ -148,52 +233,7 @@ namespace StardewModdingAPI.Internal
|
|||
}
|
||||
|
||||
// fallback (this should never happen)
|
||||
return string.Compare(this.ToString(), new SemanticVersionImpl(otherMajor, otherMinor, otherPatch, otherTag).ToString(), StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>Get a string representation of the version.</summary>
|
||||
public override string ToString()
|
||||
{
|
||||
// version
|
||||
string result = this.Patch != 0
|
||||
? $"{this.Major}.{this.Minor}.{this.Patch}"
|
||||
: $"{this.Major}.{this.Minor}";
|
||||
|
||||
// tag
|
||||
string tag = this.Tag;
|
||||
if (tag != null)
|
||||
result += $"-{tag}";
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>Parse a version string without throwing an exception if it fails.</summary>
|
||||
/// <param name="version">The version string.</param>
|
||||
/// <param name="parsed">The parsed representation.</param>
|
||||
/// <returns>Returns whether parsing the version succeeded.</returns>
|
||||
internal static bool TryParse(string version, out SemanticVersionImpl parsed)
|
||||
{
|
||||
try
|
||||
{
|
||||
parsed = new SemanticVersionImpl(version);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
parsed = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********
|
||||
** Private methods
|
||||
*********/
|
||||
/// <summary>Get a normalised build tag.</summary>
|
||||
/// <param name="tag">The tag to normalise.</param>
|
||||
private string GetNormalisedTag(string tag)
|
||||
{
|
||||
tag = tag?.Trim();
|
||||
return !string.IsNullOrWhiteSpace(tag) ? tag : null;
|
||||
return string.Compare(this.ToString(), new SemanticVersion(otherMajor, otherMinor, otherPatch, otherTag).ToString(), StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net4.5;netstandard2.0</TargetFrameworks>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputPath>..\..\bin\$(Configuration)\SMAPI.Toolkit</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.7.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="Pathoschild.Http.FluentClient" Version="3.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\..\build\common.targets" />
|
||||
|
||||
</Project>
|
|
@ -3,10 +3,10 @@ using System.Diagnostics.Contracts;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace StardewModdingAPI.Framework.Utilities
|
||||
namespace StardewModdingAPI.Toolkit.Utilities
|
||||
{
|
||||
/// <summary>Provides utilities for normalising file paths.</summary>
|
||||
internal static class PathUtilities
|
||||
public static class PathUtilities
|
||||
{
|
||||
/*********
|
||||
** Properties
|
Loading…
Reference in New Issue