diff --git a/d2common/bitstream.go b/d2common/bitstream.go index d7e7f562..543780ea 100644 --- a/d2common/bitstream.go +++ b/d2common/bitstream.go @@ -8,6 +8,11 @@ import ( var _ d2interface.BitStream = &BitStream{} // Static check to confirm struct conforms to interface +const ( + maxBits = 16 + bitsPerByte = 8 +) + // BitStream is a utility class for reading groups of bits from a stream type BitStream struct { data []byte @@ -30,7 +35,7 @@ func CreateBitStream(newData []byte) *BitStream { // ReadBits reads the specified number of bits and returns the value func (v *BitStream) ReadBits(bitCount int) int { - if bitCount > 16 { + if bitCount > maxBits { log.Panic("Maximum BitCount is 16") } @@ -38,7 +43,7 @@ func (v *BitStream) ReadBits(bitCount int) int { return -1 } - result := v.current & (0xffff >> uint(16-bitCount)) + result := v.current & (0xffff >> uint(maxBits-bitCount)) v.WasteBits(bitCount) return result @@ -46,7 +51,7 @@ func (v *BitStream) ReadBits(bitCount int) int { // PeekByte returns the current byte without adjusting the position func (v *BitStream) PeekByte() int { - if !v.EnsureBits(8) { + if !v.EnsureBits(bitsPerByte) { return -1 } diff --git a/d2common/path_tile.go b/d2common/path_tile.go index 709c74d9..cf5f9879 100644 --- a/d2common/path_tile.go +++ b/d2common/path_tile.go @@ -54,7 +54,7 @@ func (t *PathTile) PathNeighbors() []d2astar.Pather { } // PathNeighborCost calculates the exact movement cost to neighbor nodes -func (t *PathTile) PathNeighborCost(to d2astar.Pather) float64 { +func (t *PathTile) PathNeighborCost(_ d2astar.Pather) float64 { return 1 // No cost specifics currently... } diff --git a/d2common/stream_reader.go b/d2common/stream_reader.go index c0f5edf2..a262293c 100644 --- a/d2common/stream_reader.go +++ b/d2common/stream_reader.go @@ -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 @@ -40,17 +46,28 @@ func (v *StreamReader) GetByte() byte { // GetUInt16 returns a uint16 word from the stream func (v *StreamReader) GetUInt16() uint16 { - result := uint16(v.data[v.position]) - result += uint16(v.data[v.position+1]) << 8 - v.position += 2 + var result uint16 + + for offset := uint64(0); offset < bytesPerInt16; offset++ { + shift := uint8(bitsPerByte * offset) + result += uint16(v.data[v.position+offset]) << shift + } + + v.position += bytesPerInt16 return result } // GetInt16 returns a int16 word from the stream func (v *StreamReader) GetInt16() int16 { - result := (int16(v.data[v.position+1]) << uint(8)) + int16(v.data[v.position]) - v.position += 2 + var result int16 + + for offset := uint64(0); offset < bytesPerInt16; offset++ { + shift := uint8(bitsPerByte * offset) + result += int16(v.data[v.position+offset]) << shift + } + + v.position += bytesPerInt16 return result } @@ -62,37 +79,42 @@ func (v *StreamReader) SetPosition(newPosition uint64) { // GetUInt32 returns a uint32 dword from the stream func (v *StreamReader) GetUInt32() uint32 { - result := (uint32(v.data[v.position+3]) << uint(24)) + - (uint32(v.data[v.position+2]) << uint(16)) + - (uint32(v.data[v.position+1]) << uint(8)) + - uint32(v.data[v.position]) - v.position += 4 + var result uint32 + + for offset := uint64(0); offset < bytesPerInt32; offset++ { + shift := uint8(bitsPerByte * offset) + result += uint32(v.data[v.position+offset]) << shift + } + + v.position += bytesPerInt32 return result } // GetInt32 returns an int32 dword from the stream func (v *StreamReader) GetInt32() int32 { - result := (int32(v.data[v.position+3]) << uint(24)) + - (int32(v.data[v.position+2]) << uint(16)) + - (int32(v.data[v.position+1]) << uint(8)) + - int32(v.data[v.position]) - v.position += 4 + var result int32 + + for offset := uint64(0); offset < bytesPerInt32; offset++ { + shift := uint8(bitsPerByte * offset) + result += int32(v.data[v.position+offset]) << shift + } + + v.position += bytesPerInt32 return result } // GetUint64 returns a uint64 qword from the stream func (v *StreamReader) GetUint64() uint64 { - result := (uint64(v.data[v.position+7]) << uint(56)) + - (uint64(v.data[v.position+6]) << uint(48)) + - (uint64(v.data[v.position+5]) << uint(40)) + - (uint64(v.data[v.position+4]) << uint(32)) + - (uint64(v.data[v.position+3]) << uint(24)) + - (uint64(v.data[v.position+2]) << uint(16)) + - (uint64(v.data[v.position+1]) << uint(8)) + - uint64(v.data[v.position]) - v.position += 8 + var result uint64 + + for offset := uint64(0); offset < bytesPerInt64; offset++ { + shift := uint8(bitsPerByte * offset) + result += uint64(v.data[v.position+offset]) << shift + } + + v.position += bytesPerInt64 return result } diff --git a/d2common/stream_writer.go b/d2common/stream_writer.go index 111962fc..38595353 100644 --- a/d2common/stream_writer.go +++ b/d2common/stream_writer.go @@ -2,6 +2,10 @@ package d2common import "bytes" +const ( + byteMask = 0xFF +) + // StreamWriter allows you to create a byte array by streaming in writes of various sizes type StreamWriter struct { data *bytes.Buffer @@ -23,34 +27,34 @@ func (v *StreamWriter) PushByte(val byte) { // PushUint16 writes an uint16 word to the stream func (v *StreamWriter) PushUint16(val uint16) { - v.data.WriteByte(byte(val) & 0xFF) - v.data.WriteByte(byte(val>>8) & 0xFF) + for count := 0; count < bytesPerInt16; count++ { + shift := count * bitsPerByte + v.data.WriteByte(byte(val>>shift) & byteMask) + } } // PushInt16 writes a int16 word to the stream func (v *StreamWriter) PushInt16(val int16) { - v.data.WriteByte(byte(val) & 0xFF) - v.data.WriteByte(byte(val>>8) & 0xFF) + for count := 0; count < bytesPerInt16; count++ { + shift := count * bitsPerByte + v.data.WriteByte(byte(val>>shift) & byteMask) + } } // PushUint32 writes a uint32 dword to the stream func (v *StreamWriter) PushUint32(val uint32) { - v.data.WriteByte(byte(val) & 0xFF) - v.data.WriteByte(byte(val>>8) & 0xFF) - v.data.WriteByte(byte(val>>16) & 0xFF) - v.data.WriteByte(byte(val>>24) & 0xFF) + for count := 0; count < bytesPerInt32; count++ { + shift := count * bitsPerByte + v.data.WriteByte(byte(val>>shift) & byteMask) + } } // PushUint64 writes a uint64 qword to the stream func (v *StreamWriter) PushUint64(val uint64) { - v.data.WriteByte(byte(val) & 0xFF) - v.data.WriteByte(byte(val>>8) & 0xFF) - v.data.WriteByte(byte(val>>16) & 0xFF) - v.data.WriteByte(byte(val>>24) & 0xFF) - v.data.WriteByte(byte(val>>32) & 0xFF) - v.data.WriteByte(byte(val>>40) & 0xFF) - v.data.WriteByte(byte(val>>48) & 0xFF) - v.data.WriteByte(byte(val>>56) & 0xFF) + for count := 0; count < bytesPerInt64; count++ { + shift := count * bitsPerByte + v.data.WriteByte(byte(val>>shift) & byteMask) + } } // PushInt64 writes a uint64 qword to the stream diff --git a/d2common/text_dictionary.go b/d2common/text_dictionary.go index e421594f..9a8fb8fb 100644 --- a/d2common/text_dictionary.go +++ b/d2common/text_dictionary.go @@ -16,6 +16,10 @@ type textDictionaryHashEntry struct { var lookupTable map[string]string +const ( + crcByteCount = 2 +) + // TranslateString returns the translation of the given string func TranslateString(key string) string { result, ok := lookupTable[key] @@ -35,10 +39,13 @@ func LoadTextDictionary(dictionaryData []byte) { } br := CreateStreamReader(dictionaryData) - // CRC - br.ReadBytes(2) + + // skip past the CRC + br.ReadBytes(crcByteCount) + numberOfElements := br.GetUInt16() hashTableSize := br.GetUInt32() + // Version (always 0) if _, err := br.ReadByte(); err != nil { log.Fatal("Error reading Version record") diff --git a/d2common/timeutils.go b/d2common/timeutils.go index ad95e4fd..641141c9 100644 --- a/d2common/timeutils.go +++ b/d2common/timeutils.go @@ -2,8 +2,12 @@ package d2common import "time" +const ( + nanoseconds = 1000000000.0 +) + // Now returns how many seconds have elapsed since Unix time (January 1, 1970 UTC) func Now() float64 { // Unix time in nanoseconds divided by how many nanoseconds in a second - return float64(time.Now().UnixNano()) / 1000000000.0 + return float64(time.Now().UnixNano()) / nanoseconds }