mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-04 15:46:51 -05:00
Big fixes. Added start of video decode. Enhanced MPQ error messages.
This commit is contained in:
parent
02082925b5
commit
bf0412554f
22
Common/GameState.go
Normal file
22
Common/GameState.go
Normal file
@ -0,0 +1,22 @@
|
||||
package Common
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
type GameState struct {
|
||||
Seed int64
|
||||
}
|
||||
|
||||
func CreateGameState() *GameState {
|
||||
result := &GameState{
|
||||
Seed: time.Now().UnixNano(),
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func LoadGameState(path string) *GameState {
|
||||
log.Fatal("LoadGameState not implemented.")
|
||||
return nil
|
||||
}
|
@ -38,7 +38,7 @@ type EngineConfig struct {
|
||||
|
||||
// Engine is the core OpenDiablo2 engine
|
||||
type Engine struct {
|
||||
Settings *EngineConfig // Engine configuration settings from json file
|
||||
Settings *EngineConfig // Engine configuration settings from json file
|
||||
Files map[string]string // Map that defines which files are in which MPQs
|
||||
Palettes map[Palettes.Palette]Common.Palette // Color palettes
|
||||
SoundEntries map[string]Sound.SoundEntry // Sound configurations
|
||||
@ -72,6 +72,7 @@ func CreateEngine() *Engine {
|
||||
loadingSpriteSizeX, loadingSpriteSizeY := result.LoadingSprite.GetSize()
|
||||
result.LoadingSprite.MoveTo(int(400-(loadingSpriteSizeX/2)), int(300+(loadingSpriteSizeY/2)))
|
||||
result.SetNextScene(Scenes.CreateMainMenu(result, result, result.UIManager, result.SoundManager))
|
||||
//result.SetNextScene(Scenes.CreateBlizzardIntro(result, result))
|
||||
return result
|
||||
}
|
||||
|
||||
@ -92,8 +93,8 @@ func (v *Engine) loadConfigurationFile() {
|
||||
if v.Settings.MpqPath[0] != '/' {
|
||||
if _, err := os.Stat(v.Settings.MpqPath); os.IsNotExist(err) {
|
||||
homeDir, _ := homedir.Dir()
|
||||
newPath := strings.ReplaceAll(v.Settings.MpqPath, `C:\`, homeDir + "/.wine/drive_c/")
|
||||
newPath = strings.ReplaceAll(newPath, "C:/", homeDir + "/.wine/drive_c/")
|
||||
newPath := strings.ReplaceAll(v.Settings.MpqPath, `C:\`, homeDir+"/.wine/drive_c/")
|
||||
newPath = strings.ReplaceAll(newPath, "C:/", homeDir+"/.wine/drive_c/")
|
||||
newPath = strings.ReplaceAll(newPath, `\`, "/")
|
||||
if _, err := os.Stat(newPath); !os.IsNotExist(err) {
|
||||
log.Printf("Detected linux wine installation, path updated to wine prefix path.")
|
||||
@ -137,11 +138,13 @@ func (v *Engine) LoadFile(fileName string) []byte {
|
||||
mpqFile := v.Files[strings.ToLower(fileName)]
|
||||
mpq, err := MPQ.Load(mpqFile)
|
||||
if err != nil {
|
||||
log.Printf("Error loading file '%s'", fileName)
|
||||
log.Fatal(err)
|
||||
}
|
||||
fileName = strings.ReplaceAll(fileName, `/`, `\`)[1:]
|
||||
blockTableEntry, err := mpq.GetFileBlockData(fileName)
|
||||
if err != nil {
|
||||
log.Printf("Error locating block data entry for '%s' in mpq file '%s'", fileName, mpq.FileName)
|
||||
log.Fatal(err)
|
||||
}
|
||||
mpqStream := MPQ.CreateStream(mpq, blockTableEntry, fileName)
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
// MPQ represents an MPQ archive
|
||||
type MPQ struct {
|
||||
FileName string
|
||||
File *os.File
|
||||
HashTableEntries []HashTableEntry
|
||||
BlockTableEntries []BlockTableEntry
|
||||
@ -83,7 +84,9 @@ func (v BlockTableEntry) HasFlag(flag FileFlag) bool {
|
||||
|
||||
// Load loads an MPQ file and returns a MPQ structure
|
||||
func Load(fileName string) (MPQ, error) {
|
||||
result := MPQ{}
|
||||
result := MPQ{
|
||||
FileName: fileName,
|
||||
}
|
||||
file, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
return MPQ{}, err
|
||||
|
@ -1,4 +1,4 @@
|
||||
package MapEngine
|
||||
package Map
|
||||
|
||||
import (
|
||||
"github.com/essial/OpenDiablo2/Common"
|
@ -1,4 +1,4 @@
|
||||
package MapEngine
|
||||
package Map
|
||||
|
||||
import (
|
||||
"log"
|
46
Map/Engine.go
Normal file
46
Map/Engine.go
Normal file
@ -0,0 +1,46 @@
|
||||
package Map
|
||||
|
||||
import (
|
||||
"image"
|
||||
|
||||
"github.com/essial/OpenDiablo2/Common"
|
||||
"github.com/essial/OpenDiablo2/Sound"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
type EngineRegion struct {
|
||||
Rect image.Rectangle
|
||||
Region Region
|
||||
}
|
||||
|
||||
type Engine struct {
|
||||
soundManager *Sound.Manager
|
||||
gameState *Common.GameState
|
||||
fileProvider Common.FileProvider
|
||||
regions []*EngineRegion
|
||||
}
|
||||
|
||||
func CreateMapEngine(gameState *Common.GameState, soundManager *Sound.Manager, fileProvider Common.FileProvider) *Engine {
|
||||
result := &Engine{
|
||||
gameState: gameState,
|
||||
soundManager: soundManager,
|
||||
fileProvider: fileProvider,
|
||||
regions: make([]*EngineRegion, 0),
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *Engine) GenerateMap(regionType RegionIdType, levelPreset int) {
|
||||
//randomSource := rand.NewSource(v.gameState.Seed)
|
||||
//region := LoadRegion(randomSource, regionType, levelPreset, v.fileProvider)
|
||||
v.soundManager.PlayBGM("/data/global/music/Act1/tristram.wav")
|
||||
v.ReloadMapCache()
|
||||
}
|
||||
|
||||
func (v *Engine) ReloadMapCache() {
|
||||
|
||||
}
|
||||
|
||||
func (v *Engine) Render(target *ebiten.Image) {
|
||||
//v.region.RenderTile(300, 300, 0, 0, Map.RegionLayerTypeFloors, 0, screen)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package MapEngine
|
||||
package Map
|
||||
|
||||
type Orientation int32
|
||||
|
@ -1,4 +1,4 @@
|
||||
package MapEngine
|
||||
package Map
|
||||
|
||||
import (
|
||||
"log"
|
||||
@ -77,9 +77,7 @@ func LoadRegion(seed rand.Source, levelType RegionIdType, levelPreset int, fileP
|
||||
continue
|
||||
}
|
||||
dt1 := LoadDT1("/data/global/tiles/"+levelTypeDt1, fileProvider)
|
||||
for _, tileData := range dt1.Tiles {
|
||||
result.Tiles = append(result.Tiles, tileData)
|
||||
}
|
||||
result.Tiles = append(result.Tiles, dt1.Tiles...)
|
||||
}
|
||||
levelFilesToPick := make([]string, 0)
|
||||
for _, fileRecord := range result.levelPreset.Files {
|
43
Scenes/BlizzardIntro.go
Normal file
43
Scenes/BlizzardIntro.go
Normal file
@ -0,0 +1,43 @@
|
||||
package Scenes
|
||||
|
||||
import (
|
||||
"github.com/essial/OpenDiablo2/Common"
|
||||
"github.com/essial/OpenDiablo2/Video"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
type BlizzardIntro struct {
|
||||
fileProvider Common.FileProvider
|
||||
sceneProvider SceneProvider
|
||||
videoDecoder *Video.BinkDecoder
|
||||
}
|
||||
|
||||
func CreateBlizzardIntro(fileProvider Common.FileProvider, sceneProvider SceneProvider) *BlizzardIntro {
|
||||
result := &BlizzardIntro{
|
||||
fileProvider: fileProvider,
|
||||
sceneProvider: sceneProvider,
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *BlizzardIntro) Load() []func() {
|
||||
return []func(){
|
||||
func() {
|
||||
videoBytes := v.fileProvider.LoadFile("/data/local/video/BlizNorth640x480.bik")
|
||||
v.videoDecoder = Video.CreateBinkDecoder(videoBytes)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (v *BlizzardIntro) Unload() {
|
||||
|
||||
}
|
||||
|
||||
func (v *BlizzardIntro) Render(screen *ebiten.Image) {
|
||||
|
||||
}
|
||||
|
||||
func (v *BlizzardIntro) Update(tickTime float64) {
|
||||
|
||||
}
|
@ -1,11 +1,8 @@
|
||||
package Scenes
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/essial/OpenDiablo2/Common"
|
||||
"github.com/essial/OpenDiablo2/MapEngine"
|
||||
"github.com/essial/OpenDiablo2/Map"
|
||||
"github.com/essial/OpenDiablo2/Sound"
|
||||
"github.com/essial/OpenDiablo2/UI"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
@ -16,7 +13,9 @@ type MapEngineTest struct {
|
||||
soundManager *Sound.Manager
|
||||
fileProvider Common.FileProvider
|
||||
sceneProvider SceneProvider
|
||||
region *MapEngine.Region
|
||||
//region *Map.Region
|
||||
gameState *Common.GameState
|
||||
mapEngine *Map.Engine
|
||||
}
|
||||
|
||||
func CreateMapEngineTest(fileProvider Common.FileProvider, sceneProvider SceneProvider, uiManager *UI.Manager, soundManager *Sound.Manager) *MapEngineTest {
|
||||
@ -26,16 +25,18 @@ func CreateMapEngineTest(fileProvider Common.FileProvider, sceneProvider ScenePr
|
||||
soundManager: soundManager,
|
||||
sceneProvider: sceneProvider,
|
||||
}
|
||||
result.gameState = Common.CreateGameState()
|
||||
return result
|
||||
}
|
||||
|
||||
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() {
|
||||
v.region = MapEngine.LoadRegion(randomSource, MapEngine.RegionAct1Tristram, 300, v.fileProvider)
|
||||
v.mapEngine = Map.CreateMapEngine(v.gameState, v.soundManager, v.fileProvider)
|
||||
v.mapEngine.GenerateMap(Map.RegionAct1Tristram, 300)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -45,7 +46,7 @@ func (v *MapEngineTest) Unload() {
|
||||
}
|
||||
|
||||
func (v *MapEngineTest) Render(screen *ebiten.Image) {
|
||||
v.region.RenderTile(300, 300, 0, 0, MapEngine.RegionLayerTypeFloors, 0, screen)
|
||||
v.mapEngine.Render(screen)
|
||||
}
|
||||
|
||||
func (v *MapEngineTest) Update(tickTime float64) {
|
||||
|
111
Video/BinkDecoder.go
Normal file
111
Video/BinkDecoder.go
Normal file
@ -0,0 +1,111 @@
|
||||
package Video
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/essial/OpenDiablo2/Common"
|
||||
)
|
||||
|
||||
type BinkVideoMode uint32
|
||||
|
||||
const (
|
||||
BinkVideoModeNormal BinkVideoMode = 0
|
||||
BinkVideoModeHeightDoubled BinkVideoMode = 1
|
||||
BinkVideoModeHeightInterlaced BinkVideoMode = 2
|
||||
BinkVideoModeWidthDoubled BinkVideoMode = 3
|
||||
BinkVideoModeWidthAndHeightDoubled BinkVideoMode = 4
|
||||
BinkVideoModeWidthAndHeightInterlaced BinkVideoMode = 5
|
||||
)
|
||||
|
||||
type BinkAudioAlgorithm uint32
|
||||
|
||||
const (
|
||||
BinkAudioAlgorithmFFT BinkAudioAlgorithm = 0
|
||||
BinkAudioAlgorithmDCT BinkAudioAlgorithm = 1
|
||||
)
|
||||
|
||||
type BinkAudioTrack struct {
|
||||
AudioChannels uint16
|
||||
AudioSampleRateHz uint16
|
||||
Stereo bool
|
||||
Algorithm BinkAudioAlgorithm
|
||||
AudioTrackId uint32
|
||||
}
|
||||
|
||||
type BinkDecoder struct {
|
||||
videoCodecRevision byte
|
||||
fileSize uint32
|
||||
numberOfFrames uint32
|
||||
largestFrameSizeBytes uint32
|
||||
VideoWidth uint32
|
||||
VideoHeight uint32
|
||||
FPS uint32
|
||||
FrameTimeMS uint32
|
||||
streamReader *Common.StreamReader
|
||||
VideoMode BinkVideoMode
|
||||
HasAlphaPlane bool
|
||||
Grayscale bool
|
||||
AudioTracks []BinkAudioTrack
|
||||
FrameIndexTable []uint32 // Mask bit 0, as this is defined as a keyframe
|
||||
frameIndex uint32
|
||||
}
|
||||
|
||||
func CreateBinkDecoder(source []byte) *BinkDecoder {
|
||||
result := &BinkDecoder{
|
||||
streamReader: Common.CreateStreamReader(source),
|
||||
}
|
||||
result.loadHeaderInformation()
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *BinkDecoder) GetNextFrame() {
|
||||
//v.streamReader.SetPosition(uint64(v.FrameIndexTable[i] & 0xFFFFFFFE))
|
||||
lengthOfAudioPackets := v.streamReader.GetUInt32() - 4
|
||||
samplesInPacket := v.streamReader.GetUInt32()
|
||||
v.streamReader.SkipBytes(int(lengthOfAudioPackets))
|
||||
log.Printf("Frame %d:\tSamp: %d", v.frameIndex, samplesInPacket)
|
||||
|
||||
v.frameIndex++
|
||||
}
|
||||
|
||||
func (v *BinkDecoder) loadHeaderInformation() {
|
||||
v.streamReader.SetPosition(0)
|
||||
headerBytes, _ := v.streamReader.ReadBytes(3)
|
||||
if string(headerBytes) != "BIK" {
|
||||
log.Fatal("Invalid header for bink video")
|
||||
}
|
||||
v.videoCodecRevision = v.streamReader.GetByte()
|
||||
v.fileSize = v.streamReader.GetUInt32()
|
||||
v.numberOfFrames = v.streamReader.GetUInt32()
|
||||
v.largestFrameSizeBytes = v.streamReader.GetUInt32()
|
||||
v.streamReader.SkipBytes(4) // Number of frames again?
|
||||
v.VideoWidth = v.streamReader.GetUInt32()
|
||||
v.VideoHeight = v.streamReader.GetUInt32()
|
||||
fpsDividend := v.streamReader.GetUInt32()
|
||||
fpsDivider := v.streamReader.GetUInt32()
|
||||
v.FPS = uint32(float32(fpsDividend) / float32(fpsDivider))
|
||||
v.FrameTimeMS = 1000 / v.FPS
|
||||
videoFlags := v.streamReader.GetUInt32()
|
||||
v.VideoMode = BinkVideoMode((videoFlags >> 28) & 0x0F)
|
||||
v.HasAlphaPlane = ((videoFlags >> 20) & 0x1) == 1
|
||||
v.Grayscale = ((videoFlags >> 17) & 0x1) == 1
|
||||
numberOfAudioTracks := v.streamReader.GetUInt32()
|
||||
v.AudioTracks = make([]BinkAudioTrack, numberOfAudioTracks)
|
||||
for i := 0; i < int(numberOfAudioTracks); i++ {
|
||||
v.streamReader.SkipBytes(2) // Unknown
|
||||
v.AudioTracks[i].AudioChannels = v.streamReader.GetUInt16()
|
||||
}
|
||||
for i := 0; i < int(numberOfAudioTracks); i++ {
|
||||
v.AudioTracks[i].AudioSampleRateHz = v.streamReader.GetUInt16()
|
||||
flags := v.streamReader.GetUInt16()
|
||||
v.AudioTracks[i].Stereo = ((flags >> 13) & 0x1) == 1
|
||||
v.AudioTracks[i].Algorithm = BinkAudioAlgorithm((flags >> 12) & 0x1)
|
||||
}
|
||||
for i := 0; i < int(numberOfAudioTracks); i++ {
|
||||
v.AudioTracks[i].AudioTrackId = v.streamReader.GetUInt32()
|
||||
}
|
||||
v.FrameIndexTable = make([]uint32, v.numberOfFrames+1)
|
||||
for i := 0; i < int(v.numberOfFrames+1); i++ {
|
||||
v.FrameIndexTable[i] = v.streamReader.GetUInt32()
|
||||
}
|
||||
}
|
1
go.mod
1
go.mod
@ -4,6 +4,7 @@ go 1.13
|
||||
|
||||
require (
|
||||
github.com/JoshVarga/blast v0.0.0-20180421040937-681c804fb9f0
|
||||
github.com/giorgisio/goav v0.1.0
|
||||
github.com/hajimehoshi/ebiten v1.9.3
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
)
|
||||
|
4
go.sum
4
go.sum
@ -1,5 +1,7 @@
|
||||
github.com/JoshVarga/blast v0.0.0-20180421040937-681c804fb9f0 h1:tDnuU0igiBiQFjsvq1Bi7DpoUjqI76VVvW045vpeFeM=
|
||||
github.com/JoshVarga/blast v0.0.0-20180421040937-681c804fb9f0/go.mod h1:h/5OEGj4G+fpYxluLjSMZbFY011ZxAntO98nCl8mrCs=
|
||||
github.com/giorgisio/goav v0.1.0 h1:ZyfG3NfX7PMSimv4ulhmnQJf/XeHpMdGCn+afRmY5Oc=
|
||||
github.com/giorgisio/goav v0.1.0/go.mod h1:RtH8HyxLRLU1iY0pjfhWBKRhnbsnmfoI+FxMwb5bfEo=
|
||||
github.com/go-gl/glfw v0.0.0-20181213070059-819e8ce5125f h1:7MsFMbSn8Lcw0blK4+NEOf8DuHoOBDhJsHz04yh13pM=
|
||||
github.com/go-gl/glfw v0.0.0-20181213070059-819e8ce5125f/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/gofrs/flock v0.7.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
@ -11,6 +13,8 @@ github.com/gopherjs/gopherwasm v0.1.1/go.mod h1:kx4n9a+MzHH0BJJhvlsQ65hqLFXDO/m2
|
||||
github.com/gopherjs/gopherwasm v1.0.0/go.mod h1:SkZ8z7CWBz5VXbhJel8TxCmAcsQqzgWGR/8nMhyhZSI=
|
||||
github.com/gopherjs/gopherwasm v1.1.0 h1:fA2uLoctU5+T3OhOn2vYP0DVT6pxc7xhTlBB1paATqQ=
|
||||
github.com/gopherjs/gopherwasm v1.1.0/go.mod h1:SkZ8z7CWBz5VXbhJel8TxCmAcsQqzgWGR/8nMhyhZSI=
|
||||
github.com/gosuri/uilive v0.0.0-20170323041506-ac356e6e42cd/go.mod h1:qkLSc0A5EXSP6B04TrN4oQoxqFI7A8XvoXSlJi8cwk8=
|
||||
github.com/gosuri/uiprogress v0.0.0-20170224063937-d0567a9d84a1/go.mod h1:C1RTYn4Sc7iEyf6j8ft5dyoZ4212h8G1ol9QQluh5+0=
|
||||
github.com/hajimehoshi/bitmapfont v1.1.1/go.mod h1:Hamfxgney7tDSmVOSDh2AWzoDH70OaC+P24zc02Gum4=
|
||||
github.com/hajimehoshi/ebiten v1.9.3 h1:YijWGMBwH2XA1ZytUQFy33UDHeCSS6d4JZKH1wq38O0=
|
||||
github.com/hajimehoshi/ebiten v1.9.3/go.mod h1:XxiJ4Eltvb1KmcD0i6F81eIB1asJhK47y5DC+FPkyso=
|
||||
|
Loading…
Reference in New Issue
Block a user