Add IRC interface to ra/cnc server browsers

This commit is contained in:
ScottNZ
2013-09-22 17:59:38 +12:00
parent 5bdd0705b2
commit c6dc0e8c8b
13 changed files with 434 additions and 29 deletions

View File

@@ -46,7 +46,6 @@ namespace OpenRA.Widgets
base.RemoveChildren(); base.RemoveChildren();
} }
public override void AddChild(Widget child) public override void AddChild(Widget child)
{ {
// Initial setup of margins/height // Initial setup of margins/height

View File

@@ -33,7 +33,7 @@ namespace OpenRA.Widgets
public Func<bool> OnTabKey = () => false; public Func<bool> OnTabKey = () => false;
public Func<bool> OnEscKey = () => false; public Func<bool> OnEscKey = () => false;
public Action OnLoseFocus = () => { }; public Action OnLoseFocus = () => { };
public int CursorPosition { get; protected set; } public int CursorPosition { get; set; }
public Func<bool> IsDisabled = () => false; public Func<bool> IsDisabled = () => false;
public Color TextColor = Color.White; public Color TextColor = Color.White;

View File

@@ -380,6 +380,7 @@
<Compile Include="Widgets\BuildPaletteWidget.cs" /> <Compile Include="Widgets\BuildPaletteWidget.cs" />
<Compile Include="Widgets\LogicTickerWidget.cs" /> <Compile Include="Widgets\LogicTickerWidget.cs" />
<Compile Include="Widgets\Logic\IngameMenuLogic.cs" /> <Compile Include="Widgets\Logic\IngameMenuLogic.cs" />
<Compile Include="Widgets\Logic\IrcLogic.cs" />
<Compile Include="Widgets\Logic\KickClientLogic.cs" /> <Compile Include="Widgets\Logic\KickClientLogic.cs" />
<Compile Include="Widgets\Logic\ModBrowserLogic.cs" /> <Compile Include="Widgets\Logic\ModBrowserLogic.cs" />
<Compile Include="Widgets\Logic\ColorPickerLogic.cs" /> <Compile Include="Widgets\Logic\ColorPickerLogic.cs" />
@@ -482,6 +483,10 @@
<Name>OpenRA.Game</Name> <Name>OpenRA.Game</Name>
<Private>False</Private> <Private>False</Private>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\OpenRA.Irc\OpenRA.Irc.csproj">
<Project>{85b48234-8b31-4be6-af9c-665cc6866841}</Project>
<Name>OpenRA.Irc</Name>
</ProjectReference>
<ProjectReference Include="..\OpenRA.Utility\OpenRA.Utility.csproj"> <ProjectReference Include="..\OpenRA.Utility\OpenRA.Utility.csproj">
<Project>{F33337BE-CB69-4B24-850F-07D23E408DDF}</Project> <Project>{F33337BE-CB69-4B24-850F-07D23E408DDF}</Project>
<Name>OpenRA.Utility</Name> <Name>OpenRA.Utility</Name>

View File

@@ -0,0 +1,252 @@
#region Copyright & License Information
/*
* Copyright 2007-2013 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 COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Irc;
using OpenRA.Widgets;
namespace OpenRA.Mods.RA.Widgets.Logic
{
class IrcLogic
{
TextFieldWidget inputBox;
TextFieldWidget nicknameBox;
Widget connectBG;
Widget ircContainer;
[ObjectCreator.UseCtor]
public IrcLogic(Widget widget)
{
var historyPanel = widget.Get<ScrollPanelWidget>("HISTORY_PANEL");
var historyTemplate = widget.Get<LabelWidget>("HISTORY_TEMPLATE");
var nicknamePanel = widget.Get<ScrollPanelWidget>("NICKNAME_PANEL");
var nicknameTemplate = widget.Get<LabelWidget>("NICKNAME_TEMPLATE");
inputBox = widget.Get<TextFieldWidget>("INPUT_BOX");
inputBox.OnEnterKey = EnterPressed;
inputBox.OnTabKey = TabPressed;
inputBox.IsDisabled = () => IrcClient.Instance.GetChannel(IrcClient.MainChannel) == null;
nicknameBox = widget.Get<TextFieldWidget>("NICKNAME_BOX");
nicknameBox.Text = ChooseNickname(Game.Settings.Irc.Nickname);
connectBG = widget.Get("IRC_CONNECT_BG");
ircContainer = widget.Get("IRC_CONTAINER");
widget.Get<ButtonWidget>("DISCONNECT_BUTTON").OnClick = IrcClient.Instance.Disconnect;
MaybeShowConnectPanel();
historyPanel.Bind(IrcClient.Instance.History, item => MakeLabelWidget(historyTemplate, item), LabelItemEquals, true);
var mainChannel = IrcClient.Instance.GetChannel(IrcClient.MainChannel);
if (mainChannel != null)
nicknamePanel.Bind(mainChannel.Users, item => MakeLabelWidget(nicknameTemplate, item), LabelItemEquals, false);
IrcClient.Instance.OnSync += l =>
{
var channel = l.GetChannel();
if (channel.Name.EqualsIC(IrcClient.MainChannel))
nicknamePanel.Bind(channel.Users, item => MakeLabelWidget(nicknameTemplate, item), LabelItemEquals, false);
};
IrcClient.Instance.OnKick += l =>
{
if (l.KickeeNickname.EqualsIC(IrcClient.Instance.LocalUser.Nickname) && l.Target.EqualsIC(IrcClient.MainChannel))
nicknamePanel.Unbind();
};
IrcClient.Instance.OnPart += l =>
{
if (l.PrefixIsSelf() && l.Target.EqualsIC(IrcClient.MainChannel))
nicknamePanel.Unbind();
};
IrcClient.Instance.OnDisconnect += () =>
{
nicknamePanel.Unbind();
MaybeShowConnectPanel();
};
commands.Add("me", args =>
{
IrcClient.Instance.Act(IrcClient.MainChannel, args);
IrcClient.AddAction(IrcClient.Instance.LocalUser.Nickname, args);
});
commands.Add("slap", args =>
{
IrcClient.Instance.Act(IrcClient.MainChannel, "slaps {0} around a bit with a large trout".F(args));
IrcClient.AddAction(IrcClient.Instance.LocalUser.Nickname, "slaps {0} around a bit with a large trout".F(args));
});
commands.Add("notice", args =>
{
var split = args.Split(new[] { ' ' }, 2);
if (split.Length < 2)
{
IrcClient.AddHistory("/notice: Not enough arguments");
return;
}
IrcClient.Instance.Notice(split[0], split[1]);
IrcClient.AddSelfNotice(split[0], split[1]);
});
commands.Add("disconnect", args =>
{
Game.Settings.Irc.ConnectAutomatically = false;
Game.Settings.Save();
IrcClient.Instance.Disconnect();
});
commands.Add("quit", args =>
{
Game.Settings.Irc.ConnectAutomatically = false;
Game.Settings.Save();
if (IrcClient.Instance.IsConnected)
IrcClient.Instance.Quit(args);
else
IrcClient.Instance.Disconnect();
});
commands.Add("nick", args => IrcClient.Instance.SetNickname(args));
commands.Add("topic", args => IrcClient.Instance.GetTopic(IrcClient.MainChannel));
}
void MaybeShowConnectPanel()
{
if (IrcClient.Instance.IsConnected || IrcClient.Instance.IsReconnecting)
{
ircContainer.Visible = true;
connectBG.Visible = false;
return;
}
if (Game.Settings.Irc.ConnectAutomatically)
{
ircContainer.Visible = true;
connectBG.Visible = false;
Connect();
return;
}
ircContainer.Visible = false;
connectBG.Visible = true;
var connectAutomaticallyCheckBox = connectBG.Get<CheckboxWidget>("CONNECT_AUTOMATICALLY_CHECKBOX");
var connectAutomaticallyChecked = false;
connectAutomaticallyCheckBox.IsChecked = () => connectAutomaticallyChecked;
connectAutomaticallyCheckBox.OnClick = () => connectAutomaticallyChecked ^= true;
var connectButton = connectBG.Get<ButtonWidget>("CONNECT_BUTTON");
connectButton.OnClick = () =>
{
ircContainer.Visible = true;
connectBG.Visible = false;
Game.Settings.Irc.ConnectAutomatically = connectAutomaticallyCheckBox.IsChecked();
Game.Settings.Save();
Connect();
};
}
string ChooseNickname(string nickname)
{
if (!IrcUtils.IsNickname(nickname))
{
nickname = Game.Settings.Player.Name;
if (!IrcUtils.IsNickname(nickname))
nickname = Game.Settings.Irc.DefaultNickname;
}
return nickname;
}
void Connect()
{
var nickname = ChooseNickname(nicknameBox.Text);
var s = Game.Settings.Irc;
s.Nickname = nickname;
Game.Settings.Save();
IrcClient.Instance.Connect(s.Hostname, s.Port, s.ConnectionTimeout, nickname, s.Username ?? nickname, s.Realname ?? nickname);
}
Widget MakeLabelWidget(LabelWidget template, object item)
{
var itemString = item.ToString();
var widget = (LabelWidget)template.Clone();
var font = Game.Renderer.Fonts[widget.Font];
itemString = WidgetUtils.WrapText(itemString, widget.Bounds.Width, font);
widget.Bounds.Height = font.Measure(itemString).Y;
widget.GetText = () => itemString;
return widget;
}
bool LabelItemEquals(Widget widget, object item)
{
return item != null && ((LabelWidget)widget).GetText() == item.ToString();
}
bool EnterPressed()
{
if (!inputBox.Text.Any())
return true;
var text = inputBox.Text;
inputBox.Text = "";
if (text[0] == '/')
{
var parts = text.Split(new[] { ' ' }, 2);
var name = parts[0].Substring(1);
var args = parts.Length > 1 ? parts[1] : null;
Action<string> command;
if (!commands.TryGetValue(name, out command))
{
IrcClient.AddHistory("{0}: Unknown command".F(name));
return true;
}
command(args);
}
else
{
IrcClient.Instance.Message(IrcClient.MainChannel, text);
IrcClient.AddMessage(IrcClient.Instance.LocalUser.Nickname, text);
}
return true;
}
Dictionary<string, Action<string>> commands = new Dictionary<string, Action<string>>(StringComparer.OrdinalIgnoreCase);
List<string> tabMatches = new List<string>();
int tabMatchesIndex = -1;
bool TabPressed()
{
if (!inputBox.Text.Any())
return true;
var channel = IrcClient.Instance.GetChannel(IrcClient.MainChannel);
if (channel == null)
return true;
var spaceIndex = inputBox.Text.TrimEnd().LastIndexOf(' ');
var tabMatchtext = inputBox.Text.Substring(spaceIndex + 1);
if (tabMatchesIndex < 0 || !tabMatches.Any() || tabMatchtext != tabMatches[tabMatchesIndex])
tabMatches = channel.Users.Keys.Where(u => u.StartsWith(tabMatchtext, StringComparison.OrdinalIgnoreCase)).ToList();
if (!tabMatches.Any())
return true;
tabMatchesIndex = (tabMatchesIndex + 1) % tabMatches.Count;
inputBox.Text = inputBox.Text.Remove(spaceIndex + 1) + tabMatches[tabMatchesIndex];
inputBox.CursorPosition = inputBox.Text.Length;
return true;
}
}
}

View File

@@ -101,6 +101,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
showIncompatibleCheckbox.OnClick = () => { showIncompatible ^= true; ServerList.Query(games => RefreshServerList(panel, games)); }; showIncompatibleCheckbox.OnClick = () => { showIncompatible ^= true; ServerList.Query(games => RefreshServerList(panel, games)); };
} }
Game.LoadWidget(null, "SERVERBROWSER_IRC", panel.Get("IRC_ROOT"), new WidgetArgs());
ServerList.Query(games => RefreshServerList(panel, games)); ServerList.Query(games => RefreshServerList(panel, games));
} }

68
mods/cnc/chrome/irc.yaml Normal file
View File

@@ -0,0 +1,68 @@
Container@SERVERBROWSER_IRC:
Logic:IrcLogic
Width:700
Height:250
Children:
Container@IRC_CONTAINER:
Width:PARENT_RIGHT
Height:PARENT_BOTTOM
Children:
ScrollPanel@HISTORY_PANEL:
Width:565
Height:PARENT_BOTTOM - 30
ItemSpacing:5
Label@HISTORY_TEMPLATE:
X:5
Width:530
Height:25
WordWrap:True
TextField@INPUT_BOX:
Y:PARENT_BOTTOM - 25
Width:565
Height:25
ScrollPanel@NICKNAME_PANEL:
X:570
Width:130
Height:PARENT_BOTTOM - 30
Label@NICKNAME_TEMPLATE:
X:5
Button@DISCONNECT_BUTTON:
X:570
Y:PARENT_BOTTOM - 25
Width:130
Height:25
Text:Disconnect
Font:Bold
Background@IRC_CONNECT_BG:
Width:PARENT_RIGHT
Height:PARENT_BOTTOM
Background:scrollpanel-bg
Children:
Label@GLOBAL_CHAT_LABEL:
Y:PARENT_BOTTOM / 4
Width:PARENT_RIGHT
Align:Center
Text:Global Chat
Font:Bold
Label@NICKNAME_LABEL:
X:200
Y:PARENT_BOTTOM / 4 + 35
Text:Nickname:
TextField@NICKNAME_BOX:
X:270
Y:PARENT_BOTTOM / 4 + 25
Width:150
Height:25
Checkbox@CONNECT_AUTOMATICALLY_CHECKBOX:
X:270
Y:PARENT_BOTTOM / 4 + 75
Height:20
Width:180
Text:Connect Automatically
Button@CONNECT_BUTTON:
X:430
Y:PARENT_BOTTOM / 4 + 25
Width:100
Height:25
Text:Connect
Font:Bold

View File

@@ -1,27 +1,31 @@
Container@SERVERBROWSER_PANEL: Container@SERVERBROWSER_PANEL:
Logic:ServerBrowserLogic Logic:ServerBrowserLogic
X:(WINDOW_RIGHT - WIDTH)/2 X:(WINDOW_RIGHT - WIDTH)/2
Y:(WINDOW_BOTTOM - 500)/2 Y:(WINDOW_BOTTOM - HEIGHT)/2
Width:540 Width:730
Height:535 Height:645
Children: Children:
Label@TITLE: Label@TITLE:
Text:Find Server Text:Find Server
Width:540 Width:740
Y:0-25 Y:0-10
Font:BigBold Font:BigBold
Contrast:true Contrast:true
Align:Center Align:Center
Background@bg: Background@bg:
Width:540 Width:730
Height:500 Height:600
Background:panel-black Background:panel-black
Y:15
Children: Children:
Container@IRC_ROOT:
X:15
Y:15
ScrollPanel@SERVER_LIST: ScrollPanel@SERVER_LIST:
X:15 X:15
Y:30 Y:280
Width:510 Width:700
Height:450 Height:300
Children: Children:
ScrollItem@SERVER_TEMPLATE: ScrollItem@SERVER_TEMPLATE:
Width:PARENT_RIGHT-27 Width:PARENT_RIGHT-27
@@ -76,7 +80,7 @@ Container@SERVERBROWSER_PANEL:
Height:25 Height:25
Label@PROGRESS_LABEL: Label@PROGRESS_LABEL:
X:(PARENT_RIGHT - WIDTH) / 2 X:(PARENT_RIGHT - WIDTH) / 2
Y:PARENT_BOTTOM / 2 - HEIGHT Y:PARENT_BOTTOM / 2 - HEIGHT + (280 / 2)
Width:710 Width:710
Height:25 Height:25
Font:Bold Font:Bold
@@ -85,20 +89,20 @@ Container@SERVERBROWSER_PANEL:
Button@BACK_BUTTON: Button@BACK_BUTTON:
Key:escape Key:escape
X:0 X:0
Y:499 Y:614
Width:140 Width:140
Height:35 Height:35
Text:Back Text:Back
Button@REFRESH_BUTTON: Button@REFRESH_BUTTON:
X:250 X:PARENT_RIGHT - 140 - 10 - 140
Y:499 Y:614
Width:140 Width:140
Height:35 Height:35
Text:Refresh Text:Refresh
Button@JOIN_BUTTON: Button@JOIN_BUTTON:
Key:return Key:return
X:400 X:PARENT_RIGHT - 140
Y:499 Y:614
Width:140 Width:140
Height:35 Height:35
Text:Join Text:Join

View File

@@ -85,6 +85,7 @@ ChromeLayout:
mods/cnc/chrome/dialogs.yaml mods/cnc/chrome/dialogs.yaml
mods/cnc/chrome/objectives.yaml mods/cnc/chrome/objectives.yaml
mods/cnc/chrome/tooltips.yaml mods/cnc/chrome/tooltips.yaml
mods/cnc/chrome/irc.yaml
Weapons: Weapons:
mods/cnc/weapons.yaml mods/cnc/weapons.yaml

View File

@@ -72,6 +72,7 @@ ChromeLayout:
mods/d2k/chrome/tooltips.yaml mods/d2k/chrome/tooltips.yaml
mods/d2k/chrome/assetbrowser.yaml mods/d2k/chrome/assetbrowser.yaml
mods/ra/chrome/convertassets.yaml mods/ra/chrome/convertassets.yaml
mods/ra/chrome/irc.yaml
Weapons: Weapons:
mods/d2k/weapons.yaml mods/d2k/weapons.yaml

68
mods/ra/chrome/irc.yaml Normal file
View File

@@ -0,0 +1,68 @@
Container@SERVERBROWSER_IRC:
Logic:IrcLogic
Width:700
Height:250
Children:
Container@IRC_CONTAINER:
Width:PARENT_RIGHT
Height:PARENT_BOTTOM
Children:
ScrollPanel@HISTORY_PANEL:
Width:565
Height:PARENT_BOTTOM - 30
ItemSpacing:5
Label@HISTORY_TEMPLATE:
X:5
Width:530
Height:25
WordWrap:True
TextField@INPUT_BOX:
Y:PARENT_BOTTOM - 25
Width:565
Height:25
ScrollPanel@NICKNAME_PANEL:
X:570
Width:130
Height:PARENT_BOTTOM - 30
Label@NICKNAME_TEMPLATE:
X:5
Button@DISCONNECT_BUTTON:
X:570
Y:PARENT_BOTTOM - 25
Width:130
Height:25
Text:Disconnect
Font:Bold
Background@IRC_CONNECT_BG:
Width:PARENT_RIGHT
Height:PARENT_BOTTOM
Background:scrollpanel-bg
Children:
Label@GLOBAL_CHAT_LABEL:
Y:PARENT_BOTTOM / 4
Width:PARENT_RIGHT
Align:Center
Text:Global Chat
Font:Bold
Label@NICKNAME_LABEL:
X:200
Y:PARENT_BOTTOM / 4 + 35
Text:Nickname:
TextField@NICKNAME_BOX:
X:270
Y:PARENT_BOTTOM / 4 + 25
Width:150
Height:25
Checkbox@CONNECT_AUTOMATICALLY_CHECKBOX:
X:270
Y:PARENT_BOTTOM / 4 + 75
Height:20
Width:180
Text:Connect Automatically
Button@CONNECT_BUTTON:
X:430
Y:PARENT_BOTTOM / 4 + 25
Width:100
Height:25
Text:Connect
Font:Bold

View File

@@ -2,8 +2,8 @@ Background@JOINSERVER_BG:
Logic:ServerBrowserLogic Logic:ServerBrowserLogic
X:(WINDOW_RIGHT - WIDTH)/2 X:(WINDOW_RIGHT - WIDTH)/2
Y:(WINDOW_BOTTOM - HEIGHT)/2 Y:(WINDOW_BOTTOM - HEIGHT)/2
Width:540 Width:740
Height:505 Height:700
Children: Children:
Label@JOINSERVER_LABEL_TITLE: Label@JOINSERVER_LABEL_TITLE:
X:0 X:0
@@ -47,8 +47,8 @@ Background@JOINSERVER_BG:
ScrollPanel@SERVER_LIST: ScrollPanel@SERVER_LIST:
X:20 X:20
Y:80 Y:80
Width:500 Width:700
Height:355 Height:305
Children: Children:
ScrollItem@SERVER_TEMPLATE: ScrollItem@SERVER_TEMPLATE:
Width:PARENT_RIGHT-27 Width:PARENT_RIGHT-27
@@ -103,34 +103,37 @@ Background@JOINSERVER_BG:
Height:25 Height:25
Label@PROGRESS_LABEL: Label@PROGRESS_LABEL:
X:(PARENT_RIGHT - WIDTH) / 2 X:(PARENT_RIGHT - WIDTH) / 2
Y:PARENT_BOTTOM / 2 - HEIGHT Y:505 / 2 - HEIGHT
Width:150 Width:150
Height:30 Height:30
Text:Fetching games... Text:Fetching games...
Align:Center Align:Center
Button@REFRESH_BUTTON: Button@REFRESH_BUTTON:
X:20 X:20
Y:PARENT_BOTTOM - 45 Y:395
Width:100 Width:100
Height:25 Height:25
Text:Refresh Text:Refresh
Font:Bold Font:Bold
Button@JOIN_BUTTON: Button@JOIN_BUTTON:
X:PARENT_RIGHT - 140 - 130 X:PARENT_RIGHT - 120 - 120
Y:PARENT_BOTTOM - 45 Y:395
Width:100 Width:100
Height:25 Height:25
Text:Join Text:Join
Font:Bold Font:Bold
Key:return Key:return
Button@BACK_BUTTON: Button@BACK_BUTTON:
X:PARENT_RIGHT - 140 X:PARENT_RIGHT - 120
Y:PARENT_BOTTOM - 45 Y:395
Width:100 Width:100
Height:25 Height:25
Text:Cancel Text:Cancel
Font:Bold Font:Bold
Key:escape Key:escape
Container@IRC_ROOT:
X:20
Y:430
Background@DIRECTCONNECT_BG: Background@DIRECTCONNECT_BG:
Logic:DirectConnectLogic Logic:DirectConnectLogic
X:(WINDOW_RIGHT - WIDTH)/2 X:(WINDOW_RIGHT - WIDTH)/2

View File

@@ -85,6 +85,7 @@ ChromeLayout:
mods/ra/chrome/tooltips.yaml mods/ra/chrome/tooltips.yaml
mods/ra/chrome/assetbrowser.yaml mods/ra/chrome/assetbrowser.yaml
mods/ra/chrome/convertassets.yaml mods/ra/chrome/convertassets.yaml
mods/ra/chrome/irc.yaml
Weapons: Weapons:
mods/ra/weapons.yaml mods/ra/weapons.yaml

View File

@@ -115,6 +115,7 @@ ChromeLayout:
mods/ra/chrome/tooltips.yaml mods/ra/chrome/tooltips.yaml
mods/ra/chrome/assetbrowser.yaml mods/ra/chrome/assetbrowser.yaml
mods/ra/chrome/convertassets.yaml mods/ra/chrome/convertassets.yaml
mods/ra/chrome/irc.yaml
Weapons: Weapons:
mods/ts/weapons.yaml mods/ts/weapons.yaml