mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-20 23:47:16 -05:00
Performance/Memory Improvements (#365)
* Performance improvements * fix readbytes variable
This commit is contained in:
parent
99b10b2599
commit
b9f17f433f
4
.gitignore
vendored
4
.gitignore
vendored
@ -10,4 +10,6 @@
|
||||
**/*.pprof
|
||||
*.swp
|
||||
.*.swp
|
||||
tags
|
||||
tags
|
||||
heap.out
|
||||
heap.pdf
|
||||
|
@ -29,13 +29,13 @@ func LoadAnimationData(rawData []byte) {
|
||||
for !streamReader.Eof() {
|
||||
dataCount := int(streamReader.GetInt32())
|
||||
for i := 0; i < dataCount; i++ {
|
||||
cofNameBytes, _ := streamReader.ReadBytes(8)
|
||||
cofNameBytes := streamReader.ReadBytes(8)
|
||||
data := &AnimationDataRecord{
|
||||
COFName: strings.ReplaceAll(string(cofNameBytes), string(0), ""),
|
||||
FramesPerDirection: int(streamReader.GetInt32()),
|
||||
AnimationSpeed: int(streamReader.GetInt32()),
|
||||
}
|
||||
data.Flags, _ = streamReader.ReadBytes(144)
|
||||
data.Flags = streamReader.ReadBytes(144)
|
||||
cofIndex := strings.ToLower(data.COFName)
|
||||
if _, found := AnimationData[cofIndex]; !found {
|
||||
AnimationData[cofIndex] = make([]*AnimationDataRecord, 0)
|
||||
|
@ -19,8 +19,8 @@ func LoadObjectTypes(objectTypeData []byte) {
|
||||
count := streamReader.GetInt32()
|
||||
ObjectTypes = make([]ObjectTypeRecord, count)
|
||||
for i := range ObjectTypes {
|
||||
nameBytes, _ := streamReader.ReadBytes(32)
|
||||
tokenBytes, _ := streamReader.ReadBytes(20)
|
||||
nameBytes := streamReader.ReadBytes(32)
|
||||
tokenBytes := streamReader.ReadBytes(20)
|
||||
ObjectTypes[i] = ObjectTypeRecord{
|
||||
Name: strings.TrimSpace(strings.ReplaceAll(string(nameBytes), string(0), "")),
|
||||
Token: strings.TrimSpace(strings.ReplaceAll(string(tokenBytes), string(0), "")),
|
||||
|
@ -70,7 +70,7 @@ func (v *BinkDecoder) GetNextFrame() {
|
||||
|
||||
func (v *BinkDecoder) loadHeaderInformation() {
|
||||
v.streamReader.SetPosition(0)
|
||||
headerBytes, _ := v.streamReader.ReadBytes(3)
|
||||
headerBytes := v.streamReader.ReadBytes(3)
|
||||
if string(headerBytes) != "BIK" {
|
||||
log.Fatal("Invalid header for bink video")
|
||||
}
|
||||
|
@ -37,19 +37,19 @@ func LoadCOF(fileData []byte) (*COF, error) {
|
||||
layer.Selectable = streamReader.GetByte() != 0
|
||||
layer.Transparent = streamReader.GetByte() != 0
|
||||
layer.DrawEffect = d2enum.DrawEffect(streamReader.GetByte())
|
||||
weaponClassStr, _ := streamReader.ReadBytes(4)
|
||||
weaponClassStr := streamReader.ReadBytes(4)
|
||||
layer.WeaponClass = d2enum.WeaponClassFromString(strings.TrimSpace(strings.ReplaceAll(string(weaponClassStr), string(0), "")))
|
||||
result.CofLayers[i] = layer
|
||||
result.CompositeLayers[layer.Type] = i
|
||||
}
|
||||
animationFrameBytes, _ := streamReader.ReadBytes(result.FramesPerDirection)
|
||||
animationFrameBytes := streamReader.ReadBytes(result.FramesPerDirection)
|
||||
result.AnimationFrames = make([]d2enum.AnimationFrame, result.FramesPerDirection)
|
||||
for i := range animationFrameBytes {
|
||||
result.AnimationFrames[i] = d2enum.AnimationFrame(animationFrameBytes[i])
|
||||
}
|
||||
priorityLen := result.FramesPerDirection * result.NumberOfDirections * result.NumberOfLayers
|
||||
result.Priority = make([][][]d2enum.CompositeType, result.NumberOfDirections)
|
||||
priorityBytes, _ := streamReader.ReadBytes(priorityLen)
|
||||
priorityBytes := streamReader.ReadBytes(priorityLen)
|
||||
priorityIndex := 0
|
||||
for direction := 0; direction < result.NumberOfDirections; direction++ {
|
||||
result.Priority[direction] = make([][]d2enum.CompositeType, result.FramesPerDirection)
|
||||
|
@ -74,7 +74,7 @@ func LoadDT1(fileData []byte) (*DT1, error) {
|
||||
}
|
||||
for blockIndex, block := range tile.Blocks {
|
||||
br.SetPosition(uint64(tile.blockHeaderPointer + block.FileOffset))
|
||||
encodedData, _ := br.ReadBytes(int(block.Length))
|
||||
encodedData := br.ReadBytes(int(block.Length))
|
||||
tile.Blocks[blockIndex].EncodedData = encodedData
|
||||
}
|
||||
|
||||
|
@ -103,12 +103,10 @@ func (v *StreamReader) ReadByte() (byte, error) {
|
||||
}
|
||||
|
||||
// ReadBytes reads multiple bytes
|
||||
func (v *StreamReader) ReadBytes(count int) ([]byte, error) {
|
||||
result := make([]byte, count)
|
||||
for i := 0; i < count; i++ {
|
||||
result[i] = v.GetByte()
|
||||
}
|
||||
return result, nil
|
||||
func (v *StreamReader) ReadBytes(count int) []byte {
|
||||
result := v.data[v.position : v.position+uint64(count)]
|
||||
v.position += uint64(count)
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *StreamReader) SkipBytes(count int) {
|
||||
|
@ -39,9 +39,7 @@ func LoadDictionary(dictionaryData []byte) {
|
||||
}
|
||||
br := CreateStreamReader(dictionaryData)
|
||||
// CRC
|
||||
if _, err := br.ReadBytes(2); err != nil {
|
||||
log.Fatal("Error reading CRC")
|
||||
}
|
||||
br.ReadBytes(2)
|
||||
numberOfElements := br.GetUInt16()
|
||||
hashTableSize := br.GetUInt32()
|
||||
// Version (always 0)
|
||||
@ -74,7 +72,7 @@ func LoadDictionary(dictionaryData []byte) {
|
||||
continue
|
||||
}
|
||||
br.SetPosition(uint64(hashEntry.NameString))
|
||||
nameVal, _ := br.ReadBytes(int(hashEntry.NameLength - 1))
|
||||
nameVal := br.ReadBytes(int(hashEntry.NameLength - 1))
|
||||
value := string(nameVal)
|
||||
br.SetPosition(uint64(hashEntry.IndexString))
|
||||
key := ""
|
||||
|
@ -63,5 +63,4 @@ func (m *MapEngine) GenerateAct1Overworld(cacheTiles bool) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ import (
|
||||
"github.com/beefsack/go-astar"
|
||||
)
|
||||
|
||||
var imageCacheRecords map[uint32]d2render.Surface
|
||||
|
||||
type PathTile struct {
|
||||
Walkable bool
|
||||
Up, Down, Left, Right, UpLeft, UpRight, DownLeft, DownRight *PathTile
|
||||
@ -76,28 +78,31 @@ func (t *PathTile) PathEstimatedCost(to astar.Pather) float64 {
|
||||
}
|
||||
|
||||
type MapRegion struct {
|
||||
tileRect d2common.Rectangle
|
||||
regionPath string
|
||||
levelType d2datadict.LevelTypeRecord
|
||||
levelPreset d2datadict.LevelPresetRecord
|
||||
tiles []d2dt1.Tile
|
||||
ds1 *d2ds1.DS1
|
||||
palette *d2dat.DATPalette
|
||||
startX float64
|
||||
startY float64
|
||||
imageCacheRecords map[uint32]d2render.Surface
|
||||
seed int64
|
||||
currentFrame int
|
||||
lastFrameTime float64
|
||||
walkableArea [][]PathTile
|
||||
tileRect d2common.Rectangle
|
||||
regionPath string
|
||||
levelType d2datadict.LevelTypeRecord
|
||||
levelPreset d2datadict.LevelPresetRecord
|
||||
tiles []d2dt1.Tile
|
||||
ds1 *d2ds1.DS1
|
||||
palette *d2dat.DATPalette
|
||||
startX float64
|
||||
startY float64
|
||||
seed int64
|
||||
currentFrame int
|
||||
lastFrameTime float64
|
||||
walkableArea [][]PathTile
|
||||
}
|
||||
|
||||
// Invalidates the global region image cache. Call this when you are changing regions
|
||||
func InvalidateImageCache() {
|
||||
imageCacheRecords = nil
|
||||
}
|
||||
|
||||
func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.RegionIdType, levelPreset int, fileIndex int, cacheTiles bool) (*MapRegion, []MapEntity) {
|
||||
region := &MapRegion{
|
||||
levelType: d2datadict.LevelTypes[levelType],
|
||||
levelPreset: d2datadict.LevelPresets[levelPreset],
|
||||
imageCacheRecords: map[uint32]d2render.Surface{},
|
||||
seed: seed,
|
||||
levelType: d2datadict.LevelTypes[levelType],
|
||||
levelPreset: d2datadict.LevelPresets[levelPreset],
|
||||
seed: seed,
|
||||
}
|
||||
|
||||
region.palette, _ = loadPaletteForAct(levelType)
|
||||
@ -613,12 +618,15 @@ func (mr *MapRegion) generateTileCache() {
|
||||
|
||||
func (mr *MapRegion) getImageCacheRecord(style, sequence byte, tileType d2enum.TileType, randomIndex byte) d2render.Surface {
|
||||
lookupIndex := uint32(style)<<24 | uint32(sequence)<<16 | uint32(tileType)<<8 | uint32(randomIndex)
|
||||
return mr.imageCacheRecords[lookupIndex]
|
||||
return imageCacheRecords[lookupIndex]
|
||||
}
|
||||
|
||||
func (mr *MapRegion) setImageCacheRecord(style, sequence byte, tileType d2enum.TileType, randomIndex byte, image d2render.Surface) {
|
||||
lookupIndex := uint32(style)<<24 | uint32(sequence)<<16 | uint32(tileType)<<8 | uint32(randomIndex)
|
||||
mr.imageCacheRecords[lookupIndex] = image
|
||||
if imageCacheRecords == nil {
|
||||
imageCacheRecords = make(map[uint32]d2render.Surface)
|
||||
}
|
||||
imageCacheRecords[lookupIndex] = image
|
||||
}
|
||||
|
||||
func (mr *MapRegion) generateFloorCache(tile *d2ds1.FloorShadowRecord, tileX, tileY int) {
|
||||
|
@ -105,6 +105,7 @@ func CreateMapEngineTest(currentRegion int, levelPreset int) *MapEngineTest {
|
||||
}
|
||||
|
||||
func (met *MapEngineTest) LoadRegionByIndex(n int, levelPreset, fileIndex int) {
|
||||
d2map.InvalidateImageCache()
|
||||
for _, spec := range regions {
|
||||
if spec.regionType == d2enum.RegionIdType(n) {
|
||||
met.regionSpec = spec
|
||||
|
@ -44,7 +44,7 @@ func Create(openNetworkServer bool) {
|
||||
}
|
||||
|
||||
mapEngine := d2map.CreateMapEngine(singletonServer.seed)
|
||||
mapEngine.GenerateAct1Overworld(true)
|
||||
mapEngine.GenerateAct1Overworld(false)
|
||||
singletonServer.mapEngines = append(singletonServer.mapEngines, mapEngine)
|
||||
|
||||
singletonServer.scriptEngine.AddFunction("getMapEngines", func(call otto.FunctionCall) otto.Value {
|
||||
|
8
main.go
8
main.go
@ -9,7 +9,9 @@ import (
|
||||
"image/png"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
@ -120,6 +122,12 @@ func initialize() error {
|
||||
}
|
||||
|
||||
d2term.BindLogger()
|
||||
d2term.BindAction("dumpheap", "dumps the heap to heap.out", func() {
|
||||
fileOut, _ := os.Create("heap.out")
|
||||
pprof.WriteHeapProfile(fileOut)
|
||||
fileOut.Close()
|
||||
exec.Command("go", "tool", "pprof", "--pdf", "./OpenDiablo2", "./heap.out", ">", "./memprofile.pdf")
|
||||
})
|
||||
d2term.BindAction("fullscreen", "toggles fullscreen", func() {
|
||||
fullscreen := !d2render.IsFullScreen()
|
||||
d2render.SetFullScreen(fullscreen)
|
||||
|
Loading…
x
Reference in New Issue
Block a user