mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-11-16 09:25:57 -05:00
d2datautil.StreamReader refactor
*`StreamReader.Read` methods now return errors The other edits in this commit are related to cleaning up lint errors caused by the changes to StreamReader
This commit is contained in:
parent
938ce20579
commit
87d531814d
@ -150,7 +150,10 @@ func (a *App) initAnimationData(path string) error {
|
||||
|
||||
a.Debugf(fmtLoadAnimData, path)
|
||||
|
||||
animData := d2data.LoadAnimationData(animDataBytes)
|
||||
animData, err := d2data.LoadAnimationData(animDataBytes)
|
||||
if err != nil {
|
||||
a.Error(err.Error())
|
||||
}
|
||||
|
||||
a.Infof("Loaded %d animation data records", len(animData))
|
||||
|
||||
|
@ -27,20 +27,48 @@ type AnimationDataRecord struct {
|
||||
type AnimationData map[string][]*AnimationDataRecord
|
||||
|
||||
// LoadAnimationData loads the animation data table into the global AnimationData dictionary
|
||||
func LoadAnimationData(rawData []byte) AnimationData {
|
||||
func LoadAnimationData(rawData []byte) (AnimationData, error) {
|
||||
animdata := make(AnimationData)
|
||||
streamReader := d2datautils.CreateStreamReader(rawData)
|
||||
|
||||
for !streamReader.EOF() {
|
||||
dataCount := int(streamReader.GetInt32())
|
||||
var dataCount int
|
||||
|
||||
b, err := streamReader.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dataCount = int(b)
|
||||
|
||||
for i := 0; i < dataCount; i++ {
|
||||
cofNameBytes := streamReader.ReadBytes(numCofNameBytes)
|
||||
cofNameBytes, err := streamReader.ReadBytes(numCofNameBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fpd, err := streamReader.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
animSpeed, err := streamReader.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data := &AnimationDataRecord{
|
||||
COFName: strings.ReplaceAll(string(cofNameBytes), string(byte(0)), ""),
|
||||
FramesPerDirection: int(streamReader.GetInt32()),
|
||||
AnimationSpeed: int(streamReader.GetInt32()),
|
||||
FramesPerDirection: int(fpd),
|
||||
AnimationSpeed: int(animSpeed),
|
||||
}
|
||||
data.Flags = streamReader.ReadBytes(numFlagBytes)
|
||||
|
||||
flagBytes, err := streamReader.ReadBytes(numFlagBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data.Flags = flagBytes
|
||||
cofIndex := strings.ToLower(data.COFName)
|
||||
|
||||
if _, found := animdata[cofIndex]; !found {
|
||||
@ -51,5 +79,5 @@ func LoadAnimationData(rawData []byte) AnimationData {
|
||||
}
|
||||
}
|
||||
|
||||
return animdata
|
||||
return animdata, nil
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
|
||||
// WavDecompress decompresses wav files
|
||||
//nolint:gomnd // binary decode magic
|
||||
func WavDecompress(data []byte, channelCount int) []byte { //nolint:funlen,gocognit,gocyclo // can't reduce
|
||||
func WavDecompress(data []byte, channelCount int) ([]byte, error) { //nolint:funlen,gocognit,gocyclo // can't reduce
|
||||
Array1 := []int{0x2c, 0x2c}
|
||||
Array2 := make([]int, channelCount)
|
||||
|
||||
@ -35,20 +35,33 @@ func WavDecompress(data []byte, channelCount int) []byte { //nolint:funlen,gocog
|
||||
input := d2datautils.CreateStreamReader(data)
|
||||
output := d2datautils.CreateStreamWriter()
|
||||
|
||||
input.GetByte()
|
||||
_, err := input.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
shift := input.GetByte()
|
||||
shift, err := input.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < channelCount; i++ {
|
||||
temp := input.GetInt16()
|
||||
temp, err := input.ReadInt16()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Array2[i] = int(temp)
|
||||
output.PushInt16(temp)
|
||||
}
|
||||
|
||||
channel := channelCount - 1
|
||||
|
||||
for input.GetPosition() < input.GetSize() {
|
||||
value := input.GetByte()
|
||||
for input.Position() < input.Size() {
|
||||
value, err := input.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if channelCount == 2 {
|
||||
channel = 1 - channel
|
||||
@ -129,5 +142,5 @@ func WavDecompress(data []byte, channelCount int) []byte { //nolint:funlen,gocog
|
||||
}
|
||||
}
|
||||
|
||||
return output.GetBytes()
|
||||
return output.GetBytes(), nil
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package d2video
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils"
|
||||
@ -29,6 +30,12 @@ const (
|
||||
BinkVideoModeWidthAndHeightInterlaced
|
||||
)
|
||||
|
||||
const (
|
||||
numHeaderBytes = 3
|
||||
bikHeaderStr = "BIK"
|
||||
numAudioTrackUnknownBytes = 2
|
||||
)
|
||||
|
||||
// BinkAudioAlgorithm represents the type of bink audio algorithm
|
||||
type BinkAudioAlgorithm uint32
|
||||
|
||||
@ -72,75 +79,157 @@ type BinkDecoder struct {
|
||||
}
|
||||
|
||||
// CreateBinkDecoder returns a new instance of the bink decoder
|
||||
func CreateBinkDecoder(source []byte) *BinkDecoder {
|
||||
func CreateBinkDecoder(source []byte) (*BinkDecoder, error) {
|
||||
result := &BinkDecoder{
|
||||
streamReader: d2datautils.CreateStreamReader(source),
|
||||
}
|
||||
|
||||
result.loadHeaderInformation()
|
||||
err := result.loadHeaderInformation()
|
||||
|
||||
return result
|
||||
return result, err
|
||||
}
|
||||
|
||||
// GetNextFrame gets the next frame
|
||||
func (v *BinkDecoder) GetNextFrame() {
|
||||
func (v *BinkDecoder) GetNextFrame() error {
|
||||
//nolint:gocritic // v.streamReader.SetPosition(uint64(v.FrameIndexTable[i] & 0xFFFFFFFE))
|
||||
lengthOfAudioPackets := v.streamReader.GetUInt32() - 4 //nolint:gomnd // decode magic
|
||||
samplesInPacket := v.streamReader.GetUInt32()
|
||||
lengthOfAudioPackets, err := v.streamReader.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.streamReader.SkipBytes(int(lengthOfAudioPackets))
|
||||
samplesInPacket, err := v.streamReader.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.streamReader.SkipBytes(int(lengthOfAudioPackets) - 4) //nolint:gomnd // decode magic
|
||||
|
||||
log.Printf("Frame %d:\tSamp: %d", v.frameIndex, samplesInPacket)
|
||||
|
||||
v.frameIndex++
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:gomnd // Decoder magic
|
||||
func (v *BinkDecoder) loadHeaderInformation() {
|
||||
//nolint:gomnd,funlen,gocyclo // Decoder magic, can't help the long function length for now
|
||||
func (v *BinkDecoder) loadHeaderInformation() error {
|
||||
v.streamReader.SetPosition(0)
|
||||
headerBytes := v.streamReader.ReadBytes(3)
|
||||
|
||||
if string(headerBytes) != "BIK" {
|
||||
log.Fatal("Invalid header for bink video")
|
||||
var err error
|
||||
|
||||
headerBytes, err := v.streamReader.ReadBytes(numHeaderBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if string(headerBytes) != bikHeaderStr {
|
||||
return errors.New("invalid header for bink video")
|
||||
}
|
||||
|
||||
v.videoCodecRevision, err = v.streamReader.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.fileSize, err = v.streamReader.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.numberOfFrames, err = v.streamReader.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.largestFrameSizeBytes, err = v.streamReader.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const numBytesToSkip = 4 // Number of frames again?
|
||||
|
||||
v.streamReader.SkipBytes(numBytesToSkip)
|
||||
|
||||
v.VideoWidth, err = v.streamReader.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.VideoHeight, err = v.streamReader.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fpsDividend, err := v.streamReader.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fpsDivider, err := v.streamReader.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.videoCodecRevision = v.streamReader.GetByte()
|
||||
v.fileSize = v.streamReader.GetUInt32()
|
||||
v.numberOfFrames = v.streamReader.GetUInt32()
|
||||
v.largestFrameSizeBytes = v.streamReader.GetUInt32()
|
||||
v.streamReader.SkipBytes(4) // Number of frames again?
|
||||
v.VideoWidth = v.streamReader.GetUInt32()
|
||||
v.VideoHeight = v.streamReader.GetUInt32()
|
||||
fpsDividend := v.streamReader.GetUInt32()
|
||||
fpsDivider := v.streamReader.GetUInt32()
|
||||
v.FPS = uint32(float32(fpsDividend) / float32(fpsDivider))
|
||||
v.FrameTimeMS = 1000 / v.FPS
|
||||
videoFlags := v.streamReader.GetUInt32()
|
||||
|
||||
videoFlags, err := v.streamReader.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.VideoMode = BinkVideoMode((videoFlags >> 28) & 0x0F)
|
||||
v.HasAlphaPlane = ((videoFlags >> 20) & 0x1) == 1
|
||||
v.Grayscale = ((videoFlags >> 17) & 0x1) == 1
|
||||
numberOfAudioTracks := v.streamReader.GetUInt32()
|
||||
|
||||
numberOfAudioTracks, err := v.streamReader.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.AudioTracks = make([]BinkAudioTrack, numberOfAudioTracks)
|
||||
|
||||
for i := 0; i < int(numberOfAudioTracks); i++ {
|
||||
v.streamReader.SkipBytes(2) // Unknown
|
||||
v.AudioTracks[i].AudioChannels = v.streamReader.GetUInt16()
|
||||
v.streamReader.SkipBytes(numAudioTrackUnknownBytes)
|
||||
|
||||
v.AudioTracks[i].AudioChannels, err = v.streamReader.ReadUInt16()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < int(numberOfAudioTracks); i++ {
|
||||
v.AudioTracks[i].AudioSampleRateHz = v.streamReader.GetUInt16()
|
||||
flags := v.streamReader.GetUInt16()
|
||||
v.AudioTracks[i].AudioSampleRateHz, err = v.streamReader.ReadUInt16()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var flags uint16
|
||||
|
||||
flags, err = v.streamReader.ReadUInt16()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.AudioTracks[i].Stereo = ((flags >> 13) & 0x1) == 1
|
||||
v.AudioTracks[i].Algorithm = BinkAudioAlgorithm((flags >> 12) & 0x1)
|
||||
}
|
||||
|
||||
for i := 0; i < int(numberOfAudioTracks); i++ {
|
||||
v.AudioTracks[i].AudioTrackID = v.streamReader.GetUInt32()
|
||||
v.AudioTracks[i].AudioTrackID, err = v.streamReader.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
v.FrameIndexTable = make([]uint32, v.numberOfFrames+1)
|
||||
|
||||
for i := 0; i < int(v.numberOfFrames+1); i++ {
|
||||
v.FrameIndexTable[i] = v.streamReader.GetUInt32()
|
||||
v.FrameIndexTable[i], err = v.streamReader.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -4,6 +4,12 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
bytesPerint16 = 2
|
||||
bytesPerint32 = 4
|
||||
bytesPerint64 = 8
|
||||
)
|
||||
|
||||
// StreamReader allows you to read data from a byte array in various formats
|
||||
type StreamReader struct {
|
||||
data []byte
|
||||
@ -20,53 +26,72 @@ func CreateStreamReader(source []byte) *StreamReader {
|
||||
return result
|
||||
}
|
||||
|
||||
// GetByte returns a byte from the stream
|
||||
func (v *StreamReader) GetByte() byte {
|
||||
// ReadByte reads a byte from the stream
|
||||
func (v *StreamReader) ReadByte() (byte, error) {
|
||||
if v.position >= v.Size() {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
result := v.data[v.position]
|
||||
v.position++
|
||||
|
||||
return result
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetInt16 returns a int16 word from the stream
|
||||
func (v *StreamReader) GetInt16() int16 {
|
||||
return int16(v.GetUInt16())
|
||||
// ReadInt16 returns a int16 word from the stream
|
||||
func (v *StreamReader) ReadInt16() (int16, error) {
|
||||
b, err := v.ReadUInt16()
|
||||
return int16(b), err
|
||||
}
|
||||
|
||||
// GetUInt16 returns a uint16 word from the stream
|
||||
// ReadUInt16 returns a uint16 word from the stream
|
||||
func (v *StreamReader) ReadUInt16() (uint16, error) {
|
||||
b, err := v.ReadBytes(bytesPerint16)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return uint16(b[0]) | uint16(b[1])<<8, err
|
||||
}
|
||||
|
||||
// ReadInt32 returns an int32 dword from the stream
|
||||
func (v *StreamReader) ReadInt32() (int32, error) {
|
||||
b, err := v.ReadUInt32()
|
||||
return int32(b), err
|
||||
}
|
||||
|
||||
// ReadUInt32 returns a uint32 dword from the stream
|
||||
//nolint
|
||||
func (v *StreamReader) GetUInt16() uint16 {
|
||||
b := v.ReadBytes(2)
|
||||
return uint16(b[0]) | uint16(b[1])<<8
|
||||
func (v *StreamReader) ReadUInt32() (uint32, error) {
|
||||
b, err := v.ReadBytes(bytesPerint32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, err
|
||||
}
|
||||
|
||||
// GetInt32 returns an int32 dword from the stream
|
||||
func (v *StreamReader) GetInt32() int32 {
|
||||
return int32(v.GetUInt32())
|
||||
// ReadInt64 returns a uint64 qword from the stream
|
||||
func (v *StreamReader) ReadInt64() (int64, error) {
|
||||
b, err := v.ReadUInt64()
|
||||
return int64(b), err
|
||||
}
|
||||
|
||||
// GetUInt32 returns a uint32 dword from the stream
|
||||
// ReadUInt64 returns a uint64 qword from the stream
|
||||
//nolint
|
||||
func (v *StreamReader) GetUInt32() uint32 {
|
||||
b := v.ReadBytes(4)
|
||||
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
}
|
||||
func (v *StreamReader) ReadUInt64() (uint64, error) {
|
||||
b, err := v.ReadBytes(bytesPerint64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// GetInt64 returns a uint64 qword from the stream
|
||||
func (v *StreamReader) GetInt64() int64 {
|
||||
return int64(v.GetUInt64())
|
||||
}
|
||||
|
||||
// GetUInt64 returns a uint64 qword from the stream
|
||||
//nolint
|
||||
func (v *StreamReader) GetUInt64() uint64 {
|
||||
b := v.ReadBytes(8)
|
||||
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
|
||||
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
|
||||
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56, err
|
||||
}
|
||||
|
||||
// GetPosition returns the current stream position
|
||||
func (v *StreamReader) GetPosition() uint64 {
|
||||
// Position returns the current stream position
|
||||
func (v *StreamReader) Position() uint64 {
|
||||
return v.position
|
||||
}
|
||||
|
||||
@ -75,22 +100,22 @@ func (v *StreamReader) SetPosition(newPosition uint64) {
|
||||
v.position = newPosition
|
||||
}
|
||||
|
||||
// GetSize returns the total size of the stream in bytes
|
||||
func (v *StreamReader) GetSize() uint64 {
|
||||
// Size returns the total size of the stream in bytes
|
||||
func (v *StreamReader) Size() uint64 {
|
||||
return uint64(len(v.data))
|
||||
}
|
||||
|
||||
// ReadByte implements io.ByteReader
|
||||
func (v *StreamReader) ReadByte() (byte, error) {
|
||||
return v.GetByte(), nil
|
||||
}
|
||||
|
||||
// ReadBytes reads multiple bytes
|
||||
func (v *StreamReader) ReadBytes(count int) []byte {
|
||||
func (v *StreamReader) ReadBytes(count int) ([]byte, error) {
|
||||
size := v.Size()
|
||||
if v.position >= size || v.position+uint64(count) > size {
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
result := v.data[v.position : v.position+uint64(count)]
|
||||
v.position += uint64(count)
|
||||
|
||||
return result
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// SkipBytes moves the stream position forward by the given amount
|
||||
@ -100,10 +125,10 @@ func (v *StreamReader) SkipBytes(count int) {
|
||||
|
||||
// Read implements io.Reader
|
||||
func (v *StreamReader) Read(p []byte) (n int, err error) {
|
||||
streamLength := v.GetSize()
|
||||
streamLength := v.Size()
|
||||
|
||||
for i := 0; ; i++ {
|
||||
if v.GetPosition() >= streamLength {
|
||||
if v.Position() >= streamLength {
|
||||
return i, io.EOF
|
||||
}
|
||||
|
||||
@ -111,7 +136,10 @@ func (v *StreamReader) Read(p []byte) (n int, err error) {
|
||||
return i, nil
|
||||
}
|
||||
|
||||
p[i] = v.GetByte()
|
||||
p[i], err = v.ReadByte()
|
||||
if err != nil {
|
||||
return i, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,22 +8,26 @@ func TestStreamReaderByte(t *testing.T) {
|
||||
data := []byte{0x78, 0x56, 0x34, 0x12}
|
||||
sr := CreateStreamReader(data)
|
||||
|
||||
if sr.GetPosition() != 0 {
|
||||
t.Fatal("StreamReader.GetPosition() did not start at 0")
|
||||
if sr.Position() != 0 {
|
||||
t.Fatal("StreamReader.Position() did not start at 0")
|
||||
}
|
||||
|
||||
if ss := sr.GetSize(); ss != 4 {
|
||||
t.Fatalf("StreamREader.GetSize() was expected to return %d, but returned %d instead", 4, ss)
|
||||
if ss := sr.Size(); ss != 4 {
|
||||
t.Fatalf("StreamREader.Size() was expected to return %d, but returned %d instead", 4, ss)
|
||||
}
|
||||
|
||||
for i := 0; i < len(data); i++ {
|
||||
ret := sr.GetByte()
|
||||
ret, err := sr.ReadByte()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if ret != data[i] {
|
||||
t.Fatalf("StreamReader.GetDword() was expected to return %X, but returned %X instead", data[i], ret)
|
||||
}
|
||||
|
||||
if pos := sr.GetPosition(); pos != uint64(i+1) {
|
||||
t.Fatalf("StreamReader.GetPosition() should be at %d, but was at %d instead", i, pos)
|
||||
if pos := sr.Position(); pos != uint64(i+1) {
|
||||
t.Fatalf("StreamReader.Position() should be at %d, but was at %d instead", i, pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -31,36 +35,48 @@ func TestStreamReaderByte(t *testing.T) {
|
||||
func TestStreamReaderWord(t *testing.T) {
|
||||
data := []byte{0x78, 0x56, 0x34, 0x12}
|
||||
sr := CreateStreamReader(data)
|
||||
ret := sr.GetUInt16()
|
||||
|
||||
ret, err := sr.ReadUInt16()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if ret != 0x5678 {
|
||||
t.Fatalf("StreamReader.GetDword() was expected to return %X, but returned %X instead", 0x5678, ret)
|
||||
}
|
||||
|
||||
if pos := sr.GetPosition(); pos != 2 {
|
||||
t.Fatalf("StreamReader.GetPosition() should be at %d, but was at %d instead", 2, pos)
|
||||
if pos := sr.Position(); pos != 2 {
|
||||
t.Fatalf("StreamReader.Position() should be at %d, but was at %d instead", 2, pos)
|
||||
}
|
||||
|
||||
ret, err = sr.ReadUInt16()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
ret = sr.GetUInt16()
|
||||
if ret != 0x1234 {
|
||||
t.Fatalf("StreamReader.GetDword() was expected to return %X, but returned %X instead", 0x1234, ret)
|
||||
}
|
||||
|
||||
if pos := sr.GetPosition(); pos != 4 {
|
||||
t.Fatalf("StreamReader.GetPosition() should be at %d, but was at %d instead", 4, pos)
|
||||
if pos := sr.Position(); pos != 4 {
|
||||
t.Fatalf("StreamReader.Position() should be at %d, but was at %d instead", 4, pos)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStreamReaderDword(t *testing.T) {
|
||||
data := []byte{0x78, 0x56, 0x34, 0x12}
|
||||
sr := CreateStreamReader(data)
|
||||
ret := sr.GetUInt32()
|
||||
|
||||
ret, err := sr.ReadUInt32()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if ret != 0x12345678 {
|
||||
t.Fatalf("StreamReader.GetDword() was expected to return %X, but returned %X instead", 0x12345678, ret)
|
||||
}
|
||||
|
||||
if pos := sr.GetPosition(); pos != 4 {
|
||||
t.Fatalf("StreamReader.GetPosition() should be at %d, but was at %d instead", 4, pos)
|
||||
if pos := sr.Position(); pos != 4 {
|
||||
t.Fatalf("StreamReader.Position() should be at %d, but was at %d instead", 4, pos)
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ func (ad *AnimationData) GetRecords(name string) []*AnimationDataRecord {
|
||||
}
|
||||
|
||||
// Load loads the data into an AnimationData struct
|
||||
//nolint:gocognit,funlen // can't reduce
|
||||
func Load(data []byte) (*AnimationData, error) {
|
||||
reader := d2datautils.CreateStreamReader(data)
|
||||
animdata := &AnimationData{}
|
||||
@ -65,7 +66,11 @@ func Load(data []byte) (*AnimationData, error) {
|
||||
animdata.entries = make(map[string][]*AnimationDataRecord)
|
||||
|
||||
for blockIdx := range animdata.blocks {
|
||||
recordCount := reader.GetUInt32()
|
||||
recordCount, err := reader.ReadUInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if recordCount > maxRecordsPerBlock {
|
||||
return nil, fmt.Errorf("more than %d records in block", maxRecordsPerBlock)
|
||||
}
|
||||
@ -73,7 +78,10 @@ func Load(data []byte) (*AnimationData, error) {
|
||||
records := make([]*AnimationDataRecord, recordCount)
|
||||
|
||||
for recordIdx := uint32(0); recordIdx < recordCount; recordIdx++ {
|
||||
nameBytes := reader.ReadBytes(byteCountName)
|
||||
nameBytes, err := reader.ReadBytes(byteCountName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if nameBytes[byteCountName-1] != byte(0) {
|
||||
return nil, errors.New("animdata AnimationDataRecord name missing null terminator byte")
|
||||
@ -84,15 +92,27 @@ func Load(data []byte) (*AnimationData, error) {
|
||||
|
||||
animdata.hashTable[hashIdx] = hashName(name)
|
||||
|
||||
frames := reader.GetUInt32()
|
||||
speed := reader.GetUInt16()
|
||||
frames, err := reader.ReadUInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
speed, err := reader.ReadUInt16()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reader.SkipBytes(byteCountSpeedPadding)
|
||||
|
||||
events := make(map[int]AnimationEvent)
|
||||
|
||||
for eventIdx := 0; eventIdx < numEvents; eventIdx++ {
|
||||
event := AnimationEvent(reader.GetByte())
|
||||
eventByte, err := reader.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
event := AnimationEvent(eventByte)
|
||||
if event != AnimationEventNone {
|
||||
events[eventIdx] = event
|
||||
}
|
||||
@ -122,7 +142,7 @@ func Load(data []byte) (*AnimationData, error) {
|
||||
animdata.blocks[blockIdx] = b
|
||||
}
|
||||
|
||||
if reader.GetPosition() != uint64(len(data)) {
|
||||
if reader.Position() != uint64(len(data)) {
|
||||
return nil, errors.New("unable to parse animation data")
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,32 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
)
|
||||
|
||||
const (
|
||||
unknownByteCount = 21
|
||||
numHeaderBytes = 4 + unknownByteCount
|
||||
numLayerBytes = 9
|
||||
)
|
||||
|
||||
const (
|
||||
headerNumLayers = iota
|
||||
headerFramesPerDir
|
||||
headerNumDirs
|
||||
headerSpeed = numHeaderBytes - 1
|
||||
)
|
||||
|
||||
const (
|
||||
layerType = iota
|
||||
layerShadow
|
||||
layerSelectable
|
||||
layerTransparent
|
||||
layerDrawEffect
|
||||
layerWeaponClass
|
||||
)
|
||||
|
||||
const (
|
||||
badCharacter = string(byte(0))
|
||||
)
|
||||
|
||||
// COF is a structure that represents a COF file.
|
||||
type COF struct {
|
||||
NumberOfDirections int
|
||||
@ -23,13 +49,20 @@ type COF struct {
|
||||
func Load(fileData []byte) (*COF, error) {
|
||||
result := &COF{}
|
||||
streamReader := d2datautils.CreateStreamReader(fileData)
|
||||
result.NumberOfLayers = int(streamReader.GetByte())
|
||||
result.FramesPerDirection = int(streamReader.GetByte())
|
||||
result.NumberOfDirections = int(streamReader.GetByte())
|
||||
|
||||
streamReader.SkipBytes(21) //nolint:gomnd // Unknown data
|
||||
var b []byte
|
||||
|
||||
result.Speed = int(streamReader.GetByte())
|
||||
var err error
|
||||
|
||||
b, err = streamReader.ReadBytes(numHeaderBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.NumberOfLayers = int(b[headerNumLayers])
|
||||
result.FramesPerDirection = int(b[headerFramesPerDir])
|
||||
result.NumberOfDirections = int(b[headerNumDirs])
|
||||
result.Speed = int(b[headerSpeed])
|
||||
|
||||
streamReader.SkipBytes(3) //nolint:gomnd // Unknown data
|
||||
|
||||
@ -38,27 +71,44 @@ func Load(fileData []byte) (*COF, error) {
|
||||
|
||||
for i := 0; i < result.NumberOfLayers; i++ {
|
||||
layer := CofLayer{}
|
||||
layer.Type = d2enum.CompositeType(streamReader.GetByte())
|
||||
layer.Shadow = streamReader.GetByte()
|
||||
layer.Selectable = streamReader.GetByte() != 0
|
||||
layer.Transparent = streamReader.GetByte() != 0
|
||||
layer.DrawEffect = d2enum.DrawEffect(streamReader.GetByte())
|
||||
weaponClassStr := streamReader.ReadBytes(4) //nolint:gomnd // Binary data
|
||||
layer.WeaponClass = d2enum.WeaponClassFromString(strings.TrimSpace(strings.ReplaceAll(string(weaponClassStr), string(byte(0)), "")))
|
||||
|
||||
b, err = streamReader.ReadBytes(numLayerBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
layer.Type = d2enum.CompositeType(b[layerType])
|
||||
layer.Shadow = b[layerShadow]
|
||||
layer.Selectable = b[layerSelectable] > 0
|
||||
layer.Transparent = b[layerTransparent] > 0
|
||||
layer.DrawEffect = d2enum.DrawEffect(b[layerDrawEffect])
|
||||
|
||||
layer.WeaponClass = d2enum.WeaponClassFromString(strings.TrimSpace(strings.ReplaceAll(
|
||||
string(b[layerWeaponClass:]), badCharacter, "")))
|
||||
|
||||
result.CofLayers[i] = layer
|
||||
result.CompositeLayers[layer.Type] = i
|
||||
}
|
||||
|
||||
animationFrameBytes := streamReader.ReadBytes(result.FramesPerDirection)
|
||||
b, err = streamReader.ReadBytes(result.FramesPerDirection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.AnimationFrames = make([]d2enum.AnimationFrame, result.FramesPerDirection)
|
||||
|
||||
for i := range animationFrameBytes {
|
||||
result.AnimationFrames[i] = d2enum.AnimationFrame(animationFrameBytes[i])
|
||||
for i := range b {
|
||||
result.AnimationFrames[i] = d2enum.AnimationFrame(b[i])
|
||||
}
|
||||
|
||||
priorityLen := result.FramesPerDirection * result.NumberOfDirections * result.NumberOfLayers
|
||||
result.Priority = make([][][]d2enum.CompositeType, result.NumberOfDirections)
|
||||
priorityBytes := streamReader.ReadBytes(priorityLen)
|
||||
|
||||
priorityBytes, err := streamReader.ReadBytes(priorityLen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
priorityIndex := 0
|
||||
|
||||
for direction := 0; direction < result.NumberOfDirections; direction++ {
|
||||
|
@ -7,6 +7,9 @@ import (
|
||||
const (
|
||||
endOfScanLine = 0x80
|
||||
maxRunLength = 0x7f
|
||||
|
||||
terminationSize = 4
|
||||
terminatorSize = 3
|
||||
)
|
||||
|
||||
type scanlineState int
|
||||
@ -31,49 +34,118 @@ type DC6 struct {
|
||||
|
||||
// Load uses restruct to read the binary dc6 data into structs then parses image data from the frame data.
|
||||
func Load(data []byte) (*DC6, error) {
|
||||
const (
|
||||
terminationSize = 4
|
||||
terminatorSize = 3
|
||||
)
|
||||
|
||||
r := d2datautils.CreateStreamReader(data)
|
||||
|
||||
var dc DC6
|
||||
dc.Version = r.GetInt32()
|
||||
dc.Flags = r.GetUInt32()
|
||||
dc.Encoding = r.GetUInt32()
|
||||
dc.Termination = r.ReadBytes(terminationSize)
|
||||
dc.Directions = r.GetUInt32()
|
||||
dc.FramesPerDirection = r.GetUInt32()
|
||||
|
||||
var err error
|
||||
|
||||
err = dc.loadHeader(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
frameCount := int(dc.Directions * dc.FramesPerDirection)
|
||||
|
||||
dc.FramePointers = make([]uint32, frameCount)
|
||||
for i := 0; i < frameCount; i++ {
|
||||
dc.FramePointers[i] = r.GetUInt32()
|
||||
dc.FramePointers[i], err = r.ReadUInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
dc.Frames = make([]*DC6Frame, frameCount)
|
||||
|
||||
for i := 0; i < frameCount; i++ {
|
||||
frame := &DC6Frame{
|
||||
Flipped: r.GetUInt32(),
|
||||
Width: r.GetUInt32(),
|
||||
Height: r.GetUInt32(),
|
||||
OffsetX: r.GetInt32(),
|
||||
OffsetY: r.GetInt32(),
|
||||
Unknown: r.GetUInt32(),
|
||||
NextBlock: r.GetUInt32(),
|
||||
Length: r.GetUInt32(),
|
||||
}
|
||||
frame.FrameData = r.ReadBytes(int(frame.Length))
|
||||
frame.Terminator = r.ReadBytes(terminatorSize)
|
||||
dc.Frames[i] = frame
|
||||
if err := dc.loadFrames(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dc, nil
|
||||
}
|
||||
|
||||
func (d *DC6) loadHeader(r *d2datautils.StreamReader) error {
|
||||
var err error
|
||||
|
||||
if d.Version, err = r.ReadInt32(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.Flags, err = r.ReadUInt32(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.Encoding, err = r.ReadUInt32(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.Termination, err = r.ReadBytes(terminationSize); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.Directions, err = r.ReadUInt32(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.FramesPerDirection, err = r.ReadUInt32(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DC6) loadFrames(r *d2datautils.StreamReader) error {
|
||||
var err error
|
||||
|
||||
for i := 0; i < len(d.FramePointers); i++ {
|
||||
frame := &DC6Frame{}
|
||||
|
||||
if frame.Flipped, err = r.ReadUInt32(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if frame.Width, err = r.ReadUInt32(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if frame.Height, err = r.ReadUInt32(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if frame.OffsetX, err = r.ReadInt32(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if frame.OffsetY, err = r.ReadInt32(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if frame.Unknown, err = r.ReadUInt32(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if frame.NextBlock, err = r.ReadUInt32(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if frame.Length, err = r.ReadUInt32(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if frame.FrameData, err = r.ReadBytes(int(frame.Length)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if frame.Terminator, err = r.ReadBytes(terminatorSize); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Frames[i] = frame
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeFrame decodes the given frame to an indexed color texture
|
||||
func (d *DC6) DecodeFrame(frameIndex int) []byte {
|
||||
frame := d.Frames[frameIndex]
|
||||
|
@ -8,7 +8,24 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2path"
|
||||
)
|
||||
|
||||
const maxActNumber = 5
|
||||
const (
|
||||
maxActNumber = 5
|
||||
subType1 = 1
|
||||
subType2 = 2
|
||||
v2 = 2
|
||||
v3 = 3
|
||||
v4 = 4
|
||||
v7 = 7
|
||||
v8 = 8
|
||||
v9 = 9
|
||||
v10 = 10
|
||||
v12 = 12
|
||||
v13 = 13
|
||||
v14 = 14
|
||||
v15 = 15
|
||||
v16 = 16
|
||||
v18 = 18
|
||||
)
|
||||
|
||||
// DS1 represents the "stamp" data that is used to build up maps.
|
||||
type DS1 struct {
|
||||
@ -29,6 +46,7 @@ type DS1 struct {
|
||||
}
|
||||
|
||||
// LoadDS1 loads the specified DS1 file
|
||||
//nolint:funlen,gocognit,gocyclo // will refactor later
|
||||
func LoadDS1(fileData []byte) (*DS1, error) {
|
||||
ds1 := &DS1{
|
||||
Act: 1,
|
||||
@ -37,32 +55,67 @@ func LoadDS1(fileData []byte) (*DS1, error) {
|
||||
NumberOfShadowLayers: 1,
|
||||
NumberOfSubstitutionLayers: 0,
|
||||
}
|
||||
br := d2datautils.CreateStreamReader(fileData)
|
||||
ds1.Version = br.GetInt32()
|
||||
ds1.Width = br.GetInt32() + 1
|
||||
ds1.Height = br.GetInt32() + 1
|
||||
|
||||
if ds1.Version >= 8 { //nolint:gomnd // Version number
|
||||
ds1.Act = d2math.MinInt32(maxActNumber, br.GetInt32()+1)
|
||||
br := d2datautils.CreateStreamReader(fileData)
|
||||
|
||||
var err error
|
||||
|
||||
ds1.Version, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds1.Width, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds1.Height, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds1.Width++
|
||||
ds1.Height++
|
||||
|
||||
if ds1.Version >= v8 {
|
||||
ds1.Act, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds1.Act = d2math.MinInt32(maxActNumber, ds1.Act+1)
|
||||
}
|
||||
|
||||
if ds1.Version >= v10 {
|
||||
ds1.SubstitutionType, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ds1.Version >= 10 { //nolint:gomnd // Version number
|
||||
ds1.SubstitutionType = br.GetInt32()
|
||||
if ds1.SubstitutionType == 1 || ds1.SubstitutionType == 2 {
|
||||
ds1.NumberOfSubstitutionLayers = 1
|
||||
}
|
||||
}
|
||||
|
||||
if ds1.Version >= 3 { //nolint:gomnd // Version number
|
||||
if ds1.Version >= v3 {
|
||||
// These files reference things that don't exist anymore :-?
|
||||
numberOfFiles := br.GetInt32()
|
||||
numberOfFiles, err := br.ReadInt32() //nolint:govet // i want to re-use the err variable...
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds1.Files = make([]string, numberOfFiles)
|
||||
|
||||
for i := 0; i < int(numberOfFiles); i++ {
|
||||
ds1.Files[i] = ""
|
||||
|
||||
for {
|
||||
ch := br.GetByte()
|
||||
ch, err := br.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ch == 0 {
|
||||
break
|
||||
}
|
||||
@ -72,15 +125,22 @@ func LoadDS1(fileData []byte) (*DS1, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if ds1.Version >= 9 && ds1.Version <= 13 {
|
||||
if ds1.Version >= v9 && ds1.Version <= v13 {
|
||||
// Skipping two dwords because they are "meaningless"?
|
||||
br.SkipBytes(8) //nolint:gomnd // We don't know what's here
|
||||
}
|
||||
|
||||
if ds1.Version >= 4 { //nolint:gomnd // Version number
|
||||
ds1.NumberOfWalls = br.GetInt32()
|
||||
if ds1.Version >= 16 { //nolint:gomnd // Version number
|
||||
ds1.NumberOfFloors = br.GetInt32()
|
||||
if ds1.Version >= v4 {
|
||||
ds1.NumberOfWalls, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ds1.Version >= v16 {
|
||||
ds1.NumberOfFloors, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
ds1.NumberOfFloors = 1
|
||||
}
|
||||
@ -100,62 +160,139 @@ func LoadDS1(fileData []byte) (*DS1, error) {
|
||||
}
|
||||
}
|
||||
|
||||
ds1.loadLayerStreams(br, layerStream)
|
||||
ds1.loadObjects(br)
|
||||
ds1.loadSubstitutions(br)
|
||||
ds1.loadNPCs(br)
|
||||
err = ds1.loadLayerStreams(br, layerStream)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = ds1.loadObjects(br)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = ds1.loadSubstitutions(br)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = ds1.loadNPCs(br)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ds1, nil
|
||||
}
|
||||
|
||||
func (ds1 *DS1) loadObjects(br *d2datautils.StreamReader) {
|
||||
if ds1.Version >= 2 { //nolint:gomnd // Version number
|
||||
numberOfObjects := br.GetInt32()
|
||||
func (ds1 *DS1) loadObjects(br *d2datautils.StreamReader) error {
|
||||
if ds1.Version < v2 {
|
||||
ds1.Objects = make([]Object, 0)
|
||||
} else {
|
||||
numberOfObjects, err := br.ReadInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ds1.Objects = make([]Object, numberOfObjects)
|
||||
|
||||
for objIdx := 0; objIdx < int(numberOfObjects); objIdx++ {
|
||||
newObject := Object{}
|
||||
newObject.Type = int(br.GetInt32())
|
||||
newObject.ID = int(br.GetInt32())
|
||||
newObject.X = int(br.GetInt32())
|
||||
newObject.Y = int(br.GetInt32())
|
||||
newObject.Flags = int(br.GetInt32())
|
||||
obj := Object{}
|
||||
objType, err := br.ReadInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ds1.Objects[objIdx] = newObject
|
||||
objID, err := br.ReadInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
ds1.Objects = make([]Object, 0)
|
||||
|
||||
objX, err := br.ReadInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objY, err := br.ReadInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objFlags, err := br.ReadInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
obj.Type = int(objType)
|
||||
obj.ID = int(objID)
|
||||
obj.X = int(objX)
|
||||
obj.Y = int(objY)
|
||||
obj.Flags = int(objFlags)
|
||||
|
||||
ds1.Objects[objIdx] = obj
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ds1 *DS1) loadSubstitutions(br *d2datautils.StreamReader) {
|
||||
if ds1.Version >= 12 && (ds1.SubstitutionType == 1 || ds1.SubstitutionType == 2) {
|
||||
if ds1.Version >= 18 { //nolint:gomnd // Version number
|
||||
br.GetUInt32()
|
||||
func (ds1 *DS1) loadSubstitutions(br *d2datautils.StreamReader) error {
|
||||
var err error
|
||||
|
||||
hasSubstitutions := ds1.Version >= v12 && (ds1.SubstitutionType == subType1 || ds1.SubstitutionType == subType2)
|
||||
|
||||
if !hasSubstitutions {
|
||||
ds1.SubstitutionGroups = make([]SubstitutionGroup, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
if ds1.Version >= v18 {
|
||||
_, _ = br.ReadUInt32()
|
||||
}
|
||||
|
||||
numberOfSubGroups, err := br.ReadInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
numberOfSubGroups := br.GetInt32()
|
||||
ds1.SubstitutionGroups = make([]SubstitutionGroup, numberOfSubGroups)
|
||||
|
||||
for subIdx := 0; subIdx < int(numberOfSubGroups); subIdx++ {
|
||||
newSub := SubstitutionGroup{}
|
||||
newSub.TileX = br.GetInt32()
|
||||
newSub.TileY = br.GetInt32()
|
||||
newSub.WidthInTiles = br.GetInt32()
|
||||
newSub.HeightInTiles = br.GetInt32()
|
||||
newSub.Unknown = br.GetInt32()
|
||||
|
||||
newSub.TileX, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newSub.TileY, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newSub.WidthInTiles, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newSub.HeightInTiles, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newSub.Unknown, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ds1.SubstitutionGroups[subIdx] = newSub
|
||||
}
|
||||
} else {
|
||||
ds1.SubstitutionGroups = make([]SubstitutionGroup, 0)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (ds1 *DS1) setupStreamLayerTypes() []d2enum.LayerStreamType {
|
||||
var layerStream []d2enum.LayerStreamType
|
||||
|
||||
if ds1.Version < 4 { //nolint:gomnd // Version number
|
||||
if ds1.Version < v4 {
|
||||
layerStream = []d2enum.LayerStreamType{
|
||||
d2enum.LayerStreamWall1,
|
||||
d2enum.LayerStreamFloor1,
|
||||
@ -189,55 +326,100 @@ func (ds1 *DS1) setupStreamLayerTypes() []d2enum.LayerStreamType {
|
||||
return layerStream
|
||||
}
|
||||
|
||||
func (ds1 *DS1) loadNPCs(br *d2datautils.StreamReader) {
|
||||
if ds1.Version >= 14 { //nolint:gomnd // Version number
|
||||
numberOfNpcs := br.GetInt32()
|
||||
func (ds1 *DS1) loadNPCs(br *d2datautils.StreamReader) error {
|
||||
var err error
|
||||
|
||||
if ds1.Version < v14 {
|
||||
return err
|
||||
}
|
||||
|
||||
numberOfNpcs, err := br.ReadInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for npcIdx := 0; npcIdx < int(numberOfNpcs); npcIdx++ {
|
||||
numPaths := br.GetInt32()
|
||||
npcX := int(br.GetInt32())
|
||||
npcY := int(br.GetInt32())
|
||||
numPaths, err := br.ReadInt32() //nolint:govet // i want to re-use the err variable...
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
npcX, err := br.ReadInt32() //nolint:govet // i want to re-use the err variable...
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
npcY, err := br.ReadInt32() //nolint:govet // i want to re-use the err variable...
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objIdx := -1
|
||||
|
||||
for idx, ds1Obj := range ds1.Objects {
|
||||
if ds1Obj.X == npcX && ds1Obj.Y == npcY {
|
||||
if ds1Obj.X == int(npcX) && ds1Obj.Y == int(npcY) {
|
||||
objIdx = idx
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if objIdx > -1 {
|
||||
ds1.loadNpcPaths(br, objIdx, int(numPaths))
|
||||
err = ds1.loadNpcPaths(br, objIdx, int(numPaths))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if ds1.Version >= 15 { //nolint:gomnd // Version number
|
||||
if ds1.Version >= v15 {
|
||||
br.SkipBytes(int(numPaths) * 3) //nolint:gomnd // Unknown data
|
||||
} else {
|
||||
br.SkipBytes(int(numPaths) * 2) //nolint:gomnd // Unknown data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (ds1 *DS1) loadNpcPaths(br *d2datautils.StreamReader, objIdx, numPaths int) {
|
||||
func (ds1 *DS1) loadNpcPaths(br *d2datautils.StreamReader, objIdx, numPaths int) error {
|
||||
var err error
|
||||
|
||||
if ds1.Objects[objIdx].Paths == nil {
|
||||
ds1.Objects[objIdx].Paths = make([]d2path.Path, numPaths)
|
||||
}
|
||||
|
||||
for pathIdx := 0; pathIdx < numPaths; pathIdx++ {
|
||||
newPath := d2path.Path{}
|
||||
newPath.Position = d2vector.NewPosition(
|
||||
float64(br.GetInt32()),
|
||||
float64(br.GetInt32()))
|
||||
|
||||
if ds1.Version >= 15 { //nolint:gomnd // Version number
|
||||
newPath.Action = int(br.GetInt32())
|
||||
px, err := br.ReadInt32() //nolint:govet // i want to re-use the err variable...
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
py, err := br.ReadInt32() //nolint:govet // i want to re-use the err variable...
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newPath.Position = d2vector.NewPosition(float64(px), float64(py))
|
||||
|
||||
if ds1.Version >= v15 {
|
||||
action, err := br.ReadInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newPath.Action = int(action)
|
||||
}
|
||||
|
||||
ds1.Objects[objIdx].Paths[pathIdx] = newPath
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (ds1 *DS1) loadLayerStreams(br *d2datautils.StreamReader, layerStream []d2enum.LayerStreamType) {
|
||||
func (ds1 *DS1) loadLayerStreams(br *d2datautils.StreamReader, layerStream []d2enum.LayerStreamType) error {
|
||||
var err error
|
||||
|
||||
var dirLookup = []int32{
|
||||
0x00, 0x01, 0x02, 0x01, 0x02, 0x03, 0x03, 0x05, 0x05, 0x06,
|
||||
0x06, 0x07, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
|
||||
@ -249,7 +431,10 @@ func (ds1 *DS1) loadLayerStreams(br *d2datautils.StreamReader, layerStream []d2e
|
||||
|
||||
for y := 0; y < int(ds1.Height); y++ {
|
||||
for x := 0; x < int(ds1.Width); x++ {
|
||||
dw := br.GetUInt32()
|
||||
dw, err := br.ReadUInt32() //nolint:govet // i want to re-use the err variable...
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch layerStreamType {
|
||||
case d2enum.LayerStreamWall1, d2enum.LayerStreamWall2, d2enum.LayerStreamWall3, d2enum.LayerStreamWall4:
|
||||
@ -265,7 +450,7 @@ func (ds1 *DS1) loadLayerStreams(br *d2datautils.StreamReader, layerStream []d2e
|
||||
wallIndex := int(layerStreamType) - int(d2enum.LayerStreamOrientation1)
|
||||
c := int32(dw & 0x000000FF) //nolint:gomnd // Bitmask
|
||||
|
||||
if ds1.Version < 7 { //nolint:gomnd // Version number
|
||||
if ds1.Version < v7 {
|
||||
if c < int32(len(dirLookup)) {
|
||||
c = dirLookup[c]
|
||||
}
|
||||
@ -294,4 +479,6 @@ func (ds1 *DS1) loadLayerStreams(br *d2datautils.StreamReader, layerStream []d2e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
@ -22,55 +22,146 @@ const (
|
||||
BlockFormatIsometric BlockDataFormat = 1
|
||||
)
|
||||
|
||||
const (
|
||||
numUnknownHeaderBytes = 260
|
||||
knownMajorVersion = 7
|
||||
knownMinorVersion = 6
|
||||
numUnknownTileBytes1 = 4
|
||||
numUnknownTileBytes2 = 4
|
||||
numUnknownTileBytes3 = 7
|
||||
numUnknownTileBytes4 = 12
|
||||
)
|
||||
|
||||
// LoadDT1 loads a DT1 record
|
||||
//nolint:funlen // Can't reduce
|
||||
//nolint:funlen,gocognit,gocyclo // Can't reduce
|
||||
func LoadDT1(fileData []byte) (*DT1, error) {
|
||||
result := &DT1{}
|
||||
br := d2datautils.CreateStreamReader(fileData)
|
||||
ver1 := br.GetInt32()
|
||||
ver2 := br.GetInt32()
|
||||
|
||||
if ver1 != 7 || ver2 != 6 {
|
||||
return nil, fmt.Errorf("expected to have a version of 7.6, but got %d.%d instead", ver1, ver2)
|
||||
var err error
|
||||
|
||||
majorVersion, err := br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
br.SkipBytes(260) //nolint:gomnd // Unknown data
|
||||
minorVersion, err := br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
numberOfTiles := br.GetInt32()
|
||||
br.SetPosition(uint64(br.GetInt32()))
|
||||
if majorVersion != knownMajorVersion || minorVersion != knownMinorVersion {
|
||||
const fmtErr = "expected to have a version of 7.6, but got %d.%d instead"
|
||||
return nil, fmt.Errorf(fmtErr, majorVersion, minorVersion)
|
||||
}
|
||||
|
||||
br.SkipBytes(numUnknownHeaderBytes)
|
||||
|
||||
numberOfTiles, err := br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
position, err := br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
br.SetPosition(uint64(position))
|
||||
|
||||
result.Tiles = make([]Tile, numberOfTiles)
|
||||
|
||||
for tileIdx := range result.Tiles {
|
||||
newTile := Tile{}
|
||||
newTile.Direction = br.GetInt32()
|
||||
newTile.RoofHeight = br.GetInt16()
|
||||
newTile.MaterialFlags = NewMaterialFlags(br.GetUInt16())
|
||||
newTile.Height = br.GetInt32()
|
||||
newTile.Width = br.GetInt32()
|
||||
tile := Tile{}
|
||||
|
||||
br.SkipBytes(4) //nolint:gomnd // Unknown data
|
||||
|
||||
newTile.Type = br.GetInt32()
|
||||
newTile.Style = br.GetInt32()
|
||||
newTile.Sequence = br.GetInt32()
|
||||
newTile.RarityFrameIndex = br.GetInt32()
|
||||
|
||||
br.SkipBytes(4) //nolint:gomnd // Unknown data
|
||||
|
||||
for i := range newTile.SubTileFlags {
|
||||
newTile.SubTileFlags[i] = NewSubTileFlags(br.GetByte())
|
||||
tile.Direction, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
br.SkipBytes(7) //nolint:gomnd // Unknown data
|
||||
tile.RoofHeight, err = br.ReadInt16()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newTile.blockHeaderPointer = br.GetInt32()
|
||||
newTile.blockHeaderSize = br.GetInt32()
|
||||
newTile.Blocks = make([]Block, br.GetInt32())
|
||||
var matFlagBytes uint16
|
||||
|
||||
br.SkipBytes(12) //nolint:gomnd // Unknown data
|
||||
matFlagBytes, err = br.ReadUInt16()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.Tiles[tileIdx] = newTile
|
||||
tile.MaterialFlags = NewMaterialFlags(matFlagBytes)
|
||||
|
||||
tile.Height, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tile.Width, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
br.SkipBytes(numUnknownTileBytes1)
|
||||
|
||||
tile.Type, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tile.Style, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tile.Sequence, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tile.RarityFrameIndex, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
br.SkipBytes(numUnknownTileBytes2)
|
||||
|
||||
for i := range tile.SubTileFlags {
|
||||
var subtileFlagBytes byte
|
||||
|
||||
subtileFlagBytes, err = br.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tile.SubTileFlags[i] = NewSubTileFlags(subtileFlagBytes)
|
||||
}
|
||||
|
||||
br.SkipBytes(numUnknownTileBytes3)
|
||||
|
||||
tile.blockHeaderPointer, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tile.blockHeaderSize, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var numBlocks int32
|
||||
|
||||
numBlocks, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tile.Blocks = make([]Block, numBlocks)
|
||||
|
||||
br.SkipBytes(numUnknownTileBytes4)
|
||||
|
||||
result.Tiles[tileIdx] = tile
|
||||
}
|
||||
|
||||
for tileIdx := range result.Tiles {
|
||||
@ -78,14 +169,32 @@ func LoadDT1(fileData []byte) (*DT1, error) {
|
||||
br.SetPosition(uint64(tile.blockHeaderPointer))
|
||||
|
||||
for blockIdx := range tile.Blocks {
|
||||
result.Tiles[tileIdx].Blocks[blockIdx].X = br.GetInt16()
|
||||
result.Tiles[tileIdx].Blocks[blockIdx].Y = br.GetInt16()
|
||||
result.Tiles[tileIdx].Blocks[blockIdx].X, err = br.ReadInt16()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.Tiles[tileIdx].Blocks[blockIdx].Y, err = br.ReadInt16()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
br.SkipBytes(2) //nolint:gomnd // Unknown data
|
||||
|
||||
result.Tiles[tileIdx].Blocks[blockIdx].GridX = br.GetByte()
|
||||
result.Tiles[tileIdx].Blocks[blockIdx].GridY = br.GetByte()
|
||||
formatValue := br.GetInt16()
|
||||
result.Tiles[tileIdx].Blocks[blockIdx].GridX, err = br.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.Tiles[tileIdx].Blocks[blockIdx].GridY, err = br.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
formatValue, err := br.ReadInt16()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if formatValue == 1 {
|
||||
result.Tiles[tileIdx].Blocks[blockIdx].Format = BlockFormatIsometric
|
||||
@ -93,16 +202,27 @@ func LoadDT1(fileData []byte) (*DT1, error) {
|
||||
result.Tiles[tileIdx].Blocks[blockIdx].Format = BlockFormatRLE
|
||||
}
|
||||
|
||||
result.Tiles[tileIdx].Blocks[blockIdx].Length = br.GetInt32()
|
||||
result.Tiles[tileIdx].Blocks[blockIdx].Length, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
br.SkipBytes(2) //nolint:gomnd // Unknown data
|
||||
|
||||
result.Tiles[tileIdx].Blocks[blockIdx].FileOffset = br.GetInt32()
|
||||
result.Tiles[tileIdx].Blocks[blockIdx].FileOffset, err = br.ReadInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for blockIndex, block := range tile.Blocks {
|
||||
br.SetPosition(uint64(tile.blockHeaderPointer + block.FileOffset))
|
||||
encodedData := br.ReadBytes(int(block.Length))
|
||||
|
||||
encodedData, err := br.ReadBytes(int(block.Length))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tile.Blocks[blockIndex].EncodedData = encodedData
|
||||
}
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ func (v *Stream) loadBlock(blockIndex, expectedLength uint32) ([]byte, error) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
//nolint:gomnd // Will fix enum values later
|
||||
//nolint:gomnd,funlen,gocyclo // Will fix enum values later, can't help function length
|
||||
func decompressMulti(data []byte /*expectedLength*/, _ uint32) ([]byte, error) {
|
||||
compressionType := data[0]
|
||||
|
||||
@ -237,9 +237,9 @@ func decompressMulti(data []byte /*expectedLength*/, _ uint32) ([]byte, error) {
|
||||
case 0x10: // BZip2
|
||||
return []byte{}, errors.New("bzip2 decompression not supported")
|
||||
case 0x80: // IMA ADPCM Stereo
|
||||
return d2compression.WavDecompress(data[1:], 2), nil
|
||||
return d2compression.WavDecompress(data[1:], 2)
|
||||
case 0x40: // IMA ADPCM Mono
|
||||
return d2compression.WavDecompress(data[1:], 1), nil
|
||||
return d2compression.WavDecompress(data[1:], 1)
|
||||
case 0x12:
|
||||
return []byte{}, errors.New("lzma decompression not supported")
|
||||
// Combos
|
||||
@ -250,8 +250,11 @@ func decompressMulti(data []byte /*expectedLength*/, _ uint32) ([]byte, error) {
|
||||
// sparse then bzip2
|
||||
return []byte{}, errors.New("sparse decompression + bzip2 decompression not supported")
|
||||
case 0x41:
|
||||
sinput := d2compression.HuffmanDecompress(data[1:])
|
||||
sinput = d2compression.WavDecompress(sinput, 1)
|
||||
sinput, err := d2compression.WavDecompress(d2compression.HuffmanDecompress(data[1:]), 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmp := make([]byte, len(sinput))
|
||||
|
||||
copy(tmp, sinput)
|
||||
@ -262,8 +265,11 @@ func decompressMulti(data []byte /*expectedLength*/, _ uint32) ([]byte, error) {
|
||||
// return MpqWavCompression.Decompress(new MemoryStream(result), 1);
|
||||
return []byte{}, errors.New("pk + mpqwav decompression not supported")
|
||||
case 0x81:
|
||||
sinput := d2compression.HuffmanDecompress(data[1:])
|
||||
sinput = d2compression.WavDecompress(sinput, 2)
|
||||
sinput, err := d2compression.WavDecompress(d2compression.HuffmanDecompress(data[1:]), 2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmp := make([]byte, len(sinput))
|
||||
copy(tmp, sinput)
|
||||
|
||||
|
@ -10,6 +10,97 @@ import (
|
||||
// TextDictionary is a string map
|
||||
type TextDictionary map[string]string
|
||||
|
||||
func (td TextDictionary) loadHashEntries(hashEntries []*textDictionaryHashEntry, br *d2datautils.StreamReader) error {
|
||||
for i := 0; i < len(hashEntries); i++ {
|
||||
entry := textDictionaryHashEntry{}
|
||||
|
||||
active, err := br.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entry.IsActive = active > 0
|
||||
|
||||
entry.Index, err = br.ReadUInt16()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entry.HashValue, err = br.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entry.IndexString, err = br.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entry.NameString, err = br.ReadUInt32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entry.NameLength, err = br.ReadUInt16()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hashEntries[i] = &entry
|
||||
}
|
||||
|
||||
for idx := range hashEntries {
|
||||
if !hashEntries[idx].IsActive {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := td.loadHashEntry(idx, hashEntries[idx], br); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (td TextDictionary) loadHashEntry(idx int, hashEntry *textDictionaryHashEntry, br *d2datautils.StreamReader) error {
|
||||
br.SetPosition(uint64(hashEntry.NameString))
|
||||
|
||||
nameVal, err := br.ReadBytes(int(hashEntry.NameLength - 1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
value := string(nameVal)
|
||||
|
||||
br.SetPosition(uint64(hashEntry.IndexString))
|
||||
|
||||
key := ""
|
||||
|
||||
for {
|
||||
b, err := br.ReadByte()
|
||||
if b == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key += string(b)
|
||||
}
|
||||
|
||||
if key == "x" || key == "X" {
|
||||
key = "#" + strconv.Itoa(idx)
|
||||
}
|
||||
|
||||
_, exists := td[key]
|
||||
if !exists {
|
||||
td[key] = value
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type textDictionaryHashEntry struct {
|
||||
IsActive bool
|
||||
Index uint16
|
||||
@ -30,71 +121,46 @@ func LoadTextDictionary(dictionaryData []byte) (TextDictionary, error) {
|
||||
br := d2datautils.CreateStreamReader(dictionaryData)
|
||||
|
||||
// skip past the CRC
|
||||
br.ReadBytes(crcByteCount)
|
||||
_, _ = br.ReadBytes(crcByteCount)
|
||||
|
||||
numberOfElements := br.GetUInt16()
|
||||
hashTableSize := br.GetUInt32()
|
||||
var err error
|
||||
|
||||
numberOfElements, err := br.ReadUInt16()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hashTableSize, err := br.ReadUInt32()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Version (always 0)
|
||||
if _, err := br.ReadByte(); err != nil {
|
||||
if _, err = br.ReadByte(); err != nil {
|
||||
return nil, errors.New("error reading Version record")
|
||||
}
|
||||
|
||||
br.GetUInt32() // StringOffset
|
||||
br.GetUInt32() // When the number of times you have missed a match with a hash key equals this value, you give up because it is not there.
|
||||
br.GetUInt32() // FileSize
|
||||
_, _ = br.ReadUInt32() // StringOffset
|
||||
|
||||
// When the number of times you have missed a match with a
|
||||
// hash key equals this value, you give up because it is not there.
|
||||
_, _ = br.ReadUInt32()
|
||||
|
||||
_, _ = br.ReadUInt32() // FileSize
|
||||
|
||||
elementIndex := make([]uint16, numberOfElements)
|
||||
for i := 0; i < int(numberOfElements); i++ {
|
||||
elementIndex[i] = br.GetUInt16()
|
||||
}
|
||||
|
||||
hashEntries := make([]textDictionaryHashEntry, hashTableSize)
|
||||
for i := 0; i < int(hashTableSize); i++ {
|
||||
hashEntries[i] = textDictionaryHashEntry{
|
||||
br.GetByte() == 1,
|
||||
br.GetUInt16(),
|
||||
br.GetUInt32(),
|
||||
br.GetUInt32(),
|
||||
br.GetUInt32(),
|
||||
br.GetUInt16(),
|
||||
elementIndex[i], err = br.ReadUInt16()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for idx, hashEntry := range hashEntries {
|
||||
if br.EOF() {
|
||||
return nil, errors.New("unexpected end of text dictionary file")
|
||||
}
|
||||
hashEntries := make([]*textDictionaryHashEntry, hashTableSize)
|
||||
|
||||
if !hashEntry.IsActive {
|
||||
continue
|
||||
}
|
||||
|
||||
br.SetPosition(uint64(hashEntry.NameString))
|
||||
nameVal := br.ReadBytes(int(hashEntry.NameLength - 1))
|
||||
value := string(nameVal)
|
||||
|
||||
br.SetPosition(uint64(hashEntry.IndexString))
|
||||
|
||||
key := ""
|
||||
|
||||
for {
|
||||
b := br.GetByte()
|
||||
if b == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
key += string(b)
|
||||
}
|
||||
|
||||
if key == "x" || key == "X" {
|
||||
key = "#" + strconv.Itoa(idx)
|
||||
}
|
||||
|
||||
_, exists := lookupTable[key]
|
||||
if !exists {
|
||||
lookupTable[key] = value
|
||||
}
|
||||
err = lookupTable.loadHashEntries(hashEntries, br)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return lookupTable, nil
|
||||
|
@ -29,5 +29,8 @@ func (v *BlizzardIntro) OnLoad(loading d2screen.LoadingState) {
|
||||
|
||||
loading.Progress(fiftyPercent)
|
||||
|
||||
v.videoDecoder = d2video.CreateBinkDecoder(videoBytes)
|
||||
v.videoDecoder, err = d2video.CreateBinkDecoder(videoBytes)
|
||||
if err != nil {
|
||||
loading.Error(err)
|
||||
}
|
||||
}
|
||||
|
@ -176,7 +176,11 @@ func (v *Cinematics) playVideo(path string) {
|
||||
return
|
||||
}
|
||||
|
||||
v.videoDecoder = d2video.CreateBinkDecoder(videoBytes)
|
||||
v.videoDecoder, err = d2video.CreateBinkDecoder(videoBytes)
|
||||
if err != nil {
|
||||
v.Error(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Render renders the credits screen
|
||||
|
Loading…
Reference in New Issue
Block a user