void ReadRecordRoot() { MemoryStream stream = new MemoryStream(streamData); BinaryReader reader = new BinaryReader(stream); // Must have RecordRootLength of bytes to read or something has gone wrong if (stream.Length < RecordRootLength) { stream.Close(); return; } // Position reader.BaseStream.Position = 6; recordRoot.Position = SaveTree.ReadPosition(reader); // RecordID reader.BaseStream.Position = 30; recordRoot.RecordID = reader.ReadUInt32(); // QuestID reader.BaseStream.Position = 37; recordRoot.QuestID = reader.ReadByte(); // ParentRecordID reader.BaseStream.Position = 38; recordRoot.ParentRecordID = reader.ReadUInt32(); // ParentRecordType reader.BaseStream.Position = 66; recordRoot.ParentRecordType = (RecordTypes)reader.ReadInt32(); reader.Close(); }
/// <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); } return(true); }
void ReadRawData() { MemoryStream stream = new MemoryStream(RawData); BinaryReader reader = new BinaryReader(stream, Encoding.UTF8); // Read Version - must be 0x126 Version = reader.ReadInt32(); if (Version != VersionNumber) { throw new Exception("SaveTree file has an invalid version number, must be 0x126."); } // Read character position. A character position record later in the file (record type 0x04) is used for positioning the player, not this. // Currently not clear what classic uses this one for. CharacterPosition = new HeaderCharacterPositionRecord(); CharacterPosition.Position = SaveTree.ReadPosition(reader); // Read MapID MapID = reader.ReadUInt16(); // Read Environment Environment = reader.ReadByte(); reader.Close(); }
void ReadRawData() { MemoryStream stream = new MemoryStream(RawData); BinaryReader reader = new BinaryReader(stream, Encoding.UTF8); // Read Version - must be 0x26 Version = reader.ReadByte(); if (Version != VersionNumber) { throw new Exception("SaveTree file has an invalid version number, must be 0x26."); } // Read CharacterPosition.RecordType - must be 0x01 CharacterPosition = new CharacterPositionRecord(); CharacterPosition.RecordType = reader.ReadByte(); if (CharacterPosition.RecordType != (int)RecordTypes.CharacterPosition) { throw new Exception("Expected CharacterPosition in SaveTreeHeader has an invalid record type, must be 0x01."); } // Read CharacterPosition.Unknown CharacterPosition.Unknown = reader.ReadUInt16(); // Read CharacterPosition.Position CharacterPosition.Position = SaveTree.ReadPosition(reader); // Read Unknown Unknown = reader.ReadUInt16(); reader.Close(); }
void ReadRecordRoot() { MemoryStream stream = new MemoryStream(streamData); BinaryReader reader = new BinaryReader(stream); // Must have RecordRootLength of bytes to read or something has gone wrong if (stream.Length < RecordRootLength) { stream.Close(); return; } // Direction reader.BaseStream.Position = 1; recordRoot.Pitch = reader.ReadInt16(); recordRoot.Yaw = reader.ReadInt16(); // Position reader.BaseStream.Position = 7; recordRoot.Position = SaveTree.ReadPosition(reader); // 3d View Picture reader.BaseStream.Position = 27; recordRoot.Picture1 = reader.ReadUInt16(); // Inventory Picture recordRoot.Picture2 = reader.ReadUInt16(); // RecordID recordRoot.RecordID = reader.ReadUInt32(); // QuestID reader.BaseStream.Position = 38; recordRoot.QuestID = reader.ReadByte(); // ParentRecordID recordRoot.ParentRecordID = reader.ReadUInt32(); // ItemObject reader.BaseStream.Position = 47; recordRoot.ItemObject = reader.ReadUInt32(); // QuestObjectID recordRoot.QuestObjectID = reader.ReadUInt32(); // NextObject recordRoot.NextObject = reader.ReadUInt32(); // ChildObject recordRoot.ChildObject = reader.ReadUInt32(); // SublistHead recordRoot.SublistHead = reader.ReadUInt32(); // ParentRecordType recordRoot.ParentRecordType = (RecordTypes)reader.ReadInt32(); reader.Close(); }
void WriteRawData() { MemoryStream stream = new MemoryStream(RawData, true); BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8); // Write Version writer.Write(Version); // Write CharacterPosition.Position SaveTree.WritePosition(writer, CharacterPosition.Position); // Write MapID writer.Write(MapID); // Write Environment writer.Write(Environment); writer.Close(); }
void WriteRawData() { MemoryStream stream = new MemoryStream(RawData, true); BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8); // Write Version writer.Write(Version); // Write CharacterPosition.RecordType writer.Write(CharacterPosition.RecordType); // Write CharacterPosition.Unknown writer.Write(CharacterPosition.Unknown); // Write CharacterPosition.Position SaveTree.WritePosition(writer, CharacterPosition.Position); // Write Unknown writer.Write(Unknown); writer.Close(); }
/// <summary> /// Reads record data from stream. /// </summary> /// <param name="reader">Reader positioned at start of record data.</param> /// <param name="length">Length of record data to read.</param> public virtual void Open(BinaryReader reader, int length) { streamPosition = reader.BaseStream.Position; streamLength = length; // Cannot read zero-length records if (length <= 0) { return; } // Peek record type and adjust for dungeon size recordType = SaveTree.PeekRecordType(reader); if (recordType == RecordTypes.DungeonInformation) { streamLength *= DungeonDataLengthMultiplier; } // Read raw record data streamData = reader.ReadBytes(streamLength); // Read RecordRoot data from start of memory buffer ReadRecordRoot(); }
void ReadRawData() { MemoryStream stream = new MemoryStream(RawData); BinaryReader reader = new BinaryReader(stream, Encoding.UTF8); // Read Version - must be 0x126 Version = reader.ReadInt32(); if (Version != VersionNumber) { throw new Exception("SaveTree file has an invalid version number, must be 0x126."); } // Read CharacterPosition.Position CharacterPosition = new HeaderCharacterPositionRecord(); CharacterPosition.Position = SaveTree.ReadPosition(reader); // Read MapID MapID = reader.ReadUInt16(); // Read Environment Environment = reader.ReadByte(); reader.Close(); }
/// <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); }
void OnGUI() { if (!IsReady()) { EditorGUILayout.HelpBox("DaggerfallUnity instance not ready. Have you set your Arena2 path?", MessageType.Info); return; } if (selectedSave != lastSelectedSave || currentSaveTree == null) { currentSaveTree = saveTrees[selectedSave]; currentSaveVars = saveVars[selectedSave]; if (currentSaveTree == null || currentSaveVars == null) return; currentItems = currentSaveTree.FindRecords(RecordTypes.Item).ToArray(); // Merge savetree faction data factionDict = factionFile.Merge(currentSaveVars); lastSelectedSave = selectedSave; } if (saveTrees != null && saveTrees.Length > 0) { DisplaySaveSelectGUI(); DisplaySaveImageGUI(); DisplaySaveStatsGUI(); DisplaySaveCharacterGUI(); scrollPos = GUILayoutHelper.ScrollView(scrollPos, () => { EditorGUILayout.Space(); showFactionsFoldout = GUILayoutHelper.Foldout(showFactionsFoldout, new GUIContent("Factions"), () => { GUILayoutHelper.Indent(() => { DisplayFactionsFoldout(); }); }); EditorGUILayout.Space(); showItemsFoldout = GUILayoutHelper.Foldout(showItemsFoldout, new GUIContent("Items"), () => { GUILayoutHelper.Indent(() => { DisplayItemsFoldout(); }); }); EditorGUILayout.Space(); showSaveTreeFoldout = GUILayoutHelper.Foldout(showSaveTreeFoldout, new GUIContent("SaveTree"), () => { EditorGUILayout.HelpBox("Temporarily Filtering out records of type UnknownTownLink and UnknownItemRecord to keep list manageable.", MessageType.Info); DisplaySaveTree(currentSaveTree.RootRecord); }); }); } }
void OnGUI() { if (!IsReady()) { EditorGUILayout.HelpBox("DaggerfallUnity instance not ready. Have you set your Arena2 path?", MessageType.Info); return; } currentSaveTree = saveTrees[selectedSave]; if (currentSaveTree == null) return; if (saveTrees != null && saveTrees.Length > 0) { DisplaySaveSelectGUI(); DisplaySaveImageGUI(); DisplaySaveStatsGUI(); DisplaySaveCharacterGUI(); EditorGUILayout.Space(); EditorGUILayout.HelpBox("Temporarily Filtering out records of type UnknownTownLink and UnknownItemRecord to keep list manageable.", MessageType.Info); scrollPos = GUILayoutHelper.ScrollView(scrollPos, () => { DisplaySaveTree(currentSaveTree.RootRecord); }); } }
/// <summary> /// Assigns character items from classic save tree. /// </summary> public void AssignItems(SaveTree saveTree) { // Find character record, should always be a singleton CharacterRecord characterRecord = (CharacterRecord)saveTree.FindRecord(RecordTypes.Character); if (characterRecord == null) return; // Find all character-owned items List<SaveTreeBaseRecord> itemRecords = saveTree.FindRecords(RecordTypes.Item, characterRecord); // Filter for container-based inventory items List<SaveTreeBaseRecord> filteredRecords = saveTree.FilterRecordsByParentType(itemRecords, RecordTypes.Container); // Add interim Daggerfall Unity items foreach (var record in filteredRecords) { // Get container parent ContainerRecord containerRecord = (ContainerRecord)record.Parent; // Add to local inventory or wagon DaggerfallUnityItem newItem = new DaggerfallUnityItem((ItemRecord)record); if (containerRecord.IsWagon) wagonItems.AddItem(newItem); else items.AddItem(newItem); // Equip to player if equipped in save for (int i = 0; i < characterRecord.ParsedData.equippedItems.Length; i++) { if (characterRecord.ParsedData.equippedItems[i] == (record.RecordRoot.RecordID >> 8)) equipTable.EquipItem(newItem); } } }
/// <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); }
/// <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); return true; }