mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-07-26 11:24:38 -04:00
More optimizations. Fixed button rendering issue. (#115)
This commit is contained in:
parent
26efc4c05c
commit
a105bb390a
@ -2,6 +2,7 @@ package common
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -107,7 +108,7 @@ func (v *AnimatedEntity) cacheFrames() {
|
|||||||
}
|
}
|
||||||
direction := v.dcc.Directions[v.direction]
|
direction := v.dcc.Directions[v.direction]
|
||||||
frame := direction.Frames[frameIndex]
|
frame := direction.Frames[frameIndex]
|
||||||
pixelData := make([]byte, 4*frameW*frameH)
|
img := image.NewRGBA(image.Rect(0, 0, int(frameW), int(frameH)))
|
||||||
for y := 0; y < direction.Box.Height; y++ {
|
for y := 0; y < direction.Box.Height; y++ {
|
||||||
for x := 0; x < direction.Box.Width; x++ {
|
for x := 0; x < direction.Box.Width; x++ {
|
||||||
paletteIndex := frame.PixelData[x+(y*direction.Box.Width)]
|
paletteIndex := frame.PixelData[x+(y*direction.Box.Width)]
|
||||||
@ -118,13 +119,15 @@ func (v *AnimatedEntity) cacheFrames() {
|
|||||||
color := Palettes[v.palette].Colors[paletteIndex]
|
color := Palettes[v.palette].Colors[paletteIndex]
|
||||||
actualX := x + direction.Box.Left - int(minX)
|
actualX := x + direction.Box.Left - int(minX)
|
||||||
actualY := y + direction.Box.Top - int(minY)
|
actualY := y + direction.Box.Top - int(minY)
|
||||||
pixelData[(actualX*4)+(actualY*int(frameW)*4)] = color.R
|
img.Pix[(actualX*4)+(actualY*int(frameW)*4)] = color.R
|
||||||
pixelData[(actualX*4)+(actualY*int(frameW)*4)+1] = color.G
|
img.Pix[(actualX*4)+(actualY*int(frameW)*4)+1] = color.G
|
||||||
pixelData[(actualX*4)+(actualY*int(frameW)*4)+2] = color.B
|
img.Pix[(actualX*4)+(actualY*int(frameW)*4)+2] = color.B
|
||||||
pixelData[(actualX*4)+(actualY*int(frameW)*4)+3] = 255
|
img.Pix[(actualX*4)+(actualY*int(frameW)*4)+3] = 255
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
v.frames[frameIndex].ReplacePixels(pixelData)
|
newImage, _ := ebiten.NewImageFromImage(img, ebiten.FilterNearest)
|
||||||
|
img = nil
|
||||||
|
v.frames[frameIndex] = newImage
|
||||||
v.frameLocations[frameIndex] = Rectangle{
|
v.frameLocations[frameIndex] = Rectangle{
|
||||||
Left: int(minX),
|
Left: int(minX),
|
||||||
Top: int(minY),
|
Top: int(minY),
|
||||||
|
@ -3,7 +3,6 @@ package common
|
|||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
"math"
|
"math"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
)
|
)
|
||||||
@ -16,7 +15,6 @@ type colorMCacheEntry struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
textM sync.Mutex
|
|
||||||
colorMCache = map[colorMCacheKey]*colorMCacheEntry{}
|
colorMCache = map[colorMCacheKey]*colorMCacheEntry{}
|
||||||
emptyColorM ebiten.ColorM
|
emptyColorM ebiten.ColorM
|
||||||
monotonicClock int64
|
monotonicClock int64
|
||||||
|
@ -2,6 +2,7 @@ package common
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DCCPixelBufferEntry struct {
|
type DCCPixelBufferEntry struct {
|
||||||
@ -337,10 +338,12 @@ func (v *DCCDirection) GenerateFrames(pcd *BitMuncher) {
|
|||||||
}
|
}
|
||||||
v.Cells = nil
|
v.Cells = nil
|
||||||
v.PixelData = nil
|
v.PixelData = nil
|
||||||
|
v.PixelBuffer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *DCCDirection) FillPixelBuffer(pcd, ec, pm, et, rp *BitMuncher) {
|
func (v *DCCDirection) FillPixelBuffer(pcd, ec, pm, et, rp *BitMuncher) {
|
||||||
lastPixel := uint32(0)
|
lastPixel := uint32(0)
|
||||||
|
pixelStack := make([]uint32, 4)
|
||||||
maxCellX := 0
|
maxCellX := 0
|
||||||
maxCellY := 0
|
maxCellY := 0
|
||||||
for _, frame := range v.Frames {
|
for _, frame := range v.Frames {
|
||||||
@ -389,7 +392,6 @@ func (v *DCCDirection) FillPixelBuffer(pcd, ec, pm, et, rp *BitMuncher) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Decode the pixels
|
// Decode the pixels
|
||||||
pixelStack := make([]uint32, 4)
|
|
||||||
lastPixel = 0
|
lastPixel = 0
|
||||||
numberOfPixelBits := pixelMaskLookup[pixelMask]
|
numberOfPixelBits := pixelMaskLookup[pixelMask]
|
||||||
encodingType := 0
|
encodingType := 0
|
||||||
@ -512,9 +514,15 @@ func LoadDCC(path string, fileProvider FileProvider) *DCC {
|
|||||||
directionOffsets[i] = int(bm.GetInt32())
|
directionOffsets[i] = int(bm.GetInt32())
|
||||||
}
|
}
|
||||||
result.Directions = make([]*DCCDirection, result.NumberOfDirections)
|
result.Directions = make([]*DCCDirection, result.NumberOfDirections)
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(result.NumberOfDirections)
|
||||||
for i := 0; i < result.NumberOfDirections; i++ {
|
for i := 0; i < result.NumberOfDirections; i++ {
|
||||||
result.Directions[i] = CreateDCCDirection(CreateBitMuncher(fileData, directionOffsets[i]*8), result)
|
go func(i int) {
|
||||||
|
defer wg.Done()
|
||||||
|
result.Directions[i] = CreateDCCDirection(CreateBitMuncher(fileData, directionOffsets[i]*8), result)
|
||||||
|
}(i)
|
||||||
}
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,9 @@ package common
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
@ -36,7 +38,6 @@ type SpriteFrame struct {
|
|||||||
Length uint32
|
Length uint32
|
||||||
ImageData []int16
|
ImageData []int16
|
||||||
Image *ebiten.Image
|
Image *ebiten.Image
|
||||||
Loaded bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateSprite creates an instance of a sprite
|
// CreateSprite creates an instance of a sprite
|
||||||
@ -63,33 +64,36 @@ func CreateSprite(data []byte, palette PaletteRec) *Sprite {
|
|||||||
dataPointer += 4
|
dataPointer += 4
|
||||||
}
|
}
|
||||||
result.Frames = make([]*SpriteFrame, totalFrames)
|
result.Frames = make([]*SpriteFrame, totalFrames)
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(int(totalFrames))
|
||||||
for i := uint32(0); i < totalFrames; i++ {
|
for i := uint32(0); i < totalFrames; i++ {
|
||||||
dataPointer = framePointers[i]
|
go func(i uint32) {
|
||||||
result.Frames[i] = &SpriteFrame{Loaded: false}
|
defer wg.Done()
|
||||||
result.Frames[i].Flip = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
dataPointer := framePointers[i]
|
||||||
dataPointer += 4
|
result.Frames[i] = &SpriteFrame{}
|
||||||
result.Frames[i].Width = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
result.Frames[i].Flip = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
||||||
dataPointer += 4
|
dataPointer += 4
|
||||||
result.Frames[i].Height = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
result.Frames[i].Width = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
||||||
dataPointer += 4
|
dataPointer += 4
|
||||||
result.Frames[i].OffsetX = BytesToInt32(data[dataPointer : dataPointer+4])
|
result.Frames[i].Height = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
||||||
dataPointer += 4
|
dataPointer += 4
|
||||||
result.Frames[i].OffsetY = BytesToInt32(data[dataPointer : dataPointer+4])
|
result.Frames[i].OffsetX = BytesToInt32(data[dataPointer : dataPointer+4])
|
||||||
dataPointer += 4
|
dataPointer += 4
|
||||||
result.Frames[i].Unknown = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
result.Frames[i].OffsetY = BytesToInt32(data[dataPointer : dataPointer+4])
|
||||||
dataPointer += 4
|
dataPointer += 4
|
||||||
result.Frames[i].NextBlock = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
result.Frames[i].Unknown = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
||||||
dataPointer += 4
|
dataPointer += 4
|
||||||
result.Frames[i].Length = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
result.Frames[i].NextBlock = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
||||||
dataPointer += 4
|
dataPointer += 4
|
||||||
result.Frames[i].ImageData = make([]int16, result.Frames[i].Width*result.Frames[i].Height)
|
result.Frames[i].Length = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
||||||
for fi := range result.Frames[i].ImageData {
|
dataPointer += 4
|
||||||
result.Frames[i].ImageData[fi] = -1
|
result.Frames[i].ImageData = make([]int16, result.Frames[i].Width*result.Frames[i].Height)
|
||||||
}
|
for fi := range result.Frames[i].ImageData {
|
||||||
|
result.Frames[i].ImageData[fi] = -1
|
||||||
|
}
|
||||||
|
|
||||||
x := uint32(0)
|
x := uint32(0)
|
||||||
y := uint32(result.Frames[i].Height - 1)
|
y := uint32(result.Frames[i].Height - 1)
|
||||||
go func(ix, dataPointer uint32) {
|
|
||||||
for true {
|
for true {
|
||||||
b := data[dataPointer]
|
b := data[dataPointer]
|
||||||
dataPointer++
|
dataPointer++
|
||||||
@ -102,41 +106,39 @@ func CreateSprite(data []byte, palette PaletteRec) *Sprite {
|
|||||||
} else if (b & 0x80) > 0 {
|
} else if (b & 0x80) > 0 {
|
||||||
transparentPixels := b & 0x7F
|
transparentPixels := b & 0x7F
|
||||||
for ti := byte(0); ti < transparentPixels; ti++ {
|
for ti := byte(0); ti < transparentPixels; ti++ {
|
||||||
result.Frames[ix].ImageData[x+(y*result.Frames[ix].Width)+uint32(ti)] = -1
|
result.Frames[i].ImageData[x+(y*result.Frames[i].Width)+uint32(ti)] = -1
|
||||||
}
|
}
|
||||||
x += uint32(transparentPixels)
|
x += uint32(transparentPixels)
|
||||||
} else {
|
} else {
|
||||||
for bi := 0; bi < int(b); bi++ {
|
for bi := 0; bi < int(b); bi++ {
|
||||||
result.Frames[ix].ImageData[x+(y*result.Frames[ix].Width)+uint32(bi)] = int16(data[dataPointer])
|
result.Frames[i].ImageData[x+(y*result.Frames[i].Width)+uint32(bi)] = int16(data[dataPointer])
|
||||||
dataPointer++
|
dataPointer++
|
||||||
}
|
}
|
||||||
x += uint32(b)
|
x += uint32(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.Frames[ix].Image, _ = ebiten.NewImage(int(result.Frames[ix].Width), int(result.Frames[ix].Height), ebiten.FilterNearest)
|
var img = image.NewRGBA(image.Rect(0, 0, int(result.Frames[i].Width), int(result.Frames[i].Height)))
|
||||||
newData := make([]byte, result.Frames[ix].Width*result.Frames[ix].Height*4)
|
for ii := uint32(0); ii < result.Frames[i].Width*result.Frames[i].Height; ii++ {
|
||||||
for ii := uint32(0); ii < result.Frames[ix].Width*result.Frames[ix].Height; ii++ {
|
if result.Frames[i].ImageData[ii] < 1 { // TODO: Is this == -1 or < 1?
|
||||||
if result.Frames[ix].ImageData[ii] < 1 { // TODO: Is this == -1 or < 1?
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
newData[ii*4] = palette.Colors[result.Frames[ix].ImageData[ii]].R
|
img.Pix[ii*4] = palette.Colors[result.Frames[i].ImageData[ii]].R
|
||||||
newData[(ii*4)+1] = palette.Colors[result.Frames[ix].ImageData[ii]].G
|
img.Pix[(ii*4)+1] = palette.Colors[result.Frames[i].ImageData[ii]].G
|
||||||
newData[(ii*4)+2] = palette.Colors[result.Frames[ix].ImageData[ii]].B
|
img.Pix[(ii*4)+2] = palette.Colors[result.Frames[i].ImageData[ii]].B
|
||||||
newData[(ii*4)+3] = 0xFF
|
img.Pix[(ii*4)+3] = 0xFF
|
||||||
}
|
}
|
||||||
result.Frames[ix].Image.ReplacePixels(newData)
|
newImage, _ := ebiten.NewImageFromImage(img, ebiten.FilterNearest)
|
||||||
result.Frames[ix].Loaded = true
|
result.Frames[i].Image = newImage
|
||||||
}(i, dataPointer)
|
img = nil
|
||||||
|
}(i)
|
||||||
}
|
}
|
||||||
|
wg.Wait()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSize returns the size of the sprite
|
// GetSize returns the size of the sprite
|
||||||
func (v *Sprite) GetSize() (uint32, uint32) {
|
func (v *Sprite) GetSize() (uint32, uint32) {
|
||||||
frame := v.Frames[uint32(v.Frame)+(uint32(v.Direction)*v.FramesPerDirection)]
|
frame := v.Frames[uint32(v.Frame)+(uint32(v.Direction)*v.FramesPerDirection)]
|
||||||
for frame.Loaded == false {
|
|
||||||
time.Sleep(time.Millisecond * 5)
|
|
||||||
}
|
|
||||||
return frame.Width, frame.Height
|
return frame.Width, frame.Height
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,9 +177,6 @@ func (v *Sprite) OnLastFrame() bool {
|
|||||||
|
|
||||||
// GetFrameSize returns the size of the specific frame
|
// GetFrameSize returns the size of the specific frame
|
||||||
func (v *Sprite) GetFrameSize(frame int) (width, height uint32) {
|
func (v *Sprite) GetFrameSize(frame int) (width, height uint32) {
|
||||||
for v.Frames[frame].Loaded == false {
|
|
||||||
time.Sleep(time.Millisecond)
|
|
||||||
}
|
|
||||||
width = v.Frames[frame].Width
|
width = v.Frames[frame].Width
|
||||||
height = v.Frames[frame].Height
|
height = v.Frames[frame].Height
|
||||||
return
|
return
|
||||||
@ -193,9 +192,6 @@ func (v *Sprite) Draw(target *ebiten.Image) {
|
|||||||
v.updateAnimation()
|
v.updateAnimation()
|
||||||
opts := &ebiten.DrawImageOptions{}
|
opts := &ebiten.DrawImageOptions{}
|
||||||
frame := v.Frames[uint32(v.Frame)+(uint32(v.Direction)*v.FramesPerDirection)]
|
frame := v.Frames[uint32(v.Frame)+(uint32(v.Direction)*v.FramesPerDirection)]
|
||||||
for frame.Loaded == false {
|
|
||||||
time.Sleep(time.Millisecond)
|
|
||||||
}
|
|
||||||
opts.GeoM.Translate(
|
opts.GeoM.Translate(
|
||||||
float64(int32(v.X)+frame.OffsetX),
|
float64(int32(v.X)+frame.OffsetX),
|
||||||
float64((int32(v.Y) - int32(frame.Height) + frame.OffsetY)),
|
float64((int32(v.Y) - int32(frame.Height) + frame.OffsetY)),
|
||||||
@ -233,9 +229,6 @@ func (v *Sprite) DrawSegments(target *ebiten.Image, xSegments, ySegments, offset
|
|||||||
if v.ColorMod != nil {
|
if v.ColorMod != nil {
|
||||||
opts.ColorM = ColorToColorM(v.ColorMod)
|
opts.ColorM = ColorToColorM(v.ColorMod)
|
||||||
}
|
}
|
||||||
for frame.Loaded == false {
|
|
||||||
time.Sleep(time.Millisecond * 5)
|
|
||||||
}
|
|
||||||
target.DrawImage(frame.Image, opts)
|
target.DrawImage(frame.Image, opts)
|
||||||
xOffset += int32(frame.Width)
|
xOffset += int32(frame.Width)
|
||||||
biggestYOffset = MaxInt32(biggestYOffset, int32(frame.Height))
|
biggestYOffset = MaxInt32(biggestYOffset, int32(frame.Height))
|
||||||
|
@ -255,7 +255,7 @@ func createWeaponVendorParams(r *[]string, inc func() int) map[string]*ItemVendo
|
|||||||
|
|
||||||
func CreateItemVendorParams(r *[]string, inc func() int, vs []string) map[string]*ItemVendorParams {
|
func CreateItemVendorParams(r *[]string, inc func() int, vs []string) map[string]*ItemVendorParams {
|
||||||
result := make(map[string]*ItemVendorParams)
|
result := make(map[string]*ItemVendorParams)
|
||||||
|
|
||||||
for _, name := range vs {
|
for _, name := range vs {
|
||||||
wvp := ItemVendorParams{
|
wvp := ItemVendorParams{
|
||||||
Min: StringToInt(EmptyToZero((*r)[inc()])),
|
Min: StringToInt(EmptyToZero((*r)[inc()])),
|
||||||
|
@ -28,6 +28,8 @@ type Engine struct {
|
|||||||
CheckedPatch map[string]bool // First time we check a file, we'll check if it's in the patch. This notes that we've already checked that.
|
CheckedPatch map[string]bool // First time we check a file, we'll check if it's in the patch. This notes that we've already checked that.
|
||||||
LoadingSprite *common.Sprite // The sprite shown when loading stuff
|
LoadingSprite *common.Sprite // The sprite shown when loading stuff
|
||||||
loadingProgress float64 // LoadingProcess is a range between 0.0 and 1.0. If set, loading screen displays.
|
loadingProgress float64 // LoadingProcess is a range between 0.0 and 1.0. If set, loading screen displays.
|
||||||
|
loadingIndex int // Determines which load function is currently being called
|
||||||
|
thingsToLoad []func() // The load functions for the next scene
|
||||||
stepLoadingSize float64 // The size for each loading step
|
stepLoadingSize float64 // The size for each loading step
|
||||||
CurrentScene scenes.Scene // The current scene being rendered
|
CurrentScene scenes.Scene // The current scene being rendered
|
||||||
UIManager *ui.Manager // The UI manager
|
UIManager *ui.Manager // The UI manager
|
||||||
@ -129,6 +131,19 @@ func (v *Engine) LoadSprite(fileName string, palette palettedefs.PaletteType) *c
|
|||||||
// updateScene handles the scene maintenance for the engine
|
// updateScene handles the scene maintenance for the engine
|
||||||
func (v *Engine) updateScene() {
|
func (v *Engine) updateScene() {
|
||||||
if v.nextScene == nil {
|
if v.nextScene == nil {
|
||||||
|
if v.thingsToLoad != nil {
|
||||||
|
if v.loadingIndex < len(v.thingsToLoad) {
|
||||||
|
v.thingsToLoad[v.loadingIndex]()
|
||||||
|
v.loadingIndex++
|
||||||
|
if v.loadingIndex < len(v.thingsToLoad) {
|
||||||
|
v.StepLoading()
|
||||||
|
} else {
|
||||||
|
v.FinishLoading()
|
||||||
|
v.thingsToLoad = nil
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if v.CurrentScene != nil {
|
if v.CurrentScene != nil {
|
||||||
@ -137,16 +152,10 @@ func (v *Engine) updateScene() {
|
|||||||
v.CurrentScene = v.nextScene
|
v.CurrentScene = v.nextScene
|
||||||
v.nextScene = nil
|
v.nextScene = nil
|
||||||
v.UIManager.Reset()
|
v.UIManager.Reset()
|
||||||
thingsToLoad := v.CurrentScene.Load()
|
v.thingsToLoad = v.CurrentScene.Load()
|
||||||
v.SetLoadingStepSize(1.0 / float64(len(thingsToLoad)))
|
v.loadingIndex = 0
|
||||||
|
v.SetLoadingStepSize(1.0 / float64(len(v.thingsToLoad)))
|
||||||
v.ResetLoading()
|
v.ResetLoading()
|
||||||
go func() {
|
|
||||||
for _, f := range thingsToLoad {
|
|
||||||
f()
|
|
||||||
v.StepLoading()
|
|
||||||
}
|
|
||||||
v.FinishLoading()
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates the internal state of the engine
|
// Update updates the internal state of the engine
|
||||||
|
1
go.sum
1
go.sum
@ -47,6 +47,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||||
|
github.com/pkg/profile v1.3.0 h1:OQIvuDgm00gWVWGTf4m4mCt6W1/0YqU7Ntg0mySWgaI=
|
||||||
github.com/pkg/profile v1.3.0/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
github.com/pkg/profile v1.3.0/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
33
mpq/MPQ.go
33
mpq/MPQ.go
@ -8,6 +8,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/resourcepaths"
|
"github.com/OpenDiablo2/OpenDiablo2/resourcepaths"
|
||||||
)
|
)
|
||||||
@ -19,6 +20,7 @@ type MPQ struct {
|
|||||||
HashTableEntries []HashTableEntry
|
HashTableEntries []HashTableEntry
|
||||||
BlockTableEntries []BlockTableEntry
|
BlockTableEntries []BlockTableEntry
|
||||||
Data Data
|
Data Data
|
||||||
|
fileCache map[string][]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data Represents a MPQ file
|
// Data Represents a MPQ file
|
||||||
@ -92,21 +94,31 @@ func (v BlockTableEntry) HasFlag(flag FileFlag) bool {
|
|||||||
return (v.Flags & flag) != 0
|
return (v.Flags & flag) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mpqMutex = sync.Mutex{}
|
||||||
|
var mpqCache = make(map[string]*MPQ)
|
||||||
|
|
||||||
// Load loads an MPQ file and returns a MPQ structure
|
// Load loads an MPQ file and returns a MPQ structure
|
||||||
func Load(fileName string) (MPQ, error) {
|
func Load(fileName string) (*MPQ, error) {
|
||||||
result := MPQ{
|
mpqMutex.Lock()
|
||||||
FileName: fileName,
|
defer mpqMutex.Unlock()
|
||||||
|
cached := mpqCache[fileName]
|
||||||
|
if cached != nil {
|
||||||
|
return cached, nil
|
||||||
|
}
|
||||||
|
result := &MPQ{
|
||||||
|
FileName: fileName,
|
||||||
|
fileCache: make(map[string][]byte),
|
||||||
}
|
}
|
||||||
file, err := os.Open(fileName)
|
file, err := os.Open(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return MPQ{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
result.File = file
|
result.File = file
|
||||||
err = result.readHeader()
|
err = result.readHeader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return MPQ{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
mpqCache[fileName] = result
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +237,7 @@ func (v MPQ) getFileHashEntry(fileName string) (HashTableEntry, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetFileBlockData gets a block table entry
|
// GetFileBlockData gets a block table entry
|
||||||
func (v MPQ) GetFileBlockData(fileName string) (BlockTableEntry, error) {
|
func (v MPQ) getFileBlockData(fileName string) (BlockTableEntry, error) {
|
||||||
fileName = strings.ReplaceAll(fileName, "{LANG}", resourcepaths.LanguageCode)
|
fileName = strings.ReplaceAll(fileName, "{LANG}", resourcepaths.LanguageCode)
|
||||||
fileEntry, err := v.getFileHashEntry(fileName)
|
fileEntry, err := v.getFileHashEntry(fileName)
|
||||||
if err != nil || fileEntry.BlockIndex >= uint32(len(v.BlockTableEntries)) {
|
if err != nil || fileEntry.BlockIndex >= uint32(len(v.BlockTableEntries)) {
|
||||||
@ -249,8 +261,12 @@ func (v MPQ) FileExists(fileName string) bool {
|
|||||||
|
|
||||||
// ReadFile reads a file from the MPQ and returns a memory stream
|
// ReadFile reads a file from the MPQ and returns a memory stream
|
||||||
func (v MPQ) ReadFile(fileName string) ([]byte, error) {
|
func (v MPQ) ReadFile(fileName string) ([]byte, error) {
|
||||||
|
cached := v.fileCache[fileName]
|
||||||
|
if cached != nil {
|
||||||
|
return cached, nil
|
||||||
|
}
|
||||||
fileName = strings.ReplaceAll(fileName, "{LANG}", resourcepaths.LanguageCode)
|
fileName = strings.ReplaceAll(fileName, "{LANG}", resourcepaths.LanguageCode)
|
||||||
fileBlockData, err := v.GetFileBlockData(fileName)
|
fileBlockData, err := v.getFileBlockData(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, err
|
return []byte{}, err
|
||||||
}
|
}
|
||||||
@ -259,6 +275,7 @@ func (v MPQ) ReadFile(fileName string) ([]byte, error) {
|
|||||||
mpqStream := CreateStream(v, fileBlockData, fileName)
|
mpqStream := CreateStream(v, fileBlockData, fileName)
|
||||||
buffer := make([]byte, fileBlockData.UncompressedFileSize)
|
buffer := make([]byte, fileBlockData.UncompressedFileSize)
|
||||||
mpqStream.Read(buffer, 0, fileBlockData.UncompressedFileSize)
|
mpqStream.Read(buffer, 0, fileBlockData.UncompressedFileSize)
|
||||||
|
v.fileCache[fileName] = buffer
|
||||||
return buffer, nil
|
return buffer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
func TestMapGenerationPerformance(t *testing.T) {
|
func TestMapGenerationPerformance(t *testing.T) {
|
||||||
mpq.InitializeCryptoBuffer()
|
mpq.InitializeCryptoBuffer()
|
||||||
common.ConfigBasePath = "../"
|
common.ConfigBasePath = "../"
|
||||||
|
|
||||||
engine := core.CreateEngine()
|
engine := core.CreateEngine()
|
||||||
gameState := common.CreateGameState()
|
gameState := common.CreateGameState()
|
||||||
mapEngine := _map.CreateMapEngine(gameState, engine.SoundManager, engine)
|
mapEngine := _map.CreateMapEngine(gameState, engine.SoundManager, engine)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user