diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index f539c40362..50db00bcd6 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -917,6 +917,7 @@
+
diff --git a/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs
index a0793b6888..d3a46e836a 100644
--- a/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs
+++ b/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs
@@ -228,6 +228,16 @@ namespace OpenRA.Mods.Common.Widgets.Logic
menuType != MenuType.SystemInfoPrompt &&
webServices.ModVersionStatus == ModVersionStatus.Outdated;
+ var playerProfile = widget.GetOrNull("PLAYER_PROFILE_CONTAINER");
+ if (playerProfile != null)
+ {
+ Func minimalProfile = () => Ui.CurrentWindow() != null;
+ Game.LoadWidget(world, "LOCAL_PROFILE_PANEL", playerProfile, new WidgetArgs()
+ {
+ { "minimalProfile", minimalProfile }
+ });
+ }
+
// System information opt-out prompt
var sysInfoPrompt = widget.Get("SYSTEM_INFO_PROMPT");
sysInfoPrompt.IsVisible = () => menuType == MenuType.SystemInfoPrompt;
diff --git a/OpenRA.Mods.Common/Widgets/Logic/PlayerProfileLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/PlayerProfileLogic.cs
new file mode 100644
index 0000000000..3ec8ace4d2
--- /dev/null
+++ b/OpenRA.Mods.Common/Widgets/Logic/PlayerProfileLogic.cs
@@ -0,0 +1,91 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2018 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, either version 3 of
+ * the License, or (at your option) any later version. For more
+ * information, see COPYING.
+ */
+#endregion
+
+using System;
+using OpenRA.Graphics;
+using OpenRA.Widgets;
+
+namespace OpenRA.Mods.Common.Widgets.Logic
+{
+ public class LocalProfileLogic : ChromeLogic
+ {
+ readonly LocalPlayerProfile localProfile;
+ readonly Widget detailsContainer;
+ bool notFound;
+
+ [ObjectCreator.UseCtor]
+ public LocalProfileLogic(Widget widget, WorldRenderer worldRenderer, Func minimalProfile)
+ {
+ localProfile = Game.LocalPlayerProfile;
+
+ // Key registration
+ widget.Get("GENERATE_KEYS").IsVisible = () => localProfile.State == LocalPlayerProfile.LinkState.Uninitialized && !minimalProfile();
+ widget.Get("GENERATING_KEYS").IsVisible = () => localProfile.State == LocalPlayerProfile.LinkState.GeneratingKeys && !minimalProfile();
+
+ var lastProfileState = LocalPlayerProfile.LinkState.CheckingLink;
+ widget.Get("REGISTER_FINGERPRINT").IsVisible = () =>
+ {
+ // Take a copy of the state to avoid race conditions
+ var state = localProfile.State;
+
+ // Copy the key to the clipboard when displaying the link instructions
+ if (state != lastProfileState && state == LocalPlayerProfile.LinkState.Unlinked)
+ Game.SetClipboardText(localProfile.PublicKey);
+
+ lastProfileState = state;
+ return localProfile.State == LocalPlayerProfile.LinkState.Unlinked && !notFound && !minimalProfile();
+ };
+
+ widget.Get("CHECKING_FINGERPRINT").IsVisible = () => localProfile.State == LocalPlayerProfile.LinkState.CheckingLink && !minimalProfile();
+ widget.Get("FINGERPRINT_NOT_FOUND").IsVisible = () => localProfile.State == LocalPlayerProfile.LinkState.Unlinked && notFound && !minimalProfile();
+ widget.Get("CONNECTION_ERROR").IsVisible = () => localProfile.State == LocalPlayerProfile.LinkState.ConnectionFailed && !minimalProfile();
+
+ widget.Get("GENERATE_KEY").OnClick = localProfile.GenerateKeypair;
+
+ widget.Get("CHECK_KEY").OnClick = () => localProfile.RefreshPlayerData(() => RefreshComplete(true));
+
+ widget.Get("DELETE_KEY").OnClick = () =>
+ {
+ localProfile.DeleteKeypair();
+ Game.RunAfterTick(Ui.ResetTooltips);
+ };
+
+ widget.Get("FINGERPRINT_NOT_FOUND_CONTINUE").OnClick = () =>
+ {
+ notFound = false;
+ Game.RunAfterTick(Ui.ResetTooltips);
+ };
+
+ widget.Get("CONNECTION_ERROR_RETRY").OnClick = () => localProfile.RefreshPlayerData(() => RefreshComplete(true));
+
+ // Profile view
+ widget.Get("PROFILE_HEADER").IsVisible = () => localProfile.State == LocalPlayerProfile.LinkState.Linked;
+ widget.Get("PROFILE_NAME").GetText = () => localProfile.ProfileData.ProfileName;
+ widget.Get("PROFILE_RANK").GetText = () => localProfile.ProfileData.ProfileRank;
+
+ var destroyKey = widget.Get("DESTROY_KEY");
+ destroyKey.OnClick = localProfile.DeleteKeypair;
+ destroyKey.IsDisabled = minimalProfile;
+
+ detailsContainer = widget.Get("PROFILE_DETAILS");
+ detailsContainer.IsVisible = () => localProfile.State == LocalPlayerProfile.LinkState.Linked && !minimalProfile();
+ localProfile.RefreshPlayerData(() => RefreshComplete(false));
+ }
+
+ public void RefreshComplete(bool updateNotFound)
+ {
+ if (updateNotFound)
+ notFound = localProfile.State == LocalPlayerProfile.LinkState.Unlinked;
+
+ Game.RunAfterTick(Ui.ResetTooltips);
+ }
+ }
+}
diff --git a/mods/cnc/chrome/mainmenu.yaml b/mods/cnc/chrome/mainmenu.yaml
index 9eb0173397..24f6f18049 100644
--- a/mods/cnc/chrome/mainmenu.yaml
+++ b/mods/cnc/chrome/mainmenu.yaml
@@ -320,3 +320,6 @@ Container@MENU_BACKGROUND:
Y: 10
Width: 200
Height: 200
+ Container@PLAYER_PROFILE_CONTAINER:
+ X: 31
+ Y: 31
diff --git a/mods/cnc/chrome/playerprofile.yaml b/mods/cnc/chrome/playerprofile.yaml
new file mode 100644
index 0000000000..85f226e9ed
--- /dev/null
+++ b/mods/cnc/chrome/playerprofile.yaml
@@ -0,0 +1,210 @@
+Container@LOCAL_PROFILE_PANEL:
+ Logic: LocalProfileLogic
+ Width: 270
+ Height: 100
+ Children:
+ Background@PROFILE_HEADER:
+ Width: PARENT_RIGHT
+ Height: 50
+ Background: panel-black
+ Children:
+ Label@PROFILE_NAME:
+ X: 10
+ Y: 3
+ Width: PARENT_RIGHT - 20
+ Height: 25
+ Font: MediumBold
+ Label@PROFILE_RANK:
+ X: 10
+ Y: 23
+ Width: PARENT_RIGHT - 20
+ Height: 25
+ Font: TinyBold
+ Button@DESTROY_KEY:
+ X: PARENT_RIGHT - 70
+ Y: 15
+ Width: 60
+ Height: 20
+ Font: TinyBold
+ BaseLine: 1
+ Text: Logout
+ Background@GENERATE_KEYS:
+ Width: PARENT_RIGHT
+ Height: PARENT_BOTTOM
+ Background: panel-black
+ Children:
+ Label@DESC_A:
+ Y: 5
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: Connect to a forum account to identify
+ Label@DESC_B:
+ Y: 21
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: yourself to other players, join private
+ Label@DESC_C:
+ Y: 37
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: servers, and display badges.
+ Button@GENERATE_KEY:
+ X: (PARENT_RIGHT - WIDTH) / 2
+ Y: 70
+ Width: 240
+ Height: 20
+ Font: TinyBold
+ BaseLine: 1
+ Text: Connect to an OpenRA forum account
+ Background@GENERATING_KEYS:
+ Width: PARENT_RIGHT
+ Height: PARENT_BOTTOM
+ Background: panel-black
+ Children:
+ Label@DESC_A:
+ Y: 13
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: Generating authentication key pair.
+ Label@DESC_B:
+ Y: 29
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: This will take several seconds...
+ ProgressBar:
+ X: (PARENT_RIGHT - WIDTH) / 2
+ Y: 70
+ Width: 240
+ Height: 20
+ Indeterminate: true
+ Background@REGISTER_FINGERPRINT:
+ Width: PARENT_RIGHT
+ Height: PARENT_BOTTOM
+ Background: panel-black
+ Children:
+ Label@DESC_A:
+ Y: 2
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: An authentication key has been copied to your
+ Label@DESC_B:
+ Y: 18
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: clipboard. Add this to your User Control Panel
+ Label@DESC_C:
+ Y: 34
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: on the OpenRA forum then press Continue.
+ Button@DELETE_KEY:
+ X: 15
+ Y: 70
+ Width: 70
+ Height: 20
+ BaseLine: 1
+ Font: TinyBold
+ Text: Cancel
+ Button@CHECK_KEY:
+ X: 185
+ Y: 70
+ Width: 70
+ Height: 20
+ BaseLine: 1
+ Font: TinyBold
+ Text: Continue
+ Background@CHECKING_FINGERPRINT:
+ Width: PARENT_RIGHT
+ Height: PARENT_BOTTOM
+ Background: panel-black
+ Children:
+ Label@DESC_A:
+ Y: 13
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: Querying account details from
+ Label@DESC_B:
+ Y: 29
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: the OpenRA forum...
+ ProgressBar:
+ X: (PARENT_RIGHT - WIDTH) / 2
+ Y: 70
+ Width: 240
+ Height: 20
+ Indeterminate: true
+ Background@FINGERPRINT_NOT_FOUND:
+ Width: PARENT_RIGHT
+ Height: PARENT_BOTTOM
+ Background: panel-black
+ Children:
+ Label@DESC_A:
+ Y: 13
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: Your authentication key is not connected
+ Label@DESC_B:
+ Y: 29
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: to an OpenRA forum account.
+ Button@FINGERPRINT_NOT_FOUND_CONTINUE:
+ X: 185
+ Y: 70
+ Width: 70
+ Height: 20
+ BaseLine: 1
+ Font: TinyBold
+ Text: Back
+ Background@CONNECTION_ERROR:
+ Width: PARENT_RIGHT
+ Height: PARENT_BOTTOM
+ Background: panel-black
+ Children:
+ Label@DESC_A:
+ Y: 13
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: Failed to connect to the OpenRA forum.
+ Label@DESC_B:
+ Y: 29
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: Please check your internet connection.
+ Button@CONNECTION_ERROR_RETRY:
+ X: 185
+ Y: 70
+ Width: 70
+ Height: 20
+ BaseLine: 1
+ Font: TinyBold
+ Text: Retry
diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml
index 597f50dd12..51da16f769 100644
--- a/mods/cnc/mod.yaml
+++ b/mods/cnc/mod.yaml
@@ -91,6 +91,7 @@ Assemblies:
ChromeLayout:
cnc|chrome/mainmenu.yaml
+ cnc|chrome/playerprofile.yaml
cnc|chrome/multiplayer-browser.yaml
cnc|chrome/multiplayer-browserpanels.yaml
cnc|chrome/multiplayer-createserver.yaml
diff --git a/mods/common/chrome/mainmenu.yaml b/mods/common/chrome/mainmenu.yaml
index 2b493d4732..b17af26690 100644
--- a/mods/common/chrome/mainmenu.yaml
+++ b/mods/common/chrome/mainmenu.yaml
@@ -320,3 +320,6 @@ Container@MAINMENU:
Align: Center
Shadow: true
Text: Download the latest version from www.openra.net
+ Container@PLAYER_PROFILE_CONTAINER:
+ X: 25
+ Y: 25
diff --git a/mods/common/chrome/playerprofile.yaml b/mods/common/chrome/playerprofile.yaml
new file mode 100644
index 0000000000..f6b14addd5
--- /dev/null
+++ b/mods/common/chrome/playerprofile.yaml
@@ -0,0 +1,210 @@
+Container@LOCAL_PROFILE_PANEL:
+ Logic: LocalProfileLogic
+ Width: 270
+ Height: 100
+ Children:
+ Background@PROFILE_HEADER:
+ Width: PARENT_RIGHT
+ Height: 50
+ Background: dialog2
+ Children:
+ Label@PROFILE_NAME:
+ X: 10
+ Y: 3
+ Width: PARENT_RIGHT - 20
+ Height: 25
+ Font: MediumBold
+ Label@PROFILE_RANK:
+ X: 10
+ Y: 23
+ Width: PARENT_RIGHT - 20
+ Height: 25
+ Font: TinyBold
+ Button@DESTROY_KEY:
+ X: PARENT_RIGHT - 70
+ Y: 15
+ Width: 60
+ Height: 20
+ Font: TinyBold
+ BaseLine: 1
+ Text: Logout
+ Background@GENERATE_KEYS:
+ Width: PARENT_RIGHT
+ Height: PARENT_BOTTOM
+ Background: dialog2
+ Children:
+ Label@DESC_A:
+ Y: 5
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: Connect to a forum account to identify
+ Label@DESC_B:
+ Y: 21
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: yourself to other players, join private
+ Label@DESC_C:
+ Y: 37
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: servers, and display badges.
+ Button@GENERATE_KEY:
+ X: (PARENT_RIGHT - WIDTH) / 2
+ Y: 70
+ Width: 240
+ Height: 20
+ Font: TinyBold
+ BaseLine: 1
+ Text: Connect to an OpenRA forum account
+ Background@GENERATING_KEYS:
+ Width: PARENT_RIGHT
+ Height: PARENT_BOTTOM
+ Background: dialog2
+ Children:
+ Label@DESC_A:
+ Y: 13
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: Generating authentication key pair.
+ Label@DESC_B:
+ Y: 29
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: This will take several seconds...
+ ProgressBar:
+ X: (PARENT_RIGHT - WIDTH) / 2
+ Y: 70
+ Width: 240
+ Height: 20
+ Indeterminate: true
+ Background@REGISTER_FINGERPRINT:
+ Width: PARENT_RIGHT
+ Height: PARENT_BOTTOM
+ Background: dialog2
+ Children:
+ Label@DESC_A:
+ Y: 2
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: An authentication key has been copied to your
+ Label@DESC_B:
+ Y: 18
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: clipboard. Add this to your User Control Panel
+ Label@DESC_C:
+ Y: 34
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: on the OpenRA forum then press Continue.
+ Button@DELETE_KEY:
+ X: 15
+ Y: 70
+ Width: 70
+ Height: 20
+ BaseLine: 1
+ Font: TinyBold
+ Text: Cancel
+ Button@CHECK_KEY:
+ X: 185
+ Y: 70
+ Width: 70
+ Height: 20
+ BaseLine: 1
+ Font: TinyBold
+ Text: Continue
+ Background@CHECKING_FINGERPRINT:
+ Width: PARENT_RIGHT
+ Height: PARENT_BOTTOM
+ Background: dialog2
+ Children:
+ Label@DESC_A:
+ Y: 13
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: Querying account details from
+ Label@DESC_B:
+ Y: 29
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: the OpenRA forum...
+ ProgressBar:
+ X: (PARENT_RIGHT - WIDTH) / 2
+ Y: 70
+ Width: 240
+ Height: 20
+ Indeterminate: true
+ Background@FINGERPRINT_NOT_FOUND:
+ Width: PARENT_RIGHT
+ Height: PARENT_BOTTOM
+ Background: dialog2
+ Children:
+ Label@DESC_A:
+ Y: 13
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: Your authentication key is not connected
+ Label@DESC_B:
+ Y: 29
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: to an OpenRA forum account.
+ Button@FINGERPRINT_NOT_FOUND_CONTINUE:
+ X: 185
+ Y: 70
+ Width: 70
+ Height: 20
+ BaseLine: 1
+ Font: TinyBold
+ Text: Back
+ Background@CONNECTION_ERROR:
+ Width: PARENT_RIGHT
+ Height: PARENT_BOTTOM
+ Background: dialog2
+ Children:
+ Label@DESC_A:
+ Y: 13
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: Failed to connect to the OpenRA forum.
+ Label@DESC_B:
+ Y: 29
+ Width: PARENT_RIGHT
+ Height: 25
+ Font: Small
+ Align: Center
+ Text: Please check your internet connection.
+ Button@CONNECTION_ERROR_RETRY:
+ X: 185
+ Y: 70
+ Width: 70
+ Height: 20
+ BaseLine: 1
+ Font: TinyBold
+ Text: Retry
diff --git a/mods/d2k/chrome/mainmenu.yaml b/mods/d2k/chrome/mainmenu.yaml
index fac7b7b1d9..dd517591fe 100644
--- a/mods/d2k/chrome/mainmenu.yaml
+++ b/mods/d2k/chrome/mainmenu.yaml
@@ -306,3 +306,6 @@ Container@MAINMENU:
Y: 5
Width: 200
Height: 200
+ Container@PLAYER_PROFILE_CONTAINER:
+ X: 5
+ Y: 5
diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml
index c9c0d89419..e7a60b4851 100644
--- a/mods/d2k/mod.yaml
+++ b/mods/d2k/mod.yaml
@@ -86,6 +86,7 @@ ChromeLayout:
common|chrome/credits.yaml
common|chrome/lobby.yaml
common|chrome/lobby-mappreview.yaml
+ common|chrome/playerprofile.yaml
d2k|chrome/lobby-players.yaml
common|chrome/lobby-options.yaml
common|chrome/lobby-music.yaml
diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml
index 4cdd6a3fe8..3642abdd69 100644
--- a/mods/ra/mod.yaml
+++ b/mods/ra/mod.yaml
@@ -121,6 +121,7 @@ ChromeLayout:
common|chrome/missionbrowser.yaml
common|chrome/confirmation-dialogs.yaml
common|chrome/editor.yaml
+ common|chrome/playerprofile.yaml
Weapons:
ra|weapons/explosions.yaml
diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml
index 71bc08da63..83387298be 100644
--- a/mods/ts/mod.yaml
+++ b/mods/ts/mod.yaml
@@ -154,6 +154,7 @@ ChromeLayout:
common|chrome/lobby-music.yaml
common|chrome/lobby-servers.yaml
common|chrome/lobby-kickdialogs.yaml
+ common|chrome/playerprofile.yaml
ts|chrome/color-picker.yaml
common|chrome/map-chooser.yaml
common|chrome/multiplayer-browser.yaml