/// <summary> /// Changes action record at specified position. /// </summary> /// <param name="blockName">Name of block file.</param> /// <param name="position">Start position of action record.</param> /// <param name="axis">Rotation axis.</param> /// <param name="duration">Duration of action.</param> /// <param name="magnitude">Magnitude of action.</param> public void ModActionRecord(string blockName, long position, byte axis, UInt16 duration, UInt16 magnitude) { // Load resources string path = Path.Combine(arena2Path, "BLOCKS.BSA"); BsaFile bsaFile = new BsaFile( path, FileUsage.UseDisk, false); // Get binary record int index = bsaFile.GetRecordIndex(blockName); byte[] buffer = bsaFile.GetRecordBytes(index); // Create stream to binary record MemoryStream ms = new MemoryStream(buffer); ms.Position = position; // Write new data BinaryWriter writer = new BinaryWriter(ms, Encoding.UTF8); writer.Write(axis); writer.Write(duration); writer.Write(magnitude); writer.Close(); // Save back binary record bsaFile.RewriteRecord(index, buffer); }
/// <summary> /// ARCH3D.BSA: Modify base texture assigned to plane. /// </summary> /// <param name="MeshID">ID of mesh.</param> /// <param name="planeIndex">Plane index.</param> /// <param name="textureArchive">New texture archive index to set.</param> /// <param name="textureRecord">New texture record inex to set.</param> public void ModPlaneTexture(uint MeshID, int planeIndex, int textureArchive, int textureRecord) { // Load resources string path = Path.Combine(arena2Path, "ARCH3D.BSA"); Arch3dFile arch3dFile = new Arch3dFile( path, FileUsage.UseMemory, true); BsaFile bsaFile = new BsaFile( path, FileUsage.UseDisk, false); // Get mesh record int index = arch3dFile.GetRecordIndex(MeshID); arch3dFile.LoadRecord(index); Arch3dFile.MeshRecord record = arch3dFile.MeshRecords[index]; // Get binary record byte[] buffer = bsaFile.GetRecordBytes(index); // Compose new texture bitfield UInt16 textureBitfield = (UInt16)((textureArchive << 7) + textureRecord); // Get start position of plane header long position = record.PureMesh.Planes[planeIndex].Header.Position; // Offset to texture bitfield position += 2; // Create stream to binary record MemoryStream ms = new MemoryStream(buffer); ms.Position = position; // Write new bitfield BinaryWriter writer = new BinaryWriter(ms, Encoding.UTF8); writer.Write(textureBitfield); writer.Close(); // Save back binary record bsaFile.RewriteRecord(index, buffer); }
static void Main(string[] args) { // Specify Arena2 path of local Daggerfall installation string MyArena2Path = "C:\\dosgames\\DAGGER\\ARENA2"; // Path to BSA file string FilePath = Path.Combine(MyArena2Path, "BLOCKS.BSA"); // Open BSA file BsaFile bsaFile = new BsaFile( FilePath, FileUsage.UseDisk, true); // Output some information about the file Console.WriteLine("BSA file {0} has {1} records", Path.GetFileName(FilePath), bsaFile.Count); // Output some information about a record int record = 0; int length = bsaFile.GetRecordLength(record); string name = bsaFile.GetRecordName(record); Console.WriteLine("Record {0} is {1} bytes long and named {2}", record, length, name); // Get the record data byte[] data = bsaFile.GetRecordBytes(record); // This byte array now contains the binary data for this record // You can query it using streams to read in whatever data you like // (i.e. work with the file formats directly) // Here the array is just ignored and will pass out of scope // before being garbage collected. }
/// <summary> /// Opens the save game index specified. /// </summary> /// <param name="save">Save index</param> /// <param name="loadingInGame">True if the save game is being loaded for regular play, false if loading for Save Explorer.</param> /// <returns>True if successful.</returns> public bool OpenSave(int save, bool loadingInGame = true) { if (!HasSave(save)) { return(false); } if (!LoadSaveImage(save)) { throw new Exception("Could not open SaveImage for index " + save); } if (!LoadSaveName(save)) { throw new Exception("Could not open SaveName for index " + save); } saveTree = new SaveTree(); if (!saveTree.Open(Path.Combine(saveGameDict[save], SaveTree.Filename))) { throw new Exception("Could not open SaveTree for index " + save); } saveVars = new SaveVars(); if (!saveVars.Open(Path.Combine(saveGameDict[save], SaveVars.Filename))) { throw new Exception("Could not open SaveVars for index " + save); } mapSave = new BsaFile(); if (!mapSave.Load(Path.Combine(saveGameDict[save], "MAPSAVE.SAV"), FileUsage.UseMemory, true)) { throw new Exception("Could not open MapSave for index " + save); } if (loadingInGame) // Only check MAPSAVE if loading in-game, not if viewing in Save Explorer. There is a noticeable delay for // Save Explorer as the classic saves are loaded, and a null exception if the Save Explorer is opened // without the game running in the editor, due to PlayerGPS.dfUnity not being instantiated. // Save Explorer currently has no use for MAPSAVE data. This code should be revisited (speed up MAPSAVE processing, // fix null exception, remove this bool check) if MAPSAVE-related functionality is added to Save Explorer. { PlayerGPS gps = GameManager.Instance.PlayerGPS; gps.ClearDiscoveryData(); for (int regionIndex = 0; regionIndex < 62; regionIndex++) { // Generate name from region index string name = string.Format("MAPSAVE.{0:000}", regionIndex); // Get record index int index = mapSave.GetRecordIndex(name); if (index == -1) { return(false); } // Read MAPSAVE data byte[] data = mapSave.GetRecordBytes(index); // Parse MAPSAVE data for discovered locations DFRegion regionData = DaggerfallUnity.Instance.ContentReader.MapFileReader.GetRegion(regionIndex); int locationCount = Math.Min(data.Length, (int)regionData.LocationCount); for (int i = 0; i < locationCount; i++) { // If a location is marked as discovered in classic but not DF Unity, discover it for DF Unity if ((data[i] & 0x40) != 0 && !regionData.MapTable[i].Discovered) { DFLocation location = DaggerfallUnity.Instance.ContentReader.MapFileReader.GetLocation(regionIndex, i); gps.DiscoverLocation(regionData.Name, location.Name); } } } } rumorFile = new RumorFile(); if (!rumorFile.Load(Path.Combine(saveGameDict[save], "RUMOR.DAT"), FileUsage.UseMemory, true)) { UnityEngine.Debug.Log("Could not open RUMOR.DAT for index " + save); } for (int i = 0; i < rumorFile.rumors.Count; i++) { GameManager.Instance.TalkManager.ImportClassicRumor(rumorFile.rumors[i]); } bioFile = new BioFile(); if (!bioFile.Load(Path.Combine(saveGameDict[save], "BIO.DAT"))) { UnityEngine.Debug.Log("Could not open BIO.DAT for index " + save); } return(true); }
/// <summary> /// Opens the save game index specified. /// </summary> /// <param name="save">Save index</param> /// <returns>True if successful.</returns> public bool OpenSave(int save) { if (!HasSave(save)) { return(false); } if (!LoadSaveImage(save)) { throw new Exception("Could not open SaveImage for index " + save); } if (!LoadSaveName(save)) { throw new Exception("Could not open SaveName for index " + save); } saveTree = new SaveTree(); if (!saveTree.Open(Path.Combine(saveGameDict[save], SaveTree.Filename))) { throw new Exception("Could not open SaveTree for index " + save); } saveVars = new SaveVars(); if (!saveVars.Open(Path.Combine(saveGameDict[save], SaveVars.Filename))) { throw new Exception("Could not open SaveVars for index " + save); } mapSave = new BsaFile(); if (!mapSave.Load(Path.Combine(saveGameDict[save], "MAPSAVE.SAV"), FileUsage.UseMemory, true)) { throw new Exception("Could not open MapSave for index " + save); } PlayerGPS gps = GameManager.Instance.PlayerGPS; gps.ClearDiscoveryData(); for (int regionIndex = 0; regionIndex < 62; regionIndex++) { // Generate name from region index string name = string.Format("MAPSAVE.{0:000}", regionIndex); // Get record index int index = mapSave.GetRecordIndex(name); if (index == -1) { return(false); } // Read MAPSAVE data byte[] data = mapSave.GetRecordBytes(index); // Parse MAPSAVE data for discovered locations DFRegion regionData = DaggerfallUnity.Instance.ContentReader.MapFileReader.GetRegion(regionIndex); for (int i = 0; i < regionData.LocationCount; i++) { if ((data[i] & 0x40) != 0) { // Discover the location in DF Unity's data if (regionData.MapTable[i].Discovered == false) { DFLocation location = DaggerfallUnity.Instance.ContentReader.MapFileReader.GetLocation(regionIndex, i); gps.DiscoverLocation(regionData.Name, location.Name); } } } } return(true); }