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 Dec 8, 2020
2 parents 56f4c77 + 7f76d1a commit 7ce929a
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 31 deletions.
124 changes: 105 additions & 19 deletions StardewXnbHack/Framework/PlatformContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using StardewModdingAPI.Toolkit;
Expand Down Expand Up @@ -26,35 +27,81 @@ public bool Is(params Platform[] platforms)
return platforms.Contains(this.Platform);
}

/// <summary>Detect the game folder, if any.</summary>
public string DetectGameFolder()
/// <summary>Get the absolute paths to the game and content folders, if found.</summary>
/// <param name="specifiedPath">The game path specified by the user, if any.</param>
/// <param name="gamePath">The absolute path to the game folder, if found.</param>
/// <param name="contentPath">The absolute path to the content folder, if found.</param>
/// <returns>Returns whether both the game and content folders were found.</returns>
public bool TryDetectGamePaths(string specifiedPath, out string gamePath, out string contentPath)
{
string assemblyDirPath = AppDomain.CurrentDomain.BaseDirectory;
gamePath = null;
contentPath = null;

return this.IsGameFolder(assemblyDirPath)
? assemblyDirPath
: new ModToolkit().GetGameFolders().FirstOrDefault()?.FullName;
}
// check possible game paths
foreach (string candidate in this.GetCandidateGamePaths(specifiedPath))
{
// detect paths
string curGamePath = this.TryGamePath(candidate);
string curContentPath = this.FindContentPath(curGamePath);

/// <summary>Get the relative path from the game folder to the content folder.</summary>
public string GetRelativeContentPath()
{
return this.Platform == Platform.Mac
? "../../Resources/Content"
: "Content";
// valid game install found
if (curGamePath != null && curContentPath != null)
{
gamePath = curGamePath;
contentPath = curContentPath;
return true;
}

// if game folder exists without a content folder, track the first found game path (i.e. the highest-priority one)
gamePath = gamePath ?? curGamePath;
}

return false;
}


/*********
** Private methods
*********/
/// <summary>Get whether a folder contains the game files.</summary>
/// <param name="path">The absolute folder path to check.</param>
private bool IsGameFolder(string path)
/// <summary>Get the possible game paths.</summary>
/// <param name="specifiedPath">The game path specified by the user, if any.</param>
private IEnumerable<string> GetCandidateGamePaths(string specifiedPath = null)
{
return
File.Exists(Path.Combine(path, this.GetExecutableFileName()))
&& Directory.Exists(Path.Combine(path, this.GetRelativeContentPath()));
// specified path
if (!string.IsNullOrWhiteSpace(specifiedPath))
yield return specifiedPath;

// current working directory
yield return AppDomain.CurrentDomain.BaseDirectory;

// detected game path
string detectedPath = new ModToolkit().GetGameFolders().FirstOrDefault()?.FullName;
if (detectedPath != null)
yield return detectedPath;
}

/// <summary>Get the absolute path to the game folder, if it's valid.</summary>
/// <param name="path">The path to check for a game install.</param>
private string TryGamePath(string path)
{
// game path exists
if (path == null)
return null;
DirectoryInfo gameDir = new DirectoryInfo(path);
if (!gameDir.Exists)
return null;

// has game files
bool hasExecutable = File.Exists(Path.Combine(gameDir.FullName, this.GetExecutableFileName()));
if (!hasExecutable)
return null;

// isn't the build folder when compiled directly
bool isCompileFolder = File.Exists(Path.Combine(gameDir.FullName, "StardewXnbHack.exe.config"));
if (isCompileFolder)
return null;

return gameDir.FullName;
}

/// <summary>Get the filename for the Stardew Valley executable.</summary>
Expand All @@ -64,5 +111,44 @@ private string GetExecutableFileName()
? "Stardew Valley.exe"
: "StardewValley.exe";
}

/// <summary>Get the absolute path to the content folder for a given game, if found.</summary>
/// <param name="gamePath">The absolute path to the game folder.</param>
private string FindContentPath(string gamePath)
{
if (gamePath == null)
return null;

foreach (string relativePath in this.GetPossibleRelativeContentPaths())
{
DirectoryInfo folder = new DirectoryInfo(Path.Combine(gamePath, relativePath));
if (folder.Exists)
return folder.FullName;
}

return null;
}

/// <summary>Get the possible relative paths for the current platform.</summary>
private IEnumerable<string> GetPossibleRelativeContentPaths()
{
// under game folder on most platforms
if (this.Platform != Platform.Mac)
yield return "Content";

// MacOS
else
{
// Steam paths
// - game path: StardewValley/Contents/MacOS
// - content: StardewValley/Contents/Resources/Content
yield return "../Resources/Content";

// GOG paths
// - game path: Stardew Valley.app/Contents/MacOS
// - content: Stardew Valley.app/Resources/Content
yield return "../../Resources/Content";
}
}
}
}
24 changes: 15 additions & 9 deletions StardewXnbHack/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,24 @@ public static void Run(Game1 game = null, string gamePath = null, Func<IUnpackCo
new DataWriter() // check last due to more expensive CanWrite
};

// get game info
// get paths
var platform = new PlatformContext();
context.GamePath = gamePath ?? platform.DetectGameFolder();
if (context.GamePath == null || !Directory.Exists(context.GamePath))
{
logger.OnFatalError("Can't find Stardew Valley folder. Try running StardewXnbHack from the game folder instead.");
return;
if (platform.TryDetectGamePaths(gamePath, out gamePath, out string contentPath))
{
context.GamePath = gamePath;
context.ContentPath = contentPath;
}
else
{
logger.OnFatalError(gamePath == null
? "Can't find Stardew Valley folder. Try running StardewXnbHack from the game folder instead."
: $"Can't find the content folder for the game at {gamePath}. Is the game installed correctly?"
);
return;
}
}

// get import/export paths
context.ContentPath = Path.Combine(context.GamePath, platform.GetRelativeContentPath());
context.ExportPath = context.ContentPath + " (unpacked)";
context.ExportPath = Path.Combine(context.GamePath, "Content (unpacked)");
logger.OnStepChanged(ProgressStep.GameFound, $"Found game folder: {context.GamePath}.");

// symlink files on Linux/Mac
Expand Down
4 changes: 2 additions & 2 deletions StardewXnbHack/StardewXnbHack.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryUrl>https://github.com/Pathoschild/StardewXnbHack</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Version>1.0.1</Version>
<Version>1.0.2</Version>

<!--build-->
<TargetFramework>net452</TargetFramework>
Expand All @@ -24,7 +24,7 @@
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Pathoschild.Stardew.ModBuildConfig" Version="3.2.2" />
<PackageReference Include="Platonymous.TMXTile" Version="1.5.8" />
<PackageReference Include="Platonymous.TMXTile" Version="1.5.9" />
</ItemGroup>

<ItemGroup>
Expand Down
10 changes: 9 additions & 1 deletion release-notes.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
[← back to readme](README.md)

# Release notes
## 1.0.2
Released 07 December 2020.

* Assets on MacOS are now unpacked into the game folder instead of resources, for consistency with other platforms.
* Improved error if the game's content folder is missing.
* Fixed duplicate tile index properties in some cases.
* Fixed unpack error on MacOS with Steam.

## 1.0.1
Released 21 November 2020.

* Updated TMXTile to 1.5.8 to fix `.tmx` map files losing tile index properties.
* Fixed `.tmx` map files losing tile index properties.

## 1.0
Released 04 October 2020.
Expand Down

0 comments on commit 7ce929a

Please sign in to comment.