From 02082925b5d607d8f7fa6b8c641ed166a37240cf Mon Sep 17 00:00:00 2001 From: Tim Sarbin Date: Thu, 31 Oct 2019 13:39:05 -0400 Subject: [PATCH] Added logic in preparation for tile rendering --- Common/LevelPresets.go | 1 - Common/LevelTypes.go | 1 - MapEngine/DT1.go | 55 +++++++++-------- MapEngine/Region.go | 129 ++++++++++++++++++++++++++++++++++++++++ Scenes/MapEngineTest.go | 11 +++- 5 files changed, 168 insertions(+), 29 deletions(-) create mode 100644 MapEngine/Region.go diff --git a/Common/LevelPresets.go b/Common/LevelPresets.go index 744f6dee..f6853996 100644 --- a/Common/LevelPresets.go +++ b/Common/LevelPresets.go @@ -29,7 +29,6 @@ type LevelPresetRecord struct { var LevelPresets []LevelPresetRecord func LoadLevelPresets(fileProvider FileProvider) { - LevelPresets = make([]LevelPresetRecord, 0) levelTypesData := fileProvider.LoadFile(ResourcePaths.LevelPreset) sr := CreateStreamReader(levelTypesData) numRecords := sr.GetInt32() diff --git a/Common/LevelTypes.go b/Common/LevelTypes.go index 5e3f451b..838e7739 100644 --- a/Common/LevelTypes.go +++ b/Common/LevelTypes.go @@ -15,7 +15,6 @@ type LevelTypeRecord struct { var LevelTypes []LevelTypeRecord func LoadLevelTypes(fileProvider FileProvider) { - LevelTypes = make([]LevelTypeRecord, 0) levelTypesData := fileProvider.LoadFile(ResourcePaths.LevelType) sr := CreateStreamReader(levelTypesData) numRecords := sr.GetInt32() diff --git a/MapEngine/DT1.go b/MapEngine/DT1.go index 49e48369..6b17c94e 100644 --- a/MapEngine/DT1.go +++ b/MapEngine/DT1.go @@ -9,13 +9,14 @@ import ( // https://d2mods.info/forum/viewtopic.php?t=65163 type Block struct { - X int16 - Y int16 - GridX byte - GridY byte - Format int16 - Length int32 - FileOffset int32 + X int16 + Y int16 + GridX byte + GridY byte + Format BlockDataFormat + EncodedData []byte + Length int32 + FileOffset int32 } type Tile struct { @@ -32,13 +33,20 @@ type Tile struct { SubTileFlags [25]byte blockHeaderPointer int32 blockHeaderSize int32 - blocks []Block + Blocks []Block } type DT1 struct { Tiles []Tile } +type BlockDataFormat int16 + +const ( + BlockFormatRLE BlockDataFormat = 0 // Not 1 + BlockFormatIsometric BlockDataFormat = 1 +) + func LoadDT1(path string, fileProvider Common.FileProvider) *DT1 { result := &DT1{} fileData := fileProvider.LoadFile(path) @@ -72,30 +80,29 @@ func LoadDT1(path string, fileProvider Common.FileProvider) *DT1 { br.SkipBytes(7) newTile.blockHeaderPointer = br.GetInt32() newTile.blockHeaderSize = br.GetInt32() - newTile.blocks = make([]Block, br.GetInt32()) + newTile.Blocks = make([]Block, br.GetInt32()) br.SkipBytes(12) result.Tiles[tileIdx] = newTile } for tileIdx, tile := range result.Tiles { 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() + for blockIdx := range tile.Blocks { + result.Tiles[tileIdx].Blocks[blockIdx].X = br.GetInt16() + result.Tiles[tileIdx].Blocks[blockIdx].Y = br.GetInt16() br.SkipBytes(2) - result.Tiles[tileIdx].blocks[blockIdx].GridX = br.GetByte() - result.Tiles[tileIdx].blocks[blockIdx].GridY = br.GetByte() - result.Tiles[tileIdx].blocks[blockIdx].Format = br.GetInt16() - result.Tiles[tileIdx].blocks[blockIdx].Length = br.GetInt32() + result.Tiles[tileIdx].Blocks[blockIdx].GridX = br.GetByte() + result.Tiles[tileIdx].Blocks[blockIdx].GridY = br.GetByte() + result.Tiles[tileIdx].Blocks[blockIdx].Format = BlockDataFormat(br.GetInt16()) + result.Tiles[tileIdx].Blocks[blockIdx].Length = br.GetInt32() br.SkipBytes(2) - result.Tiles[tileIdx].blocks[blockIdx].FileOffset = br.GetInt32() + result.Tiles[tileIdx].Blocks[blockIdx].FileOffset = br.GetInt32() } - /* - for blockIdx, block := range tile.blocks { - br.SetPosition(uint64(tile.blockHeaderPointer + block.FileOffset)) - encodedData, _ := br.ReadBytes(block.Length) - bs := Common.CreateBitStream(encodedData) - } - */ + for blockIndex, block := range tile.Blocks { + br.SetPosition(uint64(tile.blockHeaderPointer + block.FileOffset)) + encodedData, _ := br.ReadBytes(int(block.Length)) + tile.Blocks[blockIndex].EncodedData = encodedData + } + } return result } diff --git a/MapEngine/Region.go b/MapEngine/Region.go new file mode 100644 index 00000000..e7e08fef --- /dev/null +++ b/MapEngine/Region.go @@ -0,0 +1,129 @@ +package MapEngine + +import ( + "log" + "math" + "math/rand" + + "github.com/hajimehoshi/ebiten" + + "github.com/essial/OpenDiablo2/Common" +) + +type Region struct { + levelType Common.LevelTypeRecord + levelPreset Common.LevelPresetRecord + TileWidth int32 + TileHeight int32 + Tiles []Tile + DS1 *DS1 +} + +type RegionLayerType int + +const ( + RegionLayerTypeFloors RegionLayerType = 0 + RegionLayerTypeWalls RegionLayerType = 1 +) + +type RegionIdType int + +const ( + RegionNoneRegionAct1Town = 1 + RegionAct1Wilderness RegionIdType = 2 + RegionAct1Cave RegionIdType = 3 + RegionAct1Crypt RegionIdType = 4 + RegionAct1Monestary RegionIdType = 5 + RegionAct1Courtyard RegionIdType = 6 + RegionAct1Barracks RegionIdType = 7 + RegionAct1Jail RegionIdType = 8 + RegionAct1Cathedral RegionIdType = 9 + RegionAct1Catacombs RegionIdType = 10 + RegionAct1Tristram RegionIdType = 11 + RegionAct2Town RegionIdType = 12 + RegionAct2Sewer RegionIdType = 13 + RegionAct2Harem RegionIdType = 14 + RegionAct2Basement RegionIdType = 15 + RegionAct2Desert RegionIdType = 16 + RegionAct2Tomb RegionIdType = 17 + RegionAct2Lair RegionIdType = 18 + RegionAct2Arcane RegionIdType = 19 + RegionAct3Town RegionIdType = 20 + RegionAct3Jungle RegionIdType = 21 + RegionAct3Kurast RegionIdType = 22 + RegionAct3Spider RegionIdType = 23 + RegionAct3Dungeon RegionIdType = 24 + RegionAct3Sewer RegionIdType = 25 + RegionAct4Town RegionIdType = 26 + RegionAct4Mesa RegionIdType = 27 + RegionAct4Lava RegionIdType = 28 + RegonAct5Town RegionIdType = 29 + RegionAct5Siege RegionIdType = 30 + RegionAct5Barricade RegionIdType = 31 + RegionAct5Temple RegionIdType = 32 + RegionAct5IceCaves RegionIdType = 33 + RegionAct5Baal RegionIdType = 34 + RegionAct5Lava RegionIdType = 35 +) + +func LoadRegion(seed rand.Source, levelType RegionIdType, levelPreset int, fileProvider Common.FileProvider) *Region { + result := &Region{ + levelType: Common.LevelTypes[levelType], + levelPreset: Common.LevelPresets[levelPreset], + Tiles: make([]Tile, 0), + } + for _, levelTypeDt1 := range result.levelType.Files { + if len(levelTypeDt1) == 0 || levelTypeDt1 == "" || levelTypeDt1 == "0" { + continue + } + dt1 := LoadDT1("/data/global/tiles/"+levelTypeDt1, fileProvider) + for _, tileData := range dt1.Tiles { + result.Tiles = append(result.Tiles, tileData) + } + } + levelFilesToPick := make([]string, 0) + for _, fileRecord := range result.levelPreset.Files { + if len(fileRecord) == 0 || fileRecord == "" || fileRecord == "0" { + continue + } + levelFilesToPick = append(levelFilesToPick, fileRecord) + } + random := rand.New(seed) + levelIndex := int(math.Round(float64(len(levelFilesToPick)-1) * random.Float64())) + levelFile := levelFilesToPick[levelIndex] + result.DS1 = LoadDS1("/data/global/tiles/"+levelFile, fileProvider) + result.TileWidth = result.DS1.Width + result.TileHeight = result.DS1.Height + + return result +} + +func (v *Region) RenderTile(offsetX, offsetY, tileX, tileY int, layerType RegionLayerType, layerIndex int, target *ebiten.Image) { + switch layerType { + case RegionLayerTypeFloors: + v.renderFloor(v.DS1.Tiles[tileY][tileX].Floors[layerIndex], offsetX, offsetY, target) + case RegionLayerTypeWalls: + v.renderWall(v.DS1.Tiles[tileY][tileX].Walls[layerIndex], offsetX, offsetY, target) + } +} + +func (v *Region) getTile(mainIndex, subIndex int32) Tile { + // TODO: Need to support randomly grabbing tile based on x/y as there can be multiple matches for same main/sub index + for _, tile := range v.Tiles { + if tile.MainIndex != mainIndex || tile.SubIndex != subIndex { + continue + } + return tile + } + log.Fatalf("Unknown tile ID [%d %d]", mainIndex, subIndex) + return Tile{} +} + +func (v *Region) renderFloor(tile FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) { + tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex)) + log.Printf("Pro1: %d", tileData.Direction) +} + +func (v *Region) renderWall(tile WallRecord, offsetX, offsetY int, target *ebiten.Image) { + +} diff --git a/Scenes/MapEngineTest.go b/Scenes/MapEngineTest.go index e7fb2245..07a35998 100644 --- a/Scenes/MapEngineTest.go +++ b/Scenes/MapEngineTest.go @@ -1,6 +1,9 @@ package Scenes import ( + "math/rand" + "time" + "github.com/essial/OpenDiablo2/Common" "github.com/essial/OpenDiablo2/MapEngine" "github.com/essial/OpenDiablo2/Sound" @@ -13,6 +16,7 @@ type MapEngineTest struct { soundManager *Sound.Manager fileProvider Common.FileProvider sceneProvider SceneProvider + region *MapEngine.Region } func CreateMapEngineTest(fileProvider Common.FileProvider, sceneProvider SceneProvider, uiManager *UI.Manager, soundManager *Sound.Manager) *MapEngineTest { @@ -26,11 +30,12 @@ func CreateMapEngineTest(fileProvider Common.FileProvider, sceneProvider ScenePr } func (v *MapEngineTest) Load() []func() { + // TODO: Game seed comes from the game state object + randomSource := rand.NewSource(time.Now().UnixNano()) v.soundManager.PlayBGM("") return []func(){ func() { - //_ = MapEngine.LoadDS1("/data/global/tiles/ACT1/town/townE1.ds1", v.fileProvider) - _ = MapEngine.LoadDT1("/data/global/tiles/ACT1/town/floor.dt1", v.fileProvider) + v.region = MapEngine.LoadRegion(randomSource, MapEngine.RegionAct1Tristram, 300, v.fileProvider) }, } } @@ -40,7 +45,7 @@ func (v *MapEngineTest) Unload() { } func (v *MapEngineTest) Render(screen *ebiten.Image) { - + v.region.RenderTile(300, 300, 0, 0, MapEngine.RegionLayerTypeFloors, 0, screen) } func (v *MapEngineTest) Update(tickTime float64) {