private static SteamGameData SearchAllInstallations( string libraryfoldersFile, uint appId) { if (!File.Exists(libraryfoldersFile)) { return(null); } var steamLibraryPaths = GetLibraryPaths(File.ReadAllText(libraryfoldersFile)); foreach (var steamLibraryPath in steamLibraryPaths) { var manifestFile = Path.Combine(steamLibraryPath, $"steamapps/appmanifest_{appId}.acf"); if (!File.Exists(manifestFile)) { continue; } // Validate manifest is correct. SteamGameData game = GameDataFromAppManifest(manifestFile); if (game.Id != appId) { continue; } return(game); } return(null); }
public static SteamGameData TryFrom(string path) { try { var game = new SteamGameData(); var xDoc = new XmlDocument(); xDoc.Load(path); XmlNamespaceManager nsManager = new XmlNamespaceManager(xDoc.NameTable); nsManager.AddNamespace("d", xDoc.DocumentElement.NamespaceURI); foreach (XmlElement elem in xDoc.DocumentElement.SelectNodes("//d:PropertyGroup/*", nsManager)) { switch (elem.Name) { case "GameAppId": game.Id = uint.Parse(elem.LastChild.Value); break; case "GameName": game.Name = elem.LastChild.Value; break; case "GameFolderName": game.InstallFolderName = elem.LastChild.Value; break; case "GameDir": game.InstallDir = elem.LastChild.Value; break; } } return(game); } catch (Exception) { return(null); } }
private static async Task EnsureUnityDoorstopAsync(SteamGameData game) { var zip = Path.Combine(Utils.GeneratedOutputDir, "unitydoorstop.zip"); if (!File.Exists(zip)) { using var client = new WebClient(); await client.DownloadFileTaskAsync(UnityDoorstopDownloadUrl, zip); } // Extract UnityDoorstop zip over game files. using var zipReader = ZipFile.OpenRead(zip); string[] skipIfExists = { "doorstop_config.ini" }; foreach (var entry in zipReader.Entries) { if (skipZipExtractContains.Any( name => entry.FullName.IndexOf(name, StringComparison.InvariantCultureIgnoreCase) >= 0)) { continue; } var targetFile = Path.Combine(game.InstallDir, entry.FullName); if (File.Exists(targetFile) && skipIfExists.Any(f => f.Equals(Path.GetFileName(targetFile), StringComparison.InvariantCultureIgnoreCase))) { continue; } Directory.CreateDirectory(Path.GetDirectoryName(targetFile)); entry.ExtractToFile(targetFile, true); } }
static string ValidateUnityGame(SteamGameData game, uint steamAppId) { if (game.Id != steamAppId) { return($"Steam id in game.props {game.Id} does not match {steamAppId}"); } if (!File.Exists(Path.Combine(game.InstallDir, "UnityPlayer.dll"))) { return("Steam game is not a Unity game."); } if (!Directory.Exists(game.ManagedDllsDir)) { throw new Exception("Game is missing Unity managed dlls directory."); } return(null); }
public static async Task Main(string[] args) { if (SteamAppId <= 0) { throw new Exception("SteamAppId environment variable must be set and be valid"); } Console.WriteLine($"Building mod for Steam game with id {SteamAppId}"); SteamGameData game = await Task.Factory.StartNew(() => EnsureSteamGame(SteamAppId)).ConfigureAwait(false); Console.WriteLine($"Found game at {game.InstallDir}"); await Task.WhenAll( Task.Factory.StartNew(() => EnsureBepInExAsync(game.InstallDir)).Unwrap(), Task.Factory.StartNew(() => EnsurePublicizedAssemblies(game))) .ConfigureAwait(false); }
private static async Task EnsureUnstrippedMonoAssembliesAsync(SteamGameData game) { if (Directory.Exists(Path.Combine(game.InstallDir, UnstrippedDllsFolderName))) { Console.WriteLine("Unstripped Mono Assemblies are already installed."); return; } // Detect Unity Engine version the game is using. var unityVersionUsedByGame = new Version(FileVersionInfo .GetVersionInfo(Path.Combine(game.InstallDir, "UnityPlayer.dll")) .FileVersion).ToString(3); // Create Unstripped dlls directory in game directory var targetDir = Path.Combine(game.InstallDir, UnstrippedDllsFolderName); Directory.CreateDirectory(targetDir); // Download unstripped dlls var dllsZip = Path.Combine(Utils.GeneratedOutputDir, $@"{unityVersionUsedByGame}.zip"); if (!File.Exists(dllsZip)) { using var client = new WebClient(); await client.DownloadFileTaskAsync( UnityUnstrippedDllsRepo.Replace("{VERSION}", unityVersionUsedByGame), dllsZip); } // Extract unstripped dlls to unstripped dlls directory in game directory using var zipReader = ZipFile.OpenRead(dllsZip); foreach (var entry in zipReader.Entries) { var fileName = Path.GetFileName(entry.FullName); if (string.IsNullOrWhiteSpace(fileName)) { continue; } var targetFile = Path.Combine(targetDir, fileName); entry.ExtractToFile(targetFile, true); } }
private static void EnsurePublicizedAssemblies(SteamGameData game) { if (SkipPublicizer) { Console.WriteLine("Skipping Assembly Publicizer, execute this manually."); return; } if (Directory.Exists(Path.Combine(Utils.GeneratedOutputDir, "publicized_assemblies"))) { Console.WriteLine("Assemblies are already publicized."); return; } var dllsToPublicize = Directory.GetFiles(game.ManagedDllsDir, "assembly_*.dll"); foreach (var publicizedDll in Publicizer.Execute(dllsToPublicize, "_publicized", Path.Combine(Utils.GeneratedOutputDir, "publicized_assemblies"))) { Console.WriteLine($"Wrote publicized dll: {publicizedDll}"); } }
/// <summary> /// Finds game install directory by iterating through all the steam game libraries configured and finding the appid /// that matches. /// </summary> /// <param name="steamAppId"></param> /// <returns></returns> /// <exception cref="Exception">If steam is not installed or game could not be found.</exception> public static SteamGameData FindGame(uint steamAppId) { var steamPath = (string)ReadRegistrySafe("Software\\Valve\\Steam", "SteamPath"); if (string.IsNullOrEmpty(steamPath)) { try { steamPath = (string)ReadRegistrySafe(@"SOFTWARE\Valve\Steam", "InstallPath", RegistryHive.LocalMachine); } finally { if (string.IsNullOrEmpty(steamPath)) { throw new Exception("Steam could not be found. Check if it is installed."); } } } var appsPath = Path.Combine(steamPath, "steamapps"); // Test main steamapps. SteamGameData game = GameDataFromAppManifest(Path.Combine(appsPath, $"appmanifest_{steamAppId}.acf")); if (game == null) { // Test steamapps on other drives (as defined by Steam). game = SearchAllInstallations(Path.Combine(appsPath, "libraryfolders.vdf"), steamAppId); if (game == null) { throw new Exception($"Steam game with id {steamAppId} is not installed."); } } return(game); }
private static void EnsureUnityDoorstopConfig(SteamGameData game) { // Change UnityDoorstop configuration to make it override game dlls with unstripped dlls. var unityDoorstopConfig = Path.Combine(game.InstallDir, "doorstop_config.ini"); if (!File.Exists(unityDoorstopConfig)) { throw new FileNotFoundException("UnityDoorstop config file not found", unityDoorstopConfig); } var configContent = File.ReadAllLines(unityDoorstopConfig).ToList(); var requiredValues = new Dictionary <string, string> { { "dllSearchPathOverride", UnstrippedDllsFolderName }, { "targetAssembly", @"BepInEx\core\BepInEx.Preloader.dll" } }; for (var i = 0; i < configContent.Count; i++) { var match = iniRegex.Match(configContent[i]); if (!match.Success) { continue; } if (!requiredValues.TryGetValue(match.Groups[1].Value, out var value)) { continue; } configContent[i] = $"{match.Groups[1].Value}={value}"; requiredValues.Remove(match.Groups[1].Value); } foreach (var pair in requiredValues) { configContent.Add($"{pair.Key}={pair.Value}"); } File.WriteAllLines(unityDoorstopConfig, configContent); }