public static void InitializeAndFindAssetWriters()
        {
            foreach (Assembly assembly in AssemblyHelper.GetAllUserAssemblies())
            {
                foreach (var type in AssemblyHelper.GetTypesWithInterface(assembly, typeof(IAssetWriter)))
                {
                    if (type.IsAbstract || type.ContainsGenericParameters)
                    {
                        continue;
                    }

                    IAssetWriter writer = Activator.CreateInstance(type) as IAssetWriter;
                    foreach (string extension in writer.GetAssociatedInputExtensions())
                    {
                        if (!extensionToAssetWriter.ContainsKey(extension))
                        {
                            extensionToAssetWriter.Add(extension, writer);
                        }
                        else
                        {
                            Console.WriteLine($"Conflicting filename extension {extension} between {extensionToAssetWriter[extension].GetType().Name} and {type.Name}. Using {extensionToAssetWriter[extension].GetType().Name}.");
                        }
                    }
                }
            }
        }
        public static void AddAssembly(Assembly assembly)
        {
            foreach (var type in AssemblyHelper.GetTypesWithInterface(assembly, typeof(IAssetWriter)))
            {
                if (type.IsAbstract || type.ContainsGenericParameters)
                {
                    continue;
                }

                IAssetWriter writer = Activator.CreateInstance(type) as IAssetWriter;
                foreach (string filename in writer.GetAssociatedInputExtensions())
                {
                    if (!extensionToAssetWriter.ContainsKey(filename))
                    {
                        extensionToAssetWriter.Add(filename, writer);
                    }
                }
            }
        }
Exemplo n.º 3
0
        public void Unpack(string call, string[] parameter)
        {
            IAssetWriter[] assetWriters =
            {
                new MapWriter(),
                new SpriteFontWriter(),
                new TextureWriter(),
                new XmlSourceWriter(),
                new DataWriter() // check last due to more expensive CanWrite
            };

            Platform platform = EnvironmentUtility.DetectPlatform();
            string   gamePath = Constants.ExecutionPath;

            this.Monitor.Log($"Found game folder: {gamePath}.", LogLevel.Info);
            this.Monitor.Log("");

            // get import/export paths
            string contentPath = Path.Combine(gamePath, "Content");
            string exportPath  = Path.Combine(gamePath, "Content (unpacked)");

            // symlink files on Linux/Mac
            if (platform == Platform.Linux || platform == Platform.Mac)
            {
                Process.Start("ln", $"-sf \"{Path.Combine(gamePath, "Content")}\"");
                Process.Start("ln", $"-sf \"{Path.Combine(gamePath, "lib")}\"");
                Process.Start("ln", $"-sf \"{Path.Combine(gamePath, "lib64")}\"");
            }

            ConsoleProgressBar progressBar;

            Console.ForegroundColor = ConsoleColor.DarkGray;
            Game1 game = Game1.game1;

            this.Monitor.Log("");
            this.Monitor.Log("Unpacking files...", LogLevel.Info);

            // collect files
            DirectoryInfo contentDir = new DirectoryInfo(contentPath);

            FileInfo[] files = contentDir.EnumerateFiles("*.xnb", SearchOption.AllDirectories).ToArray();
            progressBar = new ModConsoleProgressBar(this.Monitor, files.Length, Console.Title);

            // write assets
            foreach (FileInfo file in files)
            {
                // prepare paths
                string assetName      = file.FullName.Substring(contentPath.Length + 1, file.FullName.Length - contentPath.Length - 5); // remove root path + .xnb extension
                string fileExportPath = Path.Combine(exportPath, assetName);
                Directory.CreateDirectory(Path.GetDirectoryName(fileExportPath));

                // show progress bar
                progressBar.Increment();
                progressBar.Print(assetName);

                // read asset
                object asset = null;
                try
                {
                    asset = game.Content.Load <object>(assetName);
                }
                catch (Exception ex)
                {
                    this.Monitor.Log($"{assetName} => read error: {ex.Message}", LogLevel.Error);
                    continue;
                }

                // write asset
                try
                {
                    // get writer
                    IAssetWriter writer = assetWriters.FirstOrDefault(p => p.CanWrite(asset));

                    // write file
                    if (writer == null)
                    {
                        this.Monitor.Log($"{assetName}.xnb ({asset.GetType().Name}) isn't a supported asset type.", LogLevel.Warn);
                        File.Copy(file.FullName, $"{fileExportPath}.xnb", overwrite: true);
                    }
                    else if (!writer.TryWriteFile(asset, fileExportPath, assetName, platform, out string writeError))
                    {
                        this.Monitor.Log($"{assetName}.xnb ({asset.GetType().Name}) could not be saved: {writeError}.", LogLevel.Warn);
                        File.Copy(file.FullName, $"{fileExportPath}.xnb", overwrite: true);
                    }
                }
                catch (Exception ex)
                {
                    this.Monitor.Log($"{assetName} => export error: {ex.Message}", LogLevel.Error);
                }
                finally
                {
                    game.Content.Unload();
                }
            }

            this.Monitor.Log($"Done! Unpacked files to {exportPath}.", LogLevel.Info);
        }
Exemplo n.º 4
0
        /// <summary>Unpack all assets in the content folder and store them in the output folder.</summary>
        /// <param name="game">The game instance through which to unpack files, or <c>null</c> to launch a temporary internal instance.</param>
        /// <param name="gamePath">The absolute path to the game folder, or <c>null</c> to auto-detect it.</param>
        /// <param name="getLogger">Get a custom progress update logger, or <c>null</c> to use the default console logging. Receives the unpack context and default logger as arguments.</param>
        /// <param name="showPressAnyKeyToExit">Whether the default logger should show a 'press any key to exit' prompt when it finishes.</param>
        public static void Run(GameRunner game = null, string gamePath = null, Func <IUnpackContext, IProgressLogger, IProgressLogger> getLogger = null, bool showPressAnyKeyToExit = true)
        {
            // init logging
            UnpackContext   context = new UnpackContext();
            IProgressLogger logger  = new DefaultConsoleLogger(context, showPressAnyKeyToExit);

            try
            {
                // get override logger
                if (getLogger != null)
                {
                    logger = getLogger(context, logger);
                }

                // start timer
                Stopwatch timer = new Stopwatch();
                timer.Start();

                // get asset writers
                var assetWriters = new IAssetWriter[]
                {
                    new MapWriter(),
                    new SpriteFontWriter(),
                    new TextureWriter(),
                    new XmlSourceWriter(),
                    new DataWriter() // check last due to more expensive CanWrite
                };

                // get paths
                var platform = new PlatformContext();
                {
                    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;
                    }
                }
                context.ExportPath = Path.Combine(context.GamePath, "Content (unpacked)");
                logger.OnStepChanged(ProgressStep.GameFound, $"Found game folder: {context.GamePath}.");

                // symlink files on Linux/Mac
                if (platform.Is(Platform.Linux, Platform.Mac))
                {
                    foreach (string dirName in new[] { "lib", "lib64" })
                    {
                        string fullPath = Path.Combine(context.GamePath, dirName);
                        if (!Directory.Exists(dirName))
                        {
                            Process.Start("ln", $"-sf \"{fullPath}\"");
                        }
                    }
                }

                // load game instance
                bool disposeGame = false;
                if (game == null)
                {
                    logger.OnStepChanged(ProgressStep.LoadingGameInstance, "Loading game instance...");
                    game        = Program.CreateTemporaryGameInstance(platform, context.ContentPath);
                    disposeGame = true;
                }

                // unpack files
                try
                {
                    logger.OnStepChanged(ProgressStep.UnpackingFiles, "Unpacking files...");

                    // collect files
                    DirectoryInfo contentDir = new DirectoryInfo(context.ContentPath);
                    FileInfo[]    files      = contentDir.EnumerateFiles("*.xnb", SearchOption.AllDirectories).ToArray();
                    context.Files = files;

                    // write assets
                    foreach (FileInfo file in files)
                    {
                        // prepare paths
                        string assetName      = file.FullName.Substring(context.ContentPath.Length + 1, file.FullName.Length - context.ContentPath.Length - 5); // remove root path + .xnb extension
                        string relativePath   = $"{assetName}.xnb";
                        string fileExportPath = Path.Combine(context.ExportPath, assetName);
                        Directory.CreateDirectory(Path.GetDirectoryName(fileExportPath));

                        // fallback logic
                        void ExportRawXnb()
                        {
                            File.Copy(file.FullName, $"{fileExportPath}.xnb", overwrite: true);
                        }

                        // show progress bar
                        logger.OnFileUnpacking(assetName);

                        // read asset
                        object asset = null;
                        try
                        {
                            asset = game.Content.Load <object>(assetName);
                        }
                        catch (Exception ex)
                        {
                            if (platform.Platform.IsMono() && ex.Message == "This does not appear to be a MonoGame MGFX file!")
                            {
                                logger.OnFileUnpackFailed(relativePath, UnpackFailedReason.UnsupportedFileType, $"{nameof(Effect)} isn't a supported asset type."); // use same friendly error as Windows
                            }
                            else
                            {
                                logger.OnFileUnpackFailed(relativePath, UnpackFailedReason.ReadError, $"read error: {ex.Message}");
                            }
                            ExportRawXnb();
                            continue;
                        }

                        // write asset
                        try
                        {
                            // get writer
                            IAssetWriter writer = assetWriters.FirstOrDefault(p => p.CanWrite(asset));

                            // write file
                            if (writer == null)
                            {
                                logger.OnFileUnpackFailed(relativePath, UnpackFailedReason.UnsupportedFileType, $"{asset.GetType().Name} isn't a supported asset type.");
                                ExportRawXnb();
                            }
                            else if (!writer.TryWriteFile(asset, fileExportPath, assetName, platform.Platform, out string writeError))
                            {
                                logger.OnFileUnpackFailed(relativePath, UnpackFailedReason.WriteError, $"{asset.GetType().Name} file could not be saved: {writeError}.");
                                ExportRawXnb();
                            }
                        }
                        catch (Exception ex)
                        {
                            logger.OnFileUnpackFailed(relativePath, UnpackFailedReason.UnknownError, $"unhandled export error: {ex.Message}");
                        }
                        finally
                        {
                            game.Content.Unload();
                        }
                    }
                }
                finally
                {
                    if (disposeGame)
                    {
                        game.Dispose();
                    }
                }

                logger.OnStepChanged(ProgressStep.Done, $"Done! Unpacked {context.Files.Count()} files in {Program.GetHumanTime(timer.Elapsed)}.\nUnpacked into {context.ExportPath}.");
            }
            catch (Exception ex)
            {
                logger.OnFatalError($"Unhandled exception: {ex}");
            }
            finally
            {
                logger.OnEnded();
            }
        }
Exemplo n.º 5
0
        /// <summary>Unpack all assets in the content folder and store them in the output folder.</summary>
        public void Run()
        {
            // get game info
            Platform platform = EnvironmentUtility.DetectPlatform();
            string   gamePath = new ModToolkit().GetGameFolders().FirstOrDefault()?.FullName;

            if (gamePath == null)
            {
                this.PrintColor("Can't find Stardew Valley folder.", ConsoleColor.Red);
                return;
            }
            Console.WriteLine($"Found game folder: {gamePath}.");
            Console.WriteLine();

            // get import/export paths
            string contentPath = Path.Combine(gamePath, "Content");
            string exportPath  = Path.Combine(gamePath, "Content (unpacked)");

            // symlink files on Linux/Mac
            if (platform == Platform.Linux || platform == Platform.Mac)
            {
                Process.Start("ln", $"-sf \"{Path.Combine(gamePath, "Content")}\"");
                Process.Start("ln", $"-sf \"{Path.Combine(gamePath, "lib")}\"");
                Process.Start("ln", $"-sf \"{Path.Combine(gamePath, "lib64")}\"");
            }

            // load game
            ConsoleProgressBar progressBar;

            Console.WriteLine("Loading game instance...");
            Console.ForegroundColor = ConsoleColor.DarkGray;
            using (Game1 game = this.GetGameInstance(platform, contentPath))
            {
                Console.ResetColor();
                Console.WriteLine();
                Console.WriteLine("Unpacking files...");

                // collect files
                DirectoryInfo contentDir = new DirectoryInfo(contentPath);
                FileInfo[]    files      = contentDir.EnumerateFiles("*.xnb", SearchOption.AllDirectories).ToArray();
                progressBar = new ConsoleProgressBar(files.Length);

                // write assets
                foreach (FileInfo file in files)
                {
                    // prepare paths
                    string assetName      = file.FullName.Substring(contentPath.Length + 1, file.FullName.Length - contentPath.Length - 5); // remove root path + .xnb extension
                    string fileExportPath = Path.Combine(exportPath, assetName);
                    Directory.CreateDirectory(Path.GetDirectoryName(fileExportPath));

                    // show progress bar
                    progressBar.Increment();
                    progressBar.Print(assetName);

                    // read asset
                    object asset = null;
                    try
                    {
                        asset = game.Content.Load <object>(assetName);
                    }
                    catch (Exception ex)
                    {
                        progressBar.Erase();
                        this.PrintColor($"{assetName} => read error: {ex.Message}", ConsoleColor.Red);
                        continue;
                    }

                    // write asset
                    try
                    {
                        // get writer
                        IAssetWriter writer = this.AssetWriters.FirstOrDefault(p => p.CanWrite(asset));

                        // write file
                        if (writer == null)
                        {
                            progressBar.Erase();
                            this.PrintColor($"{assetName}.xnb ({asset.GetType().Name}) isn't a supported asset type.", ConsoleColor.DarkYellow);
                            File.Copy(file.FullName, $"{fileExportPath}.xnb", overwrite: true);
                        }
                        else if (!writer.TryWriteFile(asset, fileExportPath, assetName, platform, out string writeError))
                        {
                            progressBar.Erase();
                            this.PrintColor($"{assetName}.xnb ({asset.GetType().Name}) could not be saved: {writeError}.", ConsoleColor.DarkYellow);
                            File.Copy(file.FullName, $"{fileExportPath}.xnb", overwrite: true);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine($"{assetName} => export error: {ex.Message}");
                        Console.ResetColor();
                    }
                    finally
                    {
                        game.Content.Unload();
                    }
                }
            }

            progressBar.Erase();
            Console.WriteLine($"Done! Unpacked files to {exportPath}.");
        }