diff --git a/d2common/d2fileformats/d2mpq/mpq.go b/d2common/d2fileformats/d2mpq/mpq.go index 622fe32c..67cb3e18 100644 --- a/d2common/d2fileformats/d2mpq/mpq.go +++ b/d2common/d2fileformats/d2mpq/mpq.go @@ -273,17 +273,37 @@ func (v *MPQ) ReadFile(fileName string) ([]byte, error) { if err != nil { return []byte{}, err } + fileBlockData.FileName = strings.ToLower(fileName) + fileBlockData.calculateEncryptionSeed() mpqStream, err := CreateStream(v, fileBlockData, fileName) + if err != nil { return []byte{}, err } + buffer := make([]byte, fileBlockData.UncompressedFileSize) mpqStream.Read(buffer, 0, fileBlockData.UncompressedFileSize) return buffer, nil } +func (v *MPQ) ReadFileStream(fileName string) (*MpqDataStream, error) { + fileBlockData, err := v.getFileBlockData(fileName) + if err != nil { + return nil, err + } + fileBlockData.FileName = strings.ToLower(fileName) + fileBlockData.calculateEncryptionSeed() + + mpqStream, err := CreateStream(v, fileBlockData, fileName) + if err != nil { + return nil, err + } + + return &MpqDataStream{stream: mpqStream}, nil +} + // ReadTextFile reads a file and returns it as a string func (v *MPQ) ReadTextFile(fileName string) (string, error) { data, err := v.ReadFile(fileName) @@ -303,7 +323,7 @@ func (v *BlockTableEntry) calculateEncryptionSeed() { } // GetFileList returns the list of files in this MPQ -func (v * MPQ) GetFileList() ([]string, error) { +func (v *MPQ) GetFileList() ([]string, error) { data, err := v.ReadFile("(listfile)") if err != nil { return nil, err diff --git a/d2common/d2fileformats/d2mpq/mpq_data_stream.go b/d2common/d2fileformats/d2mpq/mpq_data_stream.go new file mode 100644 index 00000000..7bb500e3 --- /dev/null +++ b/d2common/d2fileformats/d2mpq/mpq_data_stream.go @@ -0,0 +1,20 @@ +package d2mpq + +type MpqDataStream struct { + stream *Stream +} + +func (m *MpqDataStream) Read(p []byte) (n int, err error) { + totalRead := m.stream.Read(p, 0, uint32(len(p))) + return int(totalRead), nil +} + +func (m *MpqDataStream) Seek(offset int64, whence int) (int64, error) { + m.stream.CurrentPosition = uint32(offset + int64(whence)) + return int64(m.stream.CurrentPosition), nil +} + +func (m *MpqDataStream) Close() error { + m.stream = nil + return nil +} diff --git a/d2common/d2fileformats/d2mpq/mpq_stream.go b/d2common/d2fileformats/d2mpq/mpq_stream.go index 3ca720e8..2a121eae 100644 --- a/d2common/d2fileformats/d2mpq/mpq_stream.go +++ b/d2common/d2fileformats/d2mpq/mpq_stream.go @@ -86,7 +86,7 @@ func (v *Stream) Read(buffer []byte, offset, count uint32) uint32 { toRead := count readTotal := uint32(0) for toRead > 0 { - read := v.readInternal(buffer, offset, count) + read := v.readInternal(buffer, offset, toRead) if read == 0 { break } diff --git a/d2core/d2asset/d2asset.go b/d2core/d2asset/d2asset.go index 7118ead4..3cf327ae 100644 --- a/d2core/d2asset/d2asset.go +++ b/d2core/d2asset/d2asset.go @@ -80,6 +80,17 @@ func LoadArchive(archivePath string) (*d2mpq.MPQ, error) { return singleton.archiveManager.loadArchive(archivePath) } +func LoadFileStream(filePath string) (*d2mpq.MpqDataStream, error) { + verifyWasInit() + + data, err := singleton.fileManager.loadFileStream(filePath) + if err != nil { + log.Printf("error loading file stream %s (%v)", filePath, err.Error()) + } + + return data, err +} + func LoadFile(filePath string) ([]byte, error) { verifyWasInit() diff --git a/d2core/d2asset/file_manager.go b/d2core/d2asset/file_manager.go index 103ace31..399e2e0c 100644 --- a/d2core/d2asset/file_manager.go +++ b/d2core/d2asset/file_manager.go @@ -1,6 +1,7 @@ package d2asset import ( + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2mpq" "strings" "github.com/OpenDiablo2/OpenDiablo2/d2common" @@ -22,6 +23,18 @@ func createFileManager(config d2config.Configuration, archiveManager *archiveMan return &fileManager{d2common.CreateCache(fileBudget), archiveManager, config} } + +func (fm *fileManager) loadFileStream(filePath string) (*d2mpq.MpqDataStream, error) { + filePath = fm.fixupFilePath(filePath) + + archive, err := fm.archiveManager.loadArchiveForFile(filePath) + if err != nil { + return nil, err + } + + return archive.ReadFileStream(filePath) +} + func (fm *fileManager) loadFile(filePath string) ([]byte, error) { filePath = fm.fixupFilePath(filePath) if value, found := fm.cache.Retrieve(filePath); found { diff --git a/d2core/d2audio/d2audio.go b/d2core/d2audio/d2audio.go index 0d21b07c..7a3ed93f 100644 --- a/d2core/d2audio/d2audio.go +++ b/d2core/d2audio/d2audio.go @@ -32,9 +32,7 @@ func Initialize(audioProvider AudioProvider) error { // PlayBGM plays an infinitely looping background track func PlayBGM(song string) error { verifyWasInit() - go func() { - singleton.PlayBGM(song) - }() + singleton.PlayBGM(song) return nil } diff --git a/d2core/d2audio/ebiten/ebiten_audio_provider.go b/d2core/d2audio/ebiten/ebiten_audio_provider.go index 7cc9c90c..c2db4f07 100644 --- a/d2core/d2audio/ebiten/ebiten_audio_provider.go +++ b/d2core/d2audio/ebiten/ebiten_audio_provider.go @@ -45,11 +45,11 @@ func (eap *AudioProvider) PlayBGM(song string) { log.Panic(err) } } - audioData, err := d2asset.LoadFile(song) + audioStream, err := d2asset.LoadFileStream(song) if err != nil { panic(err) } - d, err := wav.Decode(eap.audioContext, audio.BytesReadSeekCloser(audioData)) + d, err := wav.Decode(eap.audioContext, audioStream) if err != nil { log.Fatal(err) }