Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Modify GameInformationPanel to optionally display as an invite #633

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
99 changes: 67 additions & 32 deletions DXMainClient/DXGUI/Multiplayer/CnCNet/CnCNetLobby.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ public CnCNetLobby(WindowManager windowManager, CnCNetManager connectionManager,
private PasswordRequestWindow passwordRequestWindow;

private bool isInGameRoom = false;
private string gameRoomChannelName = "";
private bool updateDenied = false;

private string localGameID;
Expand Down Expand Up @@ -439,7 +440,7 @@ private bool HostedGameMatches(GenericHostedGame hg)

string textUpper = tbGameSearch?.Text?.ToUpperInvariant();

string translatedGameMode = string.IsNullOrEmpty(hg.GameMode)
string translatedGameMode = string.IsNullOrEmpty(hg.GameMode)
? "Unknown".L10N("Client:Main:Unknown")
: hg.GameMode.L10N($"INI:GameModes:{hg.GameMode}:UIName", notify: false);

Expand Down Expand Up @@ -746,6 +747,7 @@ private void GameLoadingLobby_GameLeft(object sender, EventArgs e)
{
topBar.SwitchToSecondary();
isInGameRoom = false;
gameRoomChannelName = "";
SetLogOutButtonText();

// keep the friends window up to date so it can disable the Invite option
Expand All @@ -756,6 +758,7 @@ private void GameLobby_GameLeft(object sender, EventArgs e)
{
topBar.SwitchToSecondary();
isInGameRoom = false;
gameRoomChannelName = "";
SetLogOutButtonText();

// keep the friends window up to date so it can disable the Invite option
Expand All @@ -782,7 +785,7 @@ private void SetLogOutButtonText()
private void BtnJoinGame_LeftClick(object sender, EventArgs e) => JoinSelectedGame();

private void LbGameList_DoubleLeftClick(object sender, EventArgs e) => JoinSelectedGame();

private void LbGameList_RightClick(object sender, EventArgs e)
{
lbGameList.SelectedIndex = lbGameList.HoveredIndex;
Expand Down Expand Up @@ -996,6 +999,7 @@ private void GameChannel_UserAdded(object sender, Online.ChannelUserEventArgs e)
if (e.User.IRCUser.Name == ProgramConstants.PLAYERNAME)
{
ClearGameChannelEvents(gameChannel);
gameRoomChannelName = gameChannel.ChannelName;
gameLobby.OnJoined();
isInGameRoom = true;
SetLogOutButtonText();
Expand Down Expand Up @@ -1102,9 +1106,10 @@ private void GameLoadingChannel_UserAdded(object sender, ChannelUserEventArgs e)
{
gameLoadingChannel.UserAdded -= GameLoadingChannel_UserAdded;
gameLoadingChannel.InvalidPasswordEntered -= GameChannel_InvalidPasswordEntered_LoadedGame;

gameLoadingLobby.OnJoined();
isInGameRoom = true;
gameRoomChannelName = gameLoadingChannel.ChannelName;
isJoiningGame = false;
}
}
Expand Down Expand Up @@ -1241,6 +1246,9 @@ private void HandleGameInviteCommand(string sender, string argumentsString)
if (!CanReceiveInvitationMessagesFrom(sender))
return;

if (channelName == gameRoomChannelName)
return;

var gameIndex = lbGameList.HostedGames.FindIndex(hg => ((HostedCnCNetGame)hg).ChannelName == channelName);

// also enforce user preference on whether to accept invitations from non-friends
Expand Down Expand Up @@ -1270,47 +1278,55 @@ private void HandleGameInviteCommand(string sender, string argumentsString)
return;
}

var gameInviteChoiceBox = new ChoiceNotificationBox(WindowManager);

WindowManager.AddAndInitializeControl(gameInviteChoiceBox);

// show the invitation at top left; it will remain until it is acted upon or the target game is closed
gameInviteChoiceBox.Show(
"GAME INVITATION".L10N("Client:Main:GameInviteTitle"),
GetUserTexture(sender),
sender,
string.Format("Join {0}?".L10N("Client:Main:GameInviteText"), gameName),
"Yes".L10N("Client:Main:ButtonYes"), "No".L10N("Client:Main:ButtonNo"), 0);
GameInvitePanel panelGameInvite;
panelGameInvite = new GameInvitePanel(WindowManager, mapLoader);
panelGameInvite.Name = nameof(panelGameInvite);
panelGameInvite.BackgroundTexture = AssetLoader.LoadTexture("cncnetlobbypanelbg.png");
panelGameInvite.DrawMode = ControlDrawMode.UNIQUE_RENDER_TARGET;
panelGameInvite.Initialize();
panelGameInvite.Enable();
panelGameInvite.InputEnabled = true;
panelGameInvite.Alpha = 0.5f;
panelGameInvite.AlphaRate = 0.5f;

var hostedGame = lbGameList.HostedGames[lbGameList.HostedGames.FindIndex(hg => ((HostedCnCNetGame)hg).ChannelName == channelName)];
WindowManager.AddAndInitializeControl(panelGameInvite);
WindowManager.CenterControlOnScreen(panelGameInvite);
panelGameInvite.SetInfo(hostedGame);

// add the invitation to the index so we can remove it if the target game is closed
// also lets us silently ignore new invitations from the same person while this one is still outstanding
invitationIndex[invitationIdentity] =
new WeakReference(gameInviteChoiceBox);
new WeakReference(panelGameInvite);

gameInviteChoiceBox.AffirmativeClickedAction = delegate (ChoiceNotificationBox choiceBox)
panelGameInvite.AcceptInvite += () =>
{
// if we're currently in a game lobby, first leave that channel
if (isInGameRoom)
if (channelName != gameRoomChannelName)
{
gameLobby.LeaveGameLobby();
}

// JoinGameByIndex does bounds checking so we're safe to pass -1 if the game doesn't exist
if (!JoinGameByIndex(lbGameList.HostedGames.FindIndex(hg => ((HostedCnCNetGame)hg).ChannelName == channelName), password))
{
XNAMessageBox.Show(WindowManager,
"Failed to join".L10N("Client:Main:JoinFailedTitle"),
string.Format("Unable to join {0}'s game. The game may be locked or closed.".L10N("Client:Main:JoinFailedText"), sender));
// if we're currently in a game lobby that differs to the invite, first leave that channel
if (isInGameRoom)
{
gameLobby.LeaveGameLobby();
}
// JoinGameByIndex does bounds checking so we're safe to pass -1 if the game doesn't exist
if (!JoinGameByIndex(lbGameList.HostedGames.FindIndex(hg => ((HostedCnCNetGame)hg).ChannelName == channelName), password))
{
XNAMessageBox.Show(WindowManager,
"Failed to join".L10N("Client:Main:JoinFailedTitle"),
string.Format("Unable to join {0}'s game. The game may be locked, closed, or on a different version.".L10N("Client:Main:JoinFailedText"), sender));
}
}

// clean up the index as this invitation no longer exists
invitationIndex.Remove(invitationIdentity);
WindowManager.RemoveControl(panelGameInvite);
};

gameInviteChoiceBox.NegativeClickedAction = delegate (ChoiceNotificationBox choiceBox)
panelGameInvite.DeclineInvite += () =>
{
// clean up the index as this invitation no longer exists
// Handle decline invite logic
invitationIndex.Remove(invitationIdentity);
WindowManager.RemoveControl(panelGameInvite);
};

sndGameInviteReceived.Play();
Expand Down Expand Up @@ -1358,7 +1374,7 @@ private void DdCurrentChannel_SelectedIndexChanged(object sender, EventArgs e)
currentChatChannel = (Channel)ddCurrentChannel.SelectedItem?.Tag;
if (currentChatChannel == null)
throw new Exception("Current selected chat channel is null. This should not happen.");

currentChatChannel.UserAdded += RefreshPlayerList;
currentChatChannel.UserLeft += RefreshPlayerList;
currentChatChannel.UserQuitIRC += RefreshPlayerList;
Expand Down Expand Up @@ -1569,12 +1585,13 @@ private void GameBroadcastChannel_CTCPReceived(object sender, ChannelCTCPEventAr
}

// Seek for the game in the internal game list based on the name of its host;
// if found, then refresh that game's information, otherwise add as new game
// if found, then refresh that game's information and invites, otherwise add as new game
int gameIndex = lbGameList.HostedGames.FindIndex(hg => hg.HostName == e.UserName);

if (gameIndex > -1)
{
lbGameList.HostedGames[gameIndex] = game;
UpdateInvitations();
}
else
{
Expand Down Expand Up @@ -1666,6 +1683,24 @@ private Texture2D GetUserTexture(string username)

return senderGameIcon;
}
private void UpdateInvitations()
{
foreach (var invitation in invitationIndex)
{
var userChannelPair = invitation.Key;
if (invitation.Value.Target is GameInvitePanel invitationNotification)
{
var game = lbGameList.HostedGames
.OfType<HostedCnCNetGame>()
.FirstOrDefault(hg => hg.HostName == userChannelPair.Item1 && hg.ChannelName == userChannelPair.Item2);

if (game != null)
{
invitationNotification.SetInfo(game);
}
}
}
}

private void DismissInvalidInvitations()
{
Expand Down Expand Up @@ -1694,7 +1729,7 @@ private void DismissInvitation(UserChannelPair invitationIdentity)
{
if (invitationIndex.ContainsKey(invitationIdentity))
{
var invitationNotification = invitationIndex[invitationIdentity].Target as ChoiceNotificationBox;
var invitationNotification = invitationIndex[invitationIdentity].Target as GameInvitePanel;

if (invitationNotification != null)
{
Expand Down
110 changes: 110 additions & 0 deletions DXMainClient/DXGUI/Multiplayer/GameInvitePanel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using System;
using System.Diagnostics;
using System.Windows.Forms;

Check failure on line 3 in DXMainClient/DXGUI/Multiplayer/GameInvitePanel.cs

View workflow job for this annotation

GitHub Actions / build-clients (Ares)

The type or namespace name 'Forms' does not exist in the namespace 'System.Windows' (are you missing an assembly reference?)

Check failure on line 3 in DXMainClient/DXGUI/Multiplayer/GameInvitePanel.cs

View workflow job for this annotation

GitHub Actions / build-clients (TS)

The type or namespace name 'Forms' does not exist in the namespace 'System.Windows' (are you missing an assembly reference?)

Check failure on line 3 in DXMainClient/DXGUI/Multiplayer/GameInvitePanel.cs

View workflow job for this annotation

GitHub Actions / build-clients (YR)

The type or namespace name 'Forms' does not exist in the namespace 'System.Windows' (are you missing an assembly reference?)

using ClientCore;
using ClientCore.Extensions;

using ClientGUI;

using DTAClient.Domain.Multiplayer;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using Rampastring.XNAUI;
using Rampastring.XNAUI.XNAControls;

namespace DTAClient.DXGUI.Multiplayer
{
/// <summary>
/// A UI panel that displays information about a hosted CnCNet or LAN game.
/// </summary>
public class GameInvitePanel : XNAPanel
{
public GameInvitePanel(WindowManager windowManager, MapLoader mapLoader)
: base(windowManager)
{
this.mapLoader = mapLoader;
DrawMode = ControlDrawMode.UNIQUE_RENDER_TARGET;
}

private readonly MapLoader mapLoader;

private GenericHostedGame game = null;

private const int buttonWidth = UIDesignConstants.BUTTON_WIDTH_92;
private const int buttonHeight = UIDesignConstants.BUTTON_HEIGHT;
private const int padding = 12;

private XNALabel lblInviteHeading;
private XNAClientButton btnInviteAccept;
private XNAClientButton btnInviteDecline;
private GameInformationPanel panelGameInformation;

public event Action AcceptInvite;
public event Action DeclineInvite;

public override void Initialize()
{
panelGameInformation = new GameInformationPanel(WindowManager, mapLoader);
panelGameInformation.Name = nameof(panelGameInformation);
panelGameInformation.BackgroundTexture = AssetLoader.LoadTexture("cncnetlobbypanelbg.png");
panelGameInformation.DrawMode = ControlDrawMode.UNIQUE_RENDER_TARGET;
panelGameInformation.Initialize();
panelGameInformation.ClearInfo();
panelGameInformation.Disable();
panelGameInformation.InputEnabled = false;
panelGameInformation.DrawBorders = false;
AddChild(panelGameInformation);

lblInviteHeading = new XNALabel(WindowManager);
AddChild(lblInviteHeading);

ClientRectangle = new Rectangle(0, 0, panelGameInformation.Width + 2, padding + lblInviteHeading.Height + panelGameInformation.Height + padding + buttonHeight + padding); //...+2 to account for panelGameInformation border width
BackgroundTexture = AssetLoader.CreateTexture(new Color(0, 0, 0, 255), 1, 1);
PanelBackgroundDrawMode = PanelBackgroundImageDrawMode.STRETCHED;

panelGameInformation.X = 1; //border width

btnInviteAccept = new XNAClientButton(WindowManager);
btnInviteAccept.Text = "Accept".L10N("Client:Main:InviteAccept");
btnInviteAccept.ClientRectangle = new Rectangle(ClientRectangle.Width / 2 - buttonWidth - (padding / 2), panelGameInformation.Y + panelGameInformation.Height + padding, buttonWidth, buttonHeight);
btnInviteAccept.LeftClick += (s, e) => AcceptInvite?.Invoke();
btnInviteAccept.Visible = true;
btnInviteAccept.Name = nameof(btnInviteAccept);
AddChild(btnInviteAccept);

btnInviteDecline = new XNAClientButton(WindowManager);
btnInviteDecline.Text = "Decline".L10N("Client:Main:InviteDecline");
btnInviteDecline.ClientRectangle = new Rectangle(ClientRectangle.Width / 2 + (padding / 2), btnInviteAccept.Y, buttonWidth, buttonHeight);
btnInviteDecline.LeftClick += (s, e) => DeclineInvite?.Invoke();
btnInviteDecline.Visible = true;
btnInviteDecline.Name = nameof(btnInviteDecline);
AddChild(btnInviteDecline);
base.Initialize();
}

public void SetInfo(GenericHostedGame game)
{
if (game != null)
{
this.game = game;
lblInviteHeading.FontIndex = 1;
lblInviteHeading.Text = string.Format("{0} IS INVITING YOU TO PLAY".L10N("Client:Main:InviteHeading"), game.HostName);
lblInviteHeading.CenterOnParentHorizontally();
lblInviteHeading.Y = ((padding + lblInviteHeading.Height + padding) / 2) - (lblInviteHeading.Height / 2);
panelGameInformation.Y = lblInviteHeading.Y + lblInviteHeading.Height + padding;
panelGameInformation.SetInfo(game);
panelGameInformation.Enable();
};
}

public override void Draw(GameTime gameTime)
{
base.Draw(gameTime);

DrawChildren(gameTime);
}
}
}
Loading