Merge pull request #8636 from Mailaender/irc

Added the in-game IRC client again
This commit is contained in:
abcdefg30
2015-09-13 17:14:36 +02:00
20 changed files with 672 additions and 66 deletions

View File

@@ -151,6 +151,9 @@ Motmans and distributed under the MIT license.
Using ICSharpCode.SharpZipLib initially by Mike
Krueger and distributed under the GNU GPL terms.
Using SmartIrc4Net developed by Mirco Bauer
distributed under the LGPL version 2.1 or later.
Finally, special thanks goes to the original teams
at Westwood Studios and EA for creating the classic

View File

@@ -40,7 +40,7 @@
CSC = dmcs
CSFLAGS = -nologo -warn:4 -codepage:utf8 -unsafe -warnaserror
DEFINE = TRACE
COMMON_LIBS = System.dll System.Core.dll System.Data.dll System.Data.DataSetExtensions.dll System.Drawing.dll System.Xml.dll thirdparty/download/ICSharpCode.SharpZipLib.dll thirdparty/download/FuzzyLogicLibrary.dll thirdparty/download/Mono.Nat.dll thirdparty/download/MaxMind.Db.dll thirdparty/download/MaxMind.GeoIP2.dll thirdparty/download/Eluant.dll
COMMON_LIBS = System.dll System.Core.dll System.Data.dll System.Data.DataSetExtensions.dll System.Drawing.dll System.Xml.dll thirdparty/download/ICSharpCode.SharpZipLib.dll thirdparty/download/FuzzyLogicLibrary.dll thirdparty/download/Mono.Nat.dll thirdparty/download/MaxMind.Db.dll thirdparty/download/MaxMind.GeoIP2.dll thirdparty/download/Eluant.dll thirdparty/download/SmarIrc4net.dll
DEBUG = true
ifeq ($(DEBUG), $(filter $(DEBUG),false no n off 0))

View File

@@ -288,6 +288,17 @@ namespace OpenRA
}
}
public class IrcSettings
{
public string[] Hostname = { "irc.openra.net" };
public int Port = 6667;
public string Channel = "lobby";
public string Nickname = "Newbie";
public string QuitMessage = "Battle control terminated!";
public string TimestampFormat = "HH:mm";
public bool ConnectAutomatically = false;
}
public class Settings
{
string settingsFile;
@@ -299,6 +310,7 @@ namespace OpenRA
public ServerSettings Server = new ServerSettings();
public DebugSettings Debug = new DebugSettings();
public KeySettings Keys = new KeySettings();
public IrcSettings Irc = new IrcSettings();
public Dictionary<string, object> Sections;
@@ -314,6 +326,7 @@ namespace OpenRA
{ "Server", Server },
{ "Debug", Debug },
{ "Keys", Keys },
{ "Irc", Irc }
};
// Override fieldloader to ignore invalid entries

View File

@@ -61,6 +61,18 @@ namespace OpenRA
catch (IOException) { }
}
public static void Write(string channel, string value)
{
ChannelInfo info;
if (!Channels.TryGetValue(channel, out info))
throw new Exception("Tried logging to non-existant channel " + channel);
if (info.Writer == null)
return;
info.Writer.WriteLine(value);
}
public static void Write(string channel, string format, params object[] args)
{
ChannelInfo info;

19
OpenRA.Mods.Common/Irc.cs Normal file
View File

@@ -0,0 +1,19 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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 Meebey.SmartIrc4net;
namespace OpenRA.Mods.Common
{
public static class Irc
{
public static volatile IrcClient Client;
}
}

View File

@@ -78,6 +78,9 @@
<HintPath>..\thirdparty\download\ICSharpCode.SharpZipLib.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SmarIrc4net">
<HintPath>..\thirdparty\download\SmarIrc4net.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj">
@@ -598,6 +601,8 @@
<Compile Include="Widgets\Logic\Installation\DownloadPackagesLogic.cs" />
<Compile Include="Widgets\Logic\Installation\InstallLogic.cs" />
<Compile Include="Widgets\Logic\Installation\InstallMusicLogic.cs" />
<Compile Include="Widgets\Logic\IrcLogic.cs" />
<Compile Include="Irc.cs" />
<Compile Include="Widgets\Logic\Lobby\ClientTooltipLogic.cs" />
<Compile Include="Widgets\Logic\Lobby\KickClientLogic.cs" />
<Compile Include="Widgets\Logic\Lobby\KickSpectatorsLogic.cs" />

View File

@@ -0,0 +1,374 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Meebey.SmartIrc4net;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets.Logic
{
class IrcLogic
{
readonly TextFieldWidget inputBox;
readonly TextFieldWidget nicknameBox;
readonly Widget connectBG;
readonly Widget ircContainer;
readonly ScrollPanelWidget historyPanel;
readonly LabelWidget historyTemplate;
readonly ScrollPanelWidget nicknamePanel;
readonly LabelWidget nicknameTemplate;
bool pingSent;
Channel channel;
[ObjectCreator.UseCtor]
public IrcLogic(Widget widget)
{
Log.AddChannel("irc", "irc.log");
historyPanel = widget.Get<ScrollPanelWidget>("HISTORY_PANEL");
historyTemplate = widget.Get<LabelWidget>("HISTORY_TEMPLATE");
nicknamePanel = widget.Get<ScrollPanelWidget>("NICKNAME_PANEL");
nicknameTemplate = widget.Get<LabelWidget>("NICKNAME_TEMPLATE");
inputBox = widget.Get<TextFieldWidget>("INPUT_BOX");
inputBox.OnEnterKey = EnterPressed;
inputBox.IsDisabled = () => Irc.Client == null;
if (Game.Settings.Irc.Nickname == new IrcSettings().Nickname)
Game.Settings.Irc.Nickname += Game.CosmeticRandom.Next(100, 999);
nicknameBox = widget.Get<TextFieldWidget>("NICKNAME_BOX");
nicknameBox.Text = SanitizedName(Game.Settings.Irc.Nickname);
nicknameBox.OnTextEdited = () =>
{
nicknameBox.Text = SanitizedName(nicknameBox.Text);
Game.Settings.Irc.Nickname = nicknameBox.Text;
Game.Settings.Save();
};
connectBG = widget.Get("IRC_CONNECT_BG");
ircContainer = widget.Get("IRC_CONTAINER");
var disconnectButton = widget.Get<ButtonWidget>("DISCONNECT_BUTTON");
disconnectButton.IsDisabled = () => Irc.Client == null;
disconnectButton.OnClick = Disconnect;
MaybeShowConnectPanel();
}
static string SanitizedName(string dirty)
{
if (string.IsNullOrEmpty(dirty))
return null;
// TODO: some special chars are allowed as well, but not at every position
var clean = new string(dirty.Where(c => char.IsLetterOrDigit(c)).ToArray());
if (string.IsNullOrEmpty(clean))
return null;
if (char.IsDigit(clean[0]))
return SanitizedName(clean.Substring(1));
// Source: https://tools.ietf.org/html/rfc2812#section-1.2.1
if (clean.Length > 9)
clean = clean.Substring(0, 9);
return clean;
}
void MaybeShowConnectPanel()
{
if (Irc.Client != null && Irc.Client.IsConnected)
{
ircContainer.Visible = true;
connectBG.Visible = false;
Initialize();
if (Irc.Client.JoinedChannels.Count > 0)
channel = Irc.Client.GetChannel(Irc.Client.JoinedChannels[0]);
SyncNicknamePanel();
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");
connectAutomaticallyCheckBox.IsChecked = () => Game.Settings.Irc.ConnectAutomatically;
connectAutomaticallyCheckBox.OnClick = () => Game.Settings.Irc.ConnectAutomatically ^= true;
var connectButton = connectBG.Get<ButtonWidget>("CONNECT_BUTTON");
connectButton.IsDisabled = () => string.IsNullOrEmpty(nicknameBox.Text);
connectButton.OnClick = () =>
{
ircContainer.Visible = true;
connectBG.Visible = false;
Game.Settings.Irc.ConnectAutomatically = connectAutomaticallyCheckBox.IsChecked();
Game.Settings.Save();
Connect();
};
}
void Initialize()
{
Irc.Client.OnConnected += OnConnected;
Irc.Client.OnError += OnError;
Irc.Client.OnRawMessage += OnRawMessage;
Irc.Client.OnJoin += OnJoin;
Irc.Client.OnChannelActiveSynced += OnChannelActiveSynced;
Irc.Client.OnNickChange += OnNickChange;
Irc.Client.OnPart += OnPart;
Irc.Client.OnQuit += OnQuit;
Irc.Client.OnChannelMessage += OnChannelMessage;
Irc.Client.OnPong += OnPong;
}
void Connect()
{
Irc.Client = new IrcClient();
Irc.Client.Encoding = System.Text.Encoding.UTF8;
Irc.Client.SendDelay = 100;
Irc.Client.ActiveChannelSyncing = true;
Initialize();
Game.OnQuit += Disconnect;
try
{
AddChatLine("Connecting to {0}...".F(Game.Settings.Irc.Hostname));
Irc.Client.Connect(Game.Settings.Irc.Hostname, Game.Settings.Irc.Port);
}
catch (Exception e)
{
AddChatLine("Connection error: {0}".F(e.Message));
Game.RunAfterTick(() =>
{
Log.Write("irc", e.ToString());
});
}
new Thread(Irc.Client.Listen) { Name = "IrcListenThread" }.Start();
}
void OnPong(object sender, PongEventArgs e)
{
if (pingSent)
{
AddChatLine("PONG recieved after {0} ms.".F(e.Lag.Milliseconds));
pingSent = false;
}
else
{
Game.RunAfterTick(() =>
{
Log.Write("irc", "PONG sent after {0} ms.".F(e.Lag.Milliseconds));
});
}
}
Widget MakeLabelWidget(LabelWidget template, string item)
{
var widget = (LabelWidget)template.Clone();
var font = Game.Renderer.Fonts[widget.Font];
item = WidgetUtils.WrapText(item, widget.Bounds.Width, font);
widget.Bounds.Height = font.Measure(item).Y;
widget.GetText = () => item;
widget.Id = item;
return widget;
}
void AddChatLine(string text)
{
Game.RunAfterTick(() =>
{
Log.Write("irc", text);
var scrolledToBottom = historyPanel.ScrolledToBottom;
var newChild = MakeLabelWidget(historyTemplate, text);
historyPanel.AddChild(newChild);
if (scrolledToBottom)
historyPanel.ScrollToBottom(smooth: true);
});
}
bool EnterPressed()
{
if (inputBox.Text.Length == 0)
return true;
var text = inputBox.Text;
inputBox.Text = "";
if (text.StartsWith("/nick "))
{
var nick = text.Replace("/nick ", string.Empty);
if (Rfc2812.IsValidNickname(nick))
Irc.Client.RfcNick(nick);
else
AddChatLine("Invalid nickname.");
}
else if (text.StartsWith("/ping "))
{
Irc.Client.RfcPing(Irc.Client.GetIrcUser(text.Replace("/ping ", string.Empty)).Host);
pingSent = true;
}
else if (text.StartsWith("/"))
AddChatLine("Unknown command.");
else
{
AddChatLine("[{0}] <{1}> {2}".F(DateTime.Now.ToString(Game.Settings.Irc.TimestampFormat), Irc.Client.Nickname, text));
Irc.Client.SendMessage(SendType.Message, "#" + Game.Settings.Irc.Channel, text);
}
return true;
}
void OnConnected(object sender, EventArgs e)
{
AddChatLine("Connected.");
if (!Rfc2812.IsValidNickname(Game.Settings.Irc.Nickname))
{
AddChatLine("Invalid nickname. Can't login.");
return;
}
Irc.Client.Login(new[] { Game.Settings.Irc.Nickname }, "in-game IRC client", 0, "OpenRA");
Irc.Client.RfcJoin("#" + Game.Settings.Irc.Channel);
}
void OnError(object sender, ErrorEventArgs e)
{
AddChatLine("Error: " + e.ErrorMessage);
Game.RunAfterTick(() =>
{
Log.Write("irc", e.ToString());
});
}
void OnRawMessage(object sender, IrcEventArgs e)
{
Game.RunAfterTick(() =>
{
Log.Write("irc", e.Data.RawMessage);
});
}
void OnChannelMessage(object sender, IrcEventArgs e)
{
AddChatLine("[{0}] <{1}> {2}".F(DateTime.Now.ToString(Game.Settings.Irc.TimestampFormat), e.Data.Nick, e.Data.Message));
}
void OnJoin(object sender, JoinEventArgs e)
{
if (e.Who == Irc.Client.Nickname)
return;
AddChatLine("{0} joined channel {1}.".F(e.Who, e.Channel));
channel = Irc.Client.GetChannel(e.Channel);
SyncNicknamePanel();
}
void OnChannelActiveSynced(object sender, IrcEventArgs e)
{
channel = Irc.Client.GetChannel(e.Data.Channel);
AddChatLine("{0} users online".F(channel.Users.Count));
if (!string.IsNullOrEmpty(channel.Topic))
AddChatLine("*** Topic: {0}".F(channel.Topic));
SyncNicknamePanel();
}
void OnNickChange(object sender, NickChangeEventArgs e)
{
AddChatLine("{0} is now known as {1}.".F(e.OldNickname, e.NewNickname));
SyncNicknamePanel();
}
void SyncNicknamePanel()
{
if (channel == null)
return;
var users = channel.Users;
Game.RunAfterTick(() =>
{
nicknamePanel.RemoveChildren();
foreach (DictionaryEntry user in users)
{
var channeluser = (ChannelUser)user.Value;
var prefix = channeluser.IsOp ? "@" : channeluser.IsVoice ? "+" : "";
var newChild = MakeLabelWidget(nicknameTemplate, prefix + channeluser.Nick);
nicknamePanel.AddChild(newChild);
}
});
}
void OnQuit(object sender, QuitEventArgs e)
{
AddChatLine("{0} quit.".F(e.Who));
}
void OnPart(object sender, PartEventArgs e)
{
AddChatLine("{0} left {1}.".F(e.Who, e.Data.Channel));
channel = Irc.Client.GetChannel(e.Data.Channel);
SyncNicknamePanel();
}
void Disconnect()
{
if (Irc.Client == null)
return;
Irc.Client.RfcQuit(Game.Settings.Irc.QuitMessage);
AddChatLine("Disconnecting from {0}...".F(Irc.Client.Address));
if (Irc.Client.IsConnected)
Irc.Client.Disconnect();
nicknamePanel.RemoveChildren();
Game.Settings.Irc.ConnectAutomatically = false;
Irc.Client = null;
MaybeShowConnectPanel();
}
}
}

View File

@@ -135,6 +135,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic
showIncompatibleCheckbox.OnClick = () => { showIncompatible ^= true; RefreshServerList(); };
}
try
{
Game.LoadWidget(null, "SERVERBROWSER_IRC", panel.Get("IRC_ROOT"), new WidgetArgs());
}
catch
{
Log.Write("debug", "Failed to load server browser IRC chrome layout");
}
RefreshServerList();
if (directConnectHost != null)

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

@@ -0,0 +1,70 @@
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
Font: Regular
Text: Connect Automatically
Button@CONNECT_BUTTON:
X: 430
Y: PARENT_BOTTOM / 4 + 25
Width: 100
Height: 25
Text: Connect
Font: Bold

View File

@@ -1,74 +1,31 @@
Container@SERVERBROWSER_PANEL:
Logic: ServerBrowserLogic
X: (WINDOW_RIGHT - WIDTH)/2
Y: (WINDOW_BOTTOM - 500)/2
Y: (WINDOW_BOTTOM - HEIGHT)/2
Width: 730
Height: 535
Height: 595
Children:
Label@TITLE:
Text: Multiplayer
Width: 740
Y: 0-25
Y: 0-10
Font: BigBold
Contrast: true
Align: Center
Background@bg:
Width: 730
Height: 500
Height: PARENT_BOTTOM - 30
Background: panel-black
Y: 15
Children:
Label@SHOW_LABEL_TITLE:
X: 20
Y: 465
Width: 20
Height: 25
Text: Show:
Font: Bold
Checkbox@WAITING_FOR_PLAYERS:
X: 80
Y: 467
Width: 100
Height: 20
Text: Waiting
TextColor: 50,205,50
Checkbox@EMPTY:
X: 180
Y: 467
Width: 100
Height: 20
Text: Empty
Checkbox@PASSWORD_PROTECTED:
X: 270
Y: 467
Width: 100
Height: 20
Text: Protected
TextColor: 255,0,0
Checkbox@ALREADY_STARTED:
X: 385
Y: 467
Width: 100
Height: 20
Text: Started
TextColor: 255,165,0
Checkbox@INCOMPATIBLE_VERSION:
X: 480
Y: 467
Width: 100
Height: 20
Text: Incompatible
TextColor: 190,190,190
Button@REFRESH_BUTTON:
X: PARENT_RIGHT - WIDTH - 15
Y: 465
Width: 100
Height: 25
Text: Refresh
ScrollPanel@SERVER_LIST:
Container@IRC_ROOT:
X: 15
Y: 15
ScrollPanel@SERVER_LIST:
X: 15
Y: 280
Width: 700
Height: 440
Height: 240
Children:
ScrollItem@HEADER_TEMPLATE:
Width: PARENT_RIGHT-27
@@ -129,35 +86,82 @@ Container@SERVERBROWSER_PANEL:
Height: 25
Label@PROGRESS_LABEL:
X: (PARENT_RIGHT - WIDTH) / 2
Y: PARENT_BOTTOM / 2 - HEIGHT
Y: PARENT_BOTTOM / 2 - HEIGHT + (280 / 2)
Width: 710
Height: 25
Font: Bold
Align: Center
Visible: false
Label@SHOW_LABEL_TITLE:
X: 20
Y: 525
Width: 20
Height: 25
Text: Show:
Font: Bold
Checkbox@WAITING_FOR_PLAYERS:
X: 80
Y: 527
Width: 100
Height: 20
Text: Waiting
TextColor: 50,205,50
Checkbox@EMPTY:
X: 180
Y: 527
Width: 100
Height: 20
Text: Empty
Checkbox@PASSWORD_PROTECTED:
X: 270
Y: 527
Width: 100
Height: 20
Text: Protected
TextColor: 255,0,0
Checkbox@ALREADY_STARTED:
X: 385
Y: 527
Width: 100
Height: 20
Text: Started
TextColor: 255,165,0
Checkbox@INCOMPATIBLE_VERSION:
X: 480
Y: 527
Width: 100
Height: 20
Text: Incompatible
TextColor: 190,190,190
Button@REFRESH_BUTTON:
X: PARENT_RIGHT - WIDTH - 15
Y: 525
Width: 100
Height: 25
Text: Refresh
Button@BACK_BUTTON:
Key: escape
X: 0
Y: 499
Y: PARENT_BOTTOM - 16
Width: 140
Height: 35
Text: Back
Button@CREATE_BUTTON:
X: PARENT_RIGHT - 140 - 10 - 140 - 10 - 140
Y: 499
Y: PARENT_BOTTOM - 16
Width: 140
Height: 35
Text: Create
Button@DIRECTCONNECT_BUTTON:
X: PARENT_RIGHT - 140 - 10 - 140
Y: 499
Y: PARENT_BOTTOM - 16
Width: 140
Height: 35
Text: Direct IP
Button@JOIN_BUTTON:
Key: return
X: PARENT_RIGHT - 140
Y: 499
Y: PARENT_BOTTOM - 16
Width: 140
Height: 35
Text: Join

View File

@@ -120,6 +120,7 @@ ChromeLayout:
./mods/cnc/chrome/assetbrowser.yaml
./mods/cnc/chrome/missionbrowser.yaml
./mods/cnc/chrome/editor.yaml
./mods/cnc/chrome/irc.yaml
Voices:
./mods/cnc/audio/voices.yaml

View File

@@ -102,6 +102,7 @@ ChromeLayout:
./mods/d2k/chrome/missionbrowser.yaml
./mods/ra/chrome/confirmation-dialogs.yaml
./mods/ra/chrome/editor.yaml
./mods/ra/chrome/irc.yaml
Weapons:
./mods/d2k/weapons.yaml

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

@@ -0,0 +1,69 @@
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

@@ -3,7 +3,7 @@ Background@SERVERBROWSER_PANEL:
X: (WINDOW_RIGHT - WIDTH)/2
Y: (WINDOW_BOTTOM - HEIGHT)/2
Width: 740
Height: 500
Height: 645
Children:
Label@MULTIPLAYER_LABEL_TITLE:
X: 0
@@ -58,7 +58,7 @@ Background@SERVERBROWSER_PANEL:
X: 20
Y: 80
Width: 700
Height: 360
Height: 240
Children:
ScrollItem@HEADER_TEMPLATE:
BaseName: scrollheader
@@ -118,6 +118,10 @@ Background@SERVERBROWSER_PANEL:
Y: 40
Align: Right
Height: 25
Container@IRC_ROOT:
X: 20
Y: 370
Width: 260
Label@PROGRESS_LABEL:
X: (PARENT_RIGHT - WIDTH) / 2
Y: PARENT_BOTTOM / 2 - HEIGHT
@@ -127,28 +131,28 @@ Background@SERVERBROWSER_PANEL:
Align: Center
Button@REFRESH_BUTTON:
X: 20
Y: PARENT_BOTTOM - 45
Y: 325
Width: 100
Height: 25
Text: Refresh
Font: Bold
Button@CREATE_BUTTON:
X: PARENT_RIGHT - 120 - 120 - 120 - 120
Y: PARENT_BOTTOM - 45
Y: 325
Width: 100
Height: 25
Text: Create
Font: Bold
Button@DIRECTCONNECT_BUTTON:
X: PARENT_RIGHT - 120 - 120 - 120
Y: PARENT_BOTTOM - 45
Y: 325
Width: 100
Height: 25
Text: Direct IP
Font: Bold
Button@JOIN_BUTTON:
X: PARENT_RIGHT - 120 - 120
Y: PARENT_BOTTOM - 45
Y: 325
Width: 100
Height: 25
Text: Join
@@ -156,7 +160,7 @@ Background@SERVERBROWSER_PANEL:
Key: return
Button@BACK_BUTTON:
X: PARENT_RIGHT - 120
Y: PARENT_BOTTOM - 45
Y: 325
Width: 100
Height: 25
Text: Cancel

View File

@@ -114,6 +114,7 @@ ChromeLayout:
./mods/ra/chrome/missionbrowser.yaml
./mods/ra/chrome/confirmation-dialogs.yaml
./mods/ra/chrome/editor.yaml
./mods/ra/chrome/irc.yaml
Weapons:
./mods/ra/weapons/explosions.yaml

View File

@@ -168,6 +168,7 @@ ChromeLayout:
./mods/ra/chrome/missionbrowser.yaml
./mods/ra/chrome/confirmation-dialogs.yaml
./mods/ra/chrome/editor.yaml
./mods/ra/chrome/irc.yaml
Voices:
./mods/ts/audio/voices.yaml

View File

@@ -67,6 +67,9 @@ cp thirdparty/download/MaxMind.GeoIP2.dll packaging/built
cp thirdparty/download/Newtonsoft.Json.dll packaging/built
cp thirdparty/download/RestSharp.dll packaging/built
# global chat
cp thirdparty/download/SmarIrc4net.dll packaging/built
# Copy game icon for windows package
cp OpenRA.Game/OpenRA.ico packaging/built

View File

@@ -104,6 +104,7 @@ Section "Game" GAME
File "${SRCDIR}\RestSharp.dll"
File "${SRCDIR}\GeoLite2-Country.mmdb.gz"
File "${SRCDIR}\eluant.dll"
File "${SRCDIR}\SmarIrc4net.dll"
File "${DEPSDIR}\soft_oal.dll"
File "${DEPSDIR}\SDL2.dll"
File "${DEPSDIR}\freetype6.dll"
@@ -214,6 +215,7 @@ Function ${UN}Clean
Delete $INSTDIR\eluant.dll
Delete $INSTDIR\freetype6.dll
Delete $INSTDIR\SDL2-CS.dll
Delete $INSTDIR\SmarIrc4net.dll
RMDir /r $INSTDIR\Support
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA"

View File

@@ -137,4 +137,12 @@ if (!(Test-Path "GeoLite2-Country.mmdb.gz") -Or (((get-date) - (get-item "GeoLit
(New-Object System.Net.WebClient).DownloadFile("http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz", $target)
}
if (!(Test-Path "SmarIrc4net.dll"))
{
echo "Fetching SmartIrc4net from NuGet."
./nuget.exe install SmartIrc4net -Version 0.4.5.1 -ExcludeVersion
cp SmartIrc4net/lib/net40/SmarIrc4net.* .
rmdir SmartIrc4net -Recurse
}
cd ..

View File

@@ -101,3 +101,10 @@ if [ ! -f Eluant.dll ]; then
echo "Fetching Eluant from GitHub."
curl -s -L -O https://github.com/OpenRA/Eluant/releases/download/20140425/Eluant.dll
fi
if [ ! -f SmarIrc4net.dll ]; then
echo "Fetching SmartIrc4net from NuGet."
get SmartIrc4net 0.4.5.1
cp ./SmartIrc4net/lib/net40/SmarIrc4net* .
rm -rf SmartIrc4net
fi