diff --git a/d2app/app.go b/d2app/app.go index b1713bd2..3548d506 100644 --- a/d2app/app.go +++ b/d2app/app.go @@ -66,6 +66,7 @@ type App struct { captureFrames []*image.RGBA gitBranch string gitCommit string + language string asset *d2asset.AssetManager inputManager d2interface.InputManager terminal d2interface.Terminal @@ -373,6 +374,8 @@ func (a *App) initialize() error { return err } + a.initLanguage() + if err := a.initDataDictionaries(); err != nil { return err } @@ -454,6 +457,11 @@ func (a *App) initConfig(config *d2config.Configuration) error { return nil } +func (a *App) initLanguage() { + a.language = a.asset.LoadLanguage(d2resource.LocalLanguage) + a.asset.Loader.SetLanguage(&a.language) +} + func (a *App) initDataDictionaries() error { dictPaths := []string{ d2resource.LevelType, d2resource.LevelPreset, d2resource.LevelWarp, diff --git a/d2common/d2loader/loader.go b/d2common/d2loader/loader.go index 27fe7d0e..c9a7ba3d 100644 --- a/d2common/d2loader/loader.go +++ b/d2common/d2loader/loader.go @@ -14,7 +14,6 @@ import ( "github.com/OpenDiablo2/OpenDiablo2/d2common/d2loader/mpq" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2util" - "github.com/OpenDiablo2/OpenDiablo2/d2core/d2config" ) const ( @@ -24,8 +23,7 @@ const ( ) const ( - defaultLanguage = "ENG" - logPrefix = "File Loader" + logPrefix = "File Loader" ) const ( @@ -49,24 +47,27 @@ func NewLoader(l d2util.LogLevel) (*Loader, error) { // Loader represents the manager that handles loading and caching assets with the asset Sources // that have been added type Loader struct { - config *d2config.Configuration + language *string d2interface.Cache *d2util.Logger Sources []asset.Source } +// SetLanguage sets the language for loader +func (l *Loader) SetLanguage(language *string) { + l.language = language +} + // Load attempts to load an asset with the given sub-path. The sub-path is relative to the root // of each asset source root (regardless of the type of asset source) func (l *Loader) Load(subPath string) (asset.Asset, error) { - lang := defaultLanguage - - if l.config != nil { - lang = l.config.Language - } - subPath = filepath.Clean(subPath) - subPath = strings.ReplaceAll(subPath, fontToken, "latin") - subPath = strings.ReplaceAll(subPath, tableToken, lang) + + if l.language != nil { + lang := l.language + subPath = strings.ReplaceAll(subPath, fontToken, "latin") + subPath = strings.ReplaceAll(subPath, tableToken, *lang) + } // first, we check the cache for an existing entry if cached, found := l.Retrieve(subPath); found { diff --git a/d2common/d2resource/languages_map.go b/d2common/d2resource/languages_map.go new file mode 100644 index 00000000..d5aadb0c --- /dev/null +++ b/d2common/d2resource/languages_map.go @@ -0,0 +1,26 @@ +package d2resource + +func getLanguages() map[byte]string { + return map[byte]string{ + 0x00: "ENG", // (English) + 0x01: "ESP", // (Spanish) + 0x02: "DEU", // (German) + 0x03: "FRA", // (French) + 0x04: "POR", // (Portuguese) + 0x05: "ITA", // (Italian) + 0x06: "JPN", // (Japanese) + 0x07: "KOR", // (Korean) + 0x08: "SIN", // + 0x09: "CHI", // (Chinese) + 0x0A: "POL", // (Polish) + 0x0B: "RUS", // (Russian) + 0x0C: "ENG", // (English) + } +} + +// GetLanguageLiteral returns string representation of language code +func GetLanguageLiteral(code byte) string { + languages := getLanguages() + + return languages[code] +} diff --git a/d2common/d2resource/resource_paths.go b/d2common/d2resource/resource_paths.go index f355b04b..01edb034 100644 --- a/d2common/d2resource/resource_paths.go +++ b/d2common/d2resource/resource_paths.go @@ -2,19 +2,25 @@ package d2resource // Paths of the resources inside the mpq files. const ( + // --- Language + + LocalLanguage = "/data/local/use" + LanguageFontToken = "{LANG_FONT}" //nolint:gosec // this is just a format string + LanguageTableToken = "{LANG}" + // --- Screens --- LoadingScreen = "/data/global/ui/Loading/loadingscreen.dc6" // --- Video Paths --- - Act1Intro = "/data/local/video/eng/d2intro640x292.bik" - Act2Intro = "/data/local/video/eng/act02start640x292.bik" - Act3Intro = "/data/local/video/eng/act03start640x292.bik" - Act4Intro = "/data/local/video/eng/act04start640x292.bik" - Act4Outro = "/data/local/video/eng/act04end640x292.bik" - Act5Intro = "/data/local/video/eng/d2x_intro_640x292.bik" - Act5Outro = "/data/local/video/eng/d2x_out_640x292.bik" + Act1Intro = "/data/local/video/" + LanguageTableToken + "/d2intro640x292.bik" + Act2Intro = "/data/local/video/" + LanguageTableToken + "/act02start640x292.bik" + Act3Intro = "/data/local/video/" + LanguageTableToken + "/act03start640x292.bik" + Act4Intro = "/data/local/video/" + LanguageTableToken + "/act04start640x292.bik" + Act4Outro = "/data/local/video/" + LanguageTableToken + "/act04end640x292.bik" + Act5Intro = "/data/local/video/" + LanguageTableToken + "/d2x_intro_640x292.bik" + Act5Outro = "/data/local/video/" + LanguageTableToken + "/d2x_out_640x292.bik" // --- Main Menu --- @@ -128,9 +134,6 @@ const ( CursorDefault = "/data/global/ui/CURSOR/ohand.DC6" // --- Fonts & Locale (strings) --- - - LanguageFontToken = "{LANG_FONT}" //nolint:gosec // this is just a format string - LanguageTableToken = "{LANG}" Font6 = "/data/local/FONT/" + LanguageFontToken + "/font6" Font8 = "/data/local/FONT/" + LanguageFontToken + "/font8" Font16 = "/data/local/FONT/" + LanguageFontToken + "/font16" diff --git a/d2core/d2asset/asset_manager.go b/d2core/d2asset/asset_manager.go index 2c40f0fc..11911aef 100644 --- a/d2core/d2asset/asset_manager.go +++ b/d2core/d2asset/asset_manager.go @@ -4,6 +4,7 @@ import ( "fmt" "image/color" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2util" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2records" @@ -34,6 +35,7 @@ const ( ) const ( + defaultLanguage = "ENG" logPrefix = "Asset Manager" fmtLoadAsset = "could not load file stream %s (%v)" fmtLoadAnimation = "loading animation %s with palette %s, draw effect %d" @@ -108,6 +110,23 @@ func (am *AssetManager) FileExists(filePath string) (bool, error) { return true, nil } +// LoadLanguage loads language from resource path +func (am *AssetManager) LoadLanguage(languagePath string) string { + languageByte, err := am.LoadFile(languagePath) + if err != nil { + am.Debugf("Unable to load language file: %s", err) + return defaultLanguage + } + + languageCode := languageByte[0] + am.Debugf("Language code: %#02x", languageCode) + + language := d2resource.GetLanguageLiteral(languageCode) + am.Infof("Language: %s", language) + + return language +} + // LoadAnimation loads an Animation by its resource path and its palette path func (am *AssetManager) LoadAnimation(animationPath, palettePath string) (d2interface.Animation, error) { return am.LoadAnimationWithEffect(animationPath, palettePath, d2enum.DrawEffectNone) diff --git a/d2core/d2config/d2config.go b/d2core/d2config/d2config.go index 535b447f..3d57e753 100644 --- a/d2core/d2config/d2config.go +++ b/d2core/d2config/d2config.go @@ -12,7 +12,6 @@ import ( // Configuration defines the configuration for the engine, loaded from config.json type Configuration struct { MpqLoadOrder []string - Language string MpqPath string TicksPerSecond int FpsCap int diff --git a/d2core/d2config/defaults.go b/d2core/d2config/defaults.go index beb0e23f..a717005d 100644 --- a/d2core/d2config/defaults.go +++ b/d2core/d2config/defaults.go @@ -16,7 +16,6 @@ func DefaultConfig() *Configuration { ) config := &Configuration{ - Language: "ENG", FullScreen: false, TicksPerSecond: -1, RunInBackground: true, diff --git a/docs/index.html b/docs/index.html index ff1c50d0..633c6a65 100644 --- a/docs/index.html +++ b/docs/index.html @@ -62,14 +62,6 @@ - - Language - - Defines the locale the game is running in. For english this should be set to ENG. Other values include - (but are not limited to) CHI, DEU, ESP, FRA, ITA, - JPN, etc. - - FullScreen Determines if the client is initially full screen or not. Do note that fullscreen mode can be toggled at any time