ds1 encoder: fixed bug, when decoded and encoded back data wasn't the same = records' encoding methods was rewritten to use streamWriter.Pushbit

This commit is contained in:
M. Sz 2021-02-05 14:45:22 +01:00
parent 3dafb3ebcd
commit 5702d96cac
4 changed files with 90 additions and 27 deletions

View File

@ -4,7 +4,9 @@ import "bytes"
// StreamWriter allows you to create a byte array by streaming in writes of various sizes
type StreamWriter struct {
data *bytes.Buffer
data *bytes.Buffer
bitOffset int
bitCache byte
}
// CreateStreamWriter creates a new StreamWriter instance
@ -28,6 +30,64 @@ func (v *StreamWriter) PushBytes(b ...byte) {
}
}
func (v *StreamWriter) PushBit(b bool) {
if b {
v.bitCache |= (1 << v.bitOffset)
}
v.bitOffset++
if v.bitOffset != bitsPerByte {
return
}
v.PushBytes(v.bitCache)
v.bitCache = 0
v.bitOffset = 0
}
func (v *StreamWriter) PushBits(b byte, bits int) {
val := b
for i := 0; i < bits; i++ {
if val&1 == 1 {
v.PushBit(true)
} else {
v.PushBit(false)
}
val >>= 1
}
}
func (v *StreamWriter) PushBits16(b uint16, bits int) {
val := b
for i := 0; i < bits; i++ {
if val&1 == 1 {
v.PushBit(true)
} else {
v.PushBit(false)
}
val >>= 1
}
}
func (v *StreamWriter) PushBits32(b uint32, bits int) {
val := b
for i := 0; i < bits; i++ {
if val&1 == 1 {
v.PushBit(true)
} else {
v.PushBit(false)
}
val >>= 1
}
}
func (v *StreamWriter) ForcePushBits() {
for i := 0; i < bitsPerByte-v.bitOffset; i++ {
v.PushBit(0 != 0)
}
}
// PushInt16 writes a int16 word to the stream
func (v *StreamWriter) PushInt16(val int16) {
v.PushUint16(uint16(val))

View File

@ -534,23 +534,23 @@ func (ds1 *DS1) Marshal() []byte {
switch layerStreamType {
case d2enum.LayerStreamWall1, d2enum.LayerStreamWall2, d2enum.LayerStreamWall3, d2enum.LayerStreamWall4:
wallIndex := int(layerStreamType) - int(d2enum.LayerStreamWall1)
dw = ds1.Tiles[y][x].Walls[wallIndex].Encode()
ds1.Tiles[y][x].Walls[wallIndex].Encode(sw)
case d2enum.LayerStreamOrientation1, d2enum.LayerStreamOrientation2,
d2enum.LayerStreamOrientation3, d2enum.LayerStreamOrientation4:
wallIndex := int(layerStreamType) - int(d2enum.LayerStreamOrientation1)
dw |= uint32(ds1.Tiles[y][x].Walls[wallIndex].Type)
dw |= (uint32(ds1.Tiles[y][x].Walls[wallIndex].Zero) & 0xFFFFFF00) << 8 //nolint:gomnd // Bitmask
sw.PushUint32(dw)
case d2enum.LayerStreamFloor1, d2enum.LayerStreamFloor2:
floorIndex := int(layerStreamType) - int(d2enum.LayerStreamFloor1)
dw = ds1.Tiles[y][x].Floors[floorIndex].Encode()
ds1.Tiles[y][x].Floors[floorIndex].Encode(sw)
case d2enum.LayerStreamShadow:
dw = ds1.Tiles[y][x].Shadows[0].Encode()
ds1.Tiles[y][x].Shadows[0].Encode(sw)
case d2enum.LayerStreamSubstitute:
dw = ds1.Tiles[y][x].Substitutions[0].Unknown
sw.PushUint32(ds1.Tiles[y][x].Substitutions[0].Unknown)
}
sw.PushUint32(dw)
}
}
}

View File

@ -1,5 +1,9 @@
package d2ds1
import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils"
)
// FloorShadowRecord represents a floor or shadow record in a DS1 file.
type FloorShadowRecord struct {
Prop1 byte
@ -28,14 +32,12 @@ func (f *FloorShadowRecord) Decode(dw uint32) {
f.hidden = byte((dw & 0x80000000) >> 31) //nolint:gomnd // Bitmask
}
// Encode encodes floor-shadow record
func (f *FloorShadowRecord) Encode() (dw uint32) {
dw |= uint32(f.Prop1) & 0xFF //nolint:gomnd // Bitmask
dw |= (uint32(f.Sequence) & 0x3F) << 8 //nolint:gomnd // Bitmask
dw |= (uint32(f.Unknown1) & 0xFC) << 14 //nolint:gomnd // Bitmask
dw |= (uint32(f.Style) & 0x3F) << 20 //nolint:gomnd // Bitmask
dw |= (uint32(f.Unknown2) & 0x7C) << 26 //nolint:gomnd // Bitmask
dw |= (uint32(f.hidden) & 0x01) << 31 //nolint:gomnd // Bitmask
return dw
// Encode adds Floor's bits to stream writter given
func (f *FloorShadowRecord) Encode(sw *d2datautils.StreamWriter) {
sw.PushBits32(uint32(f.Prop1), 8)
sw.PushBits32(uint32(f.Sequence), 6)
sw.PushBits32(uint32(f.Unknown1), 6)
sw.PushBits32(uint32(f.Style), 6)
sw.PushBits32(uint32(f.Unknown2), 5)
sw.PushBits32(uint32(f.hidden), 1)
}

View File

@ -1,6 +1,9 @@
package d2ds1
import "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
)
// WallRecord represents a wall record.
type WallRecord struct {
@ -21,16 +24,14 @@ func (w *WallRecord) Hidden() bool {
return w.hidden > 0
}
// Encode encodes wall record
func (w *WallRecord) Encode() (dw uint32) {
dw |= uint32(w.Prop1) & 0xFF //nolint:gomnd // Bitmask
dw |= (uint32(w.Sequence) & 0x3F) << 8 //nolint:gomnd // Bitmask
dw |= (uint32(w.Unknown1) & 0xFC) << 14 //nolint:gomnd // Bitmask
dw |= (uint32(w.Style) & 0x3F) << 20 //nolint:gomnd // Bitmask
dw |= (uint32(w.Unknown2) & 0x7C) << 26 //nolint:gomnd // Bitmask
dw |= (uint32(w.hidden) & 0x01) << 31 //nolint:gomnd // Bitmask
return dw
// Encode adds wall's record's bytes into stream writer given
func (w *WallRecord) Encode(sw *d2datautils.StreamWriter) {
sw.PushBits32(uint32(w.Prop1), 8)
sw.PushBits32(uint32(w.Sequence), 6)
sw.PushBits32(uint32(w.Unknown1), 6)
sw.PushBits32(uint32(w.Style), 6)
sw.PushBits32(uint32(w.Unknown2), 5)
sw.PushBits32(uint32(w.hidden), 1)
}
// Decode decodes wall record