using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Globalization; using System.IO; using System.Linq; using OMI; using OMI.Formats.Color; using OMI.Formats.GameRule; using OMI.Formats.Languages; using OMI.Formats.Model; using OMI.Formats.Pck; using OMI.Workers.Color; using OMI.Workers.GameRule; using OMI.Workers.Language; using OMI.Workers.Material; using OMI.Workers.Model; using OMI.Workers.Pck; using PckStudio.Core.App; using PckStudio.Core.Colors; using PckStudio.Core.Deserializer; using PckStudio.Core.Extensions; using PckStudio.Core.FileFormats; using PckStudio.Core.Interfaces; using PckStudio.Core.IO.PckAudio; using PckStudio.Core.Model; using PckStudio.Interfaces; namespace PckStudio.Core.DLC { public class DLCManager { internal const string DEFAULT_TEXTURE_PACK_FILENAME = "TexturePack.pck"; internal const string DEFAULT_MINIGAME_PACK_FILENAME = "WorldPack.pck"; internal const string DATA_DIRECTORY_NAME = "Data"; internal const string PACKAGE_DISPLAYNAME_ID = "IDS_DISPLAY_NAME"; private const string BASE_SAVE_NAME_GRF_PARAMETER_KEY = "baseSaveName"; private const string GRF_MAP_OPTIONS_NAME = "MapOptions"; private const string TEXTURE_PACK_DATA_PATH_KEY = "DATAPATH"; private const string CAPE_PATH_KEY = "CAPEPATH"; public ByteOrder ByteOrder => _byteOrder; public ConsolePlatform Platform => _platform; public DLCPackageContentSerilasationType ContentSerilasationType => _packageContentSerilasationType; /// /// See for details. /// public string PreferredLanguage { get; private set; } private readonly DLCPackageRegistry _packageRegistry = new DLCPackageRegistry(); private readonly Random _rng = new Random(); private ByteOrder _byteOrder; private ConsolePlatform _platform; private readonly AppLanguage _preferredAppLanguage; private readonly DLCPackageContentSerilasationType _packageContentSerilasationType; private PckFileCompiler _pckFileCompiler; /// /// /// See for details. public DLCManager(ConsolePlatform platform, AppLanguage preferredLanguage, DLCPackageContentSerilasationType packageContentSerilasationType) { _platform = platform; _preferredAppLanguage = preferredLanguage; _packageContentSerilasationType = packageContentSerilasationType; _byteOrder = GetByteOrderForPlatform(Platform); SetPreferredLanguage(preferredLanguage); } private static ByteOrder GetByteOrderForPlatform(ConsolePlatform platform) { return platform switch { ConsolePlatform.Switch => ByteOrder.LittleEndian, ConsolePlatform.PS_4 => ByteOrder.LittleEndian, _ => ByteOrder.BigEndian }; } public IDLCPackage CreateNewPackage(string name, DLCPackageType packageType) { int identifier = _rng.Next(8000, GameConstants.MAX_PACK_ID); IDLCPackage package = packageType switch { DLCPackageType.SkinPack => DLCSkinPackage.CreateEmpty(name, identifier), DLCPackageType.TexturePack => DLCTexturePackage.CreateDefaultPackage(name, "", identifier), DLCPackageType.MashUpPack => new DLCMashUpPackage(name, "", identifier), //! TODO: implemnt minigame dlc packages -null DLCPackageType.MG01 => new DLCBattlePackage(name, identifier), DLCPackageType.MG02 => new DLCMiniGamePackage(name, identifier, packageType, MiniGameId.Tumble), DLCPackageType.MG03 => new DLCMiniGamePackage(name, identifier, packageType, MiniGameId.Glide), DLCPackageType.Invalid => DLCPackage.Invalid, _ => throw new ArgumentException("Unable to create DLC Package of 'Unknown' type."), }; LOCFile localisation = new LOCFile(); localisation.AddLanguage(PreferredLanguage); localisation.AddLocKey(PACKAGE_DISPLAYNAME_ID, name); _packageRegistry.RegisterPackage(identifier, package, localisation); return package; } public IDLCPackage OpenDLCPackage(string filepath) => OpenDLCPackage(new FileInfo(filepath)); public IDLCPackage OpenDLCPackage(FileInfo fileInfo) { if (Platform == ConsolePlatform.Unknown) throw new Exception($"{nameof(Platform)} is Unknown."); if (!IsValidPckFile(fileInfo)) return DLCPackage.Invalid; using Stream stream = fileInfo.OpenRead(); PckFileReader fileReader = new PckFileReader(ByteOrder); PckFile pckFile = fileReader.FromStream(stream); if (!pckFile.TryGetAsset("0", PckAssetType.InfoFile, out PckAsset zeroAsset)) { Trace.TraceError("Could not find asset named:'0'."); return new RawAssetDLCPackage(fileInfo.Name, pckFile, ByteOrder); } int identifier = zeroAsset.HasProperty("PACKID") ? zeroAsset.GetProperty("PACKID", int.Parse) : -1; if (!identifier.IsWithinRangeOf(1, GameConstants.MAX_PACK_ID)) { Trace.TraceError($"{nameof(identifier)}({identifier}) was out of range!"); return new RawAssetDLCPackage(fileInfo.Name, pckFile, ByteOrder); } if (_packageRegistry.ContainsPackage(identifier)) return _packageRegistry[identifier]; LOCFile localisation = pckFile.GetAssetsByType(PckAssetType.LocalisationFile).FirstOrDefault()?.GetData(new LOCFileReader()); if (localisation is null) { Trace.TraceError("No localisation asset found."); return new RawAssetDLCPackage(fileInfo.Name, pckFile, ByteOrder); } IDLCPackage package = LoadDLCPackage(fileInfo, identifier, pckFile, localisation, fileReader); if (package.GetDLCPackageType() != DLCPackageType.Invalid) { _packageRegistry.RegisterPackage(identifier, package, localisation); } return new RawAssetDLCPackage(fileInfo.Name, identifier, pckFile, ByteOrder); } public bool CloseDLCPackage(int identifier) => _packageRegistry.UnregisterPackage(identifier); internal LOCFile GetLocalisation(int identifier) { return _packageRegistry.ContainsPackage(identifier) ? _packageRegistry.GetLocalisation(identifier) : new LOCFile(); } private bool IsValidPckFile(FileInfo fileInfo) { if (fileInfo is null) throw new ArgumentNullException(nameof(fileInfo)); if (!fileInfo.Exists) throw new FileNotFoundException(fileInfo.FullName); if (fileInfo.Extension != ".pck") throw new FileFormatException("File does not end with '.pck'."); return true; } private IDLCPackage LoadDLCPackage(FileInfo fileInfo, int identifier, PckFile pckFile, LOCFile localisation, PckFileReader fileReader) { bool hasLanguage = localisation?.Languages?.Contains(PreferredLanguage) ?? default; string name = hasLanguage && (localisation?.HasLocEntry(PACKAGE_DISPLAYNAME_ID) ?? default) ? localisation.GetLocEntry(PACKAGE_DISPLAYNAME_ID, PreferredLanguage) : fileInfo.Name; string description = hasLanguage && (localisation?.HasLocEntry(DLCTexturePackage.TEXTUREPACK_DESCRIPTION_ID) ?? default) ? localisation.GetLocEntry(DLCTexturePackage.TEXTUREPACK_DESCRIPTION_ID, PreferredLanguage) : string.Empty; bool couldBeTexturePack = fileInfo.Name == DEFAULT_TEXTURE_PACK_FILENAME; bool couldBeMiniGamePack = fileInfo.Name == DEFAULT_MINIGAME_PACK_FILENAME; bool hasSkins = TryGetDLCSkinPackage(name, identifier, pckFile, fileReader, out IDLCPackage skinPackage); DirectoryInfo dataDirectoryInfo = fileInfo.Directory.EnumerateDirectories().Where(dirInfo => dirInfo.Name == DATA_DIRECTORY_NAME).FirstOrDefault(); if (dataDirectoryInfo is null) { Trace.TraceInformation("No data directory found."); return skinPackage ?? new RawAssetDLCPackage(name, pckFile, ByteOrder); } bool hasTexturePack = TryGetTexturePack(name, description, identifier, dataDirectoryInfo, pckFile, fileReader, out IDLCPackage texturePackage); if (!hasTexturePack) { Trace.TraceWarning("Couldn't parse texturepack."); return skinPackage ?? new RawAssetDLCPackage(name, pckFile, ByteOrder); } PckAudioFile pckAudioFile = pckFile.GetAssetsByType(PckAssetType.AudioFile).FirstOrDefault()?.GetData(new PckAudioFileReader(ByteOrder)); IDictionary audios = default; if (pckAudioFile != null) { var songs = pckAudioFile.Categories.SelectMany(audioCategory => audioCategory.SongNames).ToList(); audios = dataDirectoryInfo.EnumerateFiles("*.binka") .Where(audioFile => songs.Contains(Path.GetFileNameWithoutExtension(audioFile.Name))) .ToDictionary(audioFile => audioFile.Name, audioFile => File.ReadAllBytes(audioFile.FullName)); } GameRuleFile.CompressionType compressionType = GetPlatformCompressionType(); var reader = new GameRuleFileReader(compressionType); IEnumerable gameRules = pckFile.GetAssetsByType(PckAssetType.GameRulesFile) .Concat(pckFile.GetAssetsByType(PckAssetType.GameRulesHeader)) .Select(asset => asset.GetData(reader)); Dictionary mapData = GetMapData(gameRules, dataDirectoryInfo); if (mapData.Count == 0) return texturePackage ?? skinPackage ?? new RawAssetDLCPackage(name, pckFile, ByteOrder); if (mapData.Count == 1) return new DLCMashUpPackage(name, description, identifier, null, null, pckAudioFile, audios, parentPackage: null, skinPackage: skinPackage, texturePackage: texturePackage); return new RawAssetDLCPackage(name, pckFile, ByteOrder); } private Dictionary GetMapData(IEnumerable gameRuleFiles, DirectoryInfo dataDirectory) { IEnumerable values = gameRuleFiles .SelectMany(grf => grf.Root.GetRules().Where(rule => rule.Name == GRF_MAP_OPTIONS_NAME && rule.ContainsParameter(BASE_SAVE_NAME_GRF_PARAMETER_KEY))) .Select(rule => rule.GetParameterValue(BASE_SAVE_NAME_GRF_PARAMETER_KEY)); return dataDirectory.EnumerateFiles("*.mcs") .Where(file => values.Contains(file.Name)) .ToDictionary(worldFile => worldFile.Name, worldFile => MapReader.OpenSaveData(worldFile.OpenRead())); } private bool TryGetTexturePack(string name, string description, int identifier, DirectoryInfo dataDirectoryInfo, PckFile pckFile, PckFileReader pckFormatReader, out IDLCPackage texturePackage) { if (dataDirectoryInfo is null) { texturePackage = default; return false; } PckAsset texturePackInfo = pckFile.GetAssetsByType(PckAssetType.TexturePackInfoFile).FirstOrDefault(); if (texturePackInfo is null) { texturePackage = default; return false; } DLCTexturePackage.TextureResolution resolution = DLCTexturePackage.GetTextureResolutionFromString(texturePackInfo.Filename); string dataPath = texturePackInfo.GetProperty(TEXTURE_PACK_DATA_PATH_KEY); if (string.IsNullOrWhiteSpace(dataPath)) { texturePackage = default; return false; } PckFile infoPck = texturePackInfo.GetData(pckFormatReader); FileInfo texturePackFileInfo = dataDirectoryInfo.EnumerateFiles().Where(fileInfo => fileInfo.Name == dataPath).FirstOrDefault(); if (!IsValidPckFile(texturePackFileInfo)) { texturePackage = null; return false; } using Stream texturePackFileStream = texturePackFileInfo.OpenRead(); PckFile texturePackPck = pckFormatReader.FromStream(texturePackFileStream); texturePackage = GetTexturePackageFromPckFile(name, description, identifier, infoPck, texturePackPck, resolution); return texturePackage is not null; } private IDLCPackage GetTexturePackageFromPckFile(string name, string description, int identifier, PckFile infoPck, PckFile dataPck, DLCTexturePackage.TextureResolution resolution) { if (infoPck is null || dataPck is null) return null; if (!infoPck.TryGetAsset("comparison.png", PckAssetType.TextureFile, out PckAsset comparisonAsset)) Trace.TraceWarning($"Could not find 'comparison.png'."); if (!infoPck.TryGetAsset("icon.png", PckAssetType.TextureFile, out PckAsset iconnAsset)) Trace.TraceWarning($"Could not find 'icon.png'."); DLCTexturePackage.MetaData metaData = new DLCTexturePackage.MetaData(comparisonAsset?.GetTexture(), iconnAsset?.GetTexture()); TryGetAtlasFromResourceCategory(dataPck, AtlasResource.AtlasType.BlockAtlas, out Atlas terrainAtlas); TryGetAtlasFromResourceCategory(dataPck, AtlasResource.AtlasType.ItemAtlas, out Atlas itemAtlas); TryGetAtlasFromResourceCategory(dataPck, AtlasResource.AtlasType.ParticleAtlas, out Atlas particleAtlas); TryGetAtlasFromResourceCategory(dataPck, AtlasResource.AtlasType.PaintingAtlas, out Atlas paintingAtlas); TryGetAtlasFromResourceCategory(dataPck, AtlasResource.AtlasType.MoonPhaseAtlas, out Atlas moonPhaseAtlas); TryGetAtlasFromResourceCategory(dataPck, AtlasResource.AtlasType.MapIconAtlas, out Atlas mapIconsAtlas); TryGetAtlasFromResourceCategory(dataPck, AtlasResource.AtlasType.AdditionalMapIconsAtlas, out Atlas additionalMapIconsAtlas); string itemAnimationAssetPath = ResourceLocation.GetPathFromCategory(ResourceCategory.ItemAnimation); string blockAnimationAssetPath = ResourceLocation.GetPathFromCategory(ResourceCategory.BlockAnimation); IPckAssetDeserializer deserializer = AnimationDeserializer.DefaultDeserializer; IDictionary itemAnimations = dataPck.GetDirectoryContent(itemAnimationAssetPath, PckAssetType.TextureFile) .Where(asset => !asset.IsMipmappedFile()) .ToDictionary(asset => Path.GetFileNameWithoutExtension(asset.Filename), deserializer.Deserialize); IDictionary blockAnimations = dataPck.GetDirectoryContent(blockAnimationAssetPath, PckAssetType.TextureFile) .Where(asset => !asset.IsMipmappedFile()) .ToDictionary(asset => Path.GetFileNameWithoutExtension(asset.Filename), deserializer.Deserialize); if (!itemAnimations.ContainsKey("compass")) Trace.TraceError("No compass animation found!"); if (!itemAnimations.ContainsKey("clock")) Trace.TraceError("No clock animation found!"); ITryGet tryGetTexture = TryGet.FromDelegate((string path, out Image image) => { bool success = dataPck.TryGetAsset(path, PckAssetType.TextureFile, out PckAsset asset); image = asset?.GetTexture(); return success; }); ImageDeserializer defaultDeserializer = ImageDeserializer.DefaultDeserializer; IEnumerable blockEntityBreakingFrames = dataPck.GetDirectoryContent("res/textures/", PckAssetType.TextureFile) .Select(defaultDeserializer.Deserialize); Animation blockEntityBreakAnimation = new Animation(blockEntityBreakingFrames); ColorContainer colorContainer = dataPck.GetAssetsByType(PckAssetType.ColourTableFile).FirstOrDefault()?.GetData(new COLFileReader()) ?? new ColorContainer(); IDictionary environmentTextures = dataPck.GetDirectoryContent("res/environment/", PckAssetType.TextureFile) .ToDictionary(a => Path.GetFileNameWithoutExtension(a.Filename), defaultDeserializer.Deserialize); environmentTextures.TryGetValue("clouds", out Image clouds); environmentTextures.TryGetValue("rain", out Image rain); environmentTextures.TryGetValue("snow", out Image snow); DLCTexturePackage.EnvironmentData environmentData = new DLCTexturePackage.EnvironmentData(clouds, rain, snow); IDictionary terrainTextures = dataPck.GetDirectoryContent("res/terrain/", PckAssetType.TextureFile) .ToDictionary(a => Path.GetFileNameWithoutExtension(a.Filename), defaultDeserializer.Deserialize); terrainTextures.TryGetValue("sun", out Image sun); terrainTextures.TryGetValue("moon", out Image moon); AbstractModelContainer customModels = null; if (dataPck.TryGetAsset("models.bin", PckAssetType.ModelsFile, out PckAsset modelsAsset)) { ModelContainer models = modelsAsset.GetData(new ModelFileReader()); customModels = AbstractModelContainer.FromModelContainer(models, null); } IDictionary materials = dataPck.GetAssetsByType(PckAssetType.MaterialFile).FirstOrDefault()?.GetData(new MaterialFileReader()) .ToDictionary(mat => mat.Name, mat => mat.Type); return new DLCTexturePackage(name, description, identifier, metaData, resolution, terrainAtlas, itemAtlas, particleAtlas, paintingAtlas, moonPhaseAtlas, mapIconsAtlas, additionalMapIconsAtlas, ArmorSetDescription.Leather.GetArmorSet(tryGetTexture), ArmorSetDescription.Chain.GetArmorSet(tryGetTexture), ArmorSetDescription.Iron.GetArmorSet(tryGetTexture), ArmorSetDescription.Gold.GetArmorSet(tryGetTexture), ArmorSetDescription.Diamond.GetArmorSet(tryGetTexture), ArmorSetDescription.Turtle.GetArmorSet(tryGetTexture), environmentData, AbstractColorContainer.FromColorContainer(colorContainer), null, null, customModels: customModels, materials: materials, blockEntityBreakAnimation: blockEntityBreakAnimation, itemAnimations: itemAnimations, blockAnimations: blockAnimations, sun: sun, moon: moon, mediaArc: null, misc: null, parentPackage: null); } private bool TryGetAtlasFromResourceCategory(PckFile pck, AtlasResource.AtlasType atlasType, out Atlas atlas) { ResourceLocation resourceLocation = ResourceLocation.GetFromCategory(AtlasResource.GetId(atlasType)); if (!pck.TryGetAsset(resourceLocation.FullPath, PckAssetType.TextureFile, out PckAsset asset)) { Trace.TraceWarning($"Could not find '{resourceLocation.FullPath}'."); atlas = null; return false; } atlas = asset.GetDeserializedData(new AtlasDeserializer(resourceLocation)); return true; } private bool TryGetDLCSkinPackage(string name, int identifier, PckFile pck, PckFileReader fileReader, out IDLCPackage skinPackage, IDLCPackage parentPackage = null) { if (!(pck.Contains(PckAssetType.SkinFile) || pck.Contains(PckAssetType.SkinDataFile))) { skinPackage = default; return false; } IDictionary capes = pck.GetAssetsByType(PckAssetType.CapeFile) .Where(asset => asset.GetId() != -1) .ToDictionary(PckAssetExtensions.GetId, PckAssetExtensions.GetTexture); Skin.Skin GetSkinWithCape(PckAsset skinAsset) { Skin.Skin skin = skinAsset.GetSkin(); if (skinAsset.TryGetProperty(CAPE_PATH_KEY, out string capeAssetPath) && pck.TryGetAsset(capeAssetPath, PckAssetType.CapeFile, out PckAsset capeAsset)) skin.CapeId = capeAsset.GetId(); return skin; } IEnumerable skins = pck.GetAssetsByType(PckAssetType.SkinFile).Select(GetSkinWithCape); skins = skins.Concat(pck.GetAssetsByType(PckAssetType.SkinDataFile) .Select(asset => asset.GetData(fileReader)) .SelectMany(pck => pck.GetAssetsByType(PckAssetType.SkinFile)) .Select(GetSkinWithCape) ); skinPackage = new DLCSkinPackage(name, identifier, skins, capes, parentPackage); return true; } public static GameRuleFile.CompressionType GetCompressionTypeForPlatform(ConsolePlatform platform) { switch (platform) { case ConsolePlatform.Xbox_360: return GameRuleFile.CompressionType.XMem; case ConsolePlatform.PS_3: return GameRuleFile.CompressionType.Deflate; case ConsolePlatform.Xbox_One: case ConsolePlatform.PS_4: case ConsolePlatform.PS_Vita: case ConsolePlatform.Wii_U: case ConsolePlatform.Switch: return GameRuleFile.CompressionType.Zlib; case ConsolePlatform.Unknown: default: throw new ArgumentException("Platform was not set"); } } internal GameRuleFile.CompressionType GetPlatformCompressionType() => GetCompressionTypeForPlatform(Platform); internal static string GetPreferredLanguage(AppLanguage appLanguage) { return appLanguage switch { AppLanguage.System_Default => LOCFile.ValidLanguages.Contains(CultureInfo.CurrentUICulture.Name) ? CultureInfo.CurrentUICulture.Name : AvailableLanguages.English, AppLanguage.Czech_Czechia => AvailableLanguages.CzechCzechia, AppLanguage.Czechia => AvailableLanguages.Czechia, AppLanguage.Denmark_Danish => AvailableLanguages.DenmarkDanish, AppLanguage.German => AvailableLanguages.German, AppLanguage.Greece => AvailableLanguages.Greece, AppLanguage.English => AvailableLanguages.English, AppLanguage.English_UnitedKingdom => AvailableLanguages.EnglishUnitedKingdom, AppLanguage.Spanish_Spain => AvailableLanguages.SpanishSpain, AppLanguage.Spanish_Mexico => AvailableLanguages.SpanishMexico, AppLanguage.Finnish_Finland => AvailableLanguages.FinnishFinland, AppLanguage.French_France => AvailableLanguages.FrenchFrance, AppLanguage.Italian_Italy => AvailableLanguages.ItalianItaly, AppLanguage.Japanese_Japan => AvailableLanguages.JapaneseJapan, AppLanguage.Korean_South_Korea => AvailableLanguages.KoreanSouthKorea, AppLanguage.Norwegian_Bokmål_Norway => AvailableLanguages.NorwegianBokmålNorway, AppLanguage.Dutch_Netherlands => AvailableLanguages.DutchNetherlands, AppLanguage.Polish_Poland => AvailableLanguages.PolishPoland, AppLanguage.Portuguese_Brazil => AvailableLanguages.PortugueseBrazil, AppLanguage.Portuguese_Portugal => AvailableLanguages.PortuguesePortugal, AppLanguage.Russian_Russia => AvailableLanguages.RussianRussia, AppLanguage.Slovak_Slovakia => AvailableLanguages.SlovakSlovakia, AppLanguage.Swedish_Sweden => AvailableLanguages.SwedishSweden, AppLanguage.Turkish_Turkey => AvailableLanguages.TurkishTurkey, AppLanguage.Chinese_China => AvailableLanguages.ChineseChina, _ => AvailableLanguages.English, }; } public void SetPreferredLanguage(AppLanguage lang) => PreferredLanguage = GetPreferredLanguage(lang); public void SetPlatform(ConsolePlatform platform) { _platform = platform; _byteOrder = GetByteOrderForPlatform(platform); } public DLCPackageContent CompilePackage(IDLCPackage package) { _pckFileCompiler = new PckFileCompiler(this); LOCFile localisation = GetLocalisation(package.Identifier); switch (package.GetDLCPackageType()) { case DLCPackageType.Invalid: break; case DLCPackageType.RawAssets: return _pckFileCompiler.CompileRawAssets(package); case DLCPackageType.SkinPack: return _pckFileCompiler.CompileSkinPackage(package, localisation); case DLCPackageType.TexturePack: return _pckFileCompiler.CompileTexturePackage(package, localisation); case DLCPackageType.MashUpPack: return _pckFileCompiler.CompileMashUpPackage(package, localisation); case DLCPackageType.MG01: break; case DLCPackageType.MG02: break; case DLCPackageType.MG03: break; } return DLCPackageContent.Empty; } private enum ConsoleRegion { US, EU, JP } public string GetInstallPath() { switch (Platform) { case ConsolePlatform.Wii_U: ConsoleRegion region = GetRegionFromLanguage(); string titleId = region switch { ConsoleRegion.US => "101d9d00", ConsoleRegion.EU => "101d7500", ConsoleRegion.JP => "101dbe00", _ => throw new Exception() }; return $"usr/title/0005000e/{titleId}/content/WiiU/DLC"; default: return ""; } } private ConsoleRegion GetRegionFromLanguage() { switch (_preferredAppLanguage) { case AppLanguage.System_Default: case AppLanguage.Czech_Czechia: case AppLanguage.Czechia: case AppLanguage.Danish: case AppLanguage.Denmark_Danish: case AppLanguage.German_Austria: case AppLanguage.German: case AppLanguage.Greek_Greece: case AppLanguage.English_UnitedKingdom: case AppLanguage.English_Ireland: case AppLanguage.Spanish_Spain: case AppLanguage.Finnish_Finland: case AppLanguage.French_France: case AppLanguage.Dutch_Netherlands: case AppLanguage.Dutch_Belgium: case AppLanguage.Polish_Poland: case AppLanguage.Norwegian_Norway: case AppLanguage.Norwegian_Bokmål_Norway: case AppLanguage.Italian_Italy: case AppLanguage.Slovak_Slovakia: case AppLanguage.Swedish_Sweden: case AppLanguage.Turkish_Turkey: case AppLanguage.Russian_Russia: case AppLanguage.Greece: return ConsoleRegion.EU; case AppLanguage.English_Australia: case AppLanguage.English_Canada: case AppLanguage.English: case AppLanguage.English_NewZealand: case AppLanguage.Spanish_Mexico: case AppLanguage.French_Canada: case AppLanguage.English_USA: return ConsoleRegion.US; case AppLanguage.Korean_South_Korea: case AppLanguage.Chinese_China: case AppLanguage.Chinese_HongKong: case AppLanguage.Chinese_Singapore: case AppLanguage.Chinese_Taiwan: case AppLanguage.Japanese_Japan: return ConsoleRegion.JP; case AppLanguage.Portuguese_Brazil: case AppLanguage.Portuguese_Portugal: case AppLanguage.Latin: default: throw new NotImplementedException(); } } } }