Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Extreme low downloads when downloading game resources for the first time. #112

Open
xNexusACS opened this issue Dec 11, 2024 · 4 comments
Labels
bug Something isn't working

Comments

@xNexusACS
Copy link

Describe the bug
Extreme slow download of game resources and assets when downloading for the first time (Download speed capped to 20Mbps for the process).

Environment (please complete the following information):

  • OS: Windows 11
  • CmlLib.Core Version: 3.3.10
  • .NET version: .NET 9
@xNexusACS xNexusACS added the bug Something isn't working label Dec 11, 2024
@AlphaBs
Copy link
Member

AlphaBs commented Dec 11, 2024

can you post your source code? and also test your internet speed via very big file.

var httpClient = new HttpClient();
var response = await httpClient.GetAsync("https://ash-speed.hetzner.com/10GB.bin", HttpCompletionOption.ResponseHeadersRead);
using var stream = await response.Content.ReadAsStreamAsync();
byte[] buffer = new byte[8192];
while (await stream.ReadAsync(buffer) > 0) ;

@xNexusACS
Copy link
Author

xNexusACS commented Dec 11, 2024

can you post your source code? and also test your internet speed via very big file.

var httpClient = new HttpClient();
var response = await httpClient.GetAsync("https://ash-speed.hetzner.com/10GB.bin", HttpCompletionOption.ResponseHeadersRead);
using var stream = await response.Content.ReadAsStreamAsync();
byte[] buffer = new byte[8192];
while (await stream.ReadAsync(buffer) > 0) ;

Tested internet speed: 300Mbps.

Source code:

using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Reflection;
using CmlLib.Core;
using CmlLib.Core.Auth.Microsoft;
using CmlLib.Core.Installer.FabricMC;
using CmlLib.Utils;
using ICSharpCode.SharpZipLib.Zip;
using WhiteFlameLauncher.Components;

namespace WhiteFlameLauncher;

public partial class MainForm : Form
{
    private readonly Label _lblStatus;
    private readonly CurvedProgressBar _progressBar;
    
    public MainForm()
    {
        var privateFontCollection = new PrivateFontCollection();
        
        var assembly = Assembly.GetExecutingAssembly();
        using (var stream = assembly.GetManifestResourceStream("WhiteFlameLauncher.Resources.app_icon.ico"))
        {
            if (stream != null)
            {
                Icon = new Icon(stream);
            }
        }
        using (var fontStream = assembly.GetManifestResourceStream("WhiteFlameLauncher.Resources.Inter-Regular.otf"))
        {
            if (fontStream != null)
            {
                var fontData = new byte[fontStream.Length];
                fontStream.ReadExactly(fontData);

                unsafe
                {
                    fixed (byte* pFontData = fontData)
                    {
                        privateFontCollection.AddMemoryFont((IntPtr)pFontData, fontData.Length);
                    }
                }
            }
        }

        var interFont = new Font(privateFontCollection.Families[0], 36, FontStyle.Bold);
        
        Text = "White Flame Launcher";
        ClientSize = new Size(1280, 720);
        MinimumSize = new Size(1280, 720);
        BackColor = Color.Black;
        FormBorderStyle = FormBorderStyle.FixedDialog;
        StartPosition = FormStartPosition.CenterScreen;
        MaximizeBox = false;
        MinimizeBox = false;
        
        var lblTitle = new Label
        {
            Text = "Please Log-In",
            Font = interFont,
            ForeColor = Color.White,
            AutoSize = true,
            BackColor = Color.Transparent
        };
        Controls.Add(lblTitle);

        var lblSubtitle = new Label
        {
            Text = "with your account",
            Font = interFont,
            ForeColor = Color.White,
            AutoSize = true,
            BackColor = Color.Transparent
        };
        Controls.Add(lblSubtitle);

        var lblSubSubtitle = new Label
        {
            Text = "Asset download and game will start automatically",
            Font = new Font(privateFontCollection.Families[0], 14, FontStyle.Regular),
            ForeColor = Color.White,
            AutoSize = true,
            BackColor = Color.Transparent
        };
        Controls.Add(lblSubSubtitle);
        
        var btnMicrosoftAccount = new RoundedButton
        {
            Text = "Microsoft Account",
            Font = new Font(privateFontCollection.Families[0], 14, FontStyle.Regular),
            ForeColor = Color.White,
            BackColor = Color.FromArgb(102, 20, 63),
            FlatStyle = FlatStyle.Flat,
            Width = 250,
            Height = 60,
            Location = new Point((ClientSize.Width - 250) / 2, 300),
            TextAlign = ContentAlignment.MiddleRight,
            ImageAlign = ContentAlignment.MiddleLeft,
            Padding = new Padding(10, 0, 0, 0)
        };
        
        _lblStatus = new Label
        {
            Font = new Font(privateFontCollection.Families[0], 12, FontStyle.Regular),
            ForeColor = Color.White,
            AutoSize = true,
            BackColor = Color.Transparent,
            Location = new Point(10, ClientSize.Height - 60)
        };
        Controls.Add(_lblStatus);

        _progressBar = new CurvedProgressBar
        {
            Width = 400,
            Height = 30,
            Minimum = 0,
            Maximum = 100,
            Value = 0,
            Visible = false,
            Location = new Point((ClientSize.Width - 400) / 2, ClientSize.Height - 100)
        };
        Controls.Add(_progressBar);
        
        using (var stream = assembly.GetManifestResourceStream("WhiteFlameLauncher.Resources.microsoft-brands-solid.png"))
        {
            if (stream != null)
            {
                var image = new Bitmap(Image.FromStream(stream), new Size(24, 24));
                btnMicrosoftAccount.Image = image;
            }
        }
        
        btnMicrosoftAccount.FlatAppearance.BorderSize = 0;
        btnMicrosoftAccount.Click += BtnMicrosoftAccount_Click;
        Controls.Add(btnMicrosoftAccount);
        
        Resize += (sender, e) =>
        {
            lblTitle.Location = new Point((ClientSize.Width - lblTitle.Width) / 2, 200);
            lblSubtitle.Location = new Point((ClientSize.Width - lblSubtitle.Width) / 2, 300);
            lblSubSubtitle.Location = new Point((ClientSize.Width - lblSubtitle.Width) / 2, 400);
            btnMicrosoftAccount.Location = new Point((ClientSize.Width - btnMicrosoftAccount.Width) / 2, 450);
        };
        
        lblTitle.Location = new Point((ClientSize.Width - lblTitle.Width) / 2, 200);
        lblSubtitle.Location = new Point((ClientSize.Width - lblSubtitle.Width) / 2, 300);
        lblSubSubtitle.Location = new Point((ClientSize.Width - lblSubtitle.Width) / 2, 400);
        btnMicrosoftAccount.Location = new Point((ClientSize.Width - btnMicrosoftAccount.Width) / 2, 450);

        InitializeComponent();
    }

    private async void BtnMicrosoftAccount_Click(object? sender, EventArgs e)
    {
        try
        {
            _lblStatus.Text = "Authenticating...";
            _lblStatus.Refresh();

            if (!Directory.Exists("/instances/"))
                Directory.CreateDirectory("/instances/");

            var loginHandler = JELoginHandlerBuilder.BuildDefault();
            var session = await loginHandler.Authenticate();
            _lblStatus.Text = "Authentication successful";
            _lblStatus.Refresh();

            _lblStatus.Text = "Downloading and Installing Assets...";
            _lblStatus.Refresh();
            _progressBar.Visible = true;
            
            //const string modsDownloadUrl = "https://REDACTED/mods.zip";
            //await DownloadAndExtractModsZip(modsDownloadUrl);
            
            var path = new MinecraftPath("/instances");
            var launcher = new CMLauncher(path);

            var fabricVersionLoader = new FabricVersionLoader();
            var fabricVersions = await fabricVersionLoader.GetVersionMetadatasAsync();
            var fabric = fabricVersions.GetVersionMetadata("fabric-loader-0.16.9-1.20.1");
            await fabric.SaveAsync(path);
            
            await launcher.GetAllVersionsAsync();
            
            for (var i = 0; i <= 100; i++)
            {
                _progressBar.Value = i;
                _progressBar.Refresh();
                await Task.Delay(50);
            }

            _progressBar.Visible = false;
            _lblStatus.Text = "Starting Minecraft...";
            _lblStatus.Refresh();

            var process = await launcher.CreateProcessAsync("fabric-loader-0.16.9-1.20.1", new MLaunchOption
            {
                Session = session,
                GameLauncherName = "White Flame Studio: Minecraft",
                GameLauncherVersion = "2",
                MaximumRamMb = 8094,
                MinimumRamMb = 1027,
            });
            
            var logForm = new LogForm();
            logForm.Show();
            
            var processUtil = new ProcessUtil(process);
            processUtil.OutputReceived += (s, e) => logForm.AppendLog(e);
            processUtil.StartWithEvents();
        }
        catch (Exception exception)
        {
            MessageBox.Show(exception.Message);
            
            _lblStatus.Text = string.Empty;
            _lblStatus.Refresh();
            _progressBar.Visible = false;
        }
    }
    
    private async Task DownloadAndExtractModsZip(string downloadUrl)
    {
        try
        {
            _lblStatus.Text = "Downloading mods...";
            _lblStatus.Refresh();

            var modsFolderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location) ?? string.Empty, "instances", "mods");
            Directory.CreateDirectory(modsFolderPath);

            var zipFilePath = Path.Combine(modsFolderPath, "mods.zip");
            
            using (var httpClient = new HttpClient())
            {
                using (var response = await httpClient.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead))
                {
                    response.EnsureSuccessStatusCode();

                    await using (var fs = new FileStream(zipFilePath, FileMode.Create, FileAccess.Write, FileShare.None))
                    {
                        await response.Content.CopyToAsync(fs);
                    }
                }
            }

            _lblStatus.Text = "Extracting mods...";
            _lblStatus.Refresh();

            await using (var fs = File.OpenRead(zipFilePath))
            await using (var zipInputStream = new ZipInputStream(fs))
            {
                while (zipInputStream.GetNextEntry() is { } entry)
                {
                    if (entry.IsDirectory)
                        continue;

                    var entryFilePath = Path.Combine(modsFolderPath, entry.Name);

                    Directory.CreateDirectory(Path.GetDirectoryName(entryFilePath) ?? string.Empty);

                    await using var entryStream = File.Create(entryFilePath);
                    await zipInputStream.CopyToAsync(entryStream);
                }
            }
            
            File.Delete(zipFilePath);

            _lblStatus.Text = "Mods downloaded and extracted!";
            _lblStatus.Refresh();
        }
        catch (Exception ex)
        {
            MessageBox.Show($"{ex.Message}");
            
            _lblStatus.Text = string.Empty;
            _lblStatus.Refresh();
            _progressBar.Visible = false;
        }
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
        using var brush = new LinearGradientBrush(ClientRectangle, Color.Black, Color.FromArgb(20, 20, 20), LinearGradientMode.ForwardDiagonal);
        e.Graphics.FillRectangle(brush, ClientRectangle);
    }
}

@AlphaBs
Copy link
Member

AlphaBs commented Dec 12, 2024

  1. Which version did you try, and exactly how long did it take?
  2. Try deleting the .minecraft directory and reinstalling the same version of the game using the Mojang launcher. How long does it take?
  3. Your code is using an outdated library version. Have you tried using the latest library version?

@xNexusACS
Copy link
Author

I tried fabric 1.20.1 (latest loader: 0.16.9), took to download everything and launch the game like 8 - 10 minutes
Installing through the mojang launcher takes 2 minutes
I did not consider using the latest library version, I'll take a look

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants