public CommandList LinkAirModifications(IReadOnlyList <Modification> modifications) { DefaultCommandList commandList = new DefaultCommandList(); foreach (var modification in modifications) { var resolutionTableComponent = modification.GetComponent <LeagueResolutionTableComponent>(); var resolutionTable = resolutionTableComponent.Table; var contentPath = Path.Combine(modification.RepositoryPath, "content"); var contentDirectory = fileSystemProxy.GetDirectoryInfo(contentPath); var contentFiles = contentDirectory.EnumerateFiles("*", SearchOption.AllDirectories); var contentRelativePaths = contentFiles.Select(f => f.FullName.Substring(contentPath.Length + 1)); var objectsPath = Path.Combine(modification.RepositoryPath, "objects"); foreach (var contentRelativePath in contentRelativePaths) { LeagueResolutionTableValue resolutionTableValue; if (!resolutionTable.TryGetValue(contentRelativePath, out resolutionTableValue)) { logger?.Warn($"Not linking {contentRelativePath}: resolution table lookup failed"); continue; } if (resolutionTableValue.Target != LeagueModificationTarget.Client) { logger?.Warn($"Not linking {contentRelativePath}: does not target air client."); continue; } string replacedPath = resolutionTableValue.ResolvedPath; string replacementPath = Path.Combine(contentPath, contentRelativePath); commandList.Add(commandFactory.CreateFileRedirectionCommand(replacedPath, replacementPath)); } } return(commandList); }
public CommandList LinkGameModifications(IReadOnlyList <Modification> modifications) { var archiveLoader = new RiotArchiveLoader(leagueConfiguration.RadsPath); Dictionary <uint, List <KeyValuePair <RiotArchive, SectorCollection> > > archivePairsById = new Dictionary <uint, List <KeyValuePair <RiotArchive, SectorCollection> > >(); var riotSolution = riotSolutionLoader.Load(leagueConfiguration.RadsPath, RiotProjectType.GameClient); var gameProject = riotSolution.ProjectsByType[RiotProjectType.GameClient]; var gameManifest = gameProject.ReleaseManifest; foreach (var modification in modifications) { var resolutionTableComponent = modification.GetComponent <LeagueResolutionTableComponent>(); var resolutionTable = resolutionTableComponent.Table; var contentPath = Path.Combine(modification.RepositoryPath, "content"); var contentDirectory = fileSystemProxy.GetDirectoryInfo(contentPath); var contentFiles = contentDirectory.EnumerateFiles("*", SearchOption.AllDirectories); var contentRelativePaths = contentFiles.Select(f => f.FullName.Substring(contentPath.Length + 1)); var objectsPath = Path.Combine(modification.RepositoryPath, "objects"); foreach (var contentRelativePath in contentRelativePaths) { LeagueResolutionTableValue resolutionTableValue; if (!resolutionTable.TryGetValue(contentRelativePath, out resolutionTableValue)) { logger?.Warn($"Not linking {contentRelativePath}: resolution table lookup failed"); continue; } if (resolutionTableValue.Target != LeagueModificationTarget.Game) { logger?.Warn($"Not linking {contentRelativePath}: does not target game client."); continue; } var manifestEntry = gameManifest.Root.GetRelativeOrNull <ReleaseManifestFileEntry>(resolutionTableValue.ResolvedPath); if (manifestEntry == null) { logger?.Warn($"Not linking {contentRelativePath}: could not find {resolutionTableValue.ResolvedPath} in manifest."); continue; } List <KeyValuePair <RiotArchive, SectorCollection> > archivePairs; if (!archivePairsById.TryGetValue(manifestEntry.ArchiveId, out archivePairs)) { archivePairs = new List <KeyValuePair <RiotArchive, SectorCollection> >(); IReadOnlyList <RiotArchive> archives; if (!archiveLoader.TryLoadArchives(manifestEntry.ArchiveId, out archives)) { logger?.Error($"Not linking {contentRelativePath}: could not load archives for {manifestEntry.ArchiveId}!"); continue; } archives.ForEach(archive => { var datLength = new FileInfo(archive.DatFilePath).Length; SectorCollection sectorCollection = new SectorCollection(); sectorCollection.AssignSector(new SectorRange(0, datLength), new FileSector(archive.DatFilePath, 0, datLength)); archivePairs.Add(archive.PairValue(sectorCollection)); }); archivePairsById.Add(manifestEntry.ArchiveId, archivePairs); } var rafPath = RAFUtil.FormatPathToRAFPath(resolutionTableValue.ResolvedPath); RAFFileListEntry rafEntry = null; SectorCollection sectors = null; foreach (var archivePair in archivePairs) { rafEntry = archivePair.Key.GetDirectoryFile().GetFileList().GetFileEntryOrNull(rafPath); if (rafEntry != null) { sectors = archivePair.Value; break; } } if (rafEntry == null) { logger?.Warn($"Not linking {contentRelativePath}: could not find {resolutionTableValue.ResolvedPath} in {manifestEntry.ArchiveId} archives."); continue; } var vfmEndOffset = sectors.EnumerateSectorPairs().Last().Key.endExclusive; sectors.DeleteRange(rafEntry.FileOffset, rafEntry.FileOffset + rafEntry.FileSize); var objectsFilePath = Path.Combine(objectsPath, contentRelativePath); var objectsFileLength = new FileInfo(objectsFilePath).Length; rafEntry.FileOffset = (uint)vfmEndOffset; rafEntry.FileSize = (uint)objectsFileLength; sectors.AssignSector(new SectorRange(vfmEndOffset, vfmEndOffset + objectsFileLength), new FileSector(objectsFilePath, 0, objectsFileLength)); var originalFileLength = new FileInfo(Path.Combine(contentPath, contentRelativePath)).Length; manifestEntry.CompressedSize = (uint)objectsFileLength; manifestEntry.DecompressedSize = (uint)originalFileLength; logger?.Warn("Successfully linked " + resolutionTableValue.ResolvedPath + " in archive " + manifestEntry.ArchiveId + "."); } } var commandList = new DefaultCommandList(); var versionStringUtilities = new VersionStringUtilities(); var tempDir = temporaryFileService.AllocateTemporaryDirectory(TimeSpan.FromMinutes(1)); logger?.Info("Allocated temporary directory " + tempDir); foreach (var archivePair in archivePairsById) { string versionString = versionStringUtilities.GetVersionString(archivePair.Key); foreach (var archiveData in archivePair.Value) { // Get archive name (e.g. archive_2.raf or archive_12930813.raf) string archiveFileName = archiveData.Key.RAFFilePath.With(x => x.Substring(x.LastIndexOfAny(new[] { '/', '\\' }) + 1)); // Serialize the VFM var vfmSerializer = new SectorCollectionSerializer(); var vfmFileName = versionString + "/" + archiveFileName + ".dat.vfm"; var vfmPath = temporaryFileService.AllocateTemporaryFile(tempDir, vfmFileName); using (var vfmFileStream = File.Open(vfmPath, FileMode.Create, FileAccess.Write, FileShare.None)) using (var writer = new BinaryWriter(vfmFileStream)) { vfmSerializer.Serialize(archiveData.Value, writer); commandList.Add(commandFactory.CreateFileRemappingCommand(archiveData.Key.DatFilePath, vfmFileStream.Name)); } logger?.Info("Wrote VFM " + vfmFileName + " to " + tempDir); // Serialize the RAF var rafFileName = versionString + "/" + archiveFileName; var rafPath = temporaryFileService.AllocateTemporaryFile(tempDir, rafFileName); using (var rafFileStream = File.Open(rafPath, FileMode.Create, FileAccess.Write, FileShare.None)) using (var writer = new BinaryWriter(rafFileStream)) { writer.Write(archiveData.Key.GetDirectoryFile().GetBytes()); commandList.Add(commandFactory.CreateFileRedirectionCommand(archiveData.Key.RAFFilePath, rafFileStream.Name)); } logger?.Info("Wrote RAF " + rafFileName + " to " + tempDir); } } // Serialize the Release Manifest var manifestPath = temporaryFileService.AllocateTemporaryFile(tempDir, "releasemanifest"); using (var manifestFileStream = File.Open(manifestPath, FileMode.Create, FileAccess.Write, FileShare.None)) using (var writer = new BinaryWriter(manifestFileStream)) { new ReleaseManifestWriter(gameManifest).Save(writer); commandList.Add(commandFactory.CreateFileRedirectionCommand(gameManifest.Path, manifestFileStream.Name)); } logger?.Info("Wrote release manifest to " + tempDir); return(commandList); }