mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-06-10 09:50:42 +00:00
Ds1 refactor (#11)
* Refactoring d2ds1 * Adding setters/getters so that state management can be maintained internally when the ds1 struct is altered * Adding unit tests for DS1 * unit tests for ds1 (#4) * ds1 refactor: added test fore some methods; put tests in right order * ds1 refactor: unit tests for all methods * ds1 refactor: fixed build errors * ds1 refactor: lintfix * ds1 refactor: fixed bug with SetWidth, SetHeight methods * ds1 refactor: rename tile_record.go -> tile.go * ds1 refactor: unit test for SetTiles Co-authored-by: M. Sz <mszeptuch@protonmail.com> * renamed some files in d2ds1 * d2ds1.FloorShadow is now private * renamed another file * DS1.Tile() now calls update if dirty * Ds1 refactor: some test improvement (#5) * ds1 refactor: floor_shadow.go: methods Encode, Decode an Hidden are methods of floorShadow * ds1 refactor: test checks, if our methods sets all fields correctly * ds1 refactor: minor bugfixes * i don't remember what's this, but i commit it ;-) * ds1 refactor: reverted some pushed by mistake things Co-authored-by: M. Sz <mszeptuch@protonmail.com> * Ds1 refactor: test bugs + descriptive errors + SetNumberOfWall/FloorLayers (#6) * ds1 refactor: - removed DS1.layerStreamTypes field - written unit test for setupStreamLayerTypes method - added more descriptive error messages for LoadDS1 (and submethods) * ds1 refactor: added some missing error messages * ds1 refactor: fixed test bugs * ds1 refactor: removed unnecessary c1. and c2. comments in ds1_test errors * ds1 refactor: removed fmt from ds1_test * ds1 refactor: fixed bug with SetTiles test + lintfix * ds1 refactor: SetNumberOfWalls * ds1 refactor: SetTile(s) now changes walls/floors length if neccesary * ds1 refactor: removed unnecessary debugging fmt * ds1 refactor: added substitution layer and object with paths to example data Co-authored-by: M. Sz <mszeptuch@protonmail.com> * Ds1 refactor: removed npcIndexes field+fixed SetNumberOfWalls bug (#7) * ds1 refactor: removed npcIndexes field it was unnecessary, because described a number of objects with paths to use in encoder, but we can calculate manually * ds1 refactor: fixed set number of (layers) bug * ds1 refactor: SetNumberOf...Layers now returns error if incorrect number given * ds1 refactor: lintfix * ds1 refactor: rename: setupStreamLayerTypes -> GetStreamLayerTypes Co-authored-by: M. Sz <mszeptuch@protonmail.com> * WIP * Ds1 refactor - tests (#10) * ds1 refactor test: example data * added loader check * ds1 refactor: fixed bug, with loading substitutions; added descriptive error message in engine.go:118 and changed Logger.Error with Logger.Fatal * ds1 refactor: fixed loading bug * ds1 refactor: fixed bug when walls wasn't rendered (now we can see only walls :-) Co-authored-by: M. Sz <mszeptuch@protonmail.com> * ds1: floor rendering bugfix * ds1: implemented encode layers method * ds1: implemented encoder * ds1: update of ds1_test Co-authored-by: gravestench <dknuth0101@gmail.com> Co-authored-by: M. Sz <mszeptuch@protonmail.com>
This commit is contained in:
parent
6f41387e30
commit
6e7e7b9d3f
|
@ -475,7 +475,7 @@ func (ds1 *DS1) loadNpcPaths(br *d2datautils.StreamReader, objIdx, numPaths int)
|
|||
}
|
||||
|
||||
func (ds1 *DS1) loadLayerStreams(br *d2datautils.StreamReader) error {
|
||||
var dirLookup = []int32{
|
||||
dirLookup := []int32{
|
||||
0x00, 0x01, 0x02, 0x01, 0x02, 0x03, 0x03, 0x05, 0x05, 0x06,
|
||||
0x06, 0x07, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
|
||||
0x0F, 0x10, 0x11, 0x12, 0x14,
|
||||
|
@ -513,9 +513,9 @@ func (ds1 *DS1) loadLayerStreams(br *d2datautils.StreamReader) error {
|
|||
floorIndex := int(layerStreamType) - int(layerStreamFloor1)
|
||||
ds1.Floors[floorIndex].Tile(x, y).DecodeFloor(dw)
|
||||
case layerStreamShadow1:
|
||||
ds1.Floors[0].Tile(x, y).DecodeShadow(dw)
|
||||
ds1.Shadows[0].Tile(x, y).DecodeShadow(dw)
|
||||
case layerStreamSubstitute1:
|
||||
ds1.Floors[0].Tile(x, y).Substitution = dw
|
||||
ds1.Substitutions[0].Tile(x, y).Substitution = dw
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -529,145 +529,144 @@ func (ds1 *DS1) SetSize(w, h int) {
|
|||
ds1.ds1Layers.SetSize(w, h)
|
||||
}
|
||||
|
||||
//
|
||||
// // Marshal encodes ds1 back to byte slice
|
||||
// func (ds1 *DS1) Marshal() []byte {
|
||||
// // create stream writer
|
||||
// sw := d2datautils.CreateStreamWriter()
|
||||
//
|
||||
// // Step 1 - encode header
|
||||
// sw.PushInt32(ds1.version)
|
||||
// sw.PushInt32(ds1.width - 1)
|
||||
// sw.PushInt32(ds1.height - 1)
|
||||
//
|
||||
// if ds1.version >= v8 {
|
||||
// sw.PushInt32(ds1.Act - 1)
|
||||
// }
|
||||
//
|
||||
// if ds1.version >= v10 {
|
||||
// sw.PushInt32(ds1.substitutionType)
|
||||
// }
|
||||
//
|
||||
// if ds1.version >= v3 {
|
||||
// sw.PushInt32(int32(len(ds1.Files)))
|
||||
//
|
||||
// for _, i := range ds1.Files {
|
||||
// sw.PushBytes([]byte(i)...)
|
||||
//
|
||||
// // separator
|
||||
// sw.PushBytes(0)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if ds1.version >= v9 && ds1.version <= v13 {
|
||||
// sw.PushBytes(ds1.unknown1...)
|
||||
// }
|
||||
//
|
||||
// if ds1.version >= v4 {
|
||||
// sw.PushInt32(ds1.numberOfWallLayers)
|
||||
//
|
||||
// if ds1.version >= v16 {
|
||||
// sw.PushInt32(ds1.numberOfFloorLayers)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Step 2 - encode grid
|
||||
// ds1.encodeLayers(sw)
|
||||
//
|
||||
// // Step 3 - encode Objects
|
||||
// if !(ds1.version < v2) {
|
||||
// sw.PushInt32(int32(len(ds1.Objects)))
|
||||
//
|
||||
// for _, i := range ds1.Objects {
|
||||
// sw.PushUint32(uint32(i.Type))
|
||||
// sw.PushUint32(uint32(i.ID))
|
||||
// sw.PushUint32(uint32(i.X))
|
||||
// sw.PushUint32(uint32(i.Y))
|
||||
// sw.PushUint32(uint32(i.Flags))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Step 4 - encode Substitutions
|
||||
// if ds1.version >= v12 && (ds1.substitutionType == subType1 || ds1.substitutionType == subType2) {
|
||||
// sw.PushUint32(ds1.unknown2)
|
||||
//
|
||||
// sw.PushUint32(uint32(len(ds1.substitutionGroups)))
|
||||
//
|
||||
// for _, i := range ds1.substitutionGroups {
|
||||
// sw.PushInt32(i.TileX)
|
||||
// sw.PushInt32(i.TileY)
|
||||
// sw.PushInt32(i.WidthInTiles)
|
||||
// sw.PushInt32(i.HeightInTiles)
|
||||
// sw.PushInt32(i.Unknown)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Step 5 - encode NPC's and its paths
|
||||
// ds1.encodeNPCs(sw)
|
||||
//
|
||||
// return sw.GetBytes()
|
||||
// }
|
||||
//
|
||||
// func (ds1 *DS1) encodeLayers(sw *d2datautils.StreamWriter) {
|
||||
// /*
|
||||
// layerStreamTypes := ds1.getLayerSchema()
|
||||
//
|
||||
// for _, layerStreamType := range layerStreamTypes {
|
||||
// for y := 0; y < int(ds1.height); y++ {
|
||||
// for x := 0; x < int(ds1.width); x++ {
|
||||
// dw := uint32(0)
|
||||
//
|
||||
// switch layerStreamType {
|
||||
// case layerStreamWall1, layerStreamWall2, layerStreamWall3, layerStreamWall4:
|
||||
// wallIndex := int(layerStreamType) - int(layerStreamWall1)
|
||||
// ds1.tiles[y][x].Walls[wallIndex].Encode(sw)
|
||||
// case layerStreamOrientation1, layerStreamOrientation2,
|
||||
// layerStreamOrientation3, layerStreamOrientation4:
|
||||
// wallIndex := int(layerStreamType) - int(layerStreamOrientation1)
|
||||
// dw |= uint32(ds1.tiles[y][x].Walls[wallIndex].Type)
|
||||
// dw |= (uint32(ds1.tiles[y][x].Walls[wallIndex].Zero) & wallZeroBitmask) << wallZeroOffset
|
||||
//
|
||||
// sw.PushUint32(dw)
|
||||
// case layerStreamFloor1, layerStreamFloor2:
|
||||
// floorIndex := int(layerStreamType) - int(layerStreamFloor1)
|
||||
// ds1.tiles[y][x].Floors[floorIndex].Encode(sw)
|
||||
// case d2enum.layerStreamShadow1:
|
||||
// ds1.tiles[y][x].Shadows[0].Encode(sw)
|
||||
// case d2enum.layerStreamSubstitute1:
|
||||
// sw.PushUint32(ds1.tiles[y][x].Substitutions[0].Unknown)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// */
|
||||
// }
|
||||
//
|
||||
// func (ds1 *DS1) encodeNPCs(sw *d2datautils.StreamWriter) {
|
||||
// objectsWithPaths := make([]int, 0)
|
||||
//
|
||||
// for n, obj := range ds1.Objects {
|
||||
// if len(obj.Paths) != 0 {
|
||||
// objectsWithPaths = append(objectsWithPaths, n)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Step 5.1 - encode npc's
|
||||
// sw.PushUint32(uint32(len(objectsWithPaths)))
|
||||
//
|
||||
// // Step 5.2 - enoce npcs' paths
|
||||
// for objectIdx := range objectsWithPaths {
|
||||
// sw.PushUint32(uint32(len(ds1.Objects[objectIdx].Paths)))
|
||||
// sw.PushUint32(uint32(ds1.Objects[objectIdx].X))
|
||||
// sw.PushUint32(uint32(ds1.Objects[objectIdx].Y))
|
||||
//
|
||||
// for _, path := range ds1.Objects[objectIdx].Paths {
|
||||
// sw.PushUint32(uint32(path.Position.X()))
|
||||
// sw.PushUint32(uint32(path.Position.Y()))
|
||||
//
|
||||
// if ds1.version >= v15 {
|
||||
// sw.PushUint32(uint32(path.Action))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Marshal encodes ds1 back to byte slice
|
||||
func (ds1 *DS1) Marshal() []byte {
|
||||
// create stream writer
|
||||
sw := d2datautils.CreateStreamWriter()
|
||||
|
||||
// Step 1 - encode header
|
||||
sw.PushInt32(int32(ds1.version))
|
||||
sw.PushInt32(int32(ds1.width - 1))
|
||||
sw.PushInt32(int32(ds1.height - 1))
|
||||
|
||||
if ds1.version.specifiesAct() {
|
||||
sw.PushInt32(ds1.Act - 1)
|
||||
}
|
||||
|
||||
if ds1.version.specifiesSubstitutionType() {
|
||||
sw.PushInt32(ds1.substitutionType)
|
||||
}
|
||||
|
||||
if ds1.version.hasFileList() {
|
||||
sw.PushInt32(int32(len(ds1.Files)))
|
||||
|
||||
for _, i := range ds1.Files {
|
||||
sw.PushBytes([]byte(i)...)
|
||||
|
||||
// separator
|
||||
sw.PushBytes(0)
|
||||
}
|
||||
}
|
||||
|
||||
if ds1.version.hasUnknown1Bytes() {
|
||||
sw.PushBytes(ds1.unknown1...)
|
||||
}
|
||||
|
||||
if ds1.version.specifiesWalls() {
|
||||
sw.PushInt32(int32(len(ds1.Walls)))
|
||||
|
||||
if ds1.version.specifiesFloors() {
|
||||
sw.PushInt32(int32(len(ds1.Walls)))
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2 - encode grid
|
||||
ds1.encodeLayers(sw)
|
||||
|
||||
// Step 3 - encode Objects
|
||||
if ds1.version.hasObjects() {
|
||||
sw.PushInt32(int32(len(ds1.Objects)))
|
||||
|
||||
for _, i := range ds1.Objects {
|
||||
sw.PushUint32(uint32(i.Type))
|
||||
sw.PushUint32(uint32(i.ID))
|
||||
sw.PushUint32(uint32(i.X))
|
||||
sw.PushUint32(uint32(i.Y))
|
||||
sw.PushUint32(uint32(i.Flags))
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4 - encode Substitutions
|
||||
hasSubstitutions := ds1.version.hasSubstitutions() &&
|
||||
(ds1.substitutionType == subType1 || ds1.substitutionType == subType2)
|
||||
|
||||
if hasSubstitutions {
|
||||
sw.PushUint32(ds1.unknown2)
|
||||
|
||||
sw.PushUint32(uint32(len(ds1.substitutionGroups)))
|
||||
|
||||
for _, i := range ds1.substitutionGroups {
|
||||
sw.PushInt32(i.TileX)
|
||||
sw.PushInt32(i.TileY)
|
||||
sw.PushInt32(i.WidthInTiles)
|
||||
sw.PushInt32(i.HeightInTiles)
|
||||
sw.PushInt32(i.Unknown)
|
||||
}
|
||||
}
|
||||
|
||||
// Step 5 - encode NPC's and its paths
|
||||
ds1.encodeNPCs(sw)
|
||||
|
||||
return sw.GetBytes()
|
||||
}
|
||||
|
||||
func (ds1 *DS1) encodeLayers(sw *d2datautils.StreamWriter) {
|
||||
layerStreamTypes := ds1.getLayerSchema()
|
||||
|
||||
for _, layerStreamType := range layerStreamTypes {
|
||||
for y := 0; y < int(ds1.height); y++ {
|
||||
for x := 0; x < int(ds1.width); x++ {
|
||||
dw := uint32(0)
|
||||
|
||||
switch layerStreamType {
|
||||
case layerStreamWall1, layerStreamWall2, layerStreamWall3, layerStreamWall4:
|
||||
wallIndex := int(layerStreamType) - int(layerStreamWall1)
|
||||
ds1.Walls[wallIndex].Tile(x, y).EncodeWall(sw)
|
||||
case layerStreamOrientation1, layerStreamOrientation2,
|
||||
layerStreamOrientation3, layerStreamOrientation4:
|
||||
wallIndex := int(layerStreamType) - int(layerStreamOrientation1)
|
||||
dw |= uint32(ds1.Walls[wallIndex].Tile(x, y).Type)
|
||||
dw |= (uint32(ds1.Walls[wallIndex].Tile(x, y).Zero) & wallZeroBitmask) << wallZeroOffset
|
||||
|
||||
sw.PushUint32(dw)
|
||||
case layerStreamFloor1, layerStreamFloor2:
|
||||
floorIndex := int(layerStreamType) - int(layerStreamFloor1)
|
||||
ds1.Floors[floorIndex].Tile(x, y).EncodeFloor(sw)
|
||||
case layerStreamShadow1:
|
||||
ds1.Shadows[0].Tile(x, y).EncodeShadow(sw)
|
||||
case layerStreamSubstitute1:
|
||||
sw.PushUint32(ds1.Substitutions[0].Tile(x, y).Substitution)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ds1 *DS1) encodeNPCs(sw *d2datautils.StreamWriter) {
|
||||
objectsWithPaths := make([]int, 0)
|
||||
|
||||
for n, obj := range ds1.Objects {
|
||||
if len(obj.Paths) != 0 {
|
||||
objectsWithPaths = append(objectsWithPaths, n)
|
||||
}
|
||||
}
|
||||
|
||||
// Step 5.1 - encode npc's
|
||||
sw.PushUint32(uint32(len(objectsWithPaths)))
|
||||
|
||||
// Step 5.2 - enoce npcs' paths
|
||||
for objectIdx := range objectsWithPaths {
|
||||
sw.PushUint32(uint32(len(ds1.Objects[objectIdx].Paths)))
|
||||
sw.PushUint32(uint32(ds1.Objects[objectIdx].X))
|
||||
sw.PushUint32(uint32(ds1.Objects[objectIdx].Y))
|
||||
|
||||
for _, path := range ds1.Objects[objectIdx].Paths {
|
||||
sw.PushUint32(uint32(path.Position.X()))
|
||||
sw.PushUint32(uint32(path.Position.Y()))
|
||||
|
||||
if ds1.version >= v15 {
|
||||
sw.PushUint32(uint32(path.Action))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,6 @@ package d2ds1
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2path"
|
||||
)
|
||||
|
@ -98,8 +95,8 @@ func exampleData() *DS1 {
|
|||
|
||||
result := &DS1{
|
||||
ds1Layers: &ds1Layers{
|
||||
width: 20,
|
||||
height: 80,
|
||||
width: 2,
|
||||
height: 2,
|
||||
Floors: layerGroup{
|
||||
// number of floors (one floor)
|
||||
{
|
||||
|
@ -188,35 +185,13 @@ func exampleData() *DS1 {
|
|||
return result
|
||||
}
|
||||
|
||||
func TestDS1_Load(t *testing.T) {
|
||||
testFile, fileErr := os.Open("testdata/testdata.ds1")
|
||||
if fileErr != nil {
|
||||
t.Error("cannot open test data file")
|
||||
return
|
||||
}
|
||||
func TestDS1_MarshalUnmarshal(t *testing.T) {
|
||||
ds1 := exampleData()
|
||||
|
||||
data := make([]byte, 0)
|
||||
buf := make([]byte, 16)
|
||||
|
||||
for {
|
||||
numRead, err := testFile.Read(buf)
|
||||
|
||||
data = append(data, buf[:numRead]...)
|
||||
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
data := ds1.Marshal()
|
||||
|
||||
_, loadErr := Unmarshal(data)
|
||||
if loadErr != nil {
|
||||
t.Error(loadErr)
|
||||
}
|
||||
|
||||
err := testFile.Close()
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user