private void FindProfiles() { if (!Directory.Exists(_profilesPath)) { Directory.CreateDirectory(_profilesPath); } if (!Directory.Exists(_profilesPath)) { return; } foreach (var profileId in Directory.EnumerateDirectories(_profilesPath).Select(Path.GetFileName)) { var path = Path.Combine(_profilesPath, profileId, ProfileIndexName); if (!File.Exists(path)) { continue; } try { _profiles.Add(profileId, _json.ReadFile <ProfileData>(path)); _log.Info($"Found profile: {profileId}"); } catch (Exception e) { _log.Error($"Corrupted profile {profileId}: {e.Message}"); } } }
public async Task Download( DownloadTarget[] targets, CancellationToken ct = default(CancellationToken), IProgress <DownloadingState> progress = null) { ct.ThrowIfCancellationRequested(); _log.Info("Downloading..."); var state = new DownloadingState { FileName = string.Empty, CurrentFile = 0, TotalFiles = targets.Length, CurrentBytes = 0, TotalBytes = targets.Sum(t => t.Size) }; var buffer = new byte[4096]; foreach (var target in targets) { _log.Info($"Get {target.Url} -> {target.Path}"); state.CurrentFile++; state.FileName = target.Path; progress?.Report(state); var targetDirectoryPath = Path.GetDirectoryName(target.Path); if (!Directory.Exists(targetDirectoryPath)) { Directory.CreateDirectory(targetDirectoryPath); } try { using (var httpStream = await _client.GetStreamAsync(target.Url)) using (var fileStream = File.Create(target.Path)) { int length; while ((length = await httpStream.ReadAsync(buffer, 0, buffer.Length, ct)) > 0) { await fileStream.WriteAsync(buffer, 0, length, ct); state.CurrentBytes += length; progress?.Report(state); } } } catch (HttpRequestException e) { _log.Error($"Can't download {target.Url}"); _log.Error(e.Message); } ct.ThrowIfCancellationRequested(); } _log.Info("Downloading complete"); }
public ProfilesManager(string dataDirectory, JsonParser json, ILogger logger) { _json = json; _hashStringBuilder = new StringBuilder(40); _log = new WrappedLogger(logger, "Profiles"); _log.Info("Initializing..."); var dataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); // XDG_DATA_HOME _profilesPath = Path.Combine(dataPath, dataDirectory, ProfilesDirectory); _versionsPath = Path.Combine(dataPath, dataDirectory, VersionsDirectory); FindProfiles(); _log.Info("Initialized!"); }
public void Start() { _log.Info("Starting..."); LoadWindowSettings(); _ui.SetWindowVisible(true); TryBecomeOnline(); }
public async Task <LoginResultData> Login(string userName, string password) { var url = string.Format(RequestPattern, _masterUrl, LoginAction); var payload = new LoginRequestData { Agent = new LoginRequestData.AgentData { Name = "Minecraft", Version = 1 }, Platform = new LoginRequestData.PlatformData { Name = Platform.Name, Version = Platform.Version, WordSize = Platform.WordSize }, UserName = userName, Password = password, Ticket = _ticket, Version = _version }; _log.Info($"Logging as {userName}..."); LoginResultData reply; try { reply = await PostJson <LoginResultData>(url, payload); } catch (Exception e) { _log.Error(e.Message); throw; } if (reply.Error != null) { _log.Error($"{reply.Error} '{reply.ErrorMessage}'"); throw new ErrorAnswerException(reply.ErrorMessage ?? reply.Error); } _log.Info($"at: '{reply.AccessToken}', ct: '{reply.ClientToken}'"); return(reply); }
public async Task <DownloadTarget[]> CheckFiles( DownloadTarget[] targets, CancellationToken ct = default(CancellationToken), IProgress <CheckingState> progress = null) { ct.ThrowIfCancellationRequested(); _log.Info("Checking files..."); var result = new List <DownloadTarget>(targets.Length); var state = new CheckingState { FileName = string.Empty, CurrentFile = 0, TotalFiles = targets.Length }; var context = SynchronizationContext.Current; void Report(string path) { context?.Post(args => { var filePath = args as string ?? string.Empty; _log.Info($"Checking file {filePath}..."); state.FileName = filePath; state.CurrentFile++; progress?.Report(state); }, path); } var tasks = targets.Select(target => Task.Run(() => CheckTarget(target, result, Report), ct)); await Task.WhenAll(tasks); _log.Info($"Checking files completed. Need to update {result.Count} files."); return(result.ToArray()); }
public VersionsManager(string storeUrl, string dataDir, HttpClient client, JsonParser json, ILogger logger) { _storeUrl = storeUrl; _client = client; _json = json; _log = new WrappedLogger(logger, "Versions"); _log.Info("Initializing..."); Prefixes = new CachedPrefixInfo[0]; var dataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); // XDG_DATA_HOME _versionsPath = Path.Combine(dataPath, dataDir, VersionsDirectory); _assetsPath = Path.Combine(dataPath, dataDir, AssetsDirectory); _librariesPath = Path.Combine(dataPath, dataDir, LibrariesDirectory); _indexPath = Path.Combine(_versionsPath, IndexName); if (!Directory.Exists(_versionsPath)) { Directory.CreateDirectory(_versionsPath); } if (File.Exists(_indexPath)) { try { _index = _json.ReadFile <PrefixesIndex>(_indexPath); } catch (JsonSerializationException e) { _log.Error("Can't parse local prefixes index: " + e.Message); } } _index = _index ?? new PrefixesIndex(); _log.Info($"Initialized with {_index.Prefixes.Count} prefix(es)!"); }
public async Task Run(string id, ProfileData data, string userName, string clientToken, string accessToken) { var prefix = data.FullVersion.Prefix; var version = data.FullVersion.Version; var versionIndexPath = Path.Combine(_versionsPath, prefix, version, $"{version}.json"); var versionIndex = _json.ReadFile <VersionIndex>(versionIndexPath); var nativesDir = Path.Combine(_nativesPath, Guid.NewGuid().ToString()); if (Directory.Exists(nativesDir)) { Directory.CreateDirectory(nativesDir); } var classPath = new List <string>(); foreach (var libraryInfo in versionIndex.Libraries) { if (!IndexTool.IsLibraryAllowed(libraryInfo)) { continue; } var libPath = Path.Combine(_librariesPath, IndexTool.GetLibraryPath(libraryInfo)); if (libraryInfo.Natives != null) { ZipFile.ExtractToDirectory(libPath, nativesDir, true); } else { classPath.Add(libPath); } } classPath.Add(Path.Combine(_versionsPath, prefix, version, $"{version}.jar")); var args = new List <string>(25); if (data.UseCustomJavaArgs && !string.IsNullOrEmpty(data.CustomJavaArgs)) { args.AddRange(data.CustomJavaArgs.Trim().Split(' ')); } args.AddRange(new [] { "-Dline.separator=\r\n", "-Dfile.encoding=UTF8", "-Dminecraft.launcher.brand=" + _launcherName, "-Dminecraft.launcher.version=" + _launcherVersion, "-Djava.library.path=" + nativesDir, "-cp", string.Join(Platform.ClassPathSeparator, classPath), versionIndex.MainClass }); var profileDir = Path.Combine(_profilesPath, id); var gameArgsMap = new Dictionary <string, string> { { "${auth_player_name}", userName }, { "${version_name}", version }, { "${auth_uuid}", clientToken }, { "${auth_access_token}", accessToken }, { "${game_directory}", profileDir }, { "${assets_root}", _assetsPath }, { "${assets_index_name}", IndexTool.GetAssetIndexName(versionIndex) }, { "${user_properties}", "{}" }, { "${user_type}", "mojang" }, { "${version_type}", prefix } }; var gameArguments = IndexTool.GetMinecraftArguments(versionIndex); for (var i = 0; i < gameArguments.Length; i++) { var token = gameArguments[i]; if (gameArgsMap.ContainsKey(token)) { gameArguments[i] = gameArgsMap[token]; } } args.AddRange(gameArguments); var javaPath = "java"; if (data.UseCustomJavaPath && !string.IsNullOrEmpty(data.CustomJavaPath)) { javaPath = data.CustomJavaPath; } _log.Info($"{javaPath} {string.Join(' ', args)}"); var exitCode = await RunProcessAsync(javaPath, profileDir, args); _log.Info($"Client terminated with exit code {exitCode}"); Directory.Delete(nativesDir, true); }
public async Task FetchPrefixes() { _log.Info("Fetching versions..."); PrefixesIndex prefixesIndex; var remoteVersions = new Dictionary <string, PrefixVersionsIndex>(); try { _log.Info("Fetching prefixes.json..."); prefixesIndex = await ParseJsonFromUrlAsync <PrefixesIndex>($"{_storeUrl}/prefixes.json"); foreach (var(prefixId, _) in prefixesIndex.Prefixes) { _log.Info($"Fetching prefix '{prefixId}'..."); var versionsIndexUrl = $"{_storeUrl}/{prefixId}/versions/versions.json"; remoteVersions.Add(prefixId, await ParseJsonFromUrlAsync <PrefixVersionsIndex>(versionsIndexUrl)); } } catch (HttpRequestException e) { _log.Error("Network request error: " + e.Message); throw; } catch (JsonSerializationException e) { _log.Error("Can't parse fetched data: " + e.Message); throw; } foreach (var(prefixId, prefixEntry) in prefixesIndex.Prefixes) { _index.Prefixes[prefixId] = prefixEntry; } _json.WriteFile(_index, _indexPath); UpdatePrefixes(remoteVersions); _log.Info("Fetching finished!"); }