예제 #1
0
        /// <inheritdoc />
        public VirtualFileSystemEntry Build(VirtualDirectory root, string hostOutputPath = null, string gameName = null, bool useCompression = false, bool useExtracted = false)
        {
            if (root == null)
            {
                throw new ArgumentNullException(nameof(root));
            }

            Log.Builder.Info($"Building {Game} Mod");
            if (hostOutputPath != null)
            {
                Log.Builder.Info($"Output directory: {hostOutputPath}");
            }

            // Get game config
            var config = ConfigStore.Get(Game) as Persona34GameConfig ?? throw new InvalidOperationException("Game config is missing.");

            if (string.IsNullOrWhiteSpace(config.DvdRootOrIsoPath))
            {
                throw new InvalidConfigException("Dvd root path/ISO path is not specified.");
            }

            // Get files
            Log.Builder.Trace($"DvdRootOrIsoPath = {config.DvdRootOrIsoPath}");
            var dvdRootDirectory = Persona34Common.GetRootDirectory(config, out var isoFileSystem);

            // Find system config
            var systemConfigFile = dvdRootDirectory["SYSTEM.CNF"] as VirtualFile ?? throw new MissingFileException("SYSTEM.CNF is missing from the file source.");

            string executablePath;

            using (var systemConfigStream = systemConfigFile.Open())
            {
                bool leaveOpen = isoFileSystem == null;
                executablePath = Ps2SystemConfig.GetExecutablePath(systemConfigStream, leaveOpen, true);
            }

            if (executablePath == null)
            {
                throw new MissingFileException("Executable file path is not specified in SYSTEM.CNF; Unable to locate executable file.");
            }

            Log.Builder.Info($"Executable path: {executablePath}");

            var executableFile = ( VirtualFile )dvdRootDirectory[executablePath] ?? throw new MissingFileException("The executable file is missing from the dvd root file source.");

            // Some basic checks have been done, let's start generating the cvms
            var dvdRootDirectoryPath = hostOutputPath ?? Path.Combine(Path.GetTempPath(), "Persona34ModCompilerTemp_" + Path.GetRandomFileName());

            Log.Builder.Trace($"Creating (temp?) output directory: {dvdRootDirectoryPath}");
            Directory.CreateDirectory(dvdRootDirectoryPath);

            var bgmCvmFile      = ( VirtualFile )dvdRootDirectory["BGM.CVM"];
            var bgmCvmModified  = false;
            var btlCvmFile      = ( VirtualFile )dvdRootDirectory["BTL.CVM"];
            var btlCvmModified  = false;
            var dataCvmFile     = ( VirtualFile )dvdRootDirectory["DATA.CVM"];
            var dataCvmModified = false;
            var envCvmFile      = ( VirtualFile )dvdRootDirectory["ENV.CVM"];
            var envCvmModified  = false;

            var newDvdRootDirectory = new VirtualDirectory();

            // Process mod files
            Log.Builder.Info("Processing mod files");
            foreach (var entry in root)
            {
                if (entry.EntryType == VirtualFileSystemEntryType.File)
                {
                    Log.Builder.Info($"Adding file {entry.Name} to root directory");
                    entry.MoveTo(newDvdRootDirectory, true);
                    continue;
                }

                var name      = entry.Name.ToLowerInvariant();
                var directory = ( VirtualDirectory )entry;

                switch (name)
                {
                case "bgm":
                    UpdateAndRecompileCvm(ref bgmCvmFile, directory, Path.Combine(dvdRootDirectoryPath, "bgm.cvm"), newDvdRootDirectory);
                    bgmCvmModified = true;
                    break;

                case "btl":
                    UpdateAndRecompileCvm(ref btlCvmFile, directory, Path.Combine(dvdRootDirectoryPath, "btl.cvm"), newDvdRootDirectory);
                    btlCvmModified = true;
                    break;

                case "data":
                    UpdateAndRecompileCvm(ref dataCvmFile, directory, Path.Combine(dvdRootDirectoryPath, "data.cvm"), newDvdRootDirectory);
                    dataCvmModified = true;
                    break;

                case "env":
                {
                    Log.Builder.Info("Replacing files in env.cvm");

                    if (envCvmFile == null)
                    {
                        throw new MissingFileException("Mod replaces files in env.cvm but env.cvm isn't present.");
                    }

                    UpdateAndRecompileCvm(ref envCvmFile, directory, Path.Combine(dvdRootDirectoryPath, "env.cvm"), newDvdRootDirectory);
                    envCvmModified = true;
                }
                break;

                default:
                    Log.Builder.Info($"Adding directory {entry.Name} to root directory");
                    entry.MoveTo(newDvdRootDirectory, true);
                    break;
                }
            }

            // Patch executable
            var executableFilePath = executableFile.SaveToHost(dvdRootDirectoryPath);

            Log.Builder.Info($"Patching executable");
            Log.Builder.Trace($"Executable file path: {executableFilePath}");
            if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
            {
                if (bgmCvmModified)
                {
                    PatchExecutable(executableFilePath, bgmCvmFile.HostPath);
                }

                if (btlCvmModified)
                {
                    PatchExecutable(executableFilePath, btlCvmFile.HostPath);
                }

                if (dataCvmModified)
                {
                    PatchExecutable(executableFilePath, dataCvmFile.HostPath);
                }

                if (envCvmModified)
                {
                    PatchExecutable(executableFilePath, envCvmFile.HostPath);
                }
            }
            else
            {
                if (bgmCvmModified)
                {
                    PatchExecutableLinux(executableFilePath, bgmCvmFile.HostPath);
                }

                if (btlCvmModified)
                {
                    PatchExecutableLinux(executableFilePath, btlCvmFile.HostPath);
                }

                if (dataCvmModified)
                {
                    PatchExecutableLinux(executableFilePath, dataCvmFile.HostPath);
                }

                if (envCvmModified)
                {
                    PatchExecutableLinux(executableFilePath, envCvmFile.HostPath);
                }
            }

            executableFile = VirtualFile.FromHostFile(executableFilePath);
            executableFile.MoveTo(newDvdRootDirectory, true);

            if (hostOutputPath != null)
            {
                Log.Builder.Info($"Copying files to output directory (might take a while): {hostOutputPath}");
                newDvdRootDirectory.SaveToHost(hostOutputPath);
            }

            if (hostOutputPath != null && isoFileSystem != null)
            {
                isoFileSystem.Dispose();
            }

            Log.Builder.Info("Done");

            return(newDvdRootDirectory);
        }
예제 #2
0
        /// <summary>
        /// Build a PS2 bootable iso from the files in the root directory.
        /// If output path is specified, it is expected to be a path to the output ISO.
        /// Otherwise, if present, the root's name will be used as the base name for the ISO output.
        /// Requires SYSTEM.CNF and an executable file to be present in the root's file structure.
        /// </summary>
        /// <param name="root"></param>
        /// <param name="hostOutputPath"></param>
        /// <returns>PS2 bootable ISO file.</returns>
        public VirtualFileSystemEntry Build(VirtualDirectory root, string hostOutputPath = null, string gameName = null, bool useCompression = false, bool useExtracted = false)
        {
            if (root == null)
            {
                throw new ArgumentNullException(nameof(root));
            }

            // Hack: get rid of root's name and restore it later
            // This is so we can use FullName with the builder without having to strip the root's name
            var rootName = root.Name;

            root.Name = string.Empty;

            // Find system.cnf first, as we need it to get the executable file path
            var systemCnfFile = root["SYSTEM.CNF"] as VirtualFile ?? throw new MissingFileException("SYSTEM.CNF is missing.");

            var executablePath = Ps2SystemConfig.GetExecutablePath(systemCnfFile.Open(), false, true) ??
                                 throw new MissingFileException(
                                           "Executable file path is not specified in SYSTEM.CNF; Unable to locate executable file.");

            var executableFile = root[executablePath] as VirtualFile ??
                                 throw new MissingFileException($"Executable file {executablePath} is missing.");

            var isoBuilder = new CDBuilder
            {
                UseJoliet = false,
                UpdateIsolinuxBootTable = false,
                VolumeIdentifier        = "AMICITIA"
            };

            // system.cnf first
            isoBuilder.AddFile(systemCnfFile.Name, systemCnfFile);

            // executable second
            isoBuilder.AddFile(executablePath, executableFile);

            // And then the rest
            AddToIsoBuilderRecursively(isoBuilder, root, executablePath);

            // HACK: Restore root name
            root.Name = rootName;

            if (hostOutputPath != null)
            {
                isoBuilder.Build(hostOutputPath);
                return(VirtualFile.FromHostFile(hostOutputPath));
            }
            else
            {
                string isoName;
                if (!string.IsNullOrWhiteSpace(root.Name))
                {
                    isoName = root.Name + ".iso";
                }
                else
                {
                    isoName = "PS2DVD.iso";
                }

                var stream = isoBuilder.Build();
                return(new VirtualFile(null, stream, isoName));
            }
        }