mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-04 15:46:51 -05:00
refactored game bootstrap, removed d2config.Config
singleton (#899)
* Remove d2config.Config singleton * refactored config file bootstrap * `d2loader.Loader` adds the config directories during init * `d2asset.AssetManager` loads the config file during init * mpq verification logic removed from d2config; this is done by d2loader * added `errorMessage` to `d2app.App` for setting the error message for the error screen. * fixed loader test
This commit is contained in:
parent
d6c9748fef
commit
5ac03d6f49
70
d2app/app.go
70
d2app/app.go
@ -73,6 +73,8 @@ type App struct {
|
||||
ui *d2ui.UIManager
|
||||
tAllocSamples *ring.Ring
|
||||
guiManager *d2gui.GuiManager
|
||||
config *d2config.Configuration
|
||||
errorMessage error
|
||||
*Options
|
||||
}
|
||||
|
||||
@ -99,12 +101,20 @@ const (
|
||||
|
||||
// Create creates a new instance of the application
|
||||
func Create(gitBranch, gitCommit string) *App {
|
||||
assetManager, assetError := d2asset.NewAssetManager()
|
||||
|
||||
// we can throw away the error here because by this time it's already been loaded
|
||||
config, _ := assetManager.LoadConfig()
|
||||
|
||||
return &App{
|
||||
gitBranch: gitBranch,
|
||||
gitCommit: gitCommit,
|
||||
asset: assetManager,
|
||||
config: config,
|
||||
Options: &Options{
|
||||
Server: &d2networking.ServerOptions{},
|
||||
},
|
||||
errorMessage: assetError,
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,20 +123,6 @@ func updateNOOP() error {
|
||||
}
|
||||
|
||||
func (a *App) startDedicatedServer() error {
|
||||
// hack, for now we need to create the asset manager here
|
||||
// Attempt to load the configuration file
|
||||
err := d2config.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
asset, err := d2asset.NewAssetManager(d2config.Config, *a.Options.LogLevel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.asset = asset
|
||||
|
||||
min, max := d2networking.ServerMinPlayers, d2networking.ServerMaxPlayersDefault
|
||||
maxPlayers := d2math.ClampInt(*a.Options.Server.MaxPlayers, min, max)
|
||||
|
||||
@ -154,35 +150,27 @@ func (a *App) startDedicatedServer() error {
|
||||
}
|
||||
|
||||
func (a *App) loadEngine() error {
|
||||
// Attempt to load the configuration file
|
||||
configError := d2config.Load()
|
||||
|
||||
// Create our renderer
|
||||
renderer, err := ebiten.CreateRenderer()
|
||||
renderer, err := ebiten.CreateRenderer(a.config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.renderer = renderer
|
||||
|
||||
// If we failed to load our config, lets show the boot panic screen
|
||||
if configError != nil {
|
||||
return configError
|
||||
if a.errorMessage != nil {
|
||||
return a.renderer.Run(a.updateInitError, updateNOOP, 800, 600, "OpenDiablo2")
|
||||
}
|
||||
|
||||
// if the log level was specified at the command line, use it
|
||||
logLevel := *a.Options.LogLevel
|
||||
if logLevel == d2util.LogLevelUnspecified {
|
||||
logLevel = d2config.Config.LogLevel
|
||||
logLevel = a.config.LogLevel
|
||||
}
|
||||
|
||||
// Create the asset manager
|
||||
asset, err := d2asset.NewAssetManager(d2config.Config, logLevel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.asset.SetLogLevel(logLevel)
|
||||
|
||||
audio := ebiten2.CreateAudio(asset)
|
||||
audio := ebiten2.CreateAudio(a.asset)
|
||||
|
||||
inputManager := d2input.NewInputManager()
|
||||
|
||||
@ -191,21 +179,20 @@ func (a *App) loadEngine() error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = asset.BindTerminalCommands(term)
|
||||
err = a.asset.BindTerminalCommands(term)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scriptEngine := d2script.CreateScriptEngine()
|
||||
|
||||
uiManager := d2ui.NewUIManager(asset, renderer, inputManager, audio)
|
||||
uiManager := d2ui.NewUIManager(a.asset, renderer, inputManager, audio)
|
||||
|
||||
a.inputManager = inputManager
|
||||
a.terminal = term
|
||||
a.scriptEngine = scriptEngine
|
||||
a.audio = audio
|
||||
a.ui = uiManager
|
||||
a.asset = asset
|
||||
a.tAllocSamples = createZeroedRing(nSamplesTAlloc)
|
||||
|
||||
if a.gitBranch == "" {
|
||||
@ -273,6 +260,13 @@ func (a *App) Run() error {
|
||||
return fmt.Errorf(fmtVersion, a.gitBranch, a.gitCommit)
|
||||
}
|
||||
|
||||
logLevel := *a.Options.LogLevel
|
||||
if logLevel == d2util.LogLevelUnspecified {
|
||||
logLevel = a.config.LogLevel
|
||||
}
|
||||
|
||||
a.asset.SetLogLevel(logLevel)
|
||||
|
||||
// start profiler if argument was supplied
|
||||
if len(*a.Options.profiler) > 0 {
|
||||
profiler := enableProfiler(*a.Options.profiler)
|
||||
@ -296,7 +290,11 @@ func (a *App) Run() error {
|
||||
windowTitle := fmt.Sprintf("OpenDiablo2 (%s)", a.gitBranch)
|
||||
// If we fail to initialize, we will show the error screen
|
||||
if err := a.initialize(); err != nil {
|
||||
if gameErr := a.renderer.Run(updateInitError, updateNOOP, 800, 600,
|
||||
if a.errorMessage == nil {
|
||||
a.errorMessage = err // if there was an error during init, don't clobber it
|
||||
}
|
||||
|
||||
if gameErr := a.renderer.Run(a.updateInitError, updateNOOP, 800, 600,
|
||||
windowTitle); gameErr != nil {
|
||||
return gameErr
|
||||
}
|
||||
@ -352,8 +350,7 @@ func (a *App) initialize() error {
|
||||
|
||||
a.screen = d2screen.NewScreenManager(a.ui, a.guiManager)
|
||||
|
||||
config := d2config.Config
|
||||
a.audio.SetVolumes(config.BgmVolume, config.SfxVolume)
|
||||
a.audio.SetVolumes(a.config.BgmVolume, a.config.SfxVolume)
|
||||
|
||||
if err := a.loadStrings(); err != nil {
|
||||
return err
|
||||
@ -727,11 +724,10 @@ func enableProfiler(profileOption string) interface{ Stop() } {
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateInitError(target d2interface.Surface) error {
|
||||
func (a *App) updateInitError(target d2interface.Surface) error {
|
||||
target.Clear(colornames.Darkred)
|
||||
target.PushTranslation(errMsgPadding, errMsgPadding)
|
||||
target.DrawTextf(`Could not find the MPQ files in the directory:
|
||||
%s\nPlease put the files and re-run the game.`, d2config.Config.MpqPath)
|
||||
target.DrawTextf(a.errorMessage.Error())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package d2loader
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -35,10 +34,8 @@ const (
|
||||
)
|
||||
|
||||
// NewLoader creates a new loader
|
||||
func NewLoader(config *d2config.Configuration, l d2util.LogLevel) (*Loader, error) {
|
||||
loader := &Loader{
|
||||
config: config,
|
||||
}
|
||||
func NewLoader(l d2util.LogLevel) (*Loader, error) {
|
||||
loader := &Loader{}
|
||||
|
||||
loader.Cache = d2cache.CreateCache(defaultCacheBudget)
|
||||
loader.Logger = d2util.NewLogger()
|
||||
@ -46,9 +43,9 @@ func NewLoader(config *d2config.Configuration, l d2util.LogLevel) (*Loader, erro
|
||||
loader.Logger.SetPrefix(logPrefix)
|
||||
loader.Logger.SetLevel(l)
|
||||
|
||||
err := loader.initFromConfig()
|
||||
loader.bootstrap()
|
||||
|
||||
return loader, err
|
||||
return loader, nil
|
||||
}
|
||||
|
||||
// Loader represents the manager that handles loading and caching assets with the asset Sources
|
||||
@ -60,35 +57,9 @@ type Loader struct {
|
||||
Sources []asset.Source
|
||||
}
|
||||
|
||||
const (
|
||||
errConfigFileNotFound = "config file not found"
|
||||
fmtErrSourceNotFound = `file not found: %s
|
||||
|
||||
Please check your config file at %s
|
||||
|
||||
Also, verify that the MPQ files exist at %s
|
||||
|
||||
Capitalization matters!
|
||||
`
|
||||
)
|
||||
|
||||
func (l *Loader) initFromConfig() error {
|
||||
if l.config == nil {
|
||||
return errors.New(errConfigFileNotFound)
|
||||
}
|
||||
|
||||
for _, mpqName := range l.config.MpqLoadOrder {
|
||||
cleanDir := filepath.Clean(l.config.MpqPath)
|
||||
srcPath := filepath.Join(cleanDir, mpqName)
|
||||
|
||||
_, err := l.AddSource(srcPath)
|
||||
if err != nil {
|
||||
// nolint:stylecheck // we want a multiline error message here..
|
||||
return fmt.Errorf(fmtErrSourceNotFound, srcPath, l.config.Path(), l.config.MpqPath)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
func (l *Loader) bootstrap() {
|
||||
_, _ = l.AddSource(filepath.Dir(d2config.LocalConfigPath()))
|
||||
_, _ = l.AddSource(filepath.Dir(d2config.DefaultConfigPath()))
|
||||
}
|
||||
|
||||
// Load attempts to load an asset with the given sub-path. The sub-path is relative to the root
|
||||
@ -125,7 +96,7 @@ func (l *Loader) Load(subPath string) (asset.Asset, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
srcBase := filepath.Base(source.Path())
|
||||
srcBase, _ := filepath.Abs(source.Path())
|
||||
l.Info(fmt.Sprintf("from %s, loading %s", srcBase, subPath))
|
||||
|
||||
return loadedAsset, l.Insert(subPath, loadedAsset, defaultCacheEntryWeight)
|
||||
|
@ -26,7 +26,7 @@ const (
|
||||
)
|
||||
|
||||
func TestLoader_NewLoader(t *testing.T) {
|
||||
loader, _ := NewLoader(nil, d2util.LogLevelDefault)
|
||||
loader, _ := NewLoader(d2util.LogLevelDefault)
|
||||
|
||||
if loader.Cache == nil {
|
||||
t.Error("loader should not be nil")
|
||||
@ -34,7 +34,7 @@ func TestLoader_NewLoader(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoader_AddSource(t *testing.T) {
|
||||
loader, _ := NewLoader(nil, d2util.LogLevelDefault)
|
||||
loader, _ := NewLoader(d2util.LogLevelDefault)
|
||||
|
||||
sourceA, errA := loader.AddSource(sourcePathA)
|
||||
sourceB, errB := loader.AddSource(sourcePathB)
|
||||
@ -85,9 +85,10 @@ func TestLoader_AddSource(t *testing.T) {
|
||||
|
||||
// nolint:gocyclo // this is just a test, not a big deal if we ignore linter here
|
||||
func TestLoader_Load(t *testing.T) {
|
||||
loader, _ := NewLoader(nil, d2util.LogLevelDefault)
|
||||
loader, _ := NewLoader(d2util.LogLevelDefault)
|
||||
|
||||
_, err := loader.AddSource(sourcePathB) // we expect files common to any source to come from here
|
||||
// we expect files common to any source to come from here
|
||||
commonSource, err := loader.AddSource(sourcePathB)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
log.Print(err)
|
||||
@ -123,7 +124,7 @@ func TestLoader_Load(t *testing.T) {
|
||||
|
||||
if entryCommon == nil || errCommon != nil {
|
||||
t.Error("common entry should exist")
|
||||
} else if entryCommon.Source() != loader.Sources[0] {
|
||||
} else if entryCommon.Source() != commonSource {
|
||||
t.Error("common entry should come from the first loader source")
|
||||
}
|
||||
|
||||
|
@ -37,10 +37,10 @@ const colorEscapeReset = "\033[0m"
|
||||
// Log format strings for log levels
|
||||
const (
|
||||
fmtPrefix = "[%s]"
|
||||
LogFmtDebug = "[DEBUG]" + colorEscapeReset + " %s"
|
||||
LogFmtInfo = "[INFO]" + colorEscapeReset + " %s"
|
||||
LogFmtWarning = "[WARNING]" + colorEscapeReset + " %s"
|
||||
LogFmtError = "[ERROR]" + colorEscapeReset + " %s"
|
||||
LogFmtDebug = "[DEBUG]" + colorEscapeReset + " %s\r\n"
|
||||
LogFmtInfo = "[INFO]" + colorEscapeReset + " %s\r\n"
|
||||
LogFmtWarning = "[WARNING]" + colorEscapeReset + " %s\r\n"
|
||||
LogFmtError = "[ERROR]" + colorEscapeReset + " %s\r\n"
|
||||
)
|
||||
|
||||
// NewLogger creates a new logger with a default
|
||||
@ -73,6 +73,10 @@ func (l *Logger) SetPrefix(s string) {
|
||||
|
||||
// SetLevel sets the log level
|
||||
func (l *Logger) SetLevel(level LogLevel) {
|
||||
if level == LogLevelUnspecified {
|
||||
level = LogLevelDefault
|
||||
}
|
||||
|
||||
l.level = level
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,12 @@
|
||||
package d2asset
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
|
||||
@ -38,8 +42,22 @@ const (
|
||||
paletteTransformBudget = 64
|
||||
)
|
||||
|
||||
const (
|
||||
logPrefix = "Asset Manager"
|
||||
fmtLoadAsset = "could not load file stream %s (%v)"
|
||||
fmtLoadAnimation = "loading animation %s with palette %s, draw effect %d"
|
||||
fmtLoadComposite = "loading composite: type %d, token %s, palette %s"
|
||||
fmtLoadFont = "loading font: table %s, sprite %s, palette %s"
|
||||
fmtLoadPalette = "loading palette %s"
|
||||
fmtLoadStringTable = "loading string table: %s"
|
||||
fmtLoadTransform = "loading palette transform: %s"
|
||||
fmtLoadDict = "loading data dictionary: %s"
|
||||
fmtLoadAnimData = "loading animation data from: %s"
|
||||
)
|
||||
|
||||
// AssetManager loads files and game objects
|
||||
type AssetManager struct {
|
||||
config *d2config.Configuration
|
||||
logger *d2util.Logger
|
||||
loader *d2loader.Loader
|
||||
tables d2interface.Cache
|
||||
@ -51,14 +69,98 @@ type AssetManager struct {
|
||||
}
|
||||
|
||||
func (am *AssetManager) init() error {
|
||||
err := am.initDataDictionaries()
|
||||
var err error
|
||||
|
||||
config, err := am.LoadConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
am.logger.SetLevel(config.LogLevel)
|
||||
am.Records.Logger.SetLevel(config.LogLevel)
|
||||
am.loader.Logger.SetLevel(config.LogLevel)
|
||||
|
||||
err = am.initConfig(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := am.initDataDictionaries(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (am *AssetManager) initConfig(config *d2config.Configuration) error {
|
||||
am.config = config
|
||||
|
||||
for _, mpqName := range am.config.MpqLoadOrder {
|
||||
cleanDir := filepath.Clean(am.config.MpqPath)
|
||||
srcPath := filepath.Join(cleanDir, mpqName)
|
||||
|
||||
_, err := am.loader.AddSource(srcPath)
|
||||
if err != nil {
|
||||
// nolint:stylecheck // we want a multiline error message here..
|
||||
return fmt.Errorf(fmtErrSourceNotFound, srcPath, am.config.Path(), am.config.MpqPath)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetLogLevel sets the log level for the asset manager, record manager, and file loader
|
||||
func (am *AssetManager) SetLogLevel(level d2util.LogLevel) {
|
||||
am.logger.SetLevel(level)
|
||||
am.Records.Logger.SetLevel(level)
|
||||
am.loader.Logger.SetLevel(level)
|
||||
}
|
||||
|
||||
// LoadConfig loads the OpenDiablo2 config file
|
||||
func (am *AssetManager) LoadConfig() (*d2config.Configuration, error) {
|
||||
// by now the, the loader has initialized and added our config dirs as sources...
|
||||
configBaseName := filepath.Base(d2config.DefaultConfigPath())
|
||||
|
||||
configAsset, _ := am.LoadAsset(configBaseName)
|
||||
|
||||
config := &d2config.Configuration{}
|
||||
|
||||
// create the default if not found
|
||||
if configAsset == nil {
|
||||
config = d2config.DefaultConfig()
|
||||
|
||||
fullPath := filepath.Join(config.Dir(), config.Base())
|
||||
config.SetPath(fullPath)
|
||||
|
||||
am.logger.Infof("creating default configuration file at %s...", fullPath)
|
||||
|
||||
saveErr := config.Save()
|
||||
|
||||
return config, saveErr
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(configAsset).Decode(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.SetPath(filepath.Join(configAsset.Source().Path(), configAsset.Path()))
|
||||
|
||||
am.logger.Infof("loaded configuration file from %s", config.Path())
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
const (
|
||||
fmtErrSourceNotFound = `file not found: %s
|
||||
|
||||
Please check your config file at %s
|
||||
|
||||
Also, verify that the MPQ files exist at %s
|
||||
|
||||
Capitalization matters!
|
||||
`
|
||||
)
|
||||
|
||||
func (am *AssetManager) initDataDictionaries() error {
|
||||
dictPaths := []string{
|
||||
d2resource.LevelType, d2resource.LevelPreset, d2resource.LevelWarp,
|
||||
@ -108,19 +210,6 @@ func (am *AssetManager) initDataDictionaries() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
logPrefix = "Asset Manager"
|
||||
fmtLoadAsset = "could not load file stream %s (%v)"
|
||||
fmtLoadAnimation = "loading animation %s with palette %s, draw effect %d"
|
||||
fmtLoadComposite = "loading composite: type %d, token %s, palette %s"
|
||||
fmtLoadFont = "loading font: table %s, sprite %s, palette %s"
|
||||
fmtLoadPalette = "loading palette %s"
|
||||
fmtLoadStringTable = "loading string table: %s"
|
||||
fmtLoadTransform = "loading palette transform: %s"
|
||||
fmtLoadDict = "loading data dictionary: %s"
|
||||
fmtLoadAnimData = "loading animation data from: %s"
|
||||
)
|
||||
|
||||
// LoadAsset loads an asset
|
||||
func (am *AssetManager) LoadAsset(filePath string) (asset.Asset, error) {
|
||||
data, err := am.loader.Load(filePath)
|
||||
|
@ -4,40 +4,35 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2cache"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2loader"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2records"
|
||||
)
|
||||
|
||||
// NewAssetManager creates and assigns all necessary dependencies for the AssetManager top-level functions to work correctly
|
||||
func NewAssetManager(config *d2config.Configuration, l d2util.LogLevel) (*AssetManager, error) {
|
||||
loader, err := d2loader.NewLoader(config, l)
|
||||
func NewAssetManager() (*AssetManager, error) {
|
||||
loader, err := d2loader.NewLoader(d2util.LogLevelDefault)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
records, err := d2records.NewRecordManager(l)
|
||||
records, err := d2records.NewRecordManager(d2util.LogLevelDebug)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
manager := &AssetManager{
|
||||
d2util.NewLogger(),
|
||||
loader,
|
||||
d2cache.CreateCache(tableBudget),
|
||||
d2cache.CreateCache(animationBudget),
|
||||
d2cache.CreateCache(fontBudget),
|
||||
d2cache.CreateCache(paletteBudget),
|
||||
d2cache.CreateCache(paletteTransformBudget),
|
||||
records,
|
||||
logger: d2util.NewLogger(),
|
||||
loader: loader,
|
||||
tables: d2cache.CreateCache(tableBudget),
|
||||
animations: d2cache.CreateCache(animationBudget),
|
||||
fonts: d2cache.CreateCache(fontBudget),
|
||||
palettes: d2cache.CreateCache(paletteBudget),
|
||||
transforms: d2cache.CreateCache(paletteTransformBudget),
|
||||
Records: records,
|
||||
}
|
||||
|
||||
manager.logger.SetPrefix(logPrefix)
|
||||
manager.logger.SetLevel(l)
|
||||
|
||||
err = manager.init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return manager, nil
|
||||
return manager, err
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ func (eap *AudioProvider) createSoundEffect(sfx string, context *audio.Context,
|
||||
loop bool) *SoundEffect {
|
||||
result := &SoundEffect{}
|
||||
|
||||
soundFile := "/data/global/sfx/"
|
||||
soundFile := "data/global/sfx/"
|
||||
|
||||
if _, exists := eap.asset.Records.Sound.Details[sfx]; exists {
|
||||
soundEntry := eap.asset.Records.Sound.Details[sfx]
|
||||
@ -132,7 +132,7 @@ func (eap *AudioProvider) createSoundEffect(sfx string, context *audio.Context,
|
||||
audioData, err := eap.asset.LoadFileStream(soundFile)
|
||||
|
||||
if err != nil {
|
||||
audioData, err = eap.asset.LoadFileStream("/data/global/music/" + sfx)
|
||||
audioData, err = eap.asset.LoadFileStream("data/global/music/" + sfx)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -2,16 +2,13 @@ package d2config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
)
|
||||
|
||||
// Config holds the configuration from config.json
|
||||
var Config *Configuration //nolint:gochecknoglobals // Currently global by design
|
||||
|
||||
// Configuration defines the configuration for the engine, loaded from config.json
|
||||
type Configuration struct {
|
||||
MpqLoadOrder []string
|
||||
@ -29,72 +26,19 @@ type Configuration struct {
|
||||
path string
|
||||
}
|
||||
|
||||
// Load loads a configuration object from disk
|
||||
func Load() error {
|
||||
Config = new(Configuration)
|
||||
|
||||
if Config.Load() != nil {
|
||||
return Config.Save()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load loads a configuration object from disk
|
||||
func (c *Configuration) Load() error {
|
||||
configPaths := []string{
|
||||
defaultConfigPath(),
|
||||
localConfigPath(),
|
||||
}
|
||||
|
||||
for _, configPath := range configPaths {
|
||||
log.Printf("loading configuration file from %s...", configPath)
|
||||
|
||||
if _, err := os.Stat(configPath); os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
configFile, err := os.Open(path.Clean(configPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(configFile).Decode(&Config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := configFile.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.path = configPath
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Println("failed to load configuration file, saving default configuration...")
|
||||
|
||||
Config = defaultConfig()
|
||||
|
||||
return Config.Save()
|
||||
}
|
||||
|
||||
// Save saves the configuration object to disk
|
||||
func (c *Configuration) Save() error {
|
||||
configPath := defaultConfigPath()
|
||||
log.Printf("saving configuration file to %s...", configPath)
|
||||
|
||||
configDir := path.Dir(configPath)
|
||||
configDir := path.Dir(c.path)
|
||||
if err := os.MkdirAll(configDir, 0750); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configFile, err := os.Create(configPath)
|
||||
configFile, err := os.Create(c.path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf, err := json.MarshalIndent(Config, "", " ")
|
||||
buf, err := json.MarshalIndent(c, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -106,23 +50,22 @@ func (c *Configuration) Save() error {
|
||||
return configFile.Close()
|
||||
}
|
||||
|
||||
// Path returns the path of the config file
|
||||
func (c *Configuration) Path() string {
|
||||
if c.path == "" {
|
||||
c.path = defaultConfigPath()
|
||||
}
|
||||
// Dir returns the directory component of the path
|
||||
func (c *Configuration) Dir() string {
|
||||
return filepath.Dir(c.path)
|
||||
}
|
||||
|
||||
// Base returns the base component of the path
|
||||
func (c *Configuration) Base() string {
|
||||
return filepath.Base(c.path)
|
||||
}
|
||||
|
||||
// Path returns the config file path
|
||||
func (c *Configuration) Path() string {
|
||||
return c.path
|
||||
}
|
||||
|
||||
func defaultConfigPath() string {
|
||||
if configDir, err := os.UserConfigDir(); err == nil {
|
||||
return path.Join(configDir, "OpenDiablo2", "config.json")
|
||||
}
|
||||
|
||||
return localConfigPath()
|
||||
}
|
||||
|
||||
func localConfigPath() string {
|
||||
return path.Join(path.Dir(os.Args[0]), "config.json")
|
||||
// SetPath sets where the config file is saved to (a full path)
|
||||
func (c *Configuration) SetPath(p string) {
|
||||
c.path = p
|
||||
}
|
||||
|
28
d2core/d2config/default_directories.go
Normal file
28
d2core/d2config/default_directories.go
Normal file
@ -0,0 +1,28 @@
|
||||
package d2config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
const (
|
||||
od2ConfigDirName = "OpenDiablo2"
|
||||
)
|
||||
|
||||
const (
|
||||
od2ConfigFileName = "config.json"
|
||||
)
|
||||
|
||||
// DefaultConfigPath returns the absolute path for the default config file location
|
||||
func DefaultConfigPath() string {
|
||||
if configDir, err := os.UserConfigDir(); err == nil {
|
||||
return path.Join(configDir, od2ConfigDirName, od2ConfigFileName)
|
||||
}
|
||||
|
||||
return LocalConfigPath()
|
||||
}
|
||||
|
||||
// LocalConfigPath returns the absolute path to the directory of the OpenDiablo2 executable
|
||||
func LocalConfigPath() string {
|
||||
return path.Join(path.Dir(os.Args[0]), od2ConfigFileName)
|
||||
}
|
@ -8,7 +8,8 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
)
|
||||
|
||||
func defaultConfig() *Configuration {
|
||||
// DefaultConfig creates and returns a default configuration
|
||||
func DefaultConfig() *Configuration {
|
||||
const (
|
||||
defaultSfxVolume = 1.0
|
||||
defaultBgmVolume = 0.3
|
||||
@ -38,6 +39,7 @@ func defaultConfig() *Configuration {
|
||||
"d2speech.mpq",
|
||||
},
|
||||
LogLevel: d2util.LogLevelDefault,
|
||||
path: DefaultConfigPath(),
|
||||
}
|
||||
|
||||
switch runtime.GOOS {
|
||||
|
@ -66,11 +66,11 @@ func (r *Renderer) Layout(_, _ int) (width, height int) {
|
||||
}
|
||||
|
||||
// CreateRenderer creates an ebiten renderer instance
|
||||
func CreateRenderer() (*Renderer, error) {
|
||||
func CreateRenderer(cfg *d2config.Configuration) (*Renderer, error) {
|
||||
result := &Renderer{}
|
||||
|
||||
if d2config.Config != nil {
|
||||
config := d2config.Config
|
||||
if cfg != nil {
|
||||
config := cfg
|
||||
|
||||
ebiten.SetCursorMode(ebiten.CursorModeHidden)
|
||||
ebiten.SetFullscreen(config.FullScreen)
|
||||
|
Loading…
Reference in New Issue
Block a user