Refactor launcher GUI

This commit is contained in:
Drew DeVault 2015-06-02 17:39:44 -06:00
parent fcfd388674
commit c8497b887a
9 changed files with 326 additions and 80 deletions

View File

@ -63,34 +63,25 @@
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup Condition=" '$(OS)' == 'Unix' ">
<Reference Include="MonoGame.Framework, Version=3.4.0.459, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="MonoGame.Framework, Version=3.4.0.459, Culture=neutral, PublicKeyToken=null">
<HintPath>..\packages\MonoGame.Framework.Linux.3.4.0.459\lib\net40\MonoGame.Framework.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenTK, Version=1.1.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4">
<HintPath>..\packages\MonoGame.Framework.Linux.3.4.0.459\lib\net40\OpenTK.dll</HintPath>
</Reference>
<Reference Include="Tao.Sdl, Version=1.2.13.0, Culture=neutral, PublicKeyToken=9c7a200e36c0094e">
<HintPath>..\packages\MonoGame.Framework.Linux.3.4.0.459\lib\net40\Tao.Sdl.dll</HintPath>
</Reference>
<Reference Include="MonoGame.Framework">
<HintPath>..\packages\MonoGame.Framework.WindowsGL.3.4.0.459\lib\net40\MonoGame.Framework.dll</HintPath>
</Reference>
<Reference Include="OpenTK">
<HintPath>..\packages\MonoGame.Framework.WindowsGL.3.4.0.459\lib\net40\OpenTK.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Reference Include="OpenTK, Version=1.1.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>..\packages\MonoGame.Framework.Linux.3.4.0.459\lib\net40\OpenTK.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="Tao.Sdl, Version=1.2.13.0, Culture=neutral, PublicKeyToken=9c7a200e36c0094e, processorArchitecture=MSIL">
<HintPath>..\packages\MonoGame.Framework.Linux.3.4.0.459\lib\net40\Tao.Sdl.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup Condition=" '$(OS)' == 'Windows_NT' ">
<Reference Include="MonoGame.Framework, Version=3.4.0.459, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\MonoGame.Framework.WindowsGL.3.4.0.459\lib\net40\MonoGame.Framework.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenTK, Version=1.1.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\MonoGame.Framework.WindowsGL.3.4.0.459\lib\net40\OpenTK.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />

View File

@ -4,6 +4,9 @@ namespace TrueCraft.Core
{
public class TrueCraftUser
{
public static string AuthServer = "http://localhost";
public string Username { get; set; }
public string SessionId { get; set; }
}
}

View File

@ -2,79 +2,43 @@
using Xwt;
using System.Diagnostics;
using Xwt.Drawing;
using TrueCraft.Launcher.Views;
using TrueCraft.Core;
namespace TrueCraft.Launcher
{
public class LauncherWindow : Window
{
public TrueCraftUser User { get; set; }
public HBox MainContainer { get; set; }
public ScrollView WebScrollView { get; set; }
public WebView WebView { get; set; }
public VBox LoginContainer { get; set; }
public TextEntry UsernameText { get; set; }
public PasswordEntry PasswordText { get; set; }
public TextEntry ServerIPText { get; set; }
public Button LogInButton { get; set; }
public Button RegisterButton { get; set; }
public ImageView TrueCraftLogoImage { get; set; }
public LoginView LoginView { get; set; }
public MainMenuView MainMenuView { get; set; }
public MultiplayerView MultiplayerView { get; set; }
public LauncherWindow()
{
this.Title = "TrueCraft Launcher";
this.Width = 1200;
this.Height = 576;
this.User = new TrueCraftUser();
MainContainer = new HBox();
WebScrollView = new ScrollView();
WebView = new WebView("http://truecraft.io/updates");
LoginContainer = new VBox();
UsernameText = new TextEntry();
PasswordText = new PasswordEntry();
ServerIPText = new TextEntry();
LogInButton = new Button("Log In");
RegisterButton = new Button("Register");
TrueCraftLogoImage = new ImageView(Image.FromFile("Content/truecraft-logo.png"));
LoginView = new LoginView(this);
MultiplayerView = new MultiplayerView(this);
LoginContainer.MinWidth = 250;
ServerIPText.PlaceholderText = "Server address";
UsernameText.PlaceholderText = "Username";
PasswordText.PlaceholderText = "Password";
RegisterButton.Clicked += (sender, e) => WebView.Url = "http://truecraft.io/register";
LogInButton.Clicked += HandleLogInClicked;
LoginContainer.PackStart(TrueCraftLogoImage);
LoginContainer.PackEnd(RegisterButton);
LoginContainer.PackEnd(LogInButton);
LoginContainer.PackEnd(ServerIPText);
LoginContainer.PackEnd(PasswordText);
LoginContainer.PackEnd(UsernameText);
WebScrollView.Content = WebView;
MainContainer.PackStart(WebScrollView, true);
MainContainer.PackEnd(LoginContainer);
MainContainer.PackEnd(LoginView);
this.Content = MainContainer;
}
void HandleLogInClicked(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(ServerIPText.Text) ||
string.IsNullOrEmpty(UsernameText.Text))
{
MessageDialog.ShowError("Username and server IP are required (for now)");
return;
}
var process = new Process();
if (RuntimeInfo.IsMono)
process.StartInfo = new ProcessStartInfo("mono", "TrueCraft.Client.exe " + ServerIPText.Text + " " + UsernameText.Text);
else
process.StartInfo = new ProcessStartInfo("TrueCraft.Client.exe", ServerIPText.Text + " " + UsernameText.Text);
process.EnableRaisingEvents = true;
process.Exited += (s, a) => Application.Invoke(ClientExited);
process.Start();
this.ShowInTaskbar = false;
this.Hide();
}
void ClientExited()
{
this.Show();

View File

@ -1,10 +1,15 @@
using System;
using Xwt;
using System.Threading;
using System.Net;
using TrueCraft.Core;
namespace TrueCraft.Launcher
{
class Program
{
public static LauncherWindow Window { get; set; }
[STAThread]
public static void Main(string[] args)
{
@ -14,11 +19,30 @@ namespace TrueCraft.Launcher
Application.Initialize(ToolkitType.Gtk);
else if (RuntimeInfo.IsWindows)
Application.Initialize(ToolkitType.Wpf);
var window = new LauncherWindow();
window.Show();
window.Closed += (sender, e) => Application.Exit();
var thread = new Thread(KeepSessionAlive);
thread.IsBackground = true;
thread.Priority = ThreadPriority.Lowest;
Window = new LauncherWindow();
thread.Start();
Window.Show();
Window.Closed += (sender, e) => Application.Exit();
Application.Run();
window.Dispose();
Window.Dispose();
thread.Abort();
}
private static void KeepSessionAlive()
{
while (true)
{
if (!string.IsNullOrEmpty(Window.User.SessionId))
{
var wc = new WebClient();
wc.DownloadString(string.Format(TrueCraftUser.AuthServer + "/session?name={0}&session={1}",
Window.User.Username, Window.User.SessionId));
}
Thread.Sleep(60 * 5 * 1000);
}
}
}
}

View File

@ -40,6 +40,9 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RuntimeInfo.cs" />
<Compile Include="LauncherWindow.cs" />
<Compile Include="Views\LoginView.cs" />
<Compile Include="Views\MainMenuView.cs" />
<Compile Include="Views\MultiplayerView.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@ -50,9 +53,6 @@
<Content Include="Xwt.Gtk.dll.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\truecraft-logo.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TrueCraft.API\TrueCraft.API.csproj">
@ -78,10 +78,14 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Content\" />
<Folder Include="Views\" />
</ItemGroup>
<ItemGroup>
<None Include="Xwt.WPF.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Content\truecraft-logo.png" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,133 @@
using System;
using Xwt;
using Xwt.Drawing;
using System.Reflection;
using TrueCraft.Core;
using System.Net;
using System.IO;
namespace TrueCraft.Launcher.Views
{
public class LoginView : VBox
{
public LauncherWindow Window { get; set; }
public TextEntry UsernameText { get; set; }
public PasswordEntry PasswordText { get; set; }
public Button LogInButton { get; set; }
public Button RegisterButton { get; set; }
public ImageView TrueCraftLogoImage { get; set; }
public Label ErrorLabel { get; set; }
public CheckBox RememberCheckBox { get; set; }
public LoginView(LauncherWindow window)
{
Window = window;
this.MinWidth = 250;
ErrorLabel = new Label("Username or password incorrect")
{
TextColor = Color.FromBytes(255, 0, 0),
TextAlignment = Alignment.Center,
Visible = false
};
UsernameText = new TextEntry();
PasswordText = new PasswordEntry();
LogInButton = new Button("Log In");
RegisterButton = new Button("Register");
RememberCheckBox = new CheckBox("Remember Me");
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("TrueCraft.Launcher.Content.truecraft-logo.png"))
TrueCraftLogoImage = new ImageView(Image.FromStream(stream));
UsernameText.PlaceholderText = "Username";
PasswordText.PlaceholderText = "Password";
PasswordText.KeyReleased += (sender, e) =>
{
if (e.Key == Key.Return || e.Key == Key.NumPadEnter)
LogInButton_Clicked(sender, e);
};
UsernameText.KeyReleased += (sender, e) =>
{
if (e.Key == Key.Return || e.Key == Key.NumPadEnter)
LogInButton_Clicked(sender, e);
};
RegisterButton.Clicked += (sender, e) => Window.WebView.Url = "http://truecraft.io/register";
LogInButton.Clicked += LogInButton_Clicked;
this.PackStart(TrueCraftLogoImage);
this.PackEnd(RegisterButton);
this.PackEnd(LogInButton);
this.PackEnd(RememberCheckBox);
this.PackEnd(PasswordText);
this.PackEnd(UsernameText);
this.PackEnd(ErrorLabel);
}
private void DisableForm()
{
UsernameText.Sensitive = PasswordText.Sensitive = LogInButton.Sensitive = RegisterButton.Sensitive = false;
}
private void EnableForm()
{
UsernameText.Sensitive = PasswordText.Sensitive = LogInButton.Sensitive = RegisterButton.Sensitive = true;
}
private void LogInButton_Clicked(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(UsernameText.Text) || string.IsNullOrEmpty(PasswordText.Password))
{
ErrorLabel.Text = "Username and password are required";
ErrorLabel.Visible = true;
return;
}
ErrorLabel.Visible = false;
DisableForm();
Window.User.Username = UsernameText.Text;
var request = WebRequest.CreateHttp(TrueCraftUser.AuthServer + "/api/login");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.BeginGetRequestStream(HandleLoginRequestReady, request);
}
private void HandleLoginRequestReady(IAsyncResult asyncResult)
{
var request = (HttpWebRequest)asyncResult.AsyncState;
var requestStream = request.EndGetRequestStream(asyncResult);
using (var writer = new StreamWriter(requestStream))
writer.Write(string.Format("user={0}&password={1}&version=12", UsernameText.Text, PasswordText.Password));
request.BeginGetResponse(HandleLoginResponse, request);
}
private void HandleLoginResponse(IAsyncResult asyncResult)
{
var request = (HttpWebRequest)asyncResult.AsyncState;
var response = request.EndGetResponse(asyncResult);
string session;
using (var reader = new StreamReader(response.GetResponseStream()))
session = reader.ReadToEnd();
if (session.Contains(":"))
{
var parts = session.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
Window.User.Username = parts[2];
Window.User.SessionId = parts[3];
Application.Invoke(() =>
{
EnableForm();
Window.MainContainer.Remove(this);
Window.MainContainer.PackEnd(Window.MainMenuView = new MainMenuView(Window));
});
}
else
{
Application.Invoke(() =>
{
EnableForm();
ErrorLabel.Text = session;
ErrorLabel.Visible = true;
});
}
}
}
}

View File

@ -0,0 +1,44 @@
using System;
using Xwt;
namespace TrueCraft.Launcher.Views
{
public class MainMenuView : VBox
{
public LauncherWindow Window { get; set; }
public Label WelcomeText { get; set; }
public Button SingleplayerButton { get; set; }
public Button MultiplayerButton { get; set; }
public Button OptionsButton { get; set; }
public Button QuitButton { get; set; }
public MainMenuView(LauncherWindow window)
{
Window = window;
this.MinWidth = 250;
WelcomeText = new Label("Welcome, " + Window.User.Username)
{
TextAlignment = Alignment.Center
};
SingleplayerButton = new Button("Singleplayer");
MultiplayerButton = new Button("Multiplayer");
OptionsButton = new Button("Options");
QuitButton = new Button("Quit Game");
MultiplayerButton.Clicked += (sender, e) =>
{
Window.MainContainer.Remove(this);
Window.MainContainer.PackEnd(Window.MultiplayerView);
};
QuitButton.Clicked += (sender, e) => Application.Exit();
this.PackStart(WelcomeText);
this.PackStart(SingleplayerButton);
this.PackStart(MultiplayerButton);
this.PackStart(OptionsButton);
this.PackEnd(QuitButton);
}
}
}

View File

@ -0,0 +1,68 @@
using System;
using Xwt;
using System.Collections.Generic;
using System.Diagnostics;
namespace TrueCraft.Launcher.Views
{
public class MultiplayerView : VBox
{
public LauncherWindow Window { get; set; }
public Label MultiplayerLabel { get; set; }
public TextEntry ServerIPEntry { get; set; }
public Button ConnectButton { get; set; }
public Button BackButton { get; set; }
public MultiplayerView(LauncherWindow window)
{
Window = window;
this.MinWidth = 250;
MultiplayerLabel = new Label("Multiplayer")
{
Font = Font.WithSize(16),
TextAlignment = Alignment.Center
};
ServerIPEntry = new TextEntry()
{
PlaceholderText = "Server IP"
};
ConnectButton = new Button("Connect");
BackButton = new Button("Back");
BackButton.Clicked += (sender, e) =>
{
Window.MainContainer.Remove(this);
Window.MainContainer.PackEnd(Window.MainMenuView);
};
ConnectButton.Clicked += ConnectButton_Clicked;
this.PackEnd(BackButton);
this.PackEnd(ConnectButton);
this.PackStart(MultiplayerLabel);
this.PackStart(ServerIPEntry);
}
void ConnectButton_Clicked(object sender, EventArgs e)
{
string TrueCraftLaunchParams = string.Format("{0} {1} {2}", ServerIPEntry.Text, Window.User.Username, Window.User.SessionId);
var process = new Process();
if (RuntimeInfo.IsMono)
process.StartInfo = new ProcessStartInfo("mono", "TrueCraft.Client.exe " + TrueCraftLaunchParams);
else
process.StartInfo = new ProcessStartInfo("TrueCraft.Client.exe", TrueCraftLaunchParams);
process.EnableRaisingEvents = true;
process.Exited += (s, a) => Application.Invoke(ClientExited);
process.Start();
Window.ShowInTaskbar = false;
Window.Hide();
}
void ClientExited()
{
Window.Show();
Window.ShowInTaskbar = true;
}
}
}

View File

@ -73,17 +73,32 @@ Global
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0
$0.TextStylePolicy = $1
$1.FileWidth = 120
$1.inheritsSet = VisualStudio
$1.inheritsScope = text/plain
$1.scope = text/x-csharp
$0.CSharpFormattingPolicy = $2
$2.IndentSwitchBody = True
$2.IndentBlocksInsideExpressions = True
$2.AnonymousMethodBraceStyle = NextLine
$2.PropertyBraceStyle = NextLine
$2.PropertyGetBraceStyle = NextLine
$2.PropertySetBraceStyle = NextLine
$2.EventBraceStyle = NextLine
$2.EventAddBraceStyle = NextLine
$2.EventRemoveBraceStyle = NextLine
$2.StatementBraceStyle = NextLine
$2.ElseNewLinePlacement = NewLine
$2.CatchNewLinePlacement = NewLine
$2.FinallyNewLinePlacement = NewLine
$2.WhileNewLinePlacement = DoNotCare
$2.ArrayInitializerWrapping = DoNotChange
$2.ArrayInitializerBraceStyle = NextLine
$2.BeforeMethodDeclarationParentheses = False
$2.BeforeMethodCallParentheses = False
$2.BeforeConstructorDeclarationParentheses = False
$2.BeforeIndexerDeclarationBracket = False
$2.NewLineBeforeConstructorInitializerColon = NewLine
$2.NewLineAfterConstructorInitializerColon = SameLine
$2.BeforeDelegateDeclarationParentheses = False
$2.AfterDelegateDeclarationParameterComma = True
$2.NewParentheses = False
$2.SpacesBeforeBrackets = False
$2.inheritsSet = Mono