Example #1
0
        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}");
                }
            }
        }
Example #2
0
        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");
        }
Example #3
0
        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!");
        }
Example #4
0
        public void Start()
        {
            _log.Info("Starting...");

            LoadWindowSettings();
            _ui.SetWindowVisible(true);
            TryBecomeOnline();
        }
Example #5
0
        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);
        }
Example #6
0
        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());
        }
Example #7
0
        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)!");
        }
Example #8
0
        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);
        }
Example #9
0
        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!");
        }