/// <summary> /// Initializes a new instance of the <see cref="ARealmReversed" /> class. /// </summary> /// <param name="gameDirectory">Directory of the game installation.</param> /// <param name="storeFile">File used for storing definitions and history.</param> /// <param name="language">Initial language to use.</param> /// <param name="libraFile">Location of the Libra Eorzea database file, or <c>null</c> if it should not be used.</param> public ARealmReversed(DirectoryInfo gameDirectory, FileInfo storeFile, Language language, FileInfo libraFile) { // Fix for being referenced in a .Net Core 2.1+ application (https://stackoverflow.com/questions/50449314/ibm437-is-not-a-supported-encoding-name => https://stackoverflow.com/questions/44659499/epplus-error-reading-file) // PM> dotnet add package System.Text.Encoding.CodePages Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); _GameDirectory = gameDirectory; _Packs = new PackCollection(Path.Combine(gameDirectory.FullName, "game", "sqpack")); _GameData = new XivCollection(Packs, libraFile) { ActiveLanguage = language }; _GameVersion = File.ReadAllText(Path.Combine(gameDirectory.FullName, "game", "ffxivgame.ver")); _StateFile = storeFile; _GameData.Definition = ReadDefinition(); using (ZipFile zipFile = new ZipFile(StateFile.FullName, ZipEncoding)) { if (!zipFile.ContainsEntry(VersionFile)) { Setup(zipFile); } } _GameData.Definition.Compile(); }
public ISheet GetSheet(string name) { const string ExHPathFormat = "exd/{0}.exh"; if (_Sheets.TryGetValue(name, out var sheetRef) && sheetRef.TryGetTarget(out var sheet)) { return(sheet); } //name = FixName(name); if (!_AvailableSheets.Contains(name)) { throw new KeyNotFoundException($"Unknown sheet '{name}'"); } var exhPath = string.Format(ExHPathFormat, name); var exh = PackCollection.GetFile(exhPath); var header = CreateHeader(name, exh); sheet = CreateSheet(header); _Sheets.GetOrAdd(name, n => new WeakReference <ISheet>(sheet)).SetTarget(sheet); return(sheet); }
public ISheet GetSheet(string name) { const string ExHPathFormat = "exd/{0}.exh"; //name = FixName(name); if (!_AvailableSheets.Contains(name)) { throw new KeyNotFoundException(); } ISheet sheet; WeakReference <ISheet> sheetRef; if (_Sheets.TryGetValue(name, out sheetRef) && sheetRef.TryGetTarget(out sheet)) { return(sheet); } var exhPath = string.Format(ExHPathFormat, name); var exh = PackCollection.GetFile(exhPath); var header = CreateHeader(name, exh); sheet = CreateSheet(header); if (_Sheets.ContainsKey(name)) { _Sheets[name].SetTarget(sheet); } else { _Sheets.Add(name, new WeakReference <ISheet>(sheet)); } return(sheet); }
/// <summary> /// Update to the current version. /// </summary> /// <param name="detectDataChanges">Boolean indicating whether the update should also look for changes in data.</param> /// <param name="progress">Optional object to which update progress is reported.</param> /// <returns>Returns the <see cref="UpdateReport" /> containing all changes.</returns> /// <exception cref="InvalidOperationException">Definition is up-to-date.</exception> public UpdateReport Update(bool detectDataChanges, IProgress <UpdateProgress> progress = null) { if (DefinitionVersion == GameVersion) { throw new InvalidOperationException(); } var previousVersion = DefinitionVersion; var exdPackId = new PackIdentifier("exd", PackIdentifier.DefaultExpansion, 0); var exdPack = Packs.GetPack(exdPackId); var exdOldKeepInMemory = exdPack.KeepInMemory; exdPack.KeepInMemory = true; string tempPath = null; UpdateReport report; try { using (var zip = new ZipFile(StateFile.FullName, ZipEncoding)) { tempPath = ExtractPacks(zip, previousVersion); var previousPack = new PackCollection(Path.Combine(tempPath, previousVersion)); previousPack.GetPack(exdPackId).KeepInMemory = true; var previousDefinition = ReadDefinition(zip); var updater = new RelationUpdater(previousPack, previousDefinition, Packs, GameVersion, progress); var changes = updater.Update(detectDataChanges); report = new UpdateReport(previousVersion, GameVersion, changes); var definition = updater.Updated; StorePacks(zip); StoreDefinition(zip, definition, DefinitionFile); StoreDefinition(zip, definition, string.Format("{0}/{1}", definition.Version, DefinitionFile)); StoreReport(zip, report); zip.Save(); GameData.Definition = definition; GameData.Definition.Compile(); } } finally { if (exdPack != null) { exdPack.KeepInMemory = exdOldKeepInMemory; } if (tempPath != null) { try { Directory.Delete(tempPath, true); } catch { Console.Error.WriteLine("Failed to delete temporary directory {0}.", tempPath); } } } return(report); }
/// <summary> /// Initializes a new instance of the <see cref="XivCollection" /> class. /// </summary> /// <param name="packCollection">The <see cref="PackCollection" /> to use to access game data.</param> /// <param name="libraDatabase"><see cref="FileInfo"/> of the Libra Eorzea database file, or <c>null</c> if Libra data should be disabled.</param> public XivCollection(PackCollection packCollection, System.IO.FileInfo libraDatabase) : base(packCollection) { if (libraDatabase != null && libraDatabase.Exists) { const string LibraConnectionStringFormat = @"metadata=res://*/Libra.LibraModel.csdl|res://*/Libra.LibraModel.ssdl|res://*/Libra.LibraModel.msl;provider=System.Data.SQLite.EF6;provider connection string='data source=""{0}""'"; string connStr = string.Format(LibraConnectionStringFormat, libraDatabase.FullName); _Libra = new Libra.Entities(connStr); } }
private void BuildIndex() { var exRoot = PackCollection.GetFile("exd/root.exl"); var available = new List <string>(); using (var ms = new MemoryStream(exRoot.GetData())) { using (var s = new StreamReader(ms, Encoding.ASCII)) { s.ReadLine(); // EXLT,2 while (!s.EndOfStream) { var line = s.ReadLine(); if (string.IsNullOrWhiteSpace(line)) { continue; } var split = line.Split(','); if (split.Length != 2) { continue; } // TODO: Had problem handling negative numbers. // I'm not sure if it is due to .net core's int.Parse or // if it is another different from .net core that makes // this numbers negative.. keeping this for the moment var format = new NumberFormatInfo(); format.NegativeSign = "-"; format.NumberNegativePattern = 1; format.NumberDecimalSeparator = "."; var name = split[0]; var id = int.Parse(split[1], System.Globalization.NumberStyles.AllowLeadingSign, format); available.Add(name); if (id >= 0) { _SheetIdentifiers.Add(id, name); } } } } _AvailableSheets = new HashSet <string>(available); }
/// <summary> /// Initializes a new instance of the <see cref="ARealmReversed" /> class. /// </summary> /// <param name="gameDirectory">Directory of the game installation.</param> /// <param name="storeFile">File used for storing definitions and history.</param> /// <param name="language">Initial language to use.</param> /// <param name="libraFile">Location of the Libra Eorzea database file, or <c>null</c> if it should not be used.</param> public ARealmReversed(DirectoryInfo gameDirectory, FileInfo storeFile, Language language, FileInfo libraFile) { _GameDirectory = gameDirectory; _Packs = new PackCollection(Path.Combine(gameDirectory.FullName, "game", "sqpack")); _GameData = new XivCollection(Packs, libraFile) { ActiveLanguage = language }; _GameVersion = File.ReadAllText(Path.Combine(gameDirectory.FullName, "game", "ffxivgame.ver")); _StateFile = storeFile; using (var zipFile = new ZipFile(StateFile.FullName, ZipEncoding)) { if (zipFile.ContainsEntry(VersionFile)) { RelationDefinition fsDef = null, zipDef = null; DateTime fsMod = DateTime.MinValue, zipMod = DateTime.MinValue; if (!TryGetDefinitionVersion(zipFile, GameVersion, out zipDef, out zipMod)) { zipDef = ReadDefinition(zipFile, DefinitionFile, out zipMod); } if (!TryGetDefinitionFromFileSystem(out fsDef, out fsMod)) { fsDef = null; } if (fsDef != null && fsMod > zipMod) { fsDef.Version = GameVersion; _GameData.Definition = fsDef; StoreDefinition(zipFile, fsDef, DefinitionFile); zipFile.Save(); } else { _GameData.Definition = zipDef; } } else { _GameData.Definition = Setup(zipFile); } } _GameData.Definition.Compile(); }
public RelationUpdater(PackCollection previousPacks, RelationDefinition previousDefinition, PackCollection updatedPacks, string updatedVersion, IProgress <UpdateProgress> progress) { _Progress = progress ?? new NullProgress(); _Previous = new RelationalExCollection(previousPacks); Previous = previousDefinition; _Updated = new RelationalExCollection(updatedPacks); Updated = new RelationDefinition { Version = updatedVersion }; _Previous.ActiveLanguage = UsedLanguage; _Updated.ActiveLanguage = UsedLanguage; }
/// <summary> /// Get the model for a specific QWord, character type, and the current <see cref="EquipSlot" />. /// </summary> /// <param name="key">The identifier of the model.</param> /// <param name="characterType">Character type to get the model for.</param> /// <param name="materialVersion">When this method returns, contains the variant contained within <c>key</c>.</param> /// <returns>Returns the <see cref="Model" /> for the specified <c>key</c> and <c>characterType</c>.</returns> public ModelDefinition GetModel(Quad key, int characterType, out Graphics.ImcVariant variant) { variant = Graphics.ImcVariant.Default; if (!ModelHelpers.TryGetValue(Key, out ModelHelper helper)) { return(null); } if (helper == null) { return(null); } PackCollection packs = Collection.Collection.PackCollection; int variantIndex = (int)((key.ToInt64() >> (helper.VariantIndexWord * 16)) & 0xFFFF); string imcPath = string.Format(helper.ImcFileFormat, key.Value1, key.Value2, key.Value3, key.Value4, characterType); if (!packs.TryGetFile(imcPath, out File imcBase)) { return(null); } ImcFile imc = new Graphics.ImcFile(imcBase); variant = imc.GetVariant(helper.ImcPartKey, variantIndex); IO.File modelBase = null; while (!packs.TryGetFile(string.Format(helper.ModelFileFormat, key.Value1, key.Value2, key.Value3, key.Value4, characterType), out modelBase) && CharacterTypeFallback.TryGetValue(characterType, out characterType)) { } ModelFile asModel = modelBase as Graphics.ModelFile; if (asModel == null) { return(null); } return(asModel.GetModelDefinition()); }
/// <summary> /// Initializes a new instance of the <see cref="ARealmReversed" /> class. /// </summary> /// <param name="gameDirectory">Directory of the game installation.</param> /// <param name="storeFile">File used for storing definitions and history.</param> /// <param name="language">Initial language to use.</param> /// <param name="libraFile">Location of the Libra Eorzea database file, or <c>null</c> if it should not be used.</param> public ARealmReversed(DirectoryInfo gameDirectory, FileInfo storeFile, Language language, FileInfo libraFile) { _GameDirectory = gameDirectory; _Packs = new PackCollection(Path.Combine(gameDirectory.FullName, "game", "sqpack")); _GameData = new XivCollection(Packs, libraFile) { ActiveLanguage = language }; _GameVersion = File.ReadAllText(Path.Combine(gameDirectory.FullName, "game", "ffxivgame.ver")); _StateFile = storeFile; _GameData.Definition = ReadDefinition(); using (var zipFile = new ZipFile(StateFile.FullName, ZipEncoding)) { if (!zipFile.ContainsEntry(VersionFile)) { Setup(zipFile); } } _GameData.Definition.Compile(); }
private void BuildIndex() { var exRoot = PackCollection.GetFile("exd/root.exl"); var available = new List <string>(); using (var ms = new MemoryStream(exRoot.GetData())) { using (var s = new StreamReader(ms, Encoding.ASCII)) { s.ReadLine(); // EXLT,2 while (!s.EndOfStream) { var line = s.ReadLine(); if (string.IsNullOrWhiteSpace(line)) { continue; } var split = line.Split(','); if (split.Length != 2) { continue; } var name = split[0]; var id = int.Parse(split[1]); available.Add(name); if (id >= 0) { _SheetIdentifiers.Add(id, name); } } } } _AvailableSheets = new HashSet <string>(available); }
public ExCollection(PackCollection packCollection) { PackCollection = packCollection; BuildIndex(); }
/// <summary> /// Initializes a new instance of the <see cref="XivCollection" /> class. /// </summary> /// <param name="packCollection">The <see cref="PackCollection" /> to use to access game data.</param> public XivCollection(PackCollection packCollection) : this(packCollection, null) { }
/// <summary> /// Update to the current version. /// </summary> /// <param name="detectDataChanges">Boolean indicating whether the update should also look for changes in data.</param> /// <param name="progress">Optional object to which update progress is reported.</param> /// <returns>Returns the <see cref="UpdateReport" /> containing all changes.</returns> /// <exception cref="InvalidOperationException">Definition is up-to-date.</exception> public UpdateReport Update(bool detectDataChanges, IProgress <UpdateProgress> progress = null) { if (DefinitionVersion == GameVersion) { throw new InvalidOperationException(); } var previousVersion = DefinitionVersion; var exdPackId = new PackIdentifier("exd", PackIdentifier.DefaultExpansion, 0); var exdPack = Packs.GetPack(exdPackId); var exdOldKeepInMemory = exdPack.KeepInMemory; exdPack.KeepInMemory = true; string tempPath = null; UpdateReport report; try { using (var zip = new ZipFile(StateFile.FullName, ZipEncoding)) { tempPath = ExtractPacks(zip, previousVersion); var previousPack = new PackCollection(Path.Combine(tempPath, previousVersion)); previousPack.GetPack(exdPackId).KeepInMemory = true; RelationDefinition previousDefinition; if (previousVersion == _GameData.Definition.Version) { // Override previous definition when current definition version matches. // Definitions may have changed since this was recorded and we want to compare that. previousDefinition = _GameData.Definition; } else { // Otherwise, read the previous definition from the zip. previousDefinition = ReadDefinition(zip, previousVersion); } var updater = new RelationUpdater(previousPack, previousDefinition, Packs, GameVersion, progress); var changes = updater.Update(detectDataChanges); report = new UpdateReport(previousVersion, GameVersion, changes); var definition = updater.Updated; StorePacks(zip); StoreDefinitionInZip(zip, definition); StoreDefinitionOnFilesystem(definition, ""); if (Debugger.IsAttached) { // Little QOL path - when updating with the debugger attached, // also write to the project definitions path so no need to copy // them manually afterward. var projectDefinitionsPath = "../../../SaintCoinach"; if (Directory.Exists(projectDefinitionsPath)) { StoreDefinitionOnFilesystem(definition, projectDefinitionsPath); } } StoreReport(zip, report); UpdateVersion(zip); zip.Save(); GameData.Definition = definition; GameData.Definition.Compile(); } } finally { if (exdPack != null) { exdPack.KeepInMemory = exdOldKeepInMemory; } if (tempPath != null) { try { Directory.Delete(tempPath, true); } catch { Console.Error.WriteLine("Failed to delete temporary directory {0}.", tempPath); } } } return(report); }
public RelationalExCollection(PackCollection packCollection) : base(packCollection) { }