2020-01-26 00:39:13 -05:00
|
|
|
package d2dt1
|
|
|
|
|
|
|
|
import (
|
2020-02-26 08:39:38 -05:00
|
|
|
"fmt"
|
2020-09-12 16:25:09 -04:00
|
|
|
|
2020-09-08 15:58:35 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils"
|
2020-01-26 00:39:13 -05:00
|
|
|
)
|
|
|
|
|
2020-06-28 22:32:34 -04:00
|
|
|
// DT1 represents a DT1 file.
|
2020-01-26 00:39:13 -05:00
|
|
|
type DT1 struct {
|
|
|
|
Tiles []Tile
|
|
|
|
}
|
|
|
|
|
2020-06-24 10:13:11 -04:00
|
|
|
// BlockDataFormat represents the format of the block data
|
2020-01-26 00:39:13 -05:00
|
|
|
type BlockDataFormat int16
|
|
|
|
|
|
|
|
const (
|
2020-06-28 22:32:34 -04:00
|
|
|
// BlockFormatRLE specifies the block format is RLE encoded
|
|
|
|
BlockFormatRLE BlockDataFormat = 0
|
|
|
|
|
|
|
|
// BlockFormatIsometric specifies the block format isometrically encoded
|
|
|
|
BlockFormatIsometric BlockDataFormat = 1
|
2020-01-26 00:39:13 -05:00
|
|
|
)
|
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
const (
|
|
|
|
numUnknownHeaderBytes = 260
|
|
|
|
knownMajorVersion = 7
|
|
|
|
knownMinorVersion = 6
|
|
|
|
numUnknownTileBytes1 = 4
|
|
|
|
numUnknownTileBytes2 = 4
|
|
|
|
numUnknownTileBytes3 = 7
|
|
|
|
numUnknownTileBytes4 = 12
|
|
|
|
)
|
|
|
|
|
2020-06-24 10:13:11 -04:00
|
|
|
// LoadDT1 loads a DT1 record
|
2021-01-11 20:23:43 -05:00
|
|
|
//nolint:funlen,gocognit,gocyclo // Can't reduce
|
2020-02-26 08:39:38 -05:00
|
|
|
func LoadDT1(fileData []byte) (*DT1, error) {
|
|
|
|
result := &DT1{}
|
2020-09-08 15:58:35 -04:00
|
|
|
br := d2datautils.CreateStreamReader(fileData)
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
var err error
|
|
|
|
|
|
|
|
majorVersion, err := br.ReadInt32()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
minorVersion, err := br.ReadInt32()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2020-01-26 00:39:13 -05:00
|
|
|
}
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
br.SkipBytes(numUnknownHeaderBytes)
|
|
|
|
|
|
|
|
numberOfTiles, err := br.ReadInt32()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
position, err := br.ReadInt32()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
br.SetPosition(uint64(position))
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2020-01-26 00:39:13 -05:00
|
|
|
result.Tiles = make([]Tile, numberOfTiles)
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2020-01-26 00:39:13 -05:00
|
|
|
for tileIdx := range result.Tiles {
|
2021-01-11 20:23:43 -05:00
|
|
|
tile := Tile{}
|
|
|
|
|
|
|
|
tile.Direction, err = br.ReadInt32()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
tile.RoofHeight, err = br.ReadInt16()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var matFlagBytes uint16
|
|
|
|
|
|
|
|
matFlagBytes, err = br.ReadUInt16()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
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
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
subtileFlagBytes, err = br.ReadByte()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
tile.SubTileFlags[i] = NewSubTileFlags(subtileFlagBytes)
|
|
|
|
}
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
br.SkipBytes(numUnknownTileBytes3)
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
tile.blockHeaderPointer, err = br.ReadInt32()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2020-01-26 00:39:13 -05:00
|
|
|
}
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
tile.blockHeaderSize, err = br.ReadInt32()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var numBlocks int32
|
|
|
|
|
|
|
|
numBlocks, err = br.ReadInt32()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
tile.Blocks = make([]Block, numBlocks)
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
br.SkipBytes(numUnknownTileBytes4)
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
result.Tiles[tileIdx] = tile
|
2020-01-26 00:39:13 -05:00
|
|
|
}
|
2020-06-24 10:13:11 -04:00
|
|
|
|
|
|
|
for tileIdx := range result.Tiles {
|
|
|
|
tile := &result.Tiles[tileIdx]
|
2020-01-26 00:39:13 -05:00
|
|
|
br.SetPosition(uint64(tile.blockHeaderPointer))
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2020-01-26 00:39:13 -05:00
|
|
|
for blockIdx := range tile.Blocks {
|
2021-01-11 20:23:43 -05:00
|
|
|
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
|
|
|
|
}
|
2020-06-24 10:13:11 -04:00
|
|
|
|
|
|
|
br.SkipBytes(2) //nolint:gomnd // Unknown data
|
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
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
|
|
|
|
}
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2020-01-26 00:39:13 -05:00
|
|
|
if formatValue == 1 {
|
|
|
|
result.Tiles[tileIdx].Blocks[blockIdx].Format = BlockFormatIsometric
|
|
|
|
} else {
|
|
|
|
result.Tiles[tileIdx].Blocks[blockIdx].Format = BlockFormatRLE
|
|
|
|
}
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
result.Tiles[tileIdx].Blocks[blockIdx].Length, err = br.ReadInt32()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-06-24 10:13:11 -04:00
|
|
|
|
|
|
|
br.SkipBytes(2) //nolint:gomnd // Unknown data
|
|
|
|
|
2021-01-11 20:23:43 -05:00
|
|
|
result.Tiles[tileIdx].Blocks[blockIdx].FileOffset, err = br.ReadInt32()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-01-26 00:39:13 -05:00
|
|
|
}
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2020-01-26 00:39:13 -05:00
|
|
|
for blockIndex, block := range tile.Blocks {
|
|
|
|
br.SetPosition(uint64(tile.blockHeaderPointer + block.FileOffset))
|
2021-01-11 20:23:43 -05:00
|
|
|
|
|
|
|
encodedData, err := br.ReadBytes(int(block.Length))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-01-26 00:39:13 -05:00
|
|
|
tile.Blocks[blockIndex].EncodedData = encodedData
|
|
|
|
}
|
|
|
|
}
|
2020-06-24 10:13:11 -04:00
|
|
|
|
2020-02-26 08:39:38 -05:00
|
|
|
return result, nil
|
2020-01-26 00:39:13 -05:00
|
|
|
}
|