• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!
  • 2026 staff recruitment is open! Check it out and consider applying!

OpenTibia Desktop Launcher made in C# with Source Code

otserverstore

New Member
Joined
Sep 5, 2025
Messages
1
Reaction score
2
Modern Launcher for Ot Servers with Source Code



C#:
<!-- MainWindow.xaml (INTERFACE) -->
    
<Window x:Class="OTLauncher.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="OTServer Store Launcher" Height="500" Width="800"
        WindowStartupLocation="CenterScreen">

    <Grid>
      
        <Image Source="pack://application:,,,/Assets/background.png" Stretch="Fill"/>

        <Button Width="150" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center"
                Click="Play_Click" FontSize="18" Foreground="White" Content="▶ JOGAR" Background="Green" BorderThickness="0">
            <Button.Template>
                <ControlTemplate TargetType="Button">
                    <Grid>
                        <Border x:Name="border" Background="{TemplateBinding Background}" CornerRadius="5"/>
                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="border" Property="Effect">
                                <Setter.Value>
                                    <DropShadowEffect Color="Lime" BlurRadius="20" ShadowDepth="0"/>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="False">
                            <Setter TargetName="border" Property="Effect">
                                <Setter.Value>
                                    <DropShadowEffect Color="Transparent" BlurRadius="0" ShadowDepth="0"/>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Button.Template>
        </Button>

        <StackPanel x:Name="ProgressPanel" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,120" Visibility="Collapsed">
            <ProgressBar x:Name="DownloadProgress" Width="400" Height="20" Minimum="0" Maximum="100"/>
            <TextBlock x:Name="ProgressText" Foreground="White" FontSize="14" HorizontalAlignment="Center" Margin="0,5,0,0"/>
        </StackPanel>

        <StackPanel Orientation="Vertical" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,20,0">

            <!-- WPP -->
            <Button Width="80" Height="80" Click="WhatsApp_Click" Background="Transparent" BorderThickness="0" Margin="0,0,0,10">
                <Button.Template>
                    <ControlTemplate TargetType="Button">
                        <Image x:Name="icon" Source="pack://application:,,,/Assets/whatsapp.png" Stretch="Uniform" RenderTransformOrigin="0.5,0.5">
                            <Image.RenderTransform>
                                <ScaleTransform ScaleX="1" ScaleY="1"/>
                            </Image.RenderTransform>
                            <Image.Effect>
                                <DropShadowEffect Color="Transparent" ShadowDepth="0" BlurRadius="0"/>
                            </Image.Effect>
                        </Image>
                        <ControlTemplate.Triggers>
                            <EventTrigger RoutedEvent="MouseEnter">
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="RenderTransform.ScaleX" To="1.2" Duration="0:0:0.2"/>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="RenderTransform.ScaleY" To="1.2" Duration="0:0:0.2"/>
                                        <ColorAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="Effect.Color" To="Lime" Duration="0:0:0.2"/>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="Effect.BlurRadius" To="20" Duration="0:0:0.2"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                            <EventTrigger RoutedEvent="MouseLeave">
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="RenderTransform.ScaleX" To="1" Duration="0:0:0.2"/>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="RenderTransform.ScaleY" To="1" Duration="0:0:0.2"/>
                                        <ColorAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="Effect.Color" To="Transparent" Duration="0:0:0.2"/>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="Effect.BlurRadius" To="0" Duration="0:0:0.2"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Button.Template>
            </Button>

            <!-- DISC -->
            <Button Width="80" Height="80" Click="Discord_Click" Background="Transparent" BorderThickness="0" Margin="0,0,0,10">
                <Button.Template>
                    <ControlTemplate TargetType="Button">
                        <Image x:Name="icon" Source="pack://application:,,,/Assets/discordinho.png" Stretch="Uniform" RenderTransformOrigin="0.5,0.5">
                            <Image.RenderTransform>
                                <ScaleTransform ScaleX="1" ScaleY="1"/>
                            </Image.RenderTransform>
                            <Image.Effect>
                                <DropShadowEffect Color="Transparent" ShadowDepth="0" BlurRadius="0"/>
                            </Image.Effect>
                        </Image>
                        <ControlTemplate.Triggers>
                            <EventTrigger RoutedEvent="MouseEnter">
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="RenderTransform.ScaleX" To="1.2" Duration="0:0:0.2"/>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="RenderTransform.ScaleY" To="1.2" Duration="0:0:0.2"/>
                                        <ColorAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="Effect.Color" To="Purple" Duration="0:0:0.2"/>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="Effect.BlurRadius" To="20" Duration="0:0:0.2"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                            <EventTrigger RoutedEvent="MouseLeave">
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="RenderTransform.ScaleX" To="1" Duration="0:0:0.2"/>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="RenderTransform.ScaleY" To="1" Duration="0:0:0.2"/>
                                        <ColorAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="Effect.Color" To="Transparent" Duration="0:0:0.2"/>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="Effect.BlurRadius" To="0" Duration="0:0:0.2"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Button.Template>
            </Button>

            <!-- INSTA -->
            <Button Width="80" Height="80" Click="Instagram_Click" Background="Transparent" BorderThickness="0">
                <Button.Template>
                    <ControlTemplate TargetType="Button">
                        <Image x:Name="icon" Source="pack://application:,,,/Assets/insta.png" Stretch="Uniform" RenderTransformOrigin="0.5,0.5">
                            <Image.RenderTransform>
                                <ScaleTransform ScaleX="1" ScaleY="1"/>
                            </Image.RenderTransform>
                            <Image.Effect>
                                <DropShadowEffect Color="Transparent" ShadowDepth="0" BlurRadius="0"/>
                            </Image.Effect>
                        </Image>
                        <ControlTemplate.Triggers>
                            <EventTrigger RoutedEvent="MouseEnter">
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="RenderTransform.ScaleX" To="1.2" Duration="0:0:0.2"/>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="RenderTransform.ScaleY" To="1.2" Duration="0:0:0.2"/>
                                        <ColorAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="Effect.Color" To="HotPink" Duration="0:0:0.2"/>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="Effect.BlurRadius" To="20" Duration="0:0:0.2"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                            <EventTrigger RoutedEvent="MouseLeave">
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="RenderTransform.ScaleX" To="1" Duration="0:0:0.2"/>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="RenderTransform.ScaleY" To="1" Duration="0:0:0.2"/>
                                        <ColorAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="Effect.Color" To="Transparent" Duration="0:0:0.2"/>
                                        <DoubleAnimation Storyboard.TargetName="icon" Storyboard.TargetProperty="Effect.BlurRadius" To="0" Duration="0:0:0.2"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Button.Template>
            </Button>

        </StackPanel>

        <!-- RODAPÉ -->
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,10">
            <TextBlock VerticalAlignment="Center" Foreground="White" FontSize="14">
                Desenvolvido por:
                <Hyperlink NavigateUri="https://otserverstore.online/" RequestNavigate="Hyperlink_RequestNavigate">
                    OTServer Store
                </Hyperlink>
            </TextBlock>
            <Image Source="pack://application:,,,/Assets/otstore_logo.png" Width="30" Height="30" Margin="5,0,0,0"/>
        </StackPanel>
    </Grid>
</Window>




<!-- MainWindow.xaml.cs -->


C#:
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Navigation;

namespace OTLauncher
{
    public partial class MainWindow : Window
    {
        private string urlZip = "https://SEUSITE/SEUZIP.zip";
        private string zipName = "NOMEDOSEUZIP.zip";
        private string extractFolder = "NOMEDAPASTAPRAEXTRAIR";

        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Play_Click(object sender, RoutedEventArgs e)
        {
            if (!Directory.Exists(extractFolder))
            {
                ProgressPanel.Visibility = Visibility.Visible;
                await DownloadAndExtract(urlZip, zipName, extractFolder);
                ProgressPanel.Visibility = Visibility.Collapsed;
            }

            RendererChoiceWindow rendererWindow = new RendererChoiceWindow();
            rendererWindow.Owner = this;
            rendererWindow.ShowDialog();
        }

        private async Task DownloadAndExtract(string url, string zipName, string extractFolder)
        {
            try
            {
                using (HttpClient client = new HttpClient())
                using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
                {
                    response.EnsureSuccessStatusCode();
                    var totalBytes = response.Content.Headers.ContentLength ?? -1L;
                    var canReportProgress = totalBytes != -1;

                    using (var contentStream = await response.Content.ReadAsStreamAsync())
                    using (var fs = new FileStream(zipName, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true))
                    {
                        var buffer = new byte[8192];
                        long totalRead = 0;
                        int read;
                        while ((read = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                        {
                            await fs.WriteAsync(buffer, 0, read);
                            totalRead += read;

                            if (canReportProgress)
                            {
                                double progress = (double)totalRead / totalBytes * 100;
                                DownloadProgress.Value = progress;
                                ProgressText.Text = $"Baixando... {progress:F1}% ({totalRead / 1024 / 1024}MB / {totalBytes / 1024 / 1024}MB)";
                            }
                            else
                            {
                                ProgressText.Text = $"Baixando... {totalRead / 1024 / 1024}MB";
                            }
                        }
                    }
                }

                using (var archive = ZipFile.OpenRead(zipName))
                {
                    foreach (var entry in archive.Entries)
                    {
                        string fullPath = Path.Combine(extractFolder, entry.FullName);
                        if (entry.FullName.EndsWith("/"))
                            Directory.CreateDirectory(fullPath);
                        else
                        {
                            Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!);
                            entry.ExtractToFile(fullPath, true);
                        }
                    }
                }

                File.Delete(zipName);

                ProgressText.Text = "Download concluído!";
                MessageBox.Show($"Download concluído!");
            }
            catch (Exception ex)
            {
                ProgressText.Text = "";
                MessageBox.Show($"Erro ao baixar {zipName}:\n{ex.Message}");
            }
        }

        public static void StartClientStatic(string renderer)
        {
            try
            {
                string exe = renderer.ToLower().Contains("gl")
                    ? Path.Combine("Folder1", "Folder2", "otclientgl.exe")
                    : Path.Combine("Folder1", "Folder2", "otclientdx.exe");

                string args = renderer.ToLower().Contains("gl") ? "--renderer gl" : "--renderer dx";

                Process.Start(new ProcessStartInfo(exe, args) { UseShellExecute = true });
                Application.Current.Shutdown();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Erro ao iniciar o cliente:\n{ex.Message}");
            }
        }

        private void WhatsApp_Click(object sender, RoutedEventArgs e) => OpenUrl("https://wa.me/seulink");
        private void Discord_Click(object sender, RoutedEventArgs e) => OpenUrl("https://discord.gg/seulink");
        private void Instagram_Click(object sender, RoutedEventArgs e) => OpenUrl("https://instagram.com/seuinsta");

        private void OpenUrl(string url)
        {
            try { Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }); }
            catch { }
        }

        private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
        {
            Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true });
        }

        private void Minimize_Click(object sender, RoutedEventArgs e) => this.WindowState = WindowState.Minimized;
        private void Maximize_Click(object sender, RoutedEventArgs e)
        {
            this.WindowState = this.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
        }
        private void Close_Click(object sender, RoutedEventArgs e) => this.Close();
    }
}



<!-- RendererChoiceWindow.xaml (INTERFACE RENDERER) -->

C#:
<Window x:Class="OTLauncher.RendererChoiceWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Escolha o Renderer" Height="200" Width="300"
        WindowStartupLocation="CenterOwner"
        WindowStyle="None"
        Background="#FF1E1E1E"
        ResizeMode="NoResize"
        Closing="Window_Closing">

    <Grid>
        <TextBlock Text="Escolha o Renderer" FontSize="16" Foreground="White"
                   HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,20,0,0"/>

        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Orientation="Horizontal">
            <!-- GL -->
            <Button Width="100" Height="40" Click="OpenGL_Click" Background="#FF3C8DBC"
                    Foreground="White" FontWeight="Bold" Content="OpenGL" Margin="10,0">
                <Button.Template>
                    <ControlTemplate TargetType="Button">
                        <Grid>
                            <Border x:Name="border" Background="{TemplateBinding Background}" CornerRadius="5"/>
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"
                                              Content="{TemplateBinding Content}"
                                              TextElement.Foreground="{TemplateBinding Foreground}"
                                              TextElement.FontWeight="{TemplateBinding FontWeight}"/>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="border" Property="Effect">
                                    <Setter.Value>
                                        <DropShadowEffect Color="Cyan" BlurRadius="20" ShadowDepth="0"/>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Button.Template>
            </Button>

            <!-- DX -->
            <Button Width="100" Height="40" Click="DirectX_Click" Background="#FFD9534F"
                    Foreground="White" FontWeight="Bold" Content="DirectX" Margin="10,0">
                <Button.Template>
                    <ControlTemplate TargetType="Button">
                        <Grid>
                            <Border x:Name="border" Background="{TemplateBinding Background}" CornerRadius="5"/>
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"
                                              Content="{TemplateBinding Content}"
                                              TextElement.Foreground="{TemplateBinding Foreground}"
                                              TextElement.FontWeight="{TemplateBinding FontWeight}"/>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="border" Property="Effect">
                                    <Setter.Value>
                                        <DropShadowEffect Color="Red" BlurRadius="20" ShadowDepth="0"/>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Button.Template>
            </Button>
        </StackPanel>

        <Button Content="X" Width="25" Height="25" HorizontalAlignment="Right"
                VerticalAlignment="Top" Margin="0,5,5,0" Click="Close_Click"/>
    </Grid>
</Window>




RendererChoiceWindow.xaml.cs



C#:
using System.Windows;

namespace OTLauncher
{
    public partial class RendererChoiceWindow : Window
    {
        private bool allowClose = false;

        public RendererChoiceWindow()
        {
            InitializeComponent();
        }

        private void OpenGL_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.StartClientStatic("gl");
            allowClose = true;
            this.Close();
        }

        private void DirectX_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.StartClientStatic("dx");
            allowClose = true;
            this.Close();
        }

        private void Close_Click(object sender, RoutedEventArgs e)
        {
            allowClose = true;
            this.Close();
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (!allowClose)
                e.Cancel = true;
        }
    }
}





1-You must create Assets folder inside the project and insert images for social medias and background

2- I wont answer question like "how to compile it", if you do not know u can ask gpt how to compile using visual studio... thats a easy task

3- U can choose where to host the download and the Launcher will check if the files are there and download it or update it if not, the it will open the client in dx or gl like the user want

4- Use it free, good luck
 

Attachments

Back
Top