diff --git a/OpenRA.Launcher/ConfigureModsDialog.Designer.cs b/OpenRA.Launcher/ConfigureModsDialog.Designer.cs
deleted file mode 100644
index 37aa1c4f1e..0000000000
--- a/OpenRA.Launcher/ConfigureModsDialog.Designer.cs
+++ /dev/null
@@ -1,233 +0,0 @@
-namespace OpenRA.Launcher
-{
- partial class ConfigureModsDialog
- {
- ///
- /// Required designer variable.
- ///
- private System.ComponentModel.IContainer components = null;
-
- ///
- /// Clean up any resources being used.
- ///
- /// true if managed resources should be disposed; otherwise, false.
- protected override void Dispose(bool disposing)
- {
- if (disposing && (components != null))
- {
- components.Dispose();
- }
- base.Dispose(disposing);
- }
-
- #region Windows Form Designer generated code
-
- ///
- /// Required method for Designer support - do not modify
- /// the contents of this method with the code editor.
- ///
- private void InitializeComponent()
- {
- this.cancelButton = new System.Windows.Forms.Button();
- this.okButton = new System.Windows.Forms.Button();
- this.installButton = new System.Windows.Forms.Button();
- this.installModDialog = new System.Windows.Forms.OpenFileDialog();
- this.treeView1 = new System.Windows.Forms.TreeView();
- this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
- this.addButton = new System.Windows.Forms.Button();
- this.removeButton = new System.Windows.Forms.Button();
- this.listView1 = new System.Windows.Forms.ListView();
- this.columnHeader1 = new System.Windows.Forms.ColumnHeader();
- this.label1 = new System.Windows.Forms.Label();
- this.propertyGrid1 = new System.Windows.Forms.PropertyGrid();
- this.label2 = new System.Windows.Forms.Label();
- this.tableLayoutPanel1.SuspendLayout();
- this.SuspendLayout();
- //
- // cancelButton
- //
- this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
- this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
- this.cancelButton.Location = new System.Drawing.Point(446, 477);
- this.cancelButton.Name = "cancelButton";
- this.cancelButton.Size = new System.Drawing.Size(75, 23);
- this.cancelButton.TabIndex = 0;
- this.cancelButton.Text = "Cancel";
- this.cancelButton.UseVisualStyleBackColor = true;
- //
- // okButton
- //
- this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
- this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
- this.okButton.Location = new System.Drawing.Point(365, 477);
- this.okButton.Name = "okButton";
- this.okButton.Size = new System.Drawing.Size(75, 23);
- this.okButton.TabIndex = 1;
- this.okButton.Text = "OK";
- this.okButton.UseVisualStyleBackColor = true;
- //
- // installButton
- //
- this.installButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
- this.installButton.Location = new System.Drawing.Point(12, 477);
- this.installButton.Name = "installButton";
- this.installButton.Size = new System.Drawing.Size(116, 23);
- this.installButton.TabIndex = 2;
- this.installButton.Text = "Install Mod...";
- this.installButton.UseVisualStyleBackColor = true;
- this.installButton.Click += new System.EventHandler(this.InstallMod);
- //
- // installModDialog
- //
- this.installModDialog.Filter = "Zip files|*.zip";
- this.installModDialog.RestoreDirectory = true;
- //
- // treeView1
- //
- this.treeView1.Dock = System.Windows.Forms.DockStyle.Fill;
- this.treeView1.Location = new System.Drawing.Point(3, 23);
- this.treeView1.Name = "treeView1";
- this.tableLayoutPanel1.SetRowSpan(this.treeView1, 2);
- this.treeView1.Size = new System.Drawing.Size(233, 212);
- this.treeView1.TabIndex = 3;
- this.treeView1.Enter += new System.EventHandler(this.treeView1_Enter);
- this.treeView1.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.TreeViewSelect);
- //
- // tableLayoutPanel1
- //
- this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
- | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.tableLayoutPanel1.ColumnCount = 3;
- this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
- this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 30F));
- this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
- this.tableLayoutPanel1.Controls.Add(this.treeView1, 0, 1);
- this.tableLayoutPanel1.Controls.Add(this.addButton, 1, 1);
- this.tableLayoutPanel1.Controls.Add(this.removeButton, 2, 1);
- this.tableLayoutPanel1.Controls.Add(this.listView1, 2, 1);
- this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0);
- this.tableLayoutPanel1.Controls.Add(this.propertyGrid1, 0, 2);
- this.tableLayoutPanel1.Controls.Add(this.label2, 2, 0);
- this.tableLayoutPanel1.Location = new System.Drawing.Point(12, 12);
- this.tableLayoutPanel1.Name = "tableLayoutPanel1";
- this.tableLayoutPanel1.RowCount = 4;
- this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
- this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F));
- this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F));
- this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
- this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
- this.tableLayoutPanel1.Size = new System.Drawing.Size(509, 459);
- this.tableLayoutPanel1.TabIndex = 4;
- //
- // addButton
- //
- this.addButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
- this.addButton.Location = new System.Drawing.Point(242, 103);
- this.addButton.Name = "addButton";
- this.addButton.Size = new System.Drawing.Size(24, 23);
- this.addButton.TabIndex = 5;
- this.addButton.Text = "+";
- this.addButton.UseVisualStyleBackColor = true;
- this.addButton.Click += new System.EventHandler(this.ActivateMod);
- //
- // removeButton
- //
- this.removeButton.Anchor = System.Windows.Forms.AnchorStyles.Top;
- this.removeButton.Location = new System.Drawing.Point(242, 132);
- this.removeButton.Name = "removeButton";
- this.removeButton.Size = new System.Drawing.Size(24, 23);
- this.removeButton.TabIndex = 6;
- this.removeButton.Text = "-";
- this.removeButton.UseVisualStyleBackColor = true;
- this.removeButton.Click += new System.EventHandler(this.DeactivateMod);
- //
- // listView1
- //
- this.listView1.Activation = System.Windows.Forms.ItemActivation.OneClick;
- this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
- this.columnHeader1});
- this.listView1.Dock = System.Windows.Forms.DockStyle.Fill;
- this.listView1.FullRowSelect = true;
- this.listView1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
- this.listView1.Location = new System.Drawing.Point(272, 23);
- this.listView1.MultiSelect = false;
- this.listView1.Name = "listView1";
- this.tableLayoutPanel1.SetRowSpan(this.listView1, 2);
- this.listView1.Size = new System.Drawing.Size(234, 212);
- this.listView1.TabIndex = 8;
- this.listView1.TileSize = new System.Drawing.Size(10, 10);
- this.listView1.UseCompatibleStateImageBehavior = false;
- this.listView1.View = System.Windows.Forms.View.Details;
- this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListViewSelect);
- this.listView1.Enter += new System.EventHandler(this.ListViewSelect);
- //
- // label1
- //
- this.label1.Anchor = System.Windows.Forms.AnchorStyles.None;
- this.label1.AutoSize = true;
- this.label1.Location = new System.Drawing.Point(96, 3);
- this.label1.Name = "label1";
- this.label1.Size = new System.Drawing.Size(47, 13);
- this.label1.TabIndex = 10;
- this.label1.Text = "All Mods";
- //
- // propertyGrid1
- //
- this.tableLayoutPanel1.SetColumnSpan(this.propertyGrid1, 3);
- this.propertyGrid1.Dock = System.Windows.Forms.DockStyle.Fill;
- this.propertyGrid1.Location = new System.Drawing.Point(3, 241);
- this.propertyGrid1.Name = "propertyGrid1";
- this.propertyGrid1.PropertySort = System.Windows.Forms.PropertySort.NoSort;
- this.propertyGrid1.Size = new System.Drawing.Size(503, 215);
- this.propertyGrid1.TabIndex = 9;
- this.propertyGrid1.ToolbarVisible = false;
- //
- // label2
- //
- this.label2.Anchor = System.Windows.Forms.AnchorStyles.None;
- this.label2.AutoSize = true;
- this.label2.Location = new System.Drawing.Point(356, 3);
- this.label2.Name = "label2";
- this.label2.Size = new System.Drawing.Size(66, 13);
- this.label2.TabIndex = 11;
- this.label2.Text = "Active Mods";
- //
- // ConfigureModsDialog
- //
- this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
- this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(533, 512);
- this.Controls.Add(this.tableLayoutPanel1);
- this.Controls.Add(this.installButton);
- this.Controls.Add(this.okButton);
- this.Controls.Add(this.cancelButton);
- this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
- this.MaximizeBox = false;
- this.MinimizeBox = false;
- this.Name = "ConfigureModsDialog";
- this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
- this.Text = "Configure Mods";
- this.tableLayoutPanel1.ResumeLayout(false);
- this.tableLayoutPanel1.PerformLayout();
- this.ResumeLayout(false);
-
- }
-
- #endregion
-
- private System.Windows.Forms.Button cancelButton;
- private System.Windows.Forms.Button okButton;
- private System.Windows.Forms.Button installButton;
- private System.Windows.Forms.OpenFileDialog installModDialog;
- private System.Windows.Forms.TreeView treeView1;
- private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
- private System.Windows.Forms.Button addButton;
- private System.Windows.Forms.Button removeButton;
- private System.Windows.Forms.ListView listView1;
- private System.Windows.Forms.PropertyGrid propertyGrid1;
- private System.Windows.Forms.ColumnHeader columnHeader1;
- private System.Windows.Forms.Label label1;
- private System.Windows.Forms.Label label2;
- }
-}
\ No newline at end of file
diff --git a/OpenRA.Launcher/ConfigureModsDialog.cs b/OpenRA.Launcher/ConfigureModsDialog.cs
deleted file mode 100644
index ee7fe062b1..0000000000
--- a/OpenRA.Launcher/ConfigureModsDialog.cs
+++ /dev/null
@@ -1,291 +0,0 @@
-#region Copyright & License Information
-/*
- * Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
- * This file is part of OpenRA, which is free software. It is made
- * available to you under the terms of the GNU General Public License
- * as published by the Free Software Foundation. For more information,
- * see LICENSE.
- */
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
-using System.Windows.Forms;
-using System.IO.Pipes;
-using System.IO;
-
-namespace OpenRA.Launcher
-{
- public partial class ConfigureModsDialog : Form
- {
- List activeMods;
-
- public List ActiveMods
- {
- get { return activeMods; }
- }
-
- Dictionary allMods;
- public ConfigureModsDialog(string[] activeMods)
- {
- InitializeComponent();
-
- Util.UacShield(installButton);
-
- this.activeMods = new List(activeMods);
-
- listView1.Items.AddRange(activeMods.Select(x => new ListViewItem(x)).ToArray());
-
- RefreshMods();
- }
-
- Mod GetMetadata(string mod)
- {
- string responseString;
- using (var response = UtilityProgram.Call("-i", mod))
- {
- responseString = response.ReadToEnd();
- }
-
- if (Util.IsError(ref responseString)) return null;
- string[] lines = responseString.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
- for (int i = 0; i < lines.Length; i++)
- lines[i] = lines[i].Trim('\r');
-
- string title = "", version = "", author = "", description = "", requires = "";
- bool standalone = false;
- foreach (string line in lines)
- {
- string s = line.Trim(' ', '\r', '\n');
- int i = s.IndexOf(':');
- if (i + 2 > s.Length) continue;
- string value = s.Substring(i + 2);
- switch (s.Substring(0, i))
- {
- case "Title":
- title = value;
- break;
- case "Version":
- version = value;
- break;
- case "Author":
- author = value;
- break;
- case "Description":
- description = value;
- break;
- case "Requires":
- requires = value;
- break;
- case "Standalone":
- standalone = bool.Parse(value);
- break;
- default:
- break;
- }
- }
-
- return new Mod(title, version, author, description, requires, standalone);
- }
-
- void RefreshMods()
- {
- string responseString;
- using (var response = UtilityProgram.Call("--list-mods"))
- {
- responseString = response.ReadToEnd();
- }
-
- string[] mods;
- if (!Util.IsError(ref responseString))
- mods = responseString.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
- else
- throw new Exception(string.Format("Could not list mods: {0}", responseString));
-
- for (int i = 0; i < mods.Length; i++)
- mods[i] = mods[i].Trim('\r');
-
- allMods = mods.ToDictionary(x => x, x => GetMetadata(x));
-
- RefreshModTree(treeView1, allMods.Keys.ToArray());
- }
-
- private void InstallMod(object sender, EventArgs e)
- {
- if (installModDialog.ShowDialog() != DialogResult.OK) return;
- var p = UtilityProgram.CallWithAdmin("--install-mod", installModDialog.FileName);
- var pipe = new NamedPipeClientStream(".", "OpenRA.Utility", PipeDirection.In);
- pipe.Connect();
-
- p.WaitForExit();
-
- using (var response = new StreamReader(pipe))
- {
- string s = response.ReadToEnd();
- }
-
- RefreshMods();
- }
-
- void RefreshModTree(TreeView treeView, string[] modList)
- {
- treeView.Nodes.Clear();
- Dictionary nodes;
- nodes = modList.Where(x => allMods[x].Standalone).ToDictionary(x => x, x => new TreeNode(x));
- string[] rootMods = modList.Where(x => allMods[x].Standalone).ToArray();
- string[] remaining = modList.Except(nodes.Keys).ToArray();
-
- while (remaining.Length > 0)
- {
- bool progress = false;
- List toRemove = new List();
- foreach (string s in remaining)
- {
- var n = new TreeNode(s);
- if (allMods[s].Requires == null) continue;
- if (!nodes.ContainsKey(allMods[s].Requires)) continue;
- nodes[allMods[s].Requires].Nodes.Add(n);
- nodes.Add(s, n);
- toRemove.Add(s);
- progress = true;
- }
-
- if (!progress)
- break;
- remaining = remaining.Except(toRemove).ToArray();
- }
-
- foreach (string s in rootMods)
- treeView.Nodes.Add(nodes[s]);
-
- if (remaining.Length > 0)
- {
- var n = new TreeNode("");
- n.ForeColor = SystemColors.GrayText;
- var m = new TreeNode("");
- m.ForeColor = SystemColors.GrayText;
-
- foreach (var s in remaining)
- {
- if (allMods[s].Requires == null)
- n.Nodes.Add(new TreeNode(s) { ForeColor = SystemColors.GrayText });
- else if (!nodes.ContainsKey(allMods[s].Requires))
- m.Nodes.Add(new TreeNode(s) { ForeColor = SystemColors.GrayText });
- }
-
- treeView.Nodes.Add(n);
- treeView.Nodes.Add(m);
- }
-
- treeView.Invalidate();
- }
-
- void TreeViewSelect(object sender, TreeViewEventArgs e)
- {
- SelectMod(e.Node.Text);
- }
-
- void ListViewSelect(object sender, EventArgs e)
- {
- if (listView1.SelectedItems.Count > 0)
- SelectMod(listView1.SelectedItems[0].Text);
- else
- SelectMod("");
- }
-
- void treeView1_Enter(object sender, EventArgs e)
- {
- if (treeView1.SelectedNode != null)
- SelectMod(treeView1.SelectedNode.Text);
- else
- SelectMod("");
- }
-
- void SelectMod(string mod)
- {
- if (!allMods.ContainsKey(mod))
- propertyGrid1.SelectedObject = null;
- else
- propertyGrid1.SelectedObject = allMods[mod];
- }
-
- void ActivateMod(object sender, EventArgs e)
- {
- if (treeView1.SelectedNode == null) return;
- string mod = treeView1.SelectedNode.Text;
- if (!allMods.ContainsKey(mod)) return;
- if (activeMods.Contains(mod)) return;
-
- Mod m = allMods[mod];
- Stack toAdd = new Stack();
- toAdd.Push(mod);
- while (!string.IsNullOrEmpty(m.Requires))
- {
- string r = m.Requires;
- if (!allMods.ContainsKey(r))
- {
- MessageBox.Show(string.Format("A requirement for the mod \"{0}\" is missing. Please install \"{1}\" or the game may not run properly.", mod, r));
- return;
- }
- if (!activeMods.Contains(r))
- toAdd.Push(r);
- mod = r;
- m = allMods[mod];
- }
-
- while (toAdd.Count > 0)
- activeMods.Add(toAdd.Pop());
-
- listView1.Items.Clear();
- listView1.Items.AddRange(activeMods.Select(x => new ListViewItem(x)).ToArray());
- }
-
- void DeactivateMod(object sender, EventArgs e)
- {
- if (listView1.SelectedItems.Count < 1) return;
- string mod = listView1.SelectedItems[0].Text;
- List toRemove = new List();
-
- Stack nodes = new Stack();
- nodes.Push(mod);
- string currentNode;
- while (nodes.Count > 0)
- {
- currentNode = nodes.Pop();
- toRemove.Add(currentNode);
- foreach (string n in activeMods.Where(x => allMods[x].Requires == currentNode))
- nodes.Push(n);
- }
-
- listView1.SuspendLayout();
- foreach (string s in toRemove)
- {
- listView1.Items.Remove(listView1.Items.OfType().Where(x => x.Text == s).SingleOrDefault());
- activeMods.Remove(s);
- }
- listView1.ResumeLayout();
- }
- }
-
- class Mod
- {
- public string Title { get; private set; }
- public string Version { get; private set; }
- public string Author { get; private set; }
- public string Description { get; private set; }
- public string Requires { get; private set; }
- public bool Standalone { get; private set; }
-
- public Mod(string title, string version, string author, string description, string requires, bool standalone)
- {
- Title = title;
- Version = version;
- Author = author;
- Description = description;
- Requires = requires;
- Standalone = standalone;
- }
- }
-}
diff --git a/OpenRA.Launcher/JSBridge.cs b/OpenRA.Launcher/JSBridge.cs
new file mode 100644
index 0000000000..930f39237f
--- /dev/null
+++ b/OpenRA.Launcher/JSBridge.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using System.Diagnostics;
+
+namespace OpenRA.Launcher
+{
+ public class JSBridge
+ {
+ Dictionary allMods;
+
+ public JSBridge(Dictionary allMods)
+ {
+ this.allMods = allMods;
+ }
+
+ public bool fileExistsInMod(string file, string mod)
+ {
+ return File.Exists(string.Format("mods{0}{1}{0}{2}", Path.DirectorySeparatorChar, mod, file));
+ }
+
+ public void log(string message)
+ {
+ Console.WriteLine("js: " + message);
+ }
+
+ public void launchMod(string mod)
+ {
+ string m = mod;
+ List modList = new List();
+ modList.Add(m);
+ if (!allMods.ContainsKey(m)) System.Windows.Forms.MessageBox.Show("allMods does not contain " + m);
+ while (!string.IsNullOrEmpty(allMods[m].Requires))
+ {
+ m = allMods[m].Requires;
+ modList.Add(m);
+ }
+
+ Process p = new Process();
+ p.StartInfo.FileName = "OpenRA.Game.exe";
+ p.StartInfo.Arguments = "Game.Mods=" + string.Join(",", modList.ToArray());
+ p.Start();
+ }
+ }
+}
diff --git a/OpenRA.Launcher/Launcher.Designer.cs b/OpenRA.Launcher/Launcher.Designer.cs
new file mode 100644
index 0000000000..8f85fdd7a4
--- /dev/null
+++ b/OpenRA.Launcher/Launcher.Designer.cs
@@ -0,0 +1,146 @@
+namespace OpenRA.Launcher
+{
+ partial class Launcher
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("Mods", -2, -2);
+ System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("Broken Mods");
+ this.installButton = new System.Windows.Forms.Button();
+ this.installModDialog = new System.Windows.Forms.OpenFileDialog();
+ this.treeView = new System.Windows.Forms.TreeView();
+ this.splitContainer1 = new System.Windows.Forms.SplitContainer();
+ this.webBrowser = new System.Windows.Forms.WebBrowser();
+ this.panel1 = new System.Windows.Forms.Panel();
+ this.splitContainer1.Panel1.SuspendLayout();
+ this.splitContainer1.Panel2.SuspendLayout();
+ this.splitContainer1.SuspendLayout();
+ this.panel1.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // installButton
+ //
+ this.installButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.installButton.Location = new System.Drawing.Point(12, 12);
+ this.installButton.Name = "installButton";
+ this.installButton.Size = new System.Drawing.Size(116, 23);
+ this.installButton.TabIndex = 2;
+ this.installButton.Text = "Install Mod...";
+ this.installButton.UseVisualStyleBackColor = true;
+ this.installButton.Click += new System.EventHandler(this.InstallMod);
+ //
+ // installModDialog
+ //
+ this.installModDialog.Filter = "Zip files|*.zip";
+ this.installModDialog.RestoreDirectory = true;
+ //
+ // treeView
+ //
+ this.treeView.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.treeView.Location = new System.Drawing.Point(0, 0);
+ this.treeView.Name = "treeView";
+ treeNode1.ImageIndex = -2;
+ treeNode1.Name = "ModsNode";
+ treeNode1.SelectedImageIndex = -2;
+ treeNode1.Text = "Mods";
+ treeNode2.Name = "BrokenModsNode";
+ treeNode2.Text = "Broken Mods";
+ this.treeView.Nodes.AddRange(new System.Windows.Forms.TreeNode[] {
+ treeNode1,
+ treeNode2});
+ this.treeView.ShowLines = false;
+ this.treeView.Size = new System.Drawing.Size(146, 465);
+ this.treeView.TabIndex = 3;
+ this.treeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView_AfterSelect);
+ //
+ // splitContainer1
+ //
+ this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.splitContainer1.Location = new System.Drawing.Point(0, 0);
+ this.splitContainer1.Name = "splitContainer1";
+ //
+ // splitContainer1.Panel1
+ //
+ this.splitContainer1.Panel1.Controls.Add(this.treeView);
+ //
+ // splitContainer1.Panel2
+ //
+ this.splitContainer1.Panel2.Controls.Add(this.webBrowser);
+ this.splitContainer1.Size = new System.Drawing.Size(671, 465);
+ this.splitContainer1.SplitterDistance = 146;
+ this.splitContainer1.TabIndex = 4;
+ //
+ // webBrowser
+ //
+ this.webBrowser.AllowWebBrowserDrop = false;
+ this.webBrowser.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.webBrowser.Location = new System.Drawing.Point(0, 0);
+ this.webBrowser.MinimumSize = new System.Drawing.Size(20, 20);
+ this.webBrowser.Name = "webBrowser";
+ this.webBrowser.Size = new System.Drawing.Size(521, 465);
+ this.webBrowser.TabIndex = 0;
+ //
+ // panel1
+ //
+ this.panel1.Controls.Add(this.installButton);
+ this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.panel1.Location = new System.Drawing.Point(0, 465);
+ this.panel1.Name = "panel1";
+ this.panel1.Size = new System.Drawing.Size(671, 47);
+ this.panel1.TabIndex = 5;
+ //
+ // Launcher
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(671, 512);
+ this.Controls.Add(this.splitContainer1);
+ this.Controls.Add(this.panel1);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "Launcher";
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ this.Text = "OpenRA Launcher";
+ this.splitContainer1.Panel1.ResumeLayout(false);
+ this.splitContainer1.Panel2.ResumeLayout(false);
+ this.splitContainer1.ResumeLayout(false);
+ this.panel1.ResumeLayout(false);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Button installButton;
+ private System.Windows.Forms.OpenFileDialog installModDialog;
+ private System.Windows.Forms.TreeView treeView;
+ private System.Windows.Forms.SplitContainer splitContainer1;
+ private System.Windows.Forms.Panel panel1;
+ private System.Windows.Forms.WebBrowser webBrowser;
+ }
+}
\ No newline at end of file
diff --git a/OpenRA.Launcher/Launcher.cs b/OpenRA.Launcher/Launcher.cs
new file mode 100644
index 0000000000..4e42c954b9
--- /dev/null
+++ b/OpenRA.Launcher/Launcher.cs
@@ -0,0 +1,181 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
+ * This file is part of OpenRA, which is free software. It is made
+ * available to you under the terms of the GNU General Public License
+ * as published by the Free Software Foundation. For more information,
+ * see LICENSE.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Windows.Forms;
+using System.IO.Pipes;
+using System.IO;
+
+namespace OpenRA.Launcher
+{
+ public partial class Launcher : Form
+ {
+ Dictionary allMods;
+ public Launcher()
+ {
+ InitializeComponent();
+
+ Util.UacShield(installButton);
+
+ //treeView.Nodes["ModsNode"].ImageIndex = 1;
+ //treeView.Nodes["ModsNode"].SelectedImageIndex = 1;
+
+ RefreshMods();
+ webBrowser.ObjectForScripting = new JSBridge(allMods);
+ }
+
+ Mod GetMetadata(string mod)
+ {
+ string responseString;
+ using (var response = UtilityProgram.Call("-i", mod))
+ {
+ responseString = response.ReadToEnd();
+ }
+
+ if (Util.IsError(ref responseString)) return null;
+ string[] lines = responseString.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
+ for (int i = 0; i < lines.Length; i++)
+ lines[i] = lines[i].Trim('\r');
+
+ string title = "", version = "", author = "", description = "", requires = "";
+ bool standalone = false;
+ foreach (string line in lines)
+ {
+ string s = line.Trim(' ', '\r', '\n');
+ int i = s.IndexOf(':');
+ if (i + 2 > s.Length) continue;
+ string value = s.Substring(i + 2);
+ switch (s.Substring(0, i))
+ {
+ case "Title":
+ title = value;
+ break;
+ case "Version":
+ version = value;
+ break;
+ case "Author":
+ author = value;
+ break;
+ case "Description":
+ description = value;
+ break;
+ case "Requires":
+ requires = value;
+ break;
+ case "Standalone":
+ standalone = bool.Parse(value);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return new Mod(title, version, author, description, requires, standalone);
+ }
+
+ void RefreshMods()
+ {
+ string responseString;
+ using (var response = UtilityProgram.Call("--list-mods"))
+ {
+ responseString = response.ReadToEnd();
+ }
+
+ string[] mods;
+ if (!Util.IsError(ref responseString))
+ mods = responseString.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
+ else
+ throw new Exception(string.Format("Could not list mods: {0}", responseString));
+
+ for (int i = 0; i < mods.Length; i++)
+ mods[i] = mods[i].Trim('\r');
+
+ allMods = mods.ToDictionary(x => x, x => GetMetadata(x));
+
+ RefreshModTree(treeView, allMods.Keys.ToArray());
+ }
+
+ private void InstallMod(object sender, EventArgs e)
+ {
+ if (installModDialog.ShowDialog() != DialogResult.OK) return;
+ var p = UtilityProgram.CallWithAdmin("--install-mod", installModDialog.FileName);
+ var pipe = new NamedPipeClientStream(".", "OpenRA.Utility", PipeDirection.In);
+ pipe.Connect();
+
+ p.WaitForExit();
+
+ using (var response = new StreamReader(pipe))
+ {
+ string s = response.ReadToEnd();
+ }
+
+ RefreshMods();
+ }
+
+ void RefreshModTree(TreeView treeView, string[] modList)
+ {
+ treeView.Nodes["ModsNode"].Nodes.Clear();
+ Dictionary nodes;
+ nodes = modList.Where(x => allMods[x].Standalone).ToDictionary(x => x,
+ x => new TreeNode(allMods[x].Title) { Name = x });
+ string[] rootMods = modList.Where(x => allMods[x].Standalone).ToArray();
+ Stack remaining = new Stack(modList.Except(nodes.Keys));
+
+ bool progress = true;
+ while (remaining.Count > 0 && progress)
+ {
+ progress = false;
+ string s = remaining.Pop();
+ var n = new TreeNode(allMods[s].Title) { Name = s };
+ if (allMods[s].Requires == null) { remaining.Push(s); continue; }
+ if (!nodes.ContainsKey(allMods[s].Requires)) { remaining.Push(s); continue; }
+ nodes[allMods[s].Requires].Nodes.Add(n);
+ nodes.Add(s, n);
+ progress = true;
+ }
+
+ foreach (string s in rootMods)
+ treeView.Nodes["ModsNode"].Nodes.Add(nodes[s]);
+
+ if (remaining.Count > 0)
+ {
+ var unspecified = new TreeNode("") { ForeColor = SystemColors.GrayText };
+ var missing = new TreeNode("") { ForeColor = SystemColors.GrayText };
+
+ foreach (var s in remaining)
+ {
+ if (allMods[s].Requires == null)
+ unspecified.Nodes.Add(new TreeNode(allMods[s].Title)
+ { ForeColor = SystemColors.GrayText, Name = s });
+ else if (!nodes.ContainsKey(allMods[s].Requires))
+ missing.Nodes.Add(new TreeNode(allMods[s].Title)
+ { ForeColor = SystemColors.GrayText, Name = s });
+ }
+
+ treeView.Nodes["BrokenModsNode"].Nodes.Add(unspecified);
+ treeView.Nodes["BrokenModsNode"].Nodes.Add(missing);
+ }
+ treeView.Nodes["ModsNode"].ExpandAll();
+ treeView.Invalidate();
+ }
+
+ void treeView_AfterSelect(object sender, TreeViewEventArgs e)
+ {
+ Mod selectedMod;
+ if (!allMods.TryGetValue(e.Node.Name, out selectedMod)) return;
+ string modHtmlPath = string.Format("mods{0}{1}{0}mod.html", Path.DirectorySeparatorChar, e.Node.Name);
+ if (!File.Exists(modHtmlPath)) return;
+ webBrowser.Navigate(Path.GetFullPath(modHtmlPath));
+ }
+ }
+}
diff --git a/OpenRA.Launcher/ConfigureModsDialog.resx b/OpenRA.Launcher/Launcher.resx
similarity index 100%
rename from OpenRA.Launcher/ConfigureModsDialog.resx
rename to OpenRA.Launcher/Launcher.resx
diff --git a/OpenRA.Launcher/MainForm.Designer.cs b/OpenRA.Launcher/MainForm.Designer.cs
deleted file mode 100644
index e45ec296c1..0000000000
--- a/OpenRA.Launcher/MainForm.Designer.cs
+++ /dev/null
@@ -1,160 +0,0 @@
-namespace OpenRA.Launcher
-{
- partial class MainForm
- {
- ///
- /// Required designer variable.
- ///
- private System.ComponentModel.IContainer components = null;
-
- ///
- /// Clean up any resources being used.
- ///
- /// true if managed resources should be disposed; otherwise, false.
- protected override void Dispose(bool disposing)
- {
- if (disposing && (components != null))
- {
- components.Dispose();
- }
- base.Dispose(disposing);
- }
-
- #region Windows Form Designer generated code
-
- ///
- /// Required method for Designer support - do not modify
- /// the contents of this method with the code editor.
- ///
- private void InitializeComponent()
- {
- System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
- this.pictureBox1 = new System.Windows.Forms.PictureBox();
- this.launchButton = new System.Windows.Forms.Button();
- this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
- this.quitButton = new System.Windows.Forms.Button();
- this.configModsButton = new System.Windows.Forms.Button();
- this.configGameButton = new System.Windows.Forms.Button();
- this.label1 = new System.Windows.Forms.Label();
- ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
- this.tableLayoutPanel1.SuspendLayout();
- this.SuspendLayout();
- //
- // pictureBox1
- //
- this.pictureBox1.Anchor = System.Windows.Forms.AnchorStyles.None;
- this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
- this.pictureBox1.Location = new System.Drawing.Point(51, 3);
- this.pictureBox1.Name = "pictureBox1";
- this.pictureBox1.Size = new System.Drawing.Size(192, 64);
- this.pictureBox1.TabIndex = 0;
- this.pictureBox1.TabStop = false;
- //
- // launchButton
- //
- this.launchButton.Anchor = System.Windows.Forms.AnchorStyles.None;
- this.launchButton.Location = new System.Drawing.Point(51, 97);
- this.launchButton.Name = "launchButton";
- this.launchButton.Size = new System.Drawing.Size(192, 50);
- this.launchButton.TabIndex = 1;
- this.launchButton.Text = "Launch OpenRA";
- this.launchButton.UseVisualStyleBackColor = true;
- this.launchButton.Click += new System.EventHandler(this.LaunchGame);
- //
- // tableLayoutPanel1
- //
- this.tableLayoutPanel1.ColumnCount = 1;
- this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
- this.tableLayoutPanel1.Controls.Add(this.pictureBox1, 0, 0);
- this.tableLayoutPanel1.Controls.Add(this.launchButton, 0, 2);
- this.tableLayoutPanel1.Controls.Add(this.quitButton, 0, 5);
- this.tableLayoutPanel1.Controls.Add(this.configModsButton, 0, 3);
- this.tableLayoutPanel1.Controls.Add(this.configGameButton, 0, 4);
- this.tableLayoutPanel1.Controls.Add(this.label1, 0, 1);
- this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
- this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
- this.tableLayoutPanel1.Name = "tableLayoutPanel1";
- this.tableLayoutPanel1.RowCount = 6;
- this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
- this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
- this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F));
- this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F));
- this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F));
- this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F));
- this.tableLayoutPanel1.Size = new System.Drawing.Size(294, 372);
- this.tableLayoutPanel1.TabIndex = 2;
- //
- // quitButton
- //
- this.quitButton.Anchor = System.Windows.Forms.AnchorStyles.None;
- this.quitButton.Location = new System.Drawing.Point(51, 311);
- this.quitButton.Name = "quitButton";
- this.quitButton.Size = new System.Drawing.Size(192, 50);
- this.quitButton.TabIndex = 2;
- this.quitButton.Text = "Quit";
- this.quitButton.UseVisualStyleBackColor = true;
- //
- // configModsButton
- //
- this.configModsButton.Anchor = System.Windows.Forms.AnchorStyles.None;
- this.configModsButton.Location = new System.Drawing.Point(51, 168);
- this.configModsButton.Name = "configModsButton";
- this.configModsButton.Size = new System.Drawing.Size(192, 50);
- this.configModsButton.TabIndex = 3;
- this.configModsButton.Text = "Configure Mods...";
- this.configModsButton.UseVisualStyleBackColor = true;
- this.configModsButton.Click += new System.EventHandler(this.ConfigureMods);
- //
- // configGameButton
- //
- this.configGameButton.Anchor = System.Windows.Forms.AnchorStyles.None;
- this.configGameButton.Enabled = false;
- this.configGameButton.Location = new System.Drawing.Point(51, 239);
- this.configGameButton.Name = "configGameButton";
- this.configGameButton.Size = new System.Drawing.Size(192, 50);
- this.configGameButton.TabIndex = 4;
- this.configGameButton.Text = "Configure Game...";
- this.configGameButton.UseVisualStyleBackColor = true;
- //
- // label1
- //
- this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
- this.label1.AutoSize = true;
- this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.label1.Location = new System.Drawing.Point(3, 70);
- this.label1.Name = "label1";
- this.label1.Size = new System.Drawing.Size(288, 17);
- this.label1.TabIndex = 5;
- this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
- //
- // MainForm
- //
- this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
- this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(294, 372);
- this.Controls.Add(this.tableLayoutPanel1);
- this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
- this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
- this.MaximizeBox = false;
- this.MinimizeBox = false;
- this.Name = "MainForm";
- this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
- this.Text = "OpenRA Launcher";
- ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
- this.tableLayoutPanel1.ResumeLayout(false);
- this.tableLayoutPanel1.PerformLayout();
- this.ResumeLayout(false);
-
- }
-
- #endregion
-
- private System.Windows.Forms.PictureBox pictureBox1;
- private System.Windows.Forms.Button launchButton;
- private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
- private System.Windows.Forms.Button quitButton;
- private System.Windows.Forms.Button configModsButton;
- private System.Windows.Forms.Button configGameButton;
- private System.Windows.Forms.Label label1;
- }
-}
\ No newline at end of file
diff --git a/OpenRA.Launcher/MainForm.cs b/OpenRA.Launcher/MainForm.cs
deleted file mode 100644
index a7f3206c4f..0000000000
--- a/OpenRA.Launcher/MainForm.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-#region Copyright & License Information
-/*
- * Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
- * This file is part of OpenRA, which is free software. It is made
- * available to you under the terms of the GNU General Public License
- * as published by the Free Software Foundation. For more information,
- * see LICENSE.
- */
-#endregion
-
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Windows.Forms;
-
-namespace OpenRA.Launcher
-{
- public partial class MainForm : Form
- {
- string configPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + Path.DirectorySeparatorChar + "OpenRA";
- string[] currentMods;
- public MainForm()
- {
- InitializeComponent();
- quitButton.Click += (o, e) => { Application.Exit(); };
- using (var s = UtilityProgram.Call("--settings-value", configPath, "Game.Mods"))
- {
- var response = s.ReadToEnd();
- if (Util.IsError(ref response))
- currentMods = new string[] { "ra" };
- else
- currentMods = response.Split(',');
- }
-
- UpdateModLabel();
- }
-
- void UpdateModLabel()
- {
- label1.Text = string.Format("Current Mods: {0}", currentMods.Length > 0 ? string.Join(",", currentMods) : "ra");
- }
-
- void ConfigureMods(object sender, EventArgs e)
- {
- var d = new ConfigureModsDialog(currentMods);
- if (d.ShowDialog() != DialogResult.OK)
- return;
-
- currentMods = d.ActiveMods.ToArray();
-
- UpdateModLabel();
- }
-
- void LaunchGame(object sender, EventArgs e)
- {
- string[] officialMods = { "ra", "cnc" };
-
- bool allOk = true;
- foreach(string s in officialMods)
- if (currentMods.Contains(s))
- allOk = CheckAndInstallPackages(s);
-
- if (!allOk) return;
-
- Process p = new Process();
- p.StartInfo.FileName = "OpenRA.Game.exe";
- p.StartInfo.Arguments = "Game.Mods=" + string.Join(",", currentMods);
- p.Start();
- }
-
- bool CheckAndInstallPackages(string mod)
- {
- string packageDir = "mods" + Path.DirectorySeparatorChar + mod + Path.DirectorySeparatorChar + "packages";
- if (Directory.Exists(packageDir) &&
- Directory.GetFiles(packageDir, "*.mix").Length > 0) return true;
- var dialog = new InstallPackagesDialog(mod);
- if (dialog.ShowDialog() != DialogResult.OK) return false;
- return true;
- }
- }
-}
diff --git a/OpenRA.Launcher/MainForm.resx b/OpenRA.Launcher/MainForm.resx
deleted file mode 100644
index 9383875582..0000000000
--- a/OpenRA.Launcher/MainForm.resx
+++ /dev/null
@@ -1,277 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
-
-
- 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
-
-
-
diff --git a/OpenRA.Launcher/Mod.cs b/OpenRA.Launcher/Mod.cs
new file mode 100644
index 0000000000..3815ab1a10
--- /dev/null
+++ b/OpenRA.Launcher/Mod.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace OpenRA.Launcher
+{
+ public class Mod
+ {
+ public string Title { get; private set; }
+ public string Version { get; private set; }
+ public string Author { get; private set; }
+ public string Description { get; private set; }
+ public string Requires { get; private set; }
+ public bool Standalone { get; private set; }
+
+ public Mod(string title, string version, string author, string description, string requires, bool standalone)
+ {
+ Title = title;
+ Version = version;
+ Author = author;
+ Description = description;
+ Requires = requires;
+ Standalone = standalone;
+ }
+ }
+}
diff --git a/OpenRA.Launcher/OpenRA.Launcher.csproj b/OpenRA.Launcher/OpenRA.Launcher.csproj
index 5a3b1b29bf..a16b8aea40 100644
--- a/OpenRA.Launcher/OpenRA.Launcher.csproj
+++ b/OpenRA.Launcher/OpenRA.Launcher.csproj
@@ -42,11 +42,12 @@
-->
-
+
+
Form
-
- ConfigureModsDialog.cs
+
+ Launcher.cs
Form
@@ -54,12 +55,7 @@
InstallPackagesDialog.cs
-
- Form
-
-
- MainForm.cs
-
+
@@ -75,15 +71,12 @@
-
- ConfigureModsDialog.cs
+
+ Launcher.cs
InstallPackagesDialog.cs
-
- MainForm.cs
-
diff --git a/OpenRA.Launcher/Program.cs b/OpenRA.Launcher/Program.cs
index ad9104302d..79ad06b49d 100644
--- a/OpenRA.Launcher/Program.cs
+++ b/OpenRA.Launcher/Program.cs
@@ -10,7 +10,7 @@ namespace OpenRA.Launcher
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
- Application.Run(new MainForm());
+ Application.Run(new Launcher());
}
}
}
diff --git a/soviet-logo.png b/soviet-logo.png
index b858fd6816..96f770fa73 100644
Binary files a/soviet-logo.png and b/soviet-logo.png differ