/// <summary> /// Obtains a stream which can be used to read and write a cache file's meta in realtime. /// The stream will be set up such that offsets in the stream correspond to meta pointers in the cache file. /// </summary> /// <param name="cacheFile">The cache file to get a stream for.</param> /// <returns>The stream if it was opened successfully, or null otherwise.</returns> public IStream GetMetaStream(ICacheFile cacheFile) { if (string.IsNullOrEmpty(ExecutableName)) { throw new InvalidOperationException("No gameExecutable value found in Engines.xml for engine " + _buildInfo.Name + "."); } if (_buildInfo.Poking == null) { throw new InvalidOperationException("No poking definitions found in Engines.xml for engine " + _buildInfo.Name + "."); } Process gameProcess = FindGameProcess(); if (gameProcess == null) { return(null); } string version = gameProcess.MainModule.FileVersionInfo.FileVersion; long pointer = _buildInfo.Poking.RetrievePointer(version); if (pointer == -1) { throw new InvalidOperationException("Game version " + version + " does not have a pointer defined in the Formats folder."); } var gameMemory = new ProcessMemoryStream(gameProcess); var mapInfo = new H2VistaMapPointerReader(gameMemory, pointer); long metaAddress; if (cacheFile.Type != CacheFileType.Shared) { metaAddress = mapInfo.CurrentMetaAddress; // The map isn't shared, so make sure the map names match if (mapInfo.MapName != cacheFile.InternalName) { gameMemory.Close(); return(null); } } else { metaAddress = mapInfo.SharedMetaAddress; // Make sure the shared and current map pointers are different, // or that the current map is the shared map if (mapInfo.MapType != CacheFileType.Shared && mapInfo.CurrentMetaAddress == mapInfo.SharedMetaAddress) { gameMemory.Close(); return(null); } } var metaStream = new OffsetStream(gameMemory, metaAddress - cacheFile.MetaArea.BasePointer); return(new EndianStream(metaStream, BitConverter.IsLittleEndian ? Endian.LittleEndian : Endian.BigEndian)); }
/// <summary> /// Obtains a stream which can be used to read and write a cache file's meta in realtime. /// The stream will be set up such that offsets in the stream correspond to meta pointers in the cache file. /// </summary> /// <param name="cacheFile">The cache file to get a stream for.</param> /// <returns>The stream if it was opened successfully, or null otherwise.</returns> public IStream GetMetaStream(ICacheFile cacheFile) { Process gameProcess = FindGameProcess(); if (gameProcess == null) { return(null); } var gameMemory = new ProcessMemoryStream(gameProcess); var mapInfo = new H2VistaMapPointerReader(gameMemory); long metaAddress; if (cacheFile.Type != CacheFileType.Shared) { metaAddress = mapInfo.CurrentMetaAddress; // The map isn't shared, so make sure the map names match if (mapInfo.MapName != cacheFile.InternalName) { gameMemory.Close(); return(null); } } else { metaAddress = mapInfo.SharedMetaAddress; // Make sure the shared and current map pointers are different, // or that the current map is the shared map if (mapInfo.MapType != CacheFileType.Shared && mapInfo.CurrentMetaAddress == mapInfo.SharedMetaAddress) { gameMemory.Close(); return(null); } } var metaStream = new OffsetStream(gameMemory, metaAddress - cacheFile.MetaArea.BasePointer); return(new EndianStream(metaStream, BitConverter.IsLittleEndian ? Endian.LittleEndian : Endian.BigEndian)); }
/// <summary> /// Obtains a stream which can be used to read and write a cache file's meta in realtime. /// The stream will be set up such that offsets in the stream correspond to meta pointers in the cache file. /// </summary> /// <param name="cacheFile">The cache file to get a stream for.</param> /// <returns>The stream if it was opened successfully, or null otherwise.</returns> public IStream GetMetaStream(ICacheFile cacheFile) { if (string.IsNullOrEmpty(_buildInfo.PokingExecutable)) { throw new InvalidOperationException("No gameExecutable value found in Engines.xml for engine " + _buildInfo.Name + "."); } if (_buildInfo.Poking == null) { throw new InvalidOperationException("No poking definitions found in Engines.xml for engine " + _buildInfo.Name + "."); } Process gameProcess = FindGameProcess(); if (gameProcess == null) { return(null); } string version = gameProcess.MainModule.FileVersionInfo.FileVersion; PokingInformation info = _buildInfo.Poking.RetrieveInformation(version); if (info == null) { throw new InvalidOperationException("Game version " + version + " does not have poking information defined in the Formats folder."); } if (!info.HeaderAddress.HasValue) { throw new NotImplementedException("First Generation poking requires a HeaderAddress value."); } if (!info.MagicAddress.HasValue) { throw new NotImplementedException("First Generation poking requires a MagicAddress value."); } var gameMemory = new ProcessMemoryStream(gameProcess); var mapInfo = new FirstGenMapPointerReader(gameMemory, _buildInfo, info); long metaAddress = mapInfo.CurrentCacheAddress; if (mapInfo.MapName != cacheFile.InternalName) { gameMemory.Close(); return(null); } var metaStream = new OffsetStream(gameMemory, metaAddress - cacheFile.MetaArea.BasePointer); return(new EndianStream(metaStream, BitConverter.IsLittleEndian ? Endian.LittleEndian : Endian.BigEndian)); }
/// <summary> /// Obtains a stream which can be used to read and write a cache file's meta in realtime. /// The stream will be set up such that offsets in the stream correspond to meta pointers in the cache file. /// </summary> /// <param name="cacheFile">The cache file to get a stream for.</param> /// <param name="tag">The tag to get a stream for.</param> /// <returns> /// The stream if it was opened successfully, or null otherwise. /// </returns> public IStream GetMetaStream(ICacheFile cacheFile, ITag tag) { // Open a handle to the game process var gameProcess = FindGameProcess(); if (gameProcess == null) { return(null); } var memoryStream = new ProcessMemoryStream(gameProcess); var exeBase = (uint)memoryStream.BaseProcess.MainModule.BaseAddress - 0x400000; var tagAddress = GetTagAddress(new EndianReader(memoryStream, Endian.LittleEndian), tag.Index.Index, exeBase); if (tagAddress == 0) { memoryStream.Close(); return(null); } var offsetStream = new OffsetStream(memoryStream, tagAddress - tag.HeaderLocation.AsOffset()); return(new EndianStream(offsetStream, Endian.LittleEndian)); }