mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-03 23:26:41 -05:00
more work on ecs impl
* added command line arg for launching ecs impl * removed render system tests, was causing gl context issues in tests * fixed all lint errors in d2systems
This commit is contained in:
parent
069201a980
commit
caafe7592c
@ -97,4 +97,3 @@ func (cm *AnimationMap) Remove(id akara.EID) {
|
||||
delete(cm.components, id)
|
||||
cm.world.UpdateEntity(id)
|
||||
}
|
||||
|
||||
|
2
d2core/d2components/doc.go
Normal file
2
d2core/d2components/doc.go
Normal file
@ -0,0 +1,2 @@
|
||||
// Package d2components provides all of the ECS components
|
||||
package d2components
|
@ -1,11 +1,12 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/gravestench/akara"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2components"
|
||||
)
|
||||
|
||||
@ -30,7 +31,7 @@ func NewAppBootstrapSystem() *AppBootstrapSystem {
|
||||
d2components.FileType,
|
||||
d2components.FileHandle,
|
||||
d2components.FilePath,
|
||||
).
|
||||
).
|
||||
Forbid( // files which have been loaded
|
||||
d2components.GameConfig,
|
||||
d2components.StringTable,
|
||||
@ -44,7 +45,7 @@ func NewAppBootstrapSystem() *AppBootstrapSystem {
|
||||
d2components.Dt1,
|
||||
d2components.Wav,
|
||||
d2components.AnimData,
|
||||
).
|
||||
).
|
||||
Build()
|
||||
|
||||
// we are interested in actual game config instances, too
|
||||
@ -52,7 +53,7 @@ func NewAppBootstrapSystem() *AppBootstrapSystem {
|
||||
|
||||
sys := &AppBootstrapSystem{
|
||||
BaseSubscriberSystem: akara.NewBaseSubscriberSystem(filesToCheck, gameConfigs),
|
||||
Logger: d2util.NewLogger(),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
sys.SetPrefix(logPrefixAppBootstrap)
|
||||
@ -75,7 +76,7 @@ type AppBootstrapSystem struct {
|
||||
*d2components.FileSourceMap
|
||||
}
|
||||
|
||||
// Init will inject (or use existing) components related to setting up the config sources and
|
||||
// Init will inject (or use existing) components related to setting up the config sources
|
||||
func (m *AppBootstrapSystem) Init(world *akara.World) {
|
||||
m.Info("initializing ...")
|
||||
|
||||
@ -102,7 +103,6 @@ func (m *AppBootstrapSystem) injectSystems() {
|
||||
m.World.AddSystem(NewGameConfigSystem())
|
||||
m.World.AddSystem(NewAssetLoader())
|
||||
m.World.AddSystem(NewGameObjectFactory())
|
||||
m.World.AddSystem(NewUpdateCounterSystem())
|
||||
}
|
||||
|
||||
// we make two entities and assign file paths for the two directories that
|
||||
@ -136,7 +136,6 @@ func (m *AppBootstrapSystem) setupConfigSources() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (m *AppBootstrapSystem) setupConfigFile() {
|
||||
// add an entity that will get picked up by the game config system and loaded
|
||||
m.AddFilePath(m.NewEntity()).Path = configFileName
|
||||
@ -154,6 +153,7 @@ func (m *AppBootstrapSystem) Update() {
|
||||
m.Infof("found %d new configs to parse", len(configs))
|
||||
|
||||
firstConfigEntityID := configs[0]
|
||||
|
||||
cfg, found := m.GetGameConfig(firstConfigEntityID)
|
||||
if !found {
|
||||
return
|
||||
|
@ -1,15 +1,13 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"io"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2cache"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2animdata"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2cof"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dat"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dc6"
|
||||
@ -19,9 +17,8 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2pl2"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2tbl"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2txt"
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2components"
|
||||
)
|
||||
|
||||
@ -31,7 +28,7 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
LogPrefixAssetLoader = "Asset Loader System"
|
||||
logPrefixAssetLoader = "Asset Loader System"
|
||||
)
|
||||
|
||||
// NewAssetLoader creates a new asset loader instance
|
||||
@ -62,24 +59,24 @@ func NewAssetLoader() *AssetLoaderSystem {
|
||||
|
||||
assetLoader := &AssetLoaderSystem{
|
||||
BaseSubscriberSystem: akara.NewBaseSubscriberSystem(filesToLoad, fileSources),
|
||||
cache: d2cache.CreateCache(assetCacheBudget).(*d2cache.Cache),
|
||||
Logger: d2util.NewLogger(),
|
||||
cache: d2cache.CreateCache(assetCacheBudget).(*d2cache.Cache),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
assetLoader.SetPrefix(LogPrefixAssetLoader)
|
||||
assetLoader.SetPrefix(logPrefixAssetLoader)
|
||||
|
||||
return assetLoader
|
||||
}
|
||||
|
||||
var _ akara.System = &AssetLoaderSystem{}
|
||||
|
||||
// AssetLoaderSystem is responsible for parsing file handle data into various structs, like COF or DC6
|
||||
// AssetLoaderSystem is responsible for parsing data from file handles into various structs, like COF or DC6
|
||||
type AssetLoaderSystem struct {
|
||||
*akara.BaseSubscriberSystem
|
||||
*d2util.Logger
|
||||
fileSub *akara.Subscription
|
||||
sourceSub *akara.Subscription
|
||||
cache *d2cache.Cache
|
||||
fileSub *akara.Subscription
|
||||
sourceSub *akara.Subscription
|
||||
cache *d2cache.Cache
|
||||
*d2components.FilePathMap
|
||||
*d2components.FileTypeMap
|
||||
*d2components.FileHandleMap
|
||||
@ -99,7 +96,7 @@ type AssetLoaderSystem struct {
|
||||
}
|
||||
|
||||
// Init injects component maps related to various asset types
|
||||
func (m *AssetLoaderSystem) Init(world *akara.World) {
|
||||
func (m *AssetLoaderSystem) Init(_ *akara.World) {
|
||||
m.Info("initializing ...")
|
||||
|
||||
m.fileSub = m.Subscriptions[0]
|
||||
@ -213,41 +210,64 @@ func (m *AssetLoaderSystem) assignFromCache(id akara.EID, path string, t d2enum.
|
||||
return found
|
||||
}
|
||||
|
||||
//nolint:gocyclo // this big switch statement is unfortunate, but necessary
|
||||
func (m *AssetLoaderSystem) parseAndCache(id akara.EID, path string, t d2enum.FileType, data []byte) {
|
||||
go func() {
|
||||
switch t {
|
||||
case d2enum.FileTypeStringTable:
|
||||
m.Infof("Loading string table: %s", path)
|
||||
m.loadStringTable(id, path, data) // TODO: add error handling for string table load
|
||||
m.loadStringTable(id, path, data)
|
||||
case d2enum.FileTypeFontTable:
|
||||
m.Infof("Loading font table: %s", path)
|
||||
m.loadFontTable(id, path, data) // TODO: add error handling for string table load
|
||||
m.loadFontTable(id, path, data)
|
||||
case d2enum.FileTypeDataDictionary:
|
||||
m.Infof("Loading data dictionary: %s", path)
|
||||
m.loadDataDictionary(id, path, data) // TODO: add error handling for data dict load
|
||||
m.loadDataDictionary(id, path, data)
|
||||
case d2enum.FileTypePalette:
|
||||
m.Infof("Loading palette: %s", path)
|
||||
m.loadPalette(id, path, data)
|
||||
|
||||
if err := m.loadPalette(id, path, data); err != nil {
|
||||
m.Error(err.Error())
|
||||
}
|
||||
case d2enum.FileTypePaletteTransform:
|
||||
m.Infof("Loading palette transform: %s", path)
|
||||
m.loadPaletteTransform(id, path, data)
|
||||
|
||||
if err := m.loadPaletteTransform(id, path, data); err != nil {
|
||||
m.Error(err.Error())
|
||||
}
|
||||
case d2enum.FileTypeCOF:
|
||||
m.Infof("Loading COF: %s", path)
|
||||
m.loadCOF(id, path, data)
|
||||
|
||||
if err := m.loadCOF(id, path, data); err != nil {
|
||||
m.Error(err.Error())
|
||||
}
|
||||
case d2enum.FileTypeDC6:
|
||||
m.Infof("Loading DC6: %s", path)
|
||||
m.loadDC6(id, path, data)
|
||||
|
||||
if err := m.loadDC6(id, path, data); err != nil {
|
||||
m.Error(err.Error())
|
||||
}
|
||||
case d2enum.FileTypeDCC:
|
||||
m.Infof("Loading DCC: %s", path)
|
||||
m.loadDCC(id, path, data)
|
||||
|
||||
if err := m.loadDCC(id, path, data); err != nil {
|
||||
m.Error(err.Error())
|
||||
}
|
||||
case d2enum.FileTypeDS1:
|
||||
m.Infof("Loading DS1: %s", path)
|
||||
m.loadDS1(id, path, data)
|
||||
|
||||
if err := m.loadDS1(id, path, data); err != nil {
|
||||
m.Error(err.Error())
|
||||
}
|
||||
case d2enum.FileTypeDT1:
|
||||
m.Infof("Loading DT1: %s", path)
|
||||
m.loadDT1(id, path, data)
|
||||
|
||||
if err := m.loadDT1(id, path, data); err != nil {
|
||||
m.Error(err.Error())
|
||||
}
|
||||
case d2enum.FileTypeWAV:
|
||||
m.Infof("Loading WAV: %s", path)
|
||||
|
||||
fh, found := m.GetFileHandle(id)
|
||||
if !found {
|
||||
return
|
||||
@ -256,7 +276,10 @@ func (m *AssetLoaderSystem) parseAndCache(id akara.EID, path string, t d2enum.Fi
|
||||
m.loadWAV(id, path, fh.Data)
|
||||
case d2enum.FileTypeD2:
|
||||
m.Infof("Loading animation data: %s", path)
|
||||
m.loadAnimData(id, path, data)
|
||||
|
||||
if err := m.loadAnimData(id, path, data); err != nil {
|
||||
m.Error(err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
@ -265,25 +288,37 @@ func (m *AssetLoaderSystem) loadStringTable(id akara.EID, path string, data []by
|
||||
txt := d2tbl.LoadTextDictionary(data)
|
||||
loaded := &txt
|
||||
m.AddStringTable(id).TextDictionary = loaded
|
||||
m.cache.Insert(path, loaded, assetCacheEntryWeight)
|
||||
|
||||
if cacheErr := m.cache.Insert(path, loaded, assetCacheEntryWeight); cacheErr != nil {
|
||||
m.Error(cacheErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (m *AssetLoaderSystem) loadFontTable(id akara.EID, path string, data []byte) {
|
||||
m.AddFontTable(id).Data = data
|
||||
m.cache.Insert(path, data, assetCacheEntryWeight)
|
||||
|
||||
if cacheErr := m.cache.Insert(path, data, assetCacheEntryWeight); cacheErr != nil {
|
||||
m.Error(cacheErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (m *AssetLoaderSystem) loadDataDictionary(id akara.EID, path string, data []byte) {
|
||||
loaded := d2txt.LoadDataDictionary(data)
|
||||
m.AddDataDictionary(id).DataDictionary = loaded
|
||||
m.cache.Insert(path, loaded, assetCacheEntryWeight)
|
||||
|
||||
if cacheErr := m.cache.Insert(path, loaded, assetCacheEntryWeight); cacheErr != nil {
|
||||
m.Error(cacheErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (m *AssetLoaderSystem) loadPalette(id akara.EID, path string, data []byte) error {
|
||||
loaded, err := d2dat.Load(data)
|
||||
if err == nil {
|
||||
m.AddPalette(id).Palette = loaded
|
||||
m.cache.Insert(path, loaded, assetCacheEntryWeight)
|
||||
|
||||
if cacheErr := m.cache.Insert(path, loaded, assetCacheEntryWeight); cacheErr != nil {
|
||||
m.Error(cacheErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
@ -293,7 +328,10 @@ func (m *AssetLoaderSystem) loadPaletteTransform(id akara.EID, path string, data
|
||||
loaded, err := d2pl2.Load(data)
|
||||
if err == nil {
|
||||
m.AddPaletteTransform(id).Transform = loaded
|
||||
m.cache.Insert(path, loaded, assetCacheEntryWeight)
|
||||
|
||||
if cacheErr := m.cache.Insert(path, loaded, assetCacheEntryWeight); cacheErr != nil {
|
||||
m.Error(cacheErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
@ -303,7 +341,10 @@ func (m *AssetLoaderSystem) loadCOF(id akara.EID, path string, data []byte) erro
|
||||
loaded, err := d2cof.Load(data)
|
||||
if err == nil {
|
||||
m.AddCof(id).COF = loaded
|
||||
m.cache.Insert(path, loaded, assetCacheEntryWeight)
|
||||
|
||||
if cacheErr := m.cache.Insert(path, loaded, assetCacheEntryWeight); cacheErr != nil {
|
||||
m.Error(cacheErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
@ -313,7 +354,10 @@ func (m *AssetLoaderSystem) loadDC6(id akara.EID, path string, data []byte) erro
|
||||
loaded, err := d2dc6.Load(data)
|
||||
if err == nil {
|
||||
m.AddDc6(id).DC6 = loaded
|
||||
m.cache.Insert(path, loaded, assetCacheEntryWeight)
|
||||
|
||||
if cacheErr := m.cache.Insert(path, loaded, assetCacheEntryWeight); cacheErr != nil {
|
||||
m.Error(cacheErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
@ -323,7 +367,10 @@ func (m *AssetLoaderSystem) loadDCC(id akara.EID, path string, data []byte) erro
|
||||
loaded, err := d2dcc.Load(data)
|
||||
if err == nil {
|
||||
m.AddDcc(id).DCC = loaded
|
||||
m.cache.Insert(path, loaded, assetCacheEntryWeight)
|
||||
|
||||
if cacheErr := m.cache.Insert(path, loaded, assetCacheEntryWeight); cacheErr != nil {
|
||||
m.Error(cacheErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
@ -333,7 +380,10 @@ func (m *AssetLoaderSystem) loadDS1(id akara.EID, path string, data []byte) erro
|
||||
loaded, err := d2ds1.LoadDS1(data)
|
||||
if err == nil {
|
||||
m.AddDs1(id).DS1 = loaded
|
||||
m.cache.Insert(path, loaded, assetCacheEntryWeight)
|
||||
|
||||
if cacheErr := m.cache.Insert(path, loaded, assetCacheEntryWeight); cacheErr != nil {
|
||||
m.Error(cacheErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
@ -343,7 +393,10 @@ func (m *AssetLoaderSystem) loadDT1(id akara.EID, path string, data []byte) erro
|
||||
loaded, err := d2dt1.LoadDT1(data)
|
||||
if err == nil {
|
||||
m.AddDt1(id).DT1 = loaded
|
||||
m.cache.Insert(path, loaded, assetCacheEntryWeight)
|
||||
|
||||
if cacheErr := m.cache.Insert(path, loaded, assetCacheEntryWeight); cacheErr != nil {
|
||||
m.Error(cacheErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
@ -352,14 +405,20 @@ func (m *AssetLoaderSystem) loadDT1(id akara.EID, path string, data []byte) erro
|
||||
func (m *AssetLoaderSystem) loadWAV(id akara.EID, path string, seeker io.ReadSeeker) {
|
||||
component := m.AddWav(id)
|
||||
component.Data = seeker
|
||||
m.cache.Insert(path, seeker, assetCacheEntryWeight)
|
||||
|
||||
if cacheErr := m.cache.Insert(path, seeker, assetCacheEntryWeight); cacheErr != nil {
|
||||
m.Error(cacheErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (m *AssetLoaderSystem) loadAnimData(id akara.EID, path string, data []byte) error {
|
||||
loaded, err := d2animdata.Load(data)
|
||||
if err == nil {
|
||||
m.AddAnimData(id).AnimationData = loaded
|
||||
m.cache.Insert(path, loaded, assetCacheEntryWeight)
|
||||
|
||||
if cacheErr := m.cache.Insert(path, loaded, assetCacheEntryWeight); cacheErr != nil {
|
||||
m.Error(cacheErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
|
2
d2core/d2systems/doc.go
Normal file
2
d2core/d2systems/doc.go
Normal file
@ -0,0 +1,2 @@
|
||||
// Package d2systems provides all of the ECS systems
|
||||
package d2systems
|
@ -1,9 +1,10 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2cache"
|
||||
@ -16,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
languageTokenFont = "{LANG_FONT}"
|
||||
languageTokenFont = "{LANG_FONT}" // nolint:gosec // no security issue here...
|
||||
languageTokenStringTable = "{LANG}"
|
||||
)
|
||||
|
||||
@ -29,6 +30,7 @@ const (
|
||||
logPrefixFileHandleResolver = "File Handle Resolver"
|
||||
)
|
||||
|
||||
// NewFileHandleResolver creates a new file handle resolver system
|
||||
func NewFileHandleResolver() *FileHandleResolutionSystem {
|
||||
// this filter is for entities that have a file path and file type but no file handle.
|
||||
filesToSource := akara.NewFilter().
|
||||
@ -44,8 +46,8 @@ func NewFileHandleResolver() *FileHandleResolutionSystem {
|
||||
|
||||
fhr := &FileHandleResolutionSystem{
|
||||
BaseSubscriberSystem: akara.NewBaseSubscriberSystem(filesToSource, sourcesToUse),
|
||||
cache: d2cache.CreateCache(fileHandleCacheBudget).(*d2cache.Cache),
|
||||
Logger: d2util.NewLogger(),
|
||||
cache: d2cache.CreateCache(fileHandleCacheBudget).(*d2cache.Cache),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
fhr.SetPrefix(logPrefixFileHandleResolver)
|
||||
@ -53,6 +55,13 @@ func NewFileHandleResolver() *FileHandleResolutionSystem {
|
||||
return fhr
|
||||
}
|
||||
|
||||
// FileHandleResolutionSystem is responsible for using file sources to resolve files.
|
||||
// File sources are checked in the order that the sources were added.
|
||||
//
|
||||
// A file source can be something like an MPQ archive or a file system directory on the host machine.
|
||||
//
|
||||
// A file handle is a primitive representation of a loaded file; something that has data
|
||||
// in the form of a byte slice, but has not been parsed into a more meaningful struct, like a DC6 animation.
|
||||
type FileHandleResolutionSystem struct {
|
||||
*akara.BaseSubscriberSystem
|
||||
*d2util.Logger
|
||||
@ -66,7 +75,7 @@ type FileHandleResolutionSystem struct {
|
||||
}
|
||||
|
||||
// Init initializes the system with the given world
|
||||
func (m *FileHandleResolutionSystem) Init(world *akara.World) {
|
||||
func (m *FileHandleResolutionSystem) Init(_ *akara.World) {
|
||||
m.Info("initializing ...")
|
||||
|
||||
m.filesToLoad = m.Subscriptions[0]
|
||||
@ -80,7 +89,9 @@ func (m *FileHandleResolutionSystem) Init(world *akara.World) {
|
||||
m.fileSources = m.InjectMap(d2components.FileSource).(*d2components.FileSourceMap)
|
||||
}
|
||||
|
||||
// Process processes all of the Entities
|
||||
// Update iterates over entities which have not had a file handle resolved.
|
||||
// For each source, it attempts to load this file with the given source.
|
||||
// If the file can be opened by the source, we create the file handle using that source.
|
||||
func (m *FileHandleResolutionSystem) Update() {
|
||||
filesToLoad := m.filesToLoad.GetEntities()
|
||||
sourcesToUse := m.sourcesToUse.GetEntities()
|
||||
@ -146,21 +157,21 @@ func (m *FileHandleResolutionSystem) loadFileWithSource(fileID, sourceID akara.E
|
||||
tryPath := strings.ReplaceAll(fp.Path, "sfx", "music")
|
||||
tmpComponent := &d2components.FilePathComponent{Path: tryPath}
|
||||
|
||||
cacheKey := m.makeCacheKey(tryPath, sourceFp.Path)
|
||||
cacheKey = m.makeCacheKey(tryPath, sourceFp.Path)
|
||||
if entry, found := m.cache.Retrieve(cacheKey); found {
|
||||
component := m.fileHandles.AddFileHandle(fileID)
|
||||
component.Data = entry.(d2interface.DataStream)
|
||||
fp.Path = tryPath
|
||||
|
||||
return true
|
||||
} else {
|
||||
data, err = source.Open(tmpComponent)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
fp.Path = tryPath
|
||||
}
|
||||
|
||||
data, err = source.Open(tmpComponent)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
fp.Path = tryPath
|
||||
}
|
||||
|
||||
m.Infof("resolved `%s` with source `%s`", fp.Path, sourceFp.Path)
|
||||
@ -168,7 +179,9 @@ func (m *FileHandleResolutionSystem) loadFileWithSource(fileID, sourceID akara.E
|
||||
component := m.fileHandles.AddFileHandle(fileID)
|
||||
component.Data = data
|
||||
|
||||
m.cache.Insert(cacheKey, data, assetCacheEntryWeight)
|
||||
if err := m.cache.Insert(cacheKey, data, fileHandleCacheEntryWeight); err != nil {
|
||||
m.Error(err.Error())
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ import (
|
||||
)
|
||||
|
||||
func Test_FileHandleResolver_Process(t *testing.T) {
|
||||
const testDataPath = "./testdata/"
|
||||
|
||||
cfg := akara.NewWorldConfig()
|
||||
|
||||
fileTypeResolver := NewFileTypeResolver()
|
||||
@ -32,9 +34,7 @@ func Test_FileHandleResolver_Process(t *testing.T) {
|
||||
|
||||
sourceEntity := world.NewEntity()
|
||||
sourceFp := filePaths.AddFilePath(sourceEntity)
|
||||
sourceFp.Path = "./testdata/"
|
||||
|
||||
//_ = world.Update(0)
|
||||
sourceFp.Path = testDataPath
|
||||
|
||||
fileEntity := world.NewEntity()
|
||||
fileFp := filePaths.AddFilePath(fileEntity)
|
||||
|
@ -1,11 +1,12 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
@ -18,6 +19,7 @@ const (
|
||||
logPrefixFileSourceResolver = "File Source Resolver"
|
||||
)
|
||||
|
||||
// NewFileSourceResolver creates a new file source resolver system
|
||||
func NewFileSourceResolver() *FileSourceResolver {
|
||||
// subscribe to entities with a file type and file path, but no file source type
|
||||
filesToCheck := akara.NewFilter().
|
||||
@ -28,7 +30,7 @@ func NewFileSourceResolver() *FileSourceResolver {
|
||||
|
||||
fsr := &FileSourceResolver{
|
||||
BaseSubscriberSystem: akara.NewBaseSubscriberSystem(filesToCheck),
|
||||
Logger: d2util.NewLogger(),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
fsr.SetPrefix(logPrefixFileSourceResolver)
|
||||
@ -36,6 +38,9 @@ func NewFileSourceResolver() *FileSourceResolver {
|
||||
return fsr
|
||||
}
|
||||
|
||||
// FileSourceResolver is responsible for determining if files can be used as a file source.
|
||||
// If it can, it sets the file up as a source, and the file handle resolver system can
|
||||
// then use the source to open files.
|
||||
type FileSourceResolver struct {
|
||||
*akara.BaseSubscriberSystem
|
||||
*d2util.Logger
|
||||
@ -45,8 +50,8 @@ type FileSourceResolver struct {
|
||||
fileSources *d2components.FileSourceMap
|
||||
}
|
||||
|
||||
// Init initializes the system with the given world
|
||||
func (m *FileSourceResolver) Init(world *akara.World) {
|
||||
// Init initializes the file source resolver, injecting the necessary components into the world
|
||||
func (m *FileSourceResolver) Init(_ *akara.World) {
|
||||
m.Info("initializing ...")
|
||||
|
||||
m.fileSub = m.Subscriptions[0]
|
||||
@ -58,7 +63,7 @@ func (m *FileSourceResolver) Init(world *akara.World) {
|
||||
m.fileSources = m.InjectMap(d2components.FileSource).(*d2components.FileSourceMap)
|
||||
}
|
||||
|
||||
// Process processes all of the Entities
|
||||
// Update iterates over entities from its subscription, and checks if it can be used as a file source
|
||||
func (m *FileSourceResolver) Update() {
|
||||
for subIdx := range m.Subscriptions {
|
||||
for _, sourceEntityID := range m.Subscriptions[subIdx].GetEntities() {
|
||||
@ -91,27 +96,22 @@ func (m *FileSourceResolver) processSourceEntity(id akara.EID) {
|
||||
}
|
||||
|
||||
source := m.fileSources.AddFileSource(id)
|
||||
source.AbstractSource = instance
|
||||
|
||||
m.Infof("using MPQ source for `%s`", fp.Path)
|
||||
source.AbstractSource = instance
|
||||
case d2enum.FileTypeDirectory:
|
||||
instance, err := m.makeFileSystemSource(fp.Path)
|
||||
|
||||
if err != nil {
|
||||
ft.Type = d2enum.FileTypeUnknown
|
||||
break
|
||||
}
|
||||
instance := m.makeFileSystemSource(fp.Path)
|
||||
|
||||
source := m.fileSources.AddFileSource(id)
|
||||
source.AbstractSource = instance
|
||||
|
||||
m.Infof("using FILESYSTEM source for `%s`", fp.Path)
|
||||
source.AbstractSource = instance
|
||||
}
|
||||
}
|
||||
|
||||
// filesystem source
|
||||
func (m *FileSourceResolver) makeFileSystemSource(path string) (d2components.AbstractSource, error) {
|
||||
return &fsSource{rootDir: path}, nil
|
||||
func (m *FileSourceResolver) makeFileSystemSource(path string) d2components.AbstractSource {
|
||||
return &fsSource{rootDir: path}
|
||||
}
|
||||
|
||||
type fsSource struct {
|
||||
|
@ -10,6 +10,8 @@ import (
|
||||
)
|
||||
|
||||
func Test_FileSourceResolution(t *testing.T) {
|
||||
const testDataPath = "./testdata/"
|
||||
|
||||
cfg := akara.NewWorldConfig()
|
||||
|
||||
srcResolver := NewFileSourceResolver()
|
||||
@ -29,7 +31,7 @@ func Test_FileSourceResolution(t *testing.T) {
|
||||
|
||||
sourceEntity := world.NewEntity()
|
||||
sourceFp := filePaths.AddFilePath(sourceEntity)
|
||||
sourceFp.Path = "./testdata/"
|
||||
sourceFp.Path = testDataPath
|
||||
|
||||
_ = world.Update(0)
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
@ -28,7 +29,7 @@ func NewFileTypeResolver() *FileTypeResolver {
|
||||
|
||||
ftr := &FileTypeResolver{
|
||||
BaseSubscriberSystem: akara.NewBaseSubscriberSystem(filesToCheck),
|
||||
Logger: d2util.NewLogger(),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
ftr.SetPrefix(logPrefixFileTypeResolver)
|
||||
@ -53,7 +54,7 @@ type FileTypeResolver struct {
|
||||
}
|
||||
|
||||
// Init initializes the system with the given world
|
||||
func (m *FileTypeResolver) Init(world *akara.World) {
|
||||
func (m *FileTypeResolver) Init(_ *akara.World) {
|
||||
m.Info("initializing ...")
|
||||
|
||||
m.filesToCheck = m.Subscriptions[0]
|
||||
@ -64,13 +65,14 @@ func (m *FileTypeResolver) Init(world *akara.World) {
|
||||
m.FileTypeMap = m.InjectMap(d2components.FileType).(*d2components.FileTypeMap)
|
||||
}
|
||||
|
||||
// Process processes all of the Entities
|
||||
// Update processes all of the Entities
|
||||
func (m *FileTypeResolver) Update() {
|
||||
for _, eid := range m.filesToCheck.GetEntities() {
|
||||
m.determineFileType(eid)
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:gocyclo // this big switch statement is unfortunate, but necessary
|
||||
func (m *FileTypeResolver) determineFileType(id akara.EID) {
|
||||
fp, found := m.GetFilePath(id)
|
||||
if !found {
|
||||
|
@ -1,8 +1,6 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
@ -16,13 +14,14 @@ const (
|
||||
// static check that the game config system implements the system interface
|
||||
var _ akara.System = &GameClientBootstrapSystem{}
|
||||
|
||||
// NewGameClientBootstrapSystem makes a new client bootstrap system
|
||||
func NewGameClientBootstrapSystem() *GameClientBootstrapSystem {
|
||||
// we are interested in actual game config instances, too
|
||||
gameConfigs := akara.NewFilter().Require(d2components.GameConfig).Build()
|
||||
|
||||
sys := &GameClientBootstrapSystem{
|
||||
BaseSubscriberSystem: akara.NewBaseSubscriberSystem(gameConfigs),
|
||||
Logger: d2util.NewLogger(),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
sys.SetPrefix(logPrefixGameClientBootstrap)
|
||||
@ -30,14 +29,16 @@ func NewGameClientBootstrapSystem() *GameClientBootstrapSystem {
|
||||
return sys
|
||||
}
|
||||
|
||||
// GameClientBootstrapSystem is responsible for setting up the regular diablo2 game launch
|
||||
// GameClientBootstrapSystem is responsible for setting up other
|
||||
// systems that are common to both the game client and the headless game server
|
||||
type GameClientBootstrapSystem struct {
|
||||
*akara.BaseSubscriberSystem
|
||||
*d2util.Logger
|
||||
*RenderSystem
|
||||
}
|
||||
|
||||
func (m *GameClientBootstrapSystem) Init(world *akara.World) {
|
||||
// Init injects the common systems required by both the game client and headless server
|
||||
func (m *GameClientBootstrapSystem) Init(_ *akara.World) {
|
||||
m.Info("initializing ...")
|
||||
|
||||
m.injectSystems()
|
||||
@ -45,31 +46,20 @@ func (m *GameClientBootstrapSystem) Init(world *akara.World) {
|
||||
m.Info("game client bootstrap complete, deactivating")
|
||||
m.SetActive(false)
|
||||
|
||||
if err := m.RenderSystem.Loop(); err != nil {
|
||||
panic(err)
|
||||
if err := m.World.Update(0); err != nil {
|
||||
m.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (m *GameClientBootstrapSystem) injectSystems() {
|
||||
m.RenderSystem = NewRenderSystem()
|
||||
|
||||
m.World.AddSystem(m.RenderSystem)
|
||||
m.World.AddSystem(NewUpdateCounterSystem())
|
||||
m.World.AddSystem(NewMainMenuScene())
|
||||
m.World.AddSystem(m.RenderSystem)
|
||||
|
||||
loadAttempts := 10
|
||||
|
||||
for loadAttempts > 0 {
|
||||
m.World.Update(0)
|
||||
|
||||
loadAttempts--
|
||||
|
||||
if m.RenderSystem.renderer != nil {
|
||||
return // we've loaded the config, everything is cool
|
||||
}
|
||||
}
|
||||
|
||||
panic(errors.New("could not initialize renderer"))
|
||||
}
|
||||
|
||||
func (m *GameClientBootstrapSystem) Update() {}
|
||||
// Update does nothing, but exists to satisfy the `akara.System` interface
|
||||
func (m *GameClientBootstrapSystem) Update() {
|
||||
// nothing to do after init ...
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/gravestench/akara"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_game_client(t *testing.T) {
|
||||
cfg := akara.NewWorldConfig()
|
||||
|
||||
cfg.
|
||||
With(NewAppBootstrapSystem()).
|
||||
With(NewGameClientBootstrapSystem())
|
||||
|
||||
akara.NewWorld(cfg)
|
||||
}
|
@ -2,6 +2,7 @@ package d2systems
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
|
||||
@ -17,6 +18,7 @@ const (
|
||||
loggerPrefixGameConfig = "Game Config"
|
||||
)
|
||||
|
||||
// NewGameConfigSystem creates a new game config system
|
||||
func NewGameConfigSystem() *GameConfigSystem {
|
||||
// we are going to check entities that dont yet have loaded asset types
|
||||
filesToCheck := akara.NewFilter().
|
||||
@ -44,7 +46,7 @@ func NewGameConfigSystem() *GameConfigSystem {
|
||||
|
||||
gcs := &GameConfigSystem{
|
||||
BaseSubscriberSystem: akara.NewBaseSubscriberSystem(filesToCheck, gameConfigs),
|
||||
Logger: d2util.NewLogger(),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
gcs.SetPrefix(loggerPrefixGameConfig)
|
||||
@ -76,6 +78,7 @@ type GameConfigSystem struct {
|
||||
ActiveConfig *d2components.GameConfigComponent
|
||||
}
|
||||
|
||||
// Init the world with the necessary components related to game config files
|
||||
func (m *GameConfigSystem) Init(world *akara.World) {
|
||||
m.Info("initializing ...")
|
||||
|
||||
@ -92,6 +95,7 @@ func (m *GameConfigSystem) Init(world *akara.World) {
|
||||
m.DirtyMap = world.InjectMap(d2components.Dirty).(*d2components.DirtyMap)
|
||||
}
|
||||
|
||||
// Update checks for new config files
|
||||
func (m *GameConfigSystem) Update() {
|
||||
m.checkForNewConfig(m.filesToCheck.GetEntities())
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ import (
|
||||
)
|
||||
|
||||
func Test_GameConfigSystem_Bootstrap(t *testing.T) {
|
||||
const testDataPath = "./testdata/"
|
||||
|
||||
cfg := akara.NewWorldConfig()
|
||||
|
||||
typeSys := NewFileTypeResolver()
|
||||
@ -34,7 +36,7 @@ func Test_GameConfigSystem_Bootstrap(t *testing.T) {
|
||||
filePaths := filePathsAbstract.(*d2components.FilePathMap)
|
||||
|
||||
cfgDir := filePaths.AddFilePath(world.NewEntity())
|
||||
cfgDir.Path = "./testdata/"
|
||||
cfgDir.Path = testDataPath
|
||||
|
||||
cfgFile := filePaths.AddFilePath(world.NewEntity())
|
||||
cfgFile.Path = "config.json"
|
||||
|
@ -1,8 +1,9 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -13,7 +14,7 @@ const (
|
||||
func NewGameObjectFactory() *GameObjectFactory {
|
||||
m := &GameObjectFactory{
|
||||
BaseSystem: &akara.BaseSystem{},
|
||||
Logger: d2util.NewLogger(),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
m.SetPrefix(logPrefixGameObjectFactory)
|
||||
@ -24,7 +25,8 @@ func NewGameObjectFactory() *GameObjectFactory {
|
||||
// static check that GameObjectFactory implements the System interface
|
||||
var _ akara.System = &GameObjectFactory{}
|
||||
|
||||
// GameObjectFactory
|
||||
// GameObjectFactory is a wrapper system for subordinate systems that
|
||||
// do the actual object creation work.
|
||||
type GameObjectFactory struct {
|
||||
*akara.BaseSystem
|
||||
*d2util.Logger
|
||||
@ -41,8 +43,7 @@ func (t *GameObjectFactory) injectSubSystems() {
|
||||
t.SpriteFactory = NewSpriteFactorySubsystem(t.BaseSystem, t.Logger)
|
||||
}
|
||||
|
||||
// Update updates all the sub-systems
|
||||
func (t *GameObjectFactory) Update() {
|
||||
t.SpriteFactory.Update()
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"time"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2components"
|
||||
@ -19,10 +20,14 @@ func NewMovementSystem() *MovementSystem {
|
||||
|
||||
filter := cfg.Build()
|
||||
|
||||
return &MovementSystem{
|
||||
sys := &MovementSystem{
|
||||
BaseSubscriberSystem: akara.NewBaseSubscriberSystem(filter),
|
||||
Logger: d2util.NewLogger(),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
sys.SetPrefix(logPrefixMovementSystem)
|
||||
|
||||
return sys
|
||||
}
|
||||
|
||||
// static check that MovementSystem implements the System interface
|
||||
@ -37,7 +42,7 @@ type MovementSystem struct {
|
||||
}
|
||||
|
||||
// Init initializes the system with the given world
|
||||
func (m *MovementSystem) Init(world *akara.World) {
|
||||
func (m *MovementSystem) Init(_ *akara.World) {
|
||||
m.Info("initializing ...")
|
||||
|
||||
// try to inject the components we require, then cast the returned
|
||||
@ -46,7 +51,7 @@ func (m *MovementSystem) Init(world *akara.World) {
|
||||
m.VelocityMap = m.InjectMap(d2components.Velocity).(*d2components.VelocityMap)
|
||||
}
|
||||
|
||||
// Process processes all of the Entities
|
||||
// Update positions of all entities with their velocities
|
||||
func (m *MovementSystem) Update() {
|
||||
for subIdx := range m.Subscriptions {
|
||||
entities := m.Subscriptions[subIdx].GetEntities()
|
||||
|
@ -1,7 +1,6 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"testing"
|
||||
@ -116,7 +115,7 @@ func TestMovementSystem_Update(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func bench_N_entities(n int, b *testing.B) {
|
||||
func benchN(n int, b *testing.B) {
|
||||
cfg := akara.NewWorldConfig()
|
||||
|
||||
movementSystem := NewMovementSystem()
|
||||
@ -131,7 +130,7 @@ func bench_N_entities(n int, b *testing.B) {
|
||||
v := movementSystem.AddVelocity(e)
|
||||
|
||||
p.Set(0, 0)
|
||||
v.Set(rand.Float64(), rand.Float64())
|
||||
v.Set(rand.Float64(), rand.Float64()) //nolint:gosec // it's just a test
|
||||
}
|
||||
|
||||
benchName := strconv.Itoa(n) + "_entity update"
|
||||
@ -140,15 +139,13 @@ func bench_N_entities(n int, b *testing.B) {
|
||||
_ = world.Update(time.Millisecond)
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Println("done!")
|
||||
}
|
||||
|
||||
func BenchmarkMovementSystem_Update(b *testing.B) {
|
||||
bench_N_entities(1e1, b)
|
||||
bench_N_entities(1e2, b)
|
||||
bench_N_entities(1e3, b)
|
||||
bench_N_entities(1e4, b)
|
||||
bench_N_entities(1e5, b)
|
||||
bench_N_entities(1e6, b)
|
||||
benchN(1e1, b)
|
||||
benchN(1e2, b)
|
||||
benchN(1e3, b)
|
||||
benchN(1e4, b)
|
||||
benchN(1e5, b)
|
||||
benchN(1e6, b)
|
||||
}
|
||||
|
@ -2,9 +2,10 @@ package d2systems
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
|
||||
"time"
|
||||
|
||||
"github.com/gravestench/akara"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
@ -15,11 +16,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
gameTitle = "Open Diablo 2"
|
||||
gameTitle = "Open Diablo 2"
|
||||
logPrefixRenderSystem = "Render System"
|
||||
)
|
||||
|
||||
// NewRenderSystem creates a movement system
|
||||
// NewRenderSystem creates a new render system
|
||||
func NewRenderSystem() *RenderSystem {
|
||||
viewports := akara.NewFilter().
|
||||
Require(d2components.Viewport).
|
||||
@ -31,7 +32,7 @@ func NewRenderSystem() *RenderSystem {
|
||||
|
||||
r := &RenderSystem{
|
||||
BaseSubscriberSystem: akara.NewBaseSubscriberSystem(viewports, gameConfigs),
|
||||
Logger: d2util.NewLogger(),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
r.SetPrefix(logPrefixRenderSystem)
|
||||
@ -42,24 +43,24 @@ func NewRenderSystem() *RenderSystem {
|
||||
// static check that RenderSystem implements the System interface
|
||||
var _ akara.System = &RenderSystem{}
|
||||
|
||||
// RenderSystem handles entity movement based on velocity and position components
|
||||
// RenderSystem is responsible for rendering the main viewports of scenes
|
||||
// to the game screen.
|
||||
type RenderSystem struct {
|
||||
*akara.BaseSubscriberSystem
|
||||
*d2util.Logger
|
||||
renderer d2interface.Renderer
|
||||
screenSurface d2interface.Surface
|
||||
viewports *akara.Subscription
|
||||
configs *akara.Subscription
|
||||
renderer d2interface.Renderer
|
||||
viewports *akara.Subscription
|
||||
configs *akara.Subscription
|
||||
*d2components.GameConfigMap
|
||||
*d2components.ViewportMap
|
||||
*d2components.MainViewportMap
|
||||
*d2components.SurfaceMap
|
||||
lastUpdate time.Time
|
||||
lastUpdate time.Time
|
||||
gameLoopInitDelay time.Duration // there is a race condition, this is a hack
|
||||
}
|
||||
|
||||
// Init initializes the system with the given world
|
||||
func (m *RenderSystem) Init(world *akara.World) {
|
||||
// Init initializes the system with the given world, injecting the necessary components
|
||||
func (m *RenderSystem) Init(_ *akara.World) {
|
||||
m.Info("initializing ...")
|
||||
|
||||
m.gameLoopInitDelay = time.Millisecond
|
||||
@ -75,15 +76,30 @@ func (m *RenderSystem) Init(world *akara.World) {
|
||||
m.SurfaceMap = m.InjectMap(d2components.Surface).(*d2components.SurfaceMap)
|
||||
}
|
||||
|
||||
// Process will create a renderer if it doesnt exist yet,
|
||||
// and then
|
||||
// Update will initialize the renderer, start the game loop, and
|
||||
// disable the system (to prevent it from being called during the game loop).
|
||||
//
|
||||
// The reason why this isn't in the init step is because we use other systems
|
||||
// for loading the config file, and it may take more than one iteration
|
||||
func (m *RenderSystem) Update() {
|
||||
if m.renderer != nil {
|
||||
return
|
||||
return // we already created the renderer
|
||||
}
|
||||
|
||||
m.createRenderer()
|
||||
|
||||
if m.renderer == nil {
|
||||
return // the renderer has not yet been created!
|
||||
}
|
||||
|
||||
// if we have created the renderer, we can safely disable
|
||||
// this system and start the run loop.
|
||||
m.SetActive(false)
|
||||
|
||||
err := m.startGameLoop()
|
||||
if err != nil {
|
||||
m.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (m *RenderSystem) createRenderer() {
|
||||
@ -99,10 +115,9 @@ func (m *RenderSystem) createRenderer() {
|
||||
return
|
||||
}
|
||||
|
||||
// d2render.CreateRenderer should use a GameConfigComponent instead ...
|
||||
// we should get rid of d2config.Configuration and use components instead...
|
||||
oldStyleConfig := &d2config.Configuration{
|
||||
MpqLoadOrder: config.MpqLoadOrder,
|
||||
Language: config.Language,
|
||||
MpqPath: config.MpqPath,
|
||||
TicksPerSecond: config.TicksPerSecond,
|
||||
FpsCap: config.FpsCap,
|
||||
@ -117,8 +132,7 @@ func (m *RenderSystem) createRenderer() {
|
||||
|
||||
renderer, err := d2render.CreateRenderer(oldStyleConfig)
|
||||
if err != nil {
|
||||
m.Error(err.Error())
|
||||
panic(err)
|
||||
m.Fatal(err.Error())
|
||||
}
|
||||
|
||||
// HACK: hardcoded with ebiten for now
|
||||
@ -147,6 +161,10 @@ func (m *RenderSystem) render(screen d2interface.Surface) error {
|
||||
return errors.New("main viewport doesn't have a surface")
|
||||
}
|
||||
|
||||
if sfc.Surface == nil {
|
||||
sfc.Surface = m.renderer.NewSurface(vp.Width, vp.Height)
|
||||
}
|
||||
|
||||
screen.PushTranslation(vp.Left, vp.Top)
|
||||
screen.Render(sfc.Surface)
|
||||
screen.Pop()
|
||||
@ -168,8 +186,8 @@ func (m *RenderSystem) updateWorld() error {
|
||||
return m.World.Update(elapsed)
|
||||
}
|
||||
|
||||
func (m *RenderSystem) Loop() error {
|
||||
m.Infof("entering game run loop ...")
|
||||
func (m *RenderSystem) startGameLoop() error {
|
||||
m.Infof("starting game loop ...")
|
||||
|
||||
return m.renderer.Run(m.render, m.updateWorld, 800, 600, gameTitle)
|
||||
}
|
||||
|
@ -1,68 +0,0 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/gravestench/akara"
|
||||
"image/color"
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_RenderSystem(t *testing.T) {
|
||||
cfg := akara.NewWorldConfig()
|
||||
|
||||
renderSys := NewRenderSystem()
|
||||
|
||||
cfg.With(renderSys)
|
||||
|
||||
world := akara.NewWorld(cfg)
|
||||
|
||||
gameConfigEntity := world.NewEntity()
|
||||
|
||||
renderSys.AddGameConfig(gameConfigEntity)
|
||||
|
||||
vpEntity := world.NewEntity()
|
||||
vp := renderSys.AddViewport(vpEntity)
|
||||
|
||||
vp.Width = 400
|
||||
vp.Height = 300
|
||||
|
||||
renderSys.AddMainViewport(vpEntity)
|
||||
|
||||
sfc := renderSys.AddSurface(vpEntity)
|
||||
|
||||
loadAttempts := 10
|
||||
for loadAttempts > 0 {
|
||||
if renderSys.renderer != nil {
|
||||
break
|
||||
}
|
||||
|
||||
_ = world.Update(0)
|
||||
|
||||
loadAttempts--
|
||||
}
|
||||
|
||||
if loadAttempts < 0 {
|
||||
t.Fatal("could not create renderer")
|
||||
}
|
||||
|
||||
sfc.Surface = renderSys.renderer.NewSurface(400, 300)
|
||||
sfc.Surface.DrawRect(20, 20, color.RGBA{100, 100, 255, 255})
|
||||
|
||||
go func(){
|
||||
x, y := 0.0, 0.0
|
||||
|
||||
for {
|
||||
ms := float64(world.TimeDelta.Milliseconds())
|
||||
x, y = x+ms/1000, y+ms/3000
|
||||
vp.Top = int(math.Abs(math.Sin(y) * 300))
|
||||
vp.Left = int(math.Abs(math.Cos(x) * 400))
|
||||
time.Sleep(time.Second/60)
|
||||
}
|
||||
}()
|
||||
|
||||
err := renderSys.Loop()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/gravestench/akara"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2components"
|
||||
)
|
||||
@ -13,14 +14,15 @@ const (
|
||||
mainViewport int = 0
|
||||
)
|
||||
|
||||
// NewBaseScene creates a new base scene instance
|
||||
func NewBaseScene(key string) *BaseScene {
|
||||
base := &BaseScene{
|
||||
BaseSystem: &akara.BaseSystem{},
|
||||
Logger: d2util.NewLogger(),
|
||||
key: key,
|
||||
Viewports: make([]akara.EID, 0),
|
||||
BaseSystem: &akara.BaseSystem{},
|
||||
Logger: d2util.NewLogger(),
|
||||
key: key,
|
||||
Viewports: make([]akara.EID, 0),
|
||||
GameObjects: make([]akara.EID, 0),
|
||||
systems: &baseSystems{},
|
||||
systems: &baseSystems{},
|
||||
}
|
||||
|
||||
base.SetPrefix(key)
|
||||
@ -35,15 +37,20 @@ type baseSystems struct {
|
||||
*GameObjectFactory
|
||||
}
|
||||
|
||||
// BaseScene encapsulates common behaviors for systems that are considered "scenes",
|
||||
// such as the main menu, the in-game map, the console, etc.
|
||||
//
|
||||
// The base scene is responsible for generic behaviors common to all scenes,
|
||||
// like initializing the default viewport, or rendering game objects to the viewports.
|
||||
type BaseScene struct {
|
||||
*akara.BaseSystem
|
||||
*d2util.Logger
|
||||
key string
|
||||
booted bool
|
||||
paused bool
|
||||
systems *baseSystems
|
||||
Add *sceneObjectAssigner
|
||||
Viewports []akara.EID
|
||||
key string
|
||||
booted bool
|
||||
paused bool
|
||||
systems *baseSystems
|
||||
Add *sceneObjectAssigner
|
||||
Viewports []akara.EID
|
||||
GameObjects []akara.EID
|
||||
*d2components.MainViewportMap
|
||||
*d2components.ViewportMap
|
||||
@ -55,14 +62,17 @@ type BaseScene struct {
|
||||
*d2components.AnimationMap
|
||||
}
|
||||
|
||||
// Booted returns whether or not the scene has booted
|
||||
func (s *BaseScene) Booted() bool {
|
||||
return s.booted
|
||||
}
|
||||
|
||||
// Paused returns whether or not the scene is paused
|
||||
func (s *BaseScene) Paused() bool {
|
||||
return s.paused
|
||||
}
|
||||
|
||||
// Init the base scene
|
||||
func (s *BaseScene) Init(world *akara.World) {
|
||||
s.World = world
|
||||
|
||||
@ -125,6 +135,7 @@ func (s *BaseScene) injectComponentMaps() {
|
||||
}
|
||||
|
||||
func (s *BaseScene) createDefaultViewport() {
|
||||
s.Info("creating default viewport")
|
||||
viewportID := s.NewEntity()
|
||||
s.AddViewport(viewportID)
|
||||
|
||||
@ -133,16 +144,18 @@ func (s *BaseScene) createDefaultViewport() {
|
||||
camera.Height = 600
|
||||
camera.Zoom = 1
|
||||
|
||||
s.AddSurface(viewportID)
|
||||
s.AddSurface(viewportID).Surface = s.systems.renderer.NewSurface(camera.Width, camera.Height)
|
||||
s.AddMainViewport(viewportID)
|
||||
|
||||
s.Viewports = append(s.Viewports, viewportID)
|
||||
}
|
||||
|
||||
// Key returns the scene's key
|
||||
func (s *BaseScene) Key() string {
|
||||
return s.key
|
||||
}
|
||||
|
||||
// Update performs scene boot and renders the scene viewports
|
||||
func (s *BaseScene) Update() {
|
||||
if !s.booted {
|
||||
s.boot()
|
||||
@ -152,27 +165,29 @@ func (s *BaseScene) Update() {
|
||||
return
|
||||
}
|
||||
|
||||
s.RenderViewports()
|
||||
s.renderViewports()
|
||||
}
|
||||
|
||||
func (s *BaseScene) RenderViewports() {
|
||||
func (s *BaseScene) renderViewports() {
|
||||
if s.systems.RenderSystem == nil {
|
||||
s.Warning("render system not present")
|
||||
return
|
||||
}
|
||||
|
||||
if s.systems.RenderSystem.renderer == nil {
|
||||
s.Warning("render system doesn't have a renderer instance")
|
||||
return
|
||||
}
|
||||
|
||||
numViewports := len(s.Viewports)
|
||||
|
||||
if numViewports < 1 {
|
||||
return
|
||||
s.createDefaultViewport()
|
||||
}
|
||||
|
||||
viewportObjects := s.binGameObjectsByViewport()
|
||||
|
||||
for idx := numViewports-1; idx >= 0; idx-- {
|
||||
for idx := numViewports - 1; idx >= 0; idx-- {
|
||||
s.renderViewport(idx, viewportObjects[idx])
|
||||
}
|
||||
}
|
||||
@ -225,10 +240,10 @@ func (s *BaseScene) renderViewport(idx int, objects []akara.EID) {
|
||||
sfc.Surface = s.systems.renderer.NewSurface(camera.Width, camera.Height)
|
||||
}
|
||||
|
||||
cx, cy := int(camera.X()) + camera.Width>>1, int(camera.Y()) + camera.Height>>1
|
||||
cx, cy := int(camera.X())+camera.Width>>1, int(camera.Y())+camera.Height>>1
|
||||
|
||||
sfc.Surface.PushTranslation(-cx, -cy) // negative because we're offsetting everything that gets rendered
|
||||
sfc.Surface.PushScale(-camera.Zoom, -camera.Zoom)
|
||||
sfc.Surface.PushScale(camera.Zoom, camera.Zoom)
|
||||
|
||||
for _, object := range objects {
|
||||
s.renderObject(sfc.Surface, object)
|
||||
|
@ -1,70 +1,69 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
//"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
)
|
||||
|
||||
const (
|
||||
SceneKeyMainMenu = "Main Menu"
|
||||
sceneKeyMainMenu = "Main Menu"
|
||||
)
|
||||
|
||||
func NewMainMenuScene() *Scene {
|
||||
scene := &Scene{
|
||||
BaseScene: NewBaseScene(SceneKeyMainMenu),
|
||||
// NewMainMenuScene creates a new main menu scene. This is the first screen that the user
|
||||
// will see when launching the game.
|
||||
func NewMainMenuScene() *MainMenuScene {
|
||||
scene := &MainMenuScene{
|
||||
BaseScene: NewBaseScene(sceneKeyMainMenu),
|
||||
}
|
||||
|
||||
return scene
|
||||
}
|
||||
|
||||
// static check that MainMenuScene implements the scene interface
|
||||
var _ d2interface.Scene = &Scene{}
|
||||
var _ d2interface.Scene = &MainMenuScene{}
|
||||
|
||||
type Scene struct {
|
||||
// MainMenuScene represents the game's main menu, where users can select single or multi player,
|
||||
// or start the map engine test.
|
||||
type MainMenuScene struct {
|
||||
*BaseScene
|
||||
booted bool
|
||||
}
|
||||
|
||||
func (s *Scene) Init(world *akara.World) {
|
||||
// Init the main menu scene
|
||||
func (s *MainMenuScene) Init(_ *akara.World) {
|
||||
s.Info("initializing ...")
|
||||
}
|
||||
|
||||
func (s *Scene) boot() {
|
||||
func (s *MainMenuScene) boot() {
|
||||
if !s.BaseScene.booted {
|
||||
return
|
||||
}
|
||||
|
||||
s.createBackground()
|
||||
//s.createButtons()
|
||||
//s.createTrademarkScreen() // done last so that it's on top of everything
|
||||
s.createButtons()
|
||||
s.createTrademarkScreen()
|
||||
|
||||
s.booted = true
|
||||
}
|
||||
|
||||
func (s *Scene) createBackground() {
|
||||
func (s *MainMenuScene) createBackground() {
|
||||
s.Info("creating background")
|
||||
s.Add.Sprite(0, 0, d2resource.GameSelectScreen, d2resource.PaletteSky)
|
||||
}
|
||||
|
||||
func (s *Scene) createButtons() {
|
||||
func (s *MainMenuScene) createButtons() {
|
||||
s.Info("creating buttons")
|
||||
|
||||
}
|
||||
|
||||
func (s *Scene) createTrademarkScreen() {
|
||||
func (s *MainMenuScene) createTrademarkScreen() {
|
||||
s.Info("creating trademark screen")
|
||||
//image := s.Add.Sprite(0, 0, d2resource.TrademarkScreen, d2resource.PaletteSky).
|
||||
// SetOrigin(0, 0).
|
||||
// SetDisplaySize(s.Camera.Width, s.Camera.Height).
|
||||
// SetInteractive(true, nil)
|
||||
//
|
||||
//s.trademark = image
|
||||
s.Add.Sprite(0, 0, d2resource.TrademarkScreen, d2resource.PaletteSky)
|
||||
}
|
||||
|
||||
func (s *Scene) Update() {
|
||||
// Update the main menu scene
|
||||
func (s *MainMenuScene) Update() {
|
||||
if s.Paused() {
|
||||
return
|
||||
}
|
||||
@ -75,552 +74,3 @@ func (s *Scene) Update() {
|
||||
|
||||
s.BaseScene.Update()
|
||||
}
|
||||
|
||||
type mainMenuScreenMode int
|
||||
|
||||
//// mainMenuScreenMode types
|
||||
//const (
|
||||
// ScreenModeUnknown mainMenuScreenMode = iota
|
||||
// ScreenModeTrademark
|
||||
// ScreenModeMainMenu
|
||||
// ScreenModeMultiplayer
|
||||
// ScreenModeTCPIP
|
||||
// ScreenModeServerIP
|
||||
//)
|
||||
//
|
||||
//const (
|
||||
// joinGameDialogX, joinGameDialogY = 318, 245
|
||||
// serverIPbackgroundX, serverIPbackgroundY = 270, 175
|
||||
// backgroundX, backgroundY = 0, 0
|
||||
// versionLabelX, versionLabelY = 795, -10
|
||||
// commitLabelX, commitLabelY = 2, 2
|
||||
// copyrightX, copyrightY = 400, 500
|
||||
// copyright2X, copyright2Y = 400, 525
|
||||
// od2LabelX, od2LabelY = 400, 580
|
||||
// tcpOptionsX, tcpOptionsY = 400, 23
|
||||
// joinGameX, joinGameY = 400, 190
|
||||
// diabloLogoX, diabloLogoY = 400, 120
|
||||
// exitDiabloBtnX, exitDiabloBtnY = 264, 535
|
||||
// creditBtnX, creditBtnY = 264, 505
|
||||
// cineBtnX, cineBtnY = 401, 505
|
||||
// singlePlayerBtnX, singlePlayerBtnY = 264, 290
|
||||
// githubBtnX, githubBtnY = 264, 400
|
||||
// mapTestBtnX, mapTestBtnY = 264, 440
|
||||
// tcpBtnX, tcpBtnY = 33, 543
|
||||
// srvCancelBtnX, srvCancelBtnY = 285, 305
|
||||
// srvOkBtnX, srvOkBtnY = 420, 305
|
||||
// multiplayerBtnX, multiplayerBtnY = 264, 330
|
||||
// tcpNetBtnX, tcpNetBtnY = 264, 280
|
||||
// networkCancelBtnX, networkCancelBtnY = 264, 540
|
||||
// tcpHostBtnX, tcpHostBtnY = 264, 280
|
||||
// tcpJoinBtnX, tcpJoinBtnY = 264, 320
|
||||
//)
|
||||
//
|
||||
//const (
|
||||
// white = 0xffffffff
|
||||
// lightYellow = 0xffff8cff
|
||||
// gold = 0xd8c480ff
|
||||
//)
|
||||
//
|
||||
//const (
|
||||
// joinGameCharacterFilter = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890._:"
|
||||
//)
|
||||
|
||||
//// BuildInfo contains information about the current build
|
||||
//type BuildInfo struct {
|
||||
// Branch, Commit string
|
||||
//}
|
||||
//
|
||||
//// MainMenu represents the main menu
|
||||
//type MainMenu struct {
|
||||
// tcpIPBackground *d2ui.Sprite
|
||||
// trademarkBackground *d2ui.Sprite
|
||||
// background *d2ui.Sprite
|
||||
// diabloLogoLeft *d2ui.Sprite
|
||||
// diabloLogoRight *d2ui.Sprite
|
||||
// diabloLogoLeftBack *d2ui.Sprite
|
||||
// diabloLogoRightBack *d2ui.Sprite
|
||||
// serverIPBackground *d2ui.Sprite
|
||||
// singlePlayerButton *d2ui.Button
|
||||
// multiplayerButton *d2ui.Button
|
||||
// githubButton *d2ui.Button
|
||||
// exitDiabloButton *d2ui.Button
|
||||
// creditsButton *d2ui.Button
|
||||
// cinematicsButton *d2ui.Button
|
||||
// mapTestButton *d2ui.Button
|
||||
// networkTCPIPButton *d2ui.Button
|
||||
// networkCancelButton *d2ui.Button
|
||||
// btnTCPIPCancel *d2ui.Button
|
||||
// btnTCPIPHostGame *d2ui.Button
|
||||
// btnTCPIPJoinGame *d2ui.Button
|
||||
// btnServerIPCancel *d2ui.Button
|
||||
// btnServerIPOk *d2ui.Button
|
||||
// copyrightLabel *d2ui.Label
|
||||
// copyrightLabel2 *d2ui.Label
|
||||
// openDiabloLabel *d2ui.Label
|
||||
// versionLabel *d2ui.Label
|
||||
// commitLabel *d2ui.Label
|
||||
// tcpIPOptionsLabel *d2ui.Label
|
||||
// tcpJoinGameLabel *d2ui.Label
|
||||
// tcpJoinGameEntry *d2ui.TextBox
|
||||
// screenMode mainMenuScreenMode
|
||||
// leftButtonHeld bool
|
||||
//
|
||||
// asset *d2asset.AssetManager
|
||||
// inputManager d2interface.InputManager
|
||||
// renderer d2interface.Renderer
|
||||
// audioProvider d2interface.AudioProvider
|
||||
// scriptEngine *d2script.ScriptEngine
|
||||
// navigator d2interface.Navigator
|
||||
// uiManager *d2ui.UIManager
|
||||
// heroState *d2hero.HeroStateFactory
|
||||
//
|
||||
// buildInfo BuildInfo
|
||||
//}
|
||||
//
|
||||
//// CreateMainMenu creates an instance of MainMenu
|
||||
//func CreateMainMenu(
|
||||
// navigator d2interface.Navigator,
|
||||
// asset *d2asset.AssetManager,
|
||||
// renderer d2interface.Renderer,
|
||||
// inputManager d2interface.InputManager,
|
||||
// audioProvider d2interface.AudioProvider,
|
||||
// ui *d2ui.UIManager,
|
||||
// buildInfo BuildInfo,
|
||||
//) (*MainMenu, error) {
|
||||
// heroStateFactory, err := d2hero.NewHeroStateFactory(asset)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// mainMenu := &MainMenu{
|
||||
// asset: asset,
|
||||
// screenMode: ScreenModeUnknown,
|
||||
// leftButtonHeld: true,
|
||||
// renderer: renderer,
|
||||
// inputManager: inputManager,
|
||||
// audioProvider: audioProvider,
|
||||
// navigator: navigator,
|
||||
// buildInfo: buildInfo,
|
||||
// uiManager: ui,
|
||||
// heroState: heroStateFactory,
|
||||
// }
|
||||
//
|
||||
// return mainMenu, nil
|
||||
//}
|
||||
//
|
||||
//// OnLoad is called to load the resources for the main menu
|
||||
//func (v *MainMenu) OnLoad(loading d2screen.LoadingState) {
|
||||
// v.audioProvider.PlayBGM(d2resource.BGMTitle)
|
||||
// loading.Progress(twentyPercent)
|
||||
//
|
||||
// v.createLabels(loading)
|
||||
// v.loadBackgroundSprites()
|
||||
// v.createLogos(loading)
|
||||
// v.createButtons(loading)
|
||||
//
|
||||
// v.tcpJoinGameEntry = v.uiManager.NewTextbox()
|
||||
// v.tcpJoinGameEntry.SetPosition(joinGameDialogX, joinGameDialogY)
|
||||
// v.tcpJoinGameEntry.SetFilter(joinGameCharacterFilter)
|
||||
// loading.Progress(ninetyPercent)
|
||||
//
|
||||
// if v.screenMode == ScreenModeUnknown {
|
||||
// v.SetScreenMode(ScreenModeTrademark)
|
||||
// } else {
|
||||
// v.SetScreenMode(ScreenModeMainMenu)
|
||||
// }
|
||||
//
|
||||
// if err := v.inputManager.BindHandler(v); err != nil {
|
||||
// fmt.Println("failed to add main menu as event handler")
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) loadBackgroundSprites() {
|
||||
// var err error
|
||||
// v.background, err = v.uiManager.NewSprite(d2resource.GameSelectScreen, d2resource.PaletteSky)
|
||||
// if err != nil {
|
||||
// log.Print(err)
|
||||
// }
|
||||
// v.background.SetPosition(backgroundX, backgroundY)
|
||||
//
|
||||
// v.trademarkBackground, err = v.uiManager.NewSprite(d2resource.TrademarkScreen, d2resource.PaletteSky)
|
||||
// if err != nil {
|
||||
// log.Print(err)
|
||||
// }
|
||||
// v.trademarkBackground.SetPosition(backgroundX, backgroundY)
|
||||
//
|
||||
// v.tcpIPBackground, err = v.uiManager.NewSprite(d2resource.TCPIPBackground, d2resource.PaletteSky)
|
||||
// if err != nil {
|
||||
// log.Print(err)
|
||||
// }
|
||||
// v.tcpIPBackground.SetPosition(backgroundX, backgroundY)
|
||||
//
|
||||
// v.serverIPBackground, err = v.uiManager.NewSprite(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
|
||||
// if err != nil {
|
||||
// log.Print(err)
|
||||
// }
|
||||
// v.serverIPBackground.SetPosition(serverIPbackgroundX, serverIPbackgroundY)
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
|
||||
// v.versionLabel = v.uiManager.NewLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
||||
// v.versionLabel.Alignment = d2gui.HorizontalAlignRight
|
||||
// v.versionLabel.SetText("OpenDiablo2 - " + v.buildInfo.Branch)
|
||||
// v.versionLabel.Color[0] = d2util.Color(white)
|
||||
// v.versionLabel.SetPosition(versionLabelX, versionLabelY)
|
||||
//
|
||||
// v.commitLabel = v.uiManager.NewLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
|
||||
// v.commitLabel.Alignment = d2gui.HorizontalAlignLeft
|
||||
// v.commitLabel.SetText(v.buildInfo.Commit)
|
||||
// v.commitLabel.Color[0] = d2util.Color(white)
|
||||
// v.commitLabel.SetPosition(commitLabelX, commitLabelY)
|
||||
//
|
||||
// v.copyrightLabel = v.uiManager.NewLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
||||
// v.copyrightLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
// v.copyrightLabel.SetText("Diablo 2 is © Copyright 2000-2016 Blizzard Entertainment")
|
||||
// v.copyrightLabel.Color[0] = d2util.Color(lightBrown)
|
||||
// v.copyrightLabel.SetPosition(copyrightX, copyrightY)
|
||||
// loading.Progress(thirtyPercent)
|
||||
//
|
||||
// v.copyrightLabel2 = v.uiManager.NewLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
||||
// v.copyrightLabel2.Alignment = d2gui.HorizontalAlignCenter
|
||||
// v.copyrightLabel2.SetText("All Rights Reserved.")
|
||||
// v.copyrightLabel2.Color[0] = d2util.Color(lightBrown)
|
||||
// v.copyrightLabel2.SetPosition(copyright2X, copyright2Y)
|
||||
//
|
||||
// v.openDiabloLabel = v.uiManager.NewLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
|
||||
// v.openDiabloLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
// v.openDiabloLabel.SetText("OpenDiablo2 is neither developed by, nor endorsed by Blizzard or its parent company Activision")
|
||||
// v.openDiabloLabel.Color[0] = d2util.Color(lightYellow)
|
||||
// v.openDiabloLabel.SetPosition(od2LabelX, od2LabelY)
|
||||
// loading.Progress(fiftyPercent)
|
||||
//
|
||||
// v.tcpIPOptionsLabel = v.uiManager.NewLabel(d2resource.Font42, d2resource.PaletteUnits)
|
||||
// v.tcpIPOptionsLabel.SetPosition(tcpOptionsX, tcpOptionsY)
|
||||
// v.tcpIPOptionsLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
// v.tcpIPOptionsLabel.SetText("TCP/IP Options")
|
||||
//
|
||||
// v.tcpJoinGameLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
// v.tcpJoinGameLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
// v.tcpJoinGameLabel.SetText("Enter Host IP Address\nto Join Game")
|
||||
//
|
||||
// v.tcpJoinGameLabel.Color[0] = d2util.Color(gold)
|
||||
// v.tcpJoinGameLabel.SetPosition(joinGameX, joinGameY)
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) createLogos(loading d2screen.LoadingState) {
|
||||
// var err error
|
||||
// v.diabloLogoLeft, err = v.uiManager.NewSprite(d2resource.Diablo2LogoFireLeft, d2resource.PaletteUnits)
|
||||
// if err != nil {
|
||||
// log.Print(err)
|
||||
// }
|
||||
// v.diabloLogoLeft.SetEffect(d2enum.DrawEffectModulate)
|
||||
// v.diabloLogoLeft.PlayForward()
|
||||
// v.diabloLogoLeft.SetPosition(diabloLogoX, diabloLogoY)
|
||||
// loading.Progress(sixtyPercent)
|
||||
//
|
||||
// v.diabloLogoRight, err = v.uiManager.NewSprite(d2resource.Diablo2LogoFireRight, d2resource.PaletteUnits)
|
||||
// if err != nil {
|
||||
// log.Print(err)
|
||||
// }
|
||||
// v.diabloLogoRight.SetEffect(d2enum.DrawEffectModulate)
|
||||
// v.diabloLogoRight.PlayForward()
|
||||
// v.diabloLogoRight.SetPosition(diabloLogoX, diabloLogoY)
|
||||
//
|
||||
// v.diabloLogoLeftBack, err = v.uiManager.NewSprite(d2resource.Diablo2LogoBlackLeft, d2resource.PaletteUnits)
|
||||
// if err != nil {
|
||||
// log.Print(err)
|
||||
// }
|
||||
// v.diabloLogoLeftBack.SetPosition(diabloLogoX, diabloLogoY)
|
||||
//
|
||||
// v.diabloLogoRightBack, err = v.uiManager.NewSprite(d2resource.Diablo2LogoBlackRight, d2resource.PaletteUnits)
|
||||
// if err != nil {
|
||||
// log.Print(err)
|
||||
// }
|
||||
// v.diabloLogoRightBack.SetPosition(diabloLogoX, diabloLogoY)
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) createButtons(loading d2screen.LoadingState) {
|
||||
// v.exitDiabloButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, "EXIT DIABLO II")
|
||||
// v.exitDiabloButton.SetPosition(exitDiabloBtnX, exitDiabloBtnY)
|
||||
// v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||
//
|
||||
// v.creditsButton = v.uiManager.NewButton(d2ui.ButtonTypeShort, "CREDITS")
|
||||
// v.creditsButton.SetPosition(creditBtnX, creditBtnY)
|
||||
// v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() })
|
||||
//
|
||||
// v.cinematicsButton = v.uiManager.NewButton(d2ui.ButtonTypeShort, "CINEMATICS")
|
||||
// v.cinematicsButton.SetPosition(cineBtnX, cineBtnY)
|
||||
// loading.Progress(seventyPercent)
|
||||
//
|
||||
// v.singlePlayerButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, "SINGLE PLAYER")
|
||||
// v.singlePlayerButton.SetPosition(singlePlayerBtnX, singlePlayerBtnY)
|
||||
// v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() })
|
||||
//
|
||||
// v.githubButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, "PROJECT WEBSITE")
|
||||
// v.githubButton.SetPosition(githubBtnX, githubBtnY)
|
||||
// v.githubButton.OnActivated(func() { v.onGithubButtonClicked() })
|
||||
//
|
||||
// v.mapTestButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, "MAP ENGINE TEST")
|
||||
// v.mapTestButton.SetPosition(mapTestBtnX, mapTestBtnY)
|
||||
// v.mapTestButton.OnActivated(func() { v.onMapTestClicked() })
|
||||
//
|
||||
// v.btnTCPIPCancel = v.uiManager.NewButton(d2ui.ButtonTypeMedium,
|
||||
// d2tbl.TranslateString("cancel"))
|
||||
// v.btnTCPIPCancel.SetPosition(tcpBtnX, tcpBtnY)
|
||||
// v.btnTCPIPCancel.OnActivated(func() { v.onTCPIPCancelClicked() })
|
||||
//
|
||||
// v.btnServerIPCancel = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, "CANCEL")
|
||||
// v.btnServerIPCancel.SetPosition(srvCancelBtnX, srvCancelBtnY)
|
||||
// v.btnServerIPCancel.OnActivated(func() { v.onBtnTCPIPCancelClicked() })
|
||||
//
|
||||
// v.btnServerIPOk = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, "OK")
|
||||
// v.btnServerIPOk.SetPosition(srvOkBtnX, srvOkBtnY)
|
||||
// v.btnServerIPOk.OnActivated(func() { v.onBtnTCPIPOkClicked() })
|
||||
//
|
||||
// v.createMultiplayerMenuButtons()
|
||||
// loading.Progress(eightyPercent)
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) createMultiplayerMenuButtons() {
|
||||
// v.multiplayerButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, "MULTIPLAYER")
|
||||
// v.multiplayerButton.SetPosition(multiplayerBtnX, multiplayerBtnY)
|
||||
// v.multiplayerButton.OnActivated(func() { v.onMultiplayerClicked() })
|
||||
//
|
||||
// v.networkTCPIPButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, "TCP/IP GAME")
|
||||
// v.networkTCPIPButton.SetPosition(tcpNetBtnX, tcpNetBtnY)
|
||||
// v.networkTCPIPButton.OnActivated(func() { v.onNetworkTCPIPClicked() })
|
||||
//
|
||||
// v.networkCancelButton = v.uiManager.NewButton(d2ui.ButtonTypeWide,
|
||||
// d2tbl.TranslateString("cancel"))
|
||||
// v.networkCancelButton.SetPosition(networkCancelBtnX, networkCancelBtnY)
|
||||
// v.networkCancelButton.OnActivated(func() { v.onNetworkCancelClicked() })
|
||||
//
|
||||
// v.btnTCPIPHostGame = v.uiManager.NewButton(d2ui.ButtonTypeWide, "HOST GAME")
|
||||
// v.btnTCPIPHostGame.SetPosition(tcpHostBtnX, tcpHostBtnY)
|
||||
// v.btnTCPIPHostGame.OnActivated(func() { v.onTCPIPHostGameClicked() })
|
||||
//
|
||||
// v.btnTCPIPJoinGame = v.uiManager.NewButton(d2ui.ButtonTypeWide, "JOIN GAME")
|
||||
// v.btnTCPIPJoinGame.SetPosition(tcpJoinBtnX, tcpJoinBtnY)
|
||||
// v.btnTCPIPJoinGame.OnActivated(func() { v.onTCPIPJoinGameClicked() })
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) onMapTestClicked() {
|
||||
// v.navigator.ToMapEngineTest(0, 1)
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) onSinglePlayerClicked() {
|
||||
// if v.heroState.HasGameStates() {
|
||||
// // Go here only if existing characters are available to select
|
||||
// v.navigator.ToCharacterSelect(d2clientconnectiontype.Local, v.tcpJoinGameEntry.GetText())
|
||||
// } else {
|
||||
// v.navigator.ToSelectHero(d2clientconnectiontype.Local, v.tcpJoinGameEntry.GetText())
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) onGithubButtonClicked() {
|
||||
// url := "https://www.github.com/OpenDiablo2/OpenDiablo2"
|
||||
//
|
||||
// var err error
|
||||
//
|
||||
// switch runtime.GOOS {
|
||||
// case "linux":
|
||||
// err = exec.Command("xdg-open", url).Start()
|
||||
// case "windows":
|
||||
// err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
|
||||
// case "darwin":
|
||||
// err = exec.Command("open", url).Start()
|
||||
// default:
|
||||
// err = fmt.Errorf("unsupported platform")
|
||||
// }
|
||||
//
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) onExitButtonClicked() {
|
||||
// os.Exit(0)
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) onCreditsButtonClicked() {
|
||||
// v.navigator.ToCredits()
|
||||
//}
|
||||
//
|
||||
//// Render renders the main menu
|
||||
//func (v *MainMenu) Render(screen d2interface.Surface) error {
|
||||
// if err := v.renderBackgrounds(screen); err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// if err := v.renderLogos(screen); err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// if err := v.renderLabels(screen); err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// return nil
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) renderBackgrounds(screen d2interface.Surface) error {
|
||||
// switch v.screenMode {
|
||||
// case ScreenModeTrademark:
|
||||
// if err := v.trademarkBackground.RenderSegmented(screen, 4, 3, 0); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// case ScreenModeServerIP:
|
||||
// if err := v.serverIPBackground.RenderSegmented(screen, 2, 1, 0); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// case ScreenModeTCPIP:
|
||||
// if err := v.tcpIPBackground.RenderSegmented(screen, 4, 3, 0); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// default:
|
||||
// if err := v.background.RenderSegmented(screen, 4, 3, 0); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return nil
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) renderLogos(screen d2interface.Surface) error {
|
||||
// switch v.screenMode {
|
||||
// case ScreenModeTrademark, ScreenModeMainMenu, ScreenModeMultiplayer:
|
||||
// if err := v.diabloLogoLeftBack.Render(screen); err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// if err := v.diabloLogoRightBack.Render(screen); err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// if err := v.diabloLogoLeft.Render(screen); err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// if err := v.diabloLogoRight.Render(screen); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return nil
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) renderLabels(screen d2interface.Surface) error {
|
||||
// switch v.screenMode {
|
||||
// case ScreenModeServerIP:
|
||||
// v.tcpIPOptionsLabel.Render(screen)
|
||||
// v.tcpJoinGameLabel.Render(screen)
|
||||
// case ScreenModeTCPIP:
|
||||
// v.tcpIPOptionsLabel.Render(screen)
|
||||
// case ScreenModeTrademark:
|
||||
// v.copyrightLabel.Render(screen)
|
||||
// v.copyrightLabel2.Render(screen)
|
||||
// case ScreenModeMainMenu:
|
||||
// v.openDiabloLabel.Render(screen)
|
||||
// v.versionLabel.Render(screen)
|
||||
// v.commitLabel.Render(screen)
|
||||
// }
|
||||
//
|
||||
// return nil
|
||||
//}
|
||||
//
|
||||
//// Advance runs the update logic on the main menu
|
||||
//func (v *MainMenu) Advance(tickTime float64) error {
|
||||
// switch v.screenMode {
|
||||
// case ScreenModeMainMenu, ScreenModeTrademark, ScreenModeMultiplayer:
|
||||
// if err := v.diabloLogoLeftBack.Advance(tickTime); err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// if err := v.diabloLogoRightBack.Advance(tickTime); err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// if err := v.diabloLogoLeft.Advance(tickTime); err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// if err := v.diabloLogoRight.Advance(tickTime); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return nil
|
||||
//}
|
||||
//
|
||||
//// OnMouseButtonDown is called when a mouse button is clicked
|
||||
//func (v *MainMenu) OnMouseButtonDown(event d2interface.MouseEvent) bool {
|
||||
// if v.screenMode == ScreenModeTrademark && event.Button() == d2enum.MouseButtonLeft {
|
||||
// v.SetScreenMode(ScreenModeMainMenu)
|
||||
// return true
|
||||
// }
|
||||
//
|
||||
// return false
|
||||
//}
|
||||
//
|
||||
//// SetScreenMode sets the screen mode (which sub-menu the screen is on)
|
||||
//func (v *MainMenu) SetScreenMode(screenMode mainMenuScreenMode) {
|
||||
// v.screenMode = screenMode
|
||||
// isMainMenu := screenMode == ScreenModeMainMenu
|
||||
// isMultiplayer := screenMode == ScreenModeMultiplayer
|
||||
// isTCPIP := screenMode == ScreenModeTCPIP
|
||||
// isServerIP := screenMode == ScreenModeServerIP
|
||||
//
|
||||
// v.exitDiabloButton.SetVisible(isMainMenu)
|
||||
// v.creditsButton.SetVisible(isMainMenu)
|
||||
// v.cinematicsButton.SetVisible(isMainMenu)
|
||||
// v.singlePlayerButton.SetVisible(isMainMenu)
|
||||
// v.githubButton.SetVisible(isMainMenu)
|
||||
// v.mapTestButton.SetVisible(isMainMenu)
|
||||
// v.multiplayerButton.SetVisible(isMainMenu)
|
||||
// v.networkTCPIPButton.SetVisible(isMultiplayer)
|
||||
// v.networkCancelButton.SetVisible(isMultiplayer)
|
||||
// v.btnTCPIPCancel.SetVisible(isTCPIP)
|
||||
// v.btnTCPIPHostGame.SetVisible(isTCPIP)
|
||||
// v.btnTCPIPJoinGame.SetVisible(isTCPIP)
|
||||
// v.tcpJoinGameEntry.SetVisible(isServerIP)
|
||||
//
|
||||
// if isServerIP {
|
||||
// v.tcpJoinGameEntry.Activate()
|
||||
// }
|
||||
//
|
||||
// v.btnServerIPOk.SetVisible(isServerIP)
|
||||
// v.btnServerIPCancel.SetVisible(isServerIP)
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) onNetworkCancelClicked() {
|
||||
// v.SetScreenMode(ScreenModeMainMenu)
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) onMultiplayerClicked() {
|
||||
// v.SetScreenMode(ScreenModeMultiplayer)
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) onNetworkTCPIPClicked() {
|
||||
// v.SetScreenMode(ScreenModeTCPIP)
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) onTCPIPCancelClicked() {
|
||||
// v.SetScreenMode(ScreenModeMultiplayer)
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) onTCPIPHostGameClicked() {
|
||||
// v.navigator.ToCharacterSelect(d2clientconnectiontype.LANServer, "")
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) onTCPIPJoinGameClicked() {
|
||||
// v.SetScreenMode(ScreenModeServerIP)
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) onBtnTCPIPCancelClicked() {
|
||||
// v.SetScreenMode(ScreenModeTCPIP)
|
||||
//}
|
||||
//
|
||||
//func (v *MainMenu) onBtnTCPIPOkClicked() {
|
||||
// v.navigator.ToCharacterSelect(d2clientconnectiontype.LANClient, v.tcpJoinGameEntry.GetText())
|
||||
//}
|
||||
|
@ -13,15 +13,17 @@ const (
|
||||
fmtCreateSpriteErr = "could not create sprite from image `%s` and palette `%s`"
|
||||
)
|
||||
|
||||
// NewSpriteFactorySubsystem creates a new sprite factory which is intended
|
||||
// to be embedded in the game object factory system.
|
||||
func NewSpriteFactorySubsystem(b *akara.BaseSystem, l *d2util.Logger) *SpriteFactory {
|
||||
spritesToRender := akara.NewFilter().
|
||||
Require(d2components.Animation). // we want to process entities that have an animation ...
|
||||
Forbid(d2components.Surface). // ... but are missing a surface
|
||||
Forbid(d2components.Surface). // ... but are missing a surface
|
||||
Build()
|
||||
|
||||
sys := &SpriteFactory{
|
||||
BaseSubscriberSystem: akara.NewBaseSubscriberSystem(spritesToRender),
|
||||
Logger: l,
|
||||
Logger: l,
|
||||
}
|
||||
|
||||
sys.BaseSystem = b
|
||||
@ -37,6 +39,8 @@ type spriteLoadQueueEntry struct {
|
||||
|
||||
type spriteLoadQueue = map[akara.EID]spriteLoadQueueEntry
|
||||
|
||||
// SpriteFactory is responsible for queueing sprites to be loaded (as animations),
|
||||
// as well as binding the animation to a renderer if one is present (which generates the sprite surfaces).
|
||||
type SpriteFactory struct {
|
||||
*akara.BaseSubscriberSystem
|
||||
*d2util.Logger
|
||||
@ -52,10 +56,11 @@ type SpriteFactory struct {
|
||||
spritesToRender *akara.Subscription
|
||||
}
|
||||
|
||||
// Init the sprite factory, injecting the necessary components
|
||||
func (t *SpriteFactory) Init(world *akara.World) {
|
||||
t.Info("initializing sprite factory ...")
|
||||
|
||||
t.loadQueue = make(spriteLoadQueue, 0)
|
||||
t.loadQueue = make(spriteLoadQueue)
|
||||
|
||||
t.spritesToRender = t.Subscriptions[0]
|
||||
|
||||
@ -68,6 +73,8 @@ func (t *SpriteFactory) Init(world *akara.World) {
|
||||
t.SurfaceMap = t.InjectMap(d2components.Surface).(*d2components.SurfaceMap)
|
||||
}
|
||||
|
||||
// Update processes the load queue which attempting to create animations, as well as
|
||||
// binding existing animations to a renderer if one is present.
|
||||
func (t *SpriteFactory) Update() {
|
||||
for _, eid := range t.spritesToRender.GetEntities() {
|
||||
t.tryRenderingSprite(eid)
|
||||
@ -78,6 +85,7 @@ func (t *SpriteFactory) Update() {
|
||||
}
|
||||
}
|
||||
|
||||
// Sprite queues a sprite animation to be loaded
|
||||
func (t *SpriteFactory) Sprite(x, y float64, imgPath, palPath string) akara.EID {
|
||||
spriteID := t.NewEntity()
|
||||
|
||||
@ -153,6 +161,10 @@ func (t *SpriteFactory) tryRenderingSprite(eid akara.EID) {
|
||||
return
|
||||
}
|
||||
|
||||
if anim.Animation == nil {
|
||||
return
|
||||
}
|
||||
|
||||
anim.BindRenderer(t.renderer)
|
||||
|
||||
sfc := anim.GetCurrentFrameSurface()
|
||||
|
@ -1,9 +1,10 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"time"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
|
||||
"github.com/gravestench/akara"
|
||||
)
|
||||
|
||||
@ -19,7 +20,7 @@ const (
|
||||
func NewTimeScaleSystem() *TimeScaleSystem {
|
||||
m := &TimeScaleSystem{
|
||||
BaseSystem: &akara.BaseSystem{},
|
||||
Logger: d2util.NewLogger(),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
m.SetPrefix(logPrefixTimeScaleSystem)
|
||||
@ -36,7 +37,7 @@ var _ akara.System = &TimeScaleSystem{}
|
||||
type TimeScaleSystem struct {
|
||||
*akara.BaseSystem
|
||||
*d2util.Logger
|
||||
scale float64
|
||||
scale float64
|
||||
lastScale float64
|
||||
}
|
||||
|
||||
@ -49,9 +50,9 @@ func (t *TimeScaleSystem) Init(world *akara.World) {
|
||||
t.scale = defaultScale
|
||||
}
|
||||
|
||||
// Process scales the worlds time delta for this frame
|
||||
// Update scales the worlds time delta for this frame
|
||||
func (t *TimeScaleSystem) Update() {
|
||||
if !t.Active() || t.scale == t.lastScale{
|
||||
if !t.Active() || t.scale == t.lastScale {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,9 @@ func TestTimeScaleSystem_Process(t *testing.T) {
|
||||
actual := time.Second
|
||||
expected := time.Duration(timescaleSystem.scale) * actual
|
||||
|
||||
world.Update(actual)
|
||||
if err := world.Update(actual); err != nil {
|
||||
timescaleSystem.Error(err.Error())
|
||||
}
|
||||
|
||||
if world.TimeDelta != expected {
|
||||
t.Error("world time delta not scaled")
|
||||
|
@ -1,14 +1,16 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
)
|
||||
|
||||
const (
|
||||
logPrefixUpdateCounter = "Update Counter"
|
||||
)
|
||||
|
||||
// NewUpdateCounterSystem creates a new update counter system
|
||||
func NewUpdateCounterSystem() *UpdateCounter {
|
||||
uc := &UpdateCounter{
|
||||
BaseSystem: &akara.BaseSystem{},
|
||||
@ -22,6 +24,7 @@ func NewUpdateCounterSystem() *UpdateCounter {
|
||||
|
||||
var _ akara.System = &UpdateCounter{}
|
||||
|
||||
// UpdateCounter is a utility system that logs the number of updates per second
|
||||
type UpdateCounter struct {
|
||||
*akara.BaseSystem
|
||||
*d2util.Logger
|
||||
@ -29,6 +32,7 @@ type UpdateCounter struct {
|
||||
count int
|
||||
}
|
||||
|
||||
// Init initializes the update counter
|
||||
func (u *UpdateCounter) Init(world *akara.World) {
|
||||
u.World = world
|
||||
|
||||
@ -39,6 +43,7 @@ func (u *UpdateCounter) Init(world *akara.World) {
|
||||
u.Info("initializing")
|
||||
}
|
||||
|
||||
// Update the world update count in 1 second intervals
|
||||
func (u *UpdateCounter) Update() {
|
||||
u.count++
|
||||
u.secondsElapsed += u.World.TimeDelta.Seconds()
|
||||
@ -51,4 +56,3 @@ func (u *UpdateCounter) Update() {
|
||||
u.secondsElapsed = 0
|
||||
u.count = 0
|
||||
}
|
||||
|
||||
|
19
main.go
19
main.go
@ -3,6 +3,10 @@ package main
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2systems"
|
||||
"github.com/gravestench/akara"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2app"
|
||||
)
|
||||
|
||||
@ -15,6 +19,21 @@ var GitBranch string
|
||||
var GitCommit string
|
||||
|
||||
func main() {
|
||||
ecs := kingpin.Flag("ecs", "start the ecs implementation").Bool()
|
||||
kingpin.Parse()
|
||||
|
||||
if *ecs {
|
||||
cfg := akara.NewWorldConfig()
|
||||
|
||||
cfg.
|
||||
With(d2systems.NewAppBootstrapSystem()).
|
||||
With(d2systems.NewGameClientBootstrapSystem())
|
||||
|
||||
akara.NewWorld(cfg)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
log.SetFlags(log.Lshortfile)
|
||||
log.Println("OpenDiablo2 - Open source Diablo 2 engine")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user