Fix the lobby slots.
- lobbyInfo.Slots is now a dictionary, keyed by the name of the PlayerReference that the slot is tied to. - LockRace/Color/Team is now specified on the slot, avoiding map lookups in the lobby - Observers are no longer tied to slots -> players will join as observers instead of crashing the game if there are no available slots - Observers are able to change their name and color
This commit is contained in:
@@ -18,7 +18,8 @@ namespace OpenRA.Network
|
|||||||
public class Session
|
public class Session
|
||||||
{
|
{
|
||||||
public List<Client> Clients = new List<Client>();
|
public List<Client> Clients = new List<Client>();
|
||||||
public List<Slot> Slots = new List<Slot>();
|
// Keyed by the PlayerReference id that the slot corresponds to
|
||||||
|
public Dictionary<string, Slot> Slots = new Dictionary<string, Slot>();
|
||||||
public Global GlobalSettings = new Global();
|
public Global GlobalSettings = new Global();
|
||||||
|
|
||||||
public Client ClientWithIndex(int clientID)
|
public Client ClientWithIndex(int clientID)
|
||||||
@@ -26,15 +27,15 @@ namespace OpenRA.Network
|
|||||||
return Clients.SingleOrDefault(c => c.Index == clientID);
|
return Clients.SingleOrDefault(c => c.Index == clientID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Client ClientInSlot(Slot slot)
|
public Client ClientInSlot(string slot)
|
||||||
{
|
{
|
||||||
return Clients.SingleOrDefault(c => c.Slot == slot.Index);
|
return Clients.SingleOrDefault(c => c.Slot == slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int FirstEmptySlot()
|
public string FirstEmptySlot()
|
||||||
{
|
{
|
||||||
return Slots.First(s => !s.Closed && ClientInSlot(s) == null
|
return Slots.FirstOrDefault(s => !s.Value.Closed && ClientInSlot(s.Key) == null
|
||||||
&& s.Bot == null).Index;
|
&& s.Value.Bot == null).Key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ClientState
|
public enum ClientState
|
||||||
@@ -53,17 +54,19 @@ namespace OpenRA.Network
|
|||||||
public string Name;
|
public string Name;
|
||||||
public ClientState State;
|
public ClientState State;
|
||||||
public int Team;
|
public int Team;
|
||||||
public int Slot; // which slot we're in, or -1 for `observer`.
|
public string Slot; // slot ID, or null for observer
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Slot
|
public class Slot
|
||||||
{
|
{
|
||||||
public int Index;
|
public string PlayerReference; // playerReference to bind against.
|
||||||
public string Bot; // trait name of the bot to initialize in this slot, or null otherwise.
|
public string Bot; // trait name of the bot to initialize in this slot, or null otherwise.
|
||||||
public bool Closed; // host has explicitly closed this slot.
|
public bool Closed; // host has explicitly closed this slot.
|
||||||
public string MapPlayer; // playerReference to bind against.
|
|
||||||
public bool Spectator = false; // Spectating or not
|
public bool AllowBots;
|
||||||
// todo: more stuff?
|
public bool LockRace;
|
||||||
|
public bool LockColor;
|
||||||
|
public bool LockTeam;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Global
|
public class Global
|
||||||
@@ -90,7 +93,7 @@ namespace OpenRA.Network
|
|||||||
clientData.Add(new MiniYamlNode("Client@{0}".F(client.Index), FieldSaver.Save(client)));
|
clientData.Add(new MiniYamlNode("Client@{0}".F(client.Index), FieldSaver.Save(client)));
|
||||||
|
|
||||||
foreach (var slot in Slots)
|
foreach (var slot in Slots)
|
||||||
clientData.Add(new MiniYamlNode("Slot@{0}".F(slot.Index), FieldSaver.Save(slot)));
|
clientData.Add(new MiniYamlNode("Slot@{0}".F(slot.Key), FieldSaver.Save(slot.Value)));
|
||||||
|
|
||||||
clientData.Add(new MiniYamlNode("GlobalSettings", FieldSaver.Save(GlobalSettings)));
|
clientData.Add(new MiniYamlNode("GlobalSettings", FieldSaver.Save(GlobalSettings)));
|
||||||
|
|
||||||
@@ -117,7 +120,8 @@ namespace OpenRA.Network
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "Slot":
|
case "Slot":
|
||||||
session.Slots.Add(FieldLoader.Load<Session.Slot>(y.Value));
|
var s = FieldLoader.Load<Session.Slot>(y.Value);
|
||||||
|
session.Slots.Add(s.PlayerReference, s);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ namespace OpenRA
|
|||||||
if (slot != null && slot.Bot != null)
|
if (slot != null && slot.Bot != null)
|
||||||
{
|
{
|
||||||
IsBot = true;
|
IsBot = true;
|
||||||
botType = pr.Bot;
|
botType = slot.Bot;
|
||||||
PlayerName = slot.Bot;
|
PlayerName = slot.Bot;
|
||||||
|
|
||||||
// pick a random color for the bot
|
// pick a random color for the bot
|
||||||
|
|||||||
@@ -218,9 +218,8 @@ namespace OpenRA.Server
|
|||||||
client.Index = newConn.PlayerIndex;
|
client.Index = newConn.PlayerIndex;
|
||||||
client.Slot = lobbyInfo.FirstEmptySlot();
|
client.Slot = lobbyInfo.FirstEmptySlot();
|
||||||
|
|
||||||
var slotData = lobbyInfo.Slots.FirstOrDefault( x => x.Index == client.Slot );
|
if (client.Slot != null)
|
||||||
if (slotData != null && slotData.MapPlayer != null)
|
SyncClientToPlayerReference(client, Map.Players[client.Slot]);
|
||||||
SyncClientToPlayerReference(client, Map.Players[slotData.MapPlayer]);
|
|
||||||
|
|
||||||
lobbyInfo.Clients.Add(client);
|
lobbyInfo.Clients.Add(client);
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
|||||||
{
|
{
|
||||||
public class CncLobbyLogic
|
public class CncLobbyLogic
|
||||||
{
|
{
|
||||||
Widget LocalPlayerTemplate, RemotePlayerTemplate, EmptySlotTemplate, EmptySlotTemplateHost;
|
Widget LocalPlayerTemplate, RemotePlayerTemplate, EmptySlotTemplate, BotTemplate,
|
||||||
|
LocalSpectatorTemplate, RemoteSpectatorTemplate, NewSpectatorTemplate;
|
||||||
ScrollPanelWidget chatPanel;
|
ScrollPanelWidget chatPanel;
|
||||||
Widget chatTemplate;
|
Widget chatTemplate;
|
||||||
|
|
||||||
@@ -107,7 +108,10 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
|||||||
LocalPlayerTemplate = Players.GetWidget("TEMPLATE_LOCAL");
|
LocalPlayerTemplate = Players.GetWidget("TEMPLATE_LOCAL");
|
||||||
RemotePlayerTemplate = Players.GetWidget("TEMPLATE_REMOTE");
|
RemotePlayerTemplate = Players.GetWidget("TEMPLATE_REMOTE");
|
||||||
EmptySlotTemplate = Players.GetWidget("TEMPLATE_EMPTY");
|
EmptySlotTemplate = Players.GetWidget("TEMPLATE_EMPTY");
|
||||||
EmptySlotTemplateHost = Players.GetWidget("TEMPLATE_EMPTY_HOST");
|
BotTemplate = Players.GetWidget("TEMPLATE_BOT");
|
||||||
|
LocalSpectatorTemplate = Players.GetWidget("TEMPLATE_LOCAL_SPECTATOR");
|
||||||
|
RemoteSpectatorTemplate = Players.GetWidget("TEMPLATE_REMOTE_SPECTATOR");
|
||||||
|
NewSpectatorTemplate = Players.GetWidget("TEMPLATE_NEW_SPECTATOR");
|
||||||
|
|
||||||
var mapPreview = lobby.GetWidget<MapPreviewWidget>("MAP_PREVIEW");
|
var mapPreview = lobby.GetWidget<MapPreviewWidget>("MAP_PREVIEW");
|
||||||
mapPreview.Map = () => Map;
|
mapPreview.Map = () => Map;
|
||||||
@@ -231,7 +235,7 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
|||||||
{
|
{
|
||||||
var slot = orderManager.LobbyInfo.FirstEmptySlot();
|
var slot = orderManager.LobbyInfo.FirstEmptySlot();
|
||||||
var bot = Rules.Info["player"].Traits.WithInterface<IBotInfo>().Select(t => t.Name).FirstOrDefault();
|
var bot = Rules.Info["player"].Traits.WithInterface<IBotInfo>().Select(t => t.Name).FirstOrDefault();
|
||||||
if (bot != null)
|
if (slot != null && bot != null)
|
||||||
orderManager.IssueOrder(Order.Command("slot_bot {0} {1}".F(slot, bot)));
|
orderManager.IssueOrder(Order.Command("slot_bot {0} {1}".F(slot, bot)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -278,11 +282,6 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
|||||||
title.Text = orderManager.LobbyInfo.GlobalSettings.ServerName;
|
title.Text = orderManager.LobbyInfo.GlobalSettings.ServerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
Session.Client GetClientInSlot(Session.Slot slot)
|
|
||||||
{
|
|
||||||
return orderManager.LobbyInfo.ClientInSlot( slot );
|
|
||||||
}
|
|
||||||
|
|
||||||
class SlotDropDownOption
|
class SlotDropDownOption
|
||||||
{
|
{
|
||||||
public string Title;
|
public string Title;
|
||||||
@@ -297,19 +296,19 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShowSlotDropDown(DropDownButtonWidget dropdown, Session.Slot slot, bool showBotOptions)
|
bool ShowSlotDropDown(DropDownButtonWidget dropdown, Session.Slot slot)
|
||||||
{
|
{
|
||||||
var options = new List<SlotDropDownOption>()
|
var options = new List<SlotDropDownOption>()
|
||||||
{
|
{
|
||||||
new SlotDropDownOption("Open", "slot_open "+slot.Index, () => (!slot.Closed && slot.Bot == null)),
|
new SlotDropDownOption("Open", "slot_open "+slot.PlayerReference, () => (!slot.Closed && slot.Bot == null)),
|
||||||
new SlotDropDownOption("Closed", "slot_close "+slot.Index, () => slot.Closed)
|
new SlotDropDownOption("Closed", "slot_close "+slot.PlayerReference, () => slot.Closed)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (showBotOptions)
|
if (slot.AllowBots)
|
||||||
foreach (var b in Rules.Info["player"].Traits.WithInterface<IBotInfo>().Select(t => t.Name))
|
foreach (var b in Rules.Info["player"].Traits.WithInterface<IBotInfo>().Select(t => t.Name))
|
||||||
{
|
{
|
||||||
var bot = b;
|
var bot = b;
|
||||||
options.Add(new SlotDropDownOption("Bot: {0}".F(bot), "slot_bot {0} {1}".F(slot.Index, bot), () => slot.Bot == bot));
|
options.Add(new SlotDropDownOption("Bot: {0}".F(bot), "slot_bot {0} {1}".F(slot.PlayerReference, bot), () => slot.Bot == bot));
|
||||||
}
|
}
|
||||||
|
|
||||||
Func<SlotDropDownOption, ScrollItemWidget, ScrollItemWidget> setupItem = (o, itemTemplate) =>
|
Func<SlotDropDownOption, ScrollItemWidget, ScrollItemWidget> setupItem = (o, itemTemplate) =>
|
||||||
@@ -325,16 +324,12 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShowRaceDropDown(DropDownButtonWidget dropdown, Session.Slot slot)
|
bool ShowRaceDropDown(DropDownButtonWidget dropdown, Session.Client client)
|
||||||
{
|
{
|
||||||
if (Map.Players[slot.MapPlayer].LockRace)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var sr = GetClientInSlot(slot).Country;
|
|
||||||
Func<string, ScrollItemWidget, ScrollItemWidget> setupItem = (race, itemTemplate) =>
|
Func<string, ScrollItemWidget, ScrollItemWidget> setupItem = (race, itemTemplate) =>
|
||||||
{
|
{
|
||||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||||
() => sr == race,
|
() => client.Country == race,
|
||||||
() => orderManager.IssueOrder(Order.Command("race "+race)));
|
() => orderManager.IssueOrder(Order.Command("race "+race)));
|
||||||
item.GetWidget<LabelWidget>("LABEL").GetText = () => CountryNames[race];
|
item.GetWidget<LabelWidget>("LABEL").GetText = () => CountryNames[race];
|
||||||
var flag = item.GetWidget<ImageWidget>("FLAG");
|
var flag = item.GetWidget<ImageWidget>("FLAG");
|
||||||
@@ -347,13 +342,12 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShowTeamDropDown(DropDownButtonWidget dropdown, Session.Slot slot)
|
bool ShowTeamDropDown(DropDownButtonWidget dropdown, Session.Client client)
|
||||||
{
|
{
|
||||||
var c = GetClientInSlot(slot);
|
|
||||||
Func<int, ScrollItemWidget, ScrollItemWidget> setupItem = (ii, itemTemplate) =>
|
Func<int, ScrollItemWidget, ScrollItemWidget> setupItem = (ii, itemTemplate) =>
|
||||||
{
|
{
|
||||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||||
() => c.Team == ii,
|
() => client.Team == ii,
|
||||||
() => orderManager.IssueOrder(Order.Command("team "+ii)));
|
() => orderManager.IssueOrder(Order.Command("team "+ii)));
|
||||||
item.GetWidget<LabelWidget>("LABEL").GetText = () => ii == 0 ? "-" : ii.ToString();
|
item.GetWidget<LabelWidget>("LABEL").GetText = () => ii == 0 ? "-" : ii.ToString();
|
||||||
return item;
|
return item;
|
||||||
@@ -364,11 +358,8 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShowColorDropDown(DropDownButtonWidget color, Session.Slot s)
|
bool ShowColorDropDown(DropDownButtonWidget color, Session.Client client)
|
||||||
{
|
{
|
||||||
if (Map.Players[s.MapPlayer].LockColor)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Action<ColorRamp> onSelect = c =>
|
Action<ColorRamp> onSelect = c =>
|
||||||
{
|
{
|
||||||
Game.Settings.Player.ColorRamp = c;
|
Game.Settings.Player.ColorRamp = c;
|
||||||
@@ -399,70 +390,74 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
|||||||
// Todo: handle this nicer
|
// Todo: handle this nicer
|
||||||
Players.RemoveChildren();
|
Players.RemoveChildren();
|
||||||
|
|
||||||
foreach (var slot in orderManager.LobbyInfo.Slots)
|
foreach (var kv in orderManager.LobbyInfo.Slots)
|
||||||
{
|
{
|
||||||
var s = slot;
|
var key = kv.Key;
|
||||||
var c = GetClientInSlot(s);
|
var slot = kv.Value;
|
||||||
|
var client = orderManager.LobbyInfo.ClientInSlot(key);
|
||||||
Widget template;
|
Widget template;
|
||||||
|
|
||||||
if (c == null)
|
// Empty slot
|
||||||
{
|
if (client == null && slot.Bot == null)
|
||||||
if (Game.IsHost)
|
|
||||||
{
|
|
||||||
if (slot.Spectator)
|
|
||||||
{
|
|
||||||
template = EmptySlotTemplateHost.Clone();
|
|
||||||
var name = template.GetWidget<DropDownButtonWidget>("NAME");
|
|
||||||
name.GetText = () => s.Closed ? "Closed" : "Open";
|
|
||||||
name.OnMouseDown = _ => ShowSlotDropDown(name, s, false);
|
|
||||||
var btn = template.GetWidget<ButtonWidget>("JOIN");
|
|
||||||
btn.GetText = () => "Spectate in this slot";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
template = EmptySlotTemplateHost.Clone();
|
|
||||||
var name = template.GetWidget<DropDownButtonWidget>("NAME");
|
|
||||||
name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : s.Bot;
|
|
||||||
name.OnMouseDown = _ => ShowSlotDropDown(name, s, Map.Players[ s.MapPlayer ].AllowBots);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
template = EmptySlotTemplate.Clone();
|
template = EmptySlotTemplate.Clone();
|
||||||
var name = template.GetWidget<LabelWidget>("NAME");
|
Func<string> getText = () => slot.Closed ? "Closed" : "Open";
|
||||||
name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : s.Bot;
|
|
||||||
|
|
||||||
if (slot.Spectator)
|
if (Game.IsHost)
|
||||||
{
|
{
|
||||||
var btn = template.GetWidget<ButtonWidget>("JOIN");
|
var name = template.GetWidget<DropDownButtonWidget>("NAME_HOST");
|
||||||
btn.GetText = () => "Spectate in this slot";
|
name.IsVisible = () => true;
|
||||||
|
name.GetText = getText;
|
||||||
|
name.OnMouseDown = _ => ShowSlotDropDown(name, slot);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var name = template.GetWidget<LabelWidget>("NAME");
|
||||||
|
name.IsVisible = () => true;
|
||||||
|
name.GetText = getText;
|
||||||
}
|
}
|
||||||
|
|
||||||
var join = template.GetWidget<ButtonWidget>("JOIN");
|
var join = template.GetWidget<ButtonWidget>("JOIN");
|
||||||
if (join != null)
|
if (join != null)
|
||||||
{
|
{
|
||||||
join.OnMouseUp = _ => { orderManager.IssueOrder(Order.Command("slot " + s.Index)); return true; };
|
join.OnMouseUp = _ => { orderManager.IssueOrder(Order.Command("slot " + key)); return true; };
|
||||||
join.IsVisible = () => !s.Closed && s.Bot == null && orderManager.LocalClient.State != Session.ClientState.Ready;
|
join.IsVisible = () => !slot.Closed && slot.Bot == null && orderManager.LocalClient.State != Session.ClientState.Ready;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// Bot
|
||||||
|
else if (client == null && slot.Bot != null)
|
||||||
|
{
|
||||||
|
template = BotTemplate.Clone();
|
||||||
|
Func<string> getText = () => slot.Bot;
|
||||||
|
|
||||||
var bot = template.GetWidget<LabelWidget>("BOT");
|
if (Game.IsHost)
|
||||||
if (bot != null)
|
{
|
||||||
bot.IsVisible = () => s.Bot != null;
|
var name = template.GetWidget<DropDownButtonWidget>("NAME_HOST");
|
||||||
|
name.IsVisible = () => true;
|
||||||
|
name.GetText = getText;
|
||||||
|
name.OnMouseDown = _ => ShowSlotDropDown(name, slot);
|
||||||
}
|
}
|
||||||
else if (c.Index == orderManager.LocalClient.Index && c.State != Session.ClientState.Ready)
|
else
|
||||||
|
{
|
||||||
|
var name = template.GetWidget<LabelWidget>("NAME");
|
||||||
|
name.IsVisible = () => true;
|
||||||
|
name.GetText = getText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Editable player in slot
|
||||||
|
else if (client.Index == orderManager.LocalClient.Index && client.State != Session.ClientState.Ready)
|
||||||
{
|
{
|
||||||
template = LocalPlayerTemplate.Clone();
|
template = LocalPlayerTemplate.Clone();
|
||||||
var name = template.GetWidget<TextFieldWidget>("NAME");
|
var name = template.GetWidget<TextFieldWidget>("NAME");
|
||||||
name.Text = c.Name;
|
name.Text = client.Name;
|
||||||
name.OnEnterKey = () =>
|
name.OnEnterKey = () =>
|
||||||
{
|
{
|
||||||
name.Text = name.Text.Trim();
|
name.Text = name.Text.Trim();
|
||||||
if (name.Text.Length == 0)
|
if (name.Text.Length == 0)
|
||||||
name.Text = c.Name;
|
name.Text = client.Name;
|
||||||
|
|
||||||
name.LoseFocus();
|
name.LoseFocus();
|
||||||
if (name.Text == c.Name)
|
if (name.Text == client.Name)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
orderManager.IssueOrder(Order.Command("name " + name.Text));
|
orderManager.IssueOrder(Order.Command("name " + name.Text));
|
||||||
@@ -473,84 +468,139 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
|||||||
name.OnLoseFocus = () => name.OnEnterKey();
|
name.OnLoseFocus = () => name.OnEnterKey();
|
||||||
|
|
||||||
var color = template.GetWidget<DropDownButtonWidget>("COLOR");
|
var color = template.GetWidget<DropDownButtonWidget>("COLOR");
|
||||||
color.OnMouseDown = _ => ShowColorDropDown(color, s);
|
color.IsDisabled = () => slot.LockColor;
|
||||||
|
color.OnMouseDown = _ => { if (slot.LockColor) return true; return ShowColorDropDown(color, client); };
|
||||||
|
|
||||||
var colorBlock = color.GetWidget<ColorBlockWidget>("COLORBLOCK");
|
var colorBlock = color.GetWidget<ColorBlockWidget>("COLORBLOCK");
|
||||||
colorBlock.GetColor = () => c.ColorRamp.GetColor(0);
|
colorBlock.GetColor = () => client.ColorRamp.GetColor(0);
|
||||||
|
|
||||||
var faction = template.GetWidget<DropDownButtonWidget>("FACTION");
|
var faction = template.GetWidget<DropDownButtonWidget>("FACTION");
|
||||||
faction.OnMouseDown = _ => ShowRaceDropDown(faction, s);
|
faction.IsDisabled = () => slot.LockRace;
|
||||||
|
faction.OnMouseDown = _ => { if (slot.LockRace) return true; return ShowRaceDropDown(faction, client); };
|
||||||
|
|
||||||
var factionname = faction.GetWidget<LabelWidget>("FACTIONNAME");
|
var factionname = faction.GetWidget<LabelWidget>("FACTIONNAME");
|
||||||
factionname.GetText = () => CountryNames[c.Country];
|
factionname.GetText = () => CountryNames[client.Country];
|
||||||
var factionflag = faction.GetWidget<ImageWidget>("FACTIONFLAG");
|
var factionflag = faction.GetWidget<ImageWidget>("FACTIONFLAG");
|
||||||
factionflag.GetImageName = () => c.Country;
|
factionflag.GetImageName = () => client.Country;
|
||||||
factionflag.GetImageCollection = () => "flags";
|
factionflag.GetImageCollection = () => "flags";
|
||||||
|
|
||||||
var team = template.GetWidget<DropDownButtonWidget>("TEAM");
|
var team = template.GetWidget<DropDownButtonWidget>("TEAM");
|
||||||
team.OnMouseDown = _ => ShowTeamDropDown(team, s);
|
team.IsDisabled = () => slot.LockTeam;
|
||||||
team.GetText = () => (c.Team == 0) ? "-" : c.Team.ToString();
|
team.OnMouseDown = _ => { if (slot.LockTeam) return true; return ShowTeamDropDown(team, client); };
|
||||||
|
team.GetText = () => (client.Team == 0) ? "-" : client.Team.ToString();
|
||||||
|
|
||||||
var status = template.GetWidget<CheckboxWidget>("STATUS");
|
var status = template.GetWidget<CheckboxWidget>("STATUS");
|
||||||
status.IsChecked = () => c.State == Session.ClientState.Ready;
|
status.IsChecked = () => client.State == Session.ClientState.Ready;
|
||||||
status.OnClick += CycleReady;
|
status.OnClick += CycleReady;
|
||||||
|
|
||||||
var spectator = template.GetWidget<LabelWidget>("SPECTATOR");
|
|
||||||
|
|
||||||
Session.Slot slot1 = slot;
|
|
||||||
color.IsVisible = () => !slot1.Spectator;
|
|
||||||
colorBlock.IsVisible = () => !slot1.Spectator;
|
|
||||||
faction.IsVisible = () => !slot1.Spectator;
|
|
||||||
factionname.IsVisible = () => !slot1.Spectator;
|
|
||||||
factionflag.IsVisible = () => !slot1.Spectator;
|
|
||||||
team.IsVisible = () => !slot1.Spectator;
|
|
||||||
spectator.IsVisible = () => slot1.Spectator || slot1.Bot != null;
|
|
||||||
}
|
}
|
||||||
|
// Non-editable player in slot
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
template = RemotePlayerTemplate.Clone();
|
template = RemotePlayerTemplate.Clone();
|
||||||
template.GetWidget<LabelWidget>("NAME").GetText = () => c.Name;
|
template.GetWidget<LabelWidget>("NAME").GetText = () => client.Name;
|
||||||
var color = template.GetWidget<ColorBlockWidget>("COLOR");
|
var color = template.GetWidget<ColorBlockWidget>("COLOR");
|
||||||
color.GetColor = () => c.ColorRamp.GetColor(0);
|
color.GetColor = () => client.ColorRamp.GetColor(0);
|
||||||
|
|
||||||
var faction = template.GetWidget<LabelWidget>("FACTION");
|
var faction = template.GetWidget<LabelWidget>("FACTION");
|
||||||
var factionname = faction.GetWidget<LabelWidget>("FACTIONNAME");
|
var factionname = faction.GetWidget<LabelWidget>("FACTIONNAME");
|
||||||
factionname.GetText = () => CountryNames[c.Country];
|
factionname.GetText = () => CountryNames[client.Country];
|
||||||
var factionflag = faction.GetWidget<ImageWidget>("FACTIONFLAG");
|
var factionflag = faction.GetWidget<ImageWidget>("FACTIONFLAG");
|
||||||
factionflag.GetImageName = () => c.Country;
|
factionflag.GetImageName = () => client.Country;
|
||||||
factionflag.GetImageCollection = () => "flags";
|
factionflag.GetImageCollection = () => "flags";
|
||||||
|
|
||||||
var team = template.GetWidget<LabelWidget>("TEAM");
|
var team = template.GetWidget<LabelWidget>("TEAM");
|
||||||
team.GetText = () => (c.Team == 0) ? "-" : c.Team.ToString();
|
team.GetText = () => (client.Team == 0) ? "-" : client.Team.ToString();
|
||||||
|
|
||||||
var status = template.GetWidget<CheckboxWidget>("STATUS");
|
var status = template.GetWidget<CheckboxWidget>("STATUS");
|
||||||
status.IsChecked = () => c.State == Session.ClientState.Ready;
|
status.IsChecked = () => client.State == Session.ClientState.Ready;
|
||||||
if (c.Index == orderManager.LocalClient.Index)
|
if (client.Index == orderManager.LocalClient.Index)
|
||||||
status.OnClick += CycleReady;
|
status.OnClick += CycleReady;
|
||||||
|
|
||||||
var spectator = template.GetWidget<LabelWidget>("SPECTATOR");
|
|
||||||
|
|
||||||
Session.Slot slot1 = slot;
|
|
||||||
color.IsVisible = () => !slot1.Spectator;
|
|
||||||
faction.IsVisible = () => !slot1.Spectator;
|
|
||||||
factionname.IsVisible = () => !slot1.Spectator;
|
|
||||||
factionflag.IsVisible = () => !slot1.Spectator;
|
|
||||||
team.IsVisible = () => !slot1.Spectator;
|
|
||||||
spectator.IsVisible = () => slot1.Spectator || slot1.Bot != null;
|
|
||||||
|
|
||||||
var kickButton = template.GetWidget<ButtonWidget>("KICK");
|
var kickButton = template.GetWidget<ButtonWidget>("KICK");
|
||||||
kickButton.IsVisible = () => Game.IsHost && c.Index != orderManager.LocalClient.Index;
|
kickButton.IsVisible = () => Game.IsHost && client.Index != orderManager.LocalClient.Index;
|
||||||
kickButton.OnMouseUp = mi =>
|
kickButton.OnMouseUp = mi =>
|
||||||
{
|
{
|
||||||
orderManager.IssueOrder(Order.Command("kick " + c.Slot));
|
orderManager.IssueOrder(Order.Command("kick " + client.Index));
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template.Id = "SLOT_{0}".F(s.Index);
|
|
||||||
template.IsVisible = () => true;
|
template.IsVisible = () => true;
|
||||||
Players.AddChild(template);
|
Players.AddChild(template);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add spectators
|
||||||
|
foreach (var client in orderManager.LobbyInfo.Clients.Where(client => client.Slot == null))
|
||||||
|
{
|
||||||
|
Widget template;
|
||||||
|
// Editable spectator
|
||||||
|
if (client.Index == orderManager.LocalClient.Index && client.State != Session.ClientState.Ready)
|
||||||
|
{
|
||||||
|
template = LocalSpectatorTemplate.Clone();
|
||||||
|
var name = template.GetWidget<TextFieldWidget>("NAME");
|
||||||
|
name.Text = client.Name;
|
||||||
|
name.OnEnterKey = () =>
|
||||||
|
{
|
||||||
|
name.Text = name.Text.Trim();
|
||||||
|
if (name.Text.Length == 0)
|
||||||
|
name.Text = client.Name;
|
||||||
|
|
||||||
|
name.LoseFocus();
|
||||||
|
if (name.Text == client.Name)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
orderManager.IssueOrder(Order.Command("name " + name.Text));
|
||||||
|
Game.Settings.Player.Name = name.Text;
|
||||||
|
Game.Settings.Save();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
name.OnLoseFocus = () => name.OnEnterKey();
|
||||||
|
|
||||||
|
var color = template.GetWidget<DropDownButtonWidget>("COLOR");
|
||||||
|
color.OnMouseDown = _ => ShowColorDropDown(color, client);
|
||||||
|
|
||||||
|
var colorBlock = color.GetWidget<ColorBlockWidget>("COLORBLOCK");
|
||||||
|
colorBlock.GetColor = () => client.ColorRamp.GetColor(0);
|
||||||
|
|
||||||
|
var status = template.GetWidget<CheckboxWidget>("STATUS");
|
||||||
|
status.IsChecked = () => client.State == Session.ClientState.Ready;
|
||||||
|
status.OnClick += CycleReady;
|
||||||
|
}
|
||||||
|
// Non-editable spectator
|
||||||
|
else
|
||||||
|
{
|
||||||
|
template = RemoteSpectatorTemplate.Clone();
|
||||||
|
template.GetWidget<LabelWidget>("NAME").GetText = () => client.Name;
|
||||||
|
var color = template.GetWidget<ColorBlockWidget>("COLOR");
|
||||||
|
color.GetColor = () => client.ColorRamp.GetColor(0);
|
||||||
|
|
||||||
|
var status = template.GetWidget<CheckboxWidget>("STATUS");
|
||||||
|
status.IsChecked = () => client.State == Session.ClientState.Ready;
|
||||||
|
if (client.Index == orderManager.LocalClient.Index)
|
||||||
|
status.OnClick += CycleReady;
|
||||||
|
|
||||||
|
var kickButton = template.GetWidget<ButtonWidget>("KICK");
|
||||||
|
kickButton.IsVisible = () => Game.IsHost && client.Index != orderManager.LocalClient.Index;
|
||||||
|
kickButton.OnMouseUp = mi =>
|
||||||
|
{
|
||||||
|
orderManager.IssueOrder(Order.Command("kick " + client.Index));
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template.IsVisible = () => true;
|
||||||
|
Players.AddChild(template);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spectate button
|
||||||
|
if (orderManager.LocalClient.Slot != null && orderManager.LocalClient.State != Session.ClientState.Ready)
|
||||||
|
{
|
||||||
|
var spec = NewSpectatorTemplate.Clone();
|
||||||
|
var btn = spec.GetWidget<ButtonWidget>("SPECTATE");
|
||||||
|
btn.OnMouseUp = _ => { orderManager.IssueOrder(Order.Command("spectate")); return true; };
|
||||||
|
spec.IsVisible = () => true;
|
||||||
|
Players.AddChild(spec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpawnPointAvailable(int index) { return (index == 0) || orderManager.LobbyInfo.Clients.All(c => c.SpawnPoint != index); }
|
bool SpawnPointAvailable(int index) { return (index == 0) || orderManager.LobbyInfo.Clients.All(c => c.SpawnPoint != index); }
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
|||||||
panel.GetWidget<LabelWidget>("MAP_TITLE").GetText =
|
panel.GetWidget<LabelWidget>("MAP_TITLE").GetText =
|
||||||
() => currentMap != null ? currentMap.Title : "(Unknown Map)";
|
() => currentMap != null ? currentMap.Title : "(Unknown Map)";
|
||||||
|
|
||||||
var players = currentSummary.LobbyInfo.Slots.Count(s => currentSummary.LobbyInfo.ClientInSlot(s) != null || s.Bot != null);
|
var players = currentSummary.LobbyInfo.Slots.Count(s => currentSummary.LobbyInfo.ClientInSlot(s.Key) != null || s.Value.Bot != null);
|
||||||
panel.GetWidget<LabelWidget>("PLAYERS").GetText = () => players.ToString();
|
panel.GetWidget<LabelWidget>("PLAYERS").GetText = () => players.ToString();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|||||||
@@ -31,13 +31,13 @@ namespace OpenRA.Mods.RA
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create the players which are bound through slots.
|
// create the players which are bound through slots.
|
||||||
foreach (var slot in w.LobbyInfo.Slots)
|
foreach (var kv in w.LobbyInfo.Slots)
|
||||||
{
|
{
|
||||||
var client = w.LobbyInfo.Clients.FirstOrDefault(c => c.Slot == slot.Index && slot.MapPlayer != null);
|
var client = w.LobbyInfo.ClientInSlot(kv.Key);
|
||||||
if (client == null && slot.Bot == null)
|
if (client == null && kv.Value.Bot == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var player = new Player(w, client, slot, w.Map.Players[slot.MapPlayer]);
|
var player = new Player(w, client, kv.Value, w.Map.Players[kv.Value.PlayerReference]);
|
||||||
w.AddPlayer(player);
|
w.AddPlayer(player);
|
||||||
|
|
||||||
if (client != null && client.Index == Game.LocalClientId)
|
if (client != null && client.Index == Game.LocalClientId)
|
||||||
@@ -60,8 +60,8 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
if (p.World.LobbyInfo.Slots.Count > 0)
|
if (p.World.LobbyInfo.Slots.Count > 0)
|
||||||
{
|
{
|
||||||
if (p.World.LobbyInfo.Slots[pc.Slot].Spectator) return Stance.Ally;
|
if (p.PlayerRef == null) return Stance.Ally;
|
||||||
if (p.World.LobbyInfo.Slots[qc.Slot].Spectator) return Stance.Ally;
|
if (q.PlayerRef == null) return Stance.Ally;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stances set via the player reference
|
// Stances set via the player reference
|
||||||
|
|||||||
@@ -28,19 +28,17 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public void WorldLoaded(World world)
|
public void WorldLoaded(World world)
|
||||||
{
|
{
|
||||||
var taken = world.LobbyInfo.Clients.Where(c => c.SpawnPoint != 0 && c.Slot != -1)
|
var taken = world.LobbyInfo.Clients.Where(c => c.SpawnPoint != 0 && c.Slot != null)
|
||||||
.Select(c => world.Map.SpawnPoints.ElementAt(c.SpawnPoint - 1)).ToList();
|
.Select(c => world.Map.SpawnPoints.ElementAt(c.SpawnPoint - 1)).ToList();
|
||||||
var available = world.Map.SpawnPoints.Except(taken).ToList();
|
var available = world.Map.SpawnPoints.Except(taken).ToList();
|
||||||
|
|
||||||
// Set spawn
|
// Set spawn
|
||||||
foreach (var slot in world.LobbyInfo.Slots)
|
foreach (var kv in world.LobbyInfo.Slots)
|
||||||
{
|
{
|
||||||
if (slot.Spectator)
|
var player = FindPlayerInSlot(world, kv.Key);
|
||||||
continue; // Skip spectator slots
|
|
||||||
var client = world.LobbyInfo.Clients.FirstOrDefault(c => c.Slot == slot.Index);
|
|
||||||
var player = FindPlayerInSlot(world, slot);
|
|
||||||
if (player == null) continue;
|
if (player == null) continue;
|
||||||
|
|
||||||
|
var client = world.LobbyInfo.ClientInSlot(kv.Key);
|
||||||
var spid = (client == null || client.SpawnPoint == 0)
|
var spid = (client == null || client.SpawnPoint == 0)
|
||||||
? ChooseSpawnPoint(world, available, taken)
|
? ChooseSpawnPoint(world, available, taken)
|
||||||
: world.Map.SpawnPoints.ElementAt(client.SpawnPoint - 1);
|
: world.Map.SpawnPoints.ElementAt(client.SpawnPoint - 1);
|
||||||
@@ -59,9 +57,9 @@ namespace OpenRA.Mods.RA
|
|||||||
Game.viewport.Center(Start[world.LocalPlayer]);
|
Game.viewport.Center(Start[world.LocalPlayer]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Player FindPlayerInSlot(World world, Session.Slot slot)
|
static Player FindPlayerInSlot(World world, string pr)
|
||||||
{
|
{
|
||||||
return world.Players.FirstOrDefault(p => p.PlayerRef.Name == slot.MapPlayer);
|
return world.Players.FirstOrDefault(p => p.PlayerRef.Name == pr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int2 ChooseSpawnPoint(World world, List<int2> available, List<int2> taken)
|
static int2 ChooseSpawnPoint(World world, List<int2> available, List<int2> taken)
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
{
|
{
|
||||||
public class LobbyCommands : ServerTrait, IInterpretCommand, INotifyServerStart
|
public class LobbyCommands : ServerTrait, IInterpretCommand, INotifyServerStart
|
||||||
{
|
{
|
||||||
public static int MaxSpectators = 4; // How many spectators to allow // @todo Expose this as an option
|
|
||||||
|
|
||||||
public bool InterpretCommand(S server, Connection conn, Session.Client client, string cmd)
|
public bool InterpretCommand(S server, Connection conn, Session.Client client, string cmd)
|
||||||
{
|
{
|
||||||
if (server.GameStarted)
|
if (server.GameStarted)
|
||||||
@@ -77,33 +75,39 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
{ "slot",
|
{ "slot",
|
||||||
s =>
|
s =>
|
||||||
{
|
{
|
||||||
int slot;
|
if (!server.lobbyInfo.Slots.ContainsKey(s))
|
||||||
if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; }
|
{
|
||||||
|
Log.Write("server", "Invalid slot: {0}", s );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var slot = server.lobbyInfo.Slots[s];
|
||||||
|
|
||||||
var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot );
|
if (slot.Closed || slot.Bot != null ||
|
||||||
if (slotData == null || slotData.Closed || slotData.Bot != null
|
server.lobbyInfo.ClientInSlot(s) != null)
|
||||||
|| server.lobbyInfo.Clients.Any( c => c.Slot == slot ))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
client.Slot = slot;
|
client.Slot = s;
|
||||||
S.SyncClientToPlayerReference(client, slotData.MapPlayer != null ? server.Map.Players[slotData.MapPlayer] : null);
|
S.SyncClientToPlayerReference(client, server.Map.Players[s]);
|
||||||
|
|
||||||
// if we're entering a spectator slot, relinquish our spawnpoint.
|
server.SyncLobbyInfo();
|
||||||
if (slotData.Spectator)
|
return true;
|
||||||
|
}},
|
||||||
|
{ "spectate",
|
||||||
|
s =>
|
||||||
|
{
|
||||||
|
client.Slot = null;
|
||||||
client.SpawnPoint = 0;
|
client.SpawnPoint = 0;
|
||||||
|
|
||||||
server.SyncLobbyInfo();
|
server.SyncLobbyInfo();
|
||||||
return true;
|
return true;
|
||||||
}},
|
}},
|
||||||
{ "slot_close",
|
{ "slot_close",
|
||||||
s =>
|
s =>
|
||||||
{
|
{
|
||||||
int slot;
|
if (!server.lobbyInfo.Slots.ContainsKey(s))
|
||||||
if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; }
|
{
|
||||||
|
Log.Write("server", "Invalid slot: {0}", s );
|
||||||
var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot );
|
|
||||||
if (slotData == null)
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (conn.PlayerIndex != 0)
|
if (conn.PlayerIndex != 0)
|
||||||
{
|
{
|
||||||
@@ -111,11 +115,8 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
slotData.Closed = true;
|
// kick any player that's in the slot
|
||||||
slotData.Bot = null;
|
var occupant = server.lobbyInfo.ClientInSlot(s);
|
||||||
|
|
||||||
/* kick any player that's in the slot */
|
|
||||||
var occupant = server.lobbyInfo.Clients.FirstOrDefault( c => c.Slot == slotData.Index );
|
|
||||||
if (occupant != null)
|
if (occupant != null)
|
||||||
{
|
{
|
||||||
var occupantConn = server.conns.FirstOrDefault( c => c.PlayerIndex == occupant.Index );
|
var occupantConn = server.conns.FirstOrDefault( c => c.PlayerIndex == occupant.Index );
|
||||||
@@ -125,6 +126,9 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
server.DropClient(occupantConn);
|
server.DropClient(occupantConn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var slot = server.lobbyInfo.Slots[s];
|
||||||
|
slot.Closed = true;
|
||||||
|
slot.Bot = null;
|
||||||
|
|
||||||
server.SyncLobbyInfo();
|
server.SyncLobbyInfo();
|
||||||
return true;
|
return true;
|
||||||
@@ -132,12 +136,11 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
{ "slot_open",
|
{ "slot_open",
|
||||||
s =>
|
s =>
|
||||||
{
|
{
|
||||||
int slot;
|
if (!server.lobbyInfo.Slots.ContainsKey(s))
|
||||||
if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; }
|
{
|
||||||
|
Log.Write("server", "Invalid slot: {0}", s );
|
||||||
var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot );
|
|
||||||
if (slotData == null)
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (conn.PlayerIndex != 0)
|
if (conn.PlayerIndex != 0)
|
||||||
{
|
{
|
||||||
@@ -145,8 +148,9 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
slotData.Closed = false;
|
var slot = server.lobbyInfo.Slots[s];
|
||||||
slotData.Bot = null;
|
slot.Closed = false;
|
||||||
|
slot.Bot = null;
|
||||||
|
|
||||||
server.SyncLobbyInfo();
|
server.SyncLobbyInfo();
|
||||||
return true;
|
return true;
|
||||||
@@ -162,12 +166,11 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int slot;
|
if (!server.lobbyInfo.Slots.ContainsKey(parts[0]))
|
||||||
if (!int.TryParse(parts[0], out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; }
|
{
|
||||||
|
Log.Write("server", "Invalid slot: {0}", parts[0] );
|
||||||
var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot );
|
|
||||||
if (slotData == null)
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (conn.PlayerIndex != 0)
|
if (conn.PlayerIndex != 0)
|
||||||
{
|
{
|
||||||
@@ -175,8 +178,9 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
slotData.Closed = false;
|
var slot = server.lobbyInfo.Slots[parts[0]];
|
||||||
slotData.Bot = string.Join(" ", parts.Skip(1).ToArray() );
|
slot.Bot = string.Join(" ", parts.Skip(1).ToArray() );
|
||||||
|
slot.Closed = false;
|
||||||
|
|
||||||
server.SyncLobbyInfo();
|
server.SyncLobbyInfo();
|
||||||
return true;
|
return true;
|
||||||
@@ -192,14 +196,17 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
server.lobbyInfo.GlobalSettings.Map = s;
|
server.lobbyInfo.GlobalSettings.Map = s;
|
||||||
LoadMap(server);
|
LoadMap(server);
|
||||||
|
|
||||||
|
// Reassign players into slots
|
||||||
|
int i = 0;
|
||||||
foreach(var c in server.lobbyInfo.Clients)
|
foreach(var c in server.lobbyInfo.Clients)
|
||||||
{
|
{
|
||||||
c.SpawnPoint = 0;
|
c.SpawnPoint = 0;
|
||||||
var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == c.Slot );
|
|
||||||
if (slotData != null && slotData.MapPlayer != null)
|
|
||||||
S.SyncClientToPlayerReference(c, server.Map.Players[slotData.MapPlayer]);
|
|
||||||
|
|
||||||
c.State = Session.ClientState.NotReady;
|
c.State = Session.ClientState.NotReady;
|
||||||
|
c.Slot = c.Slot == null || i >= server.lobbyInfo.Slots.Count ?
|
||||||
|
null : server.lobbyInfo.Slots.ElementAt(i++).Key;
|
||||||
|
|
||||||
|
if (c.Slot != null)
|
||||||
|
S.SyncClientToPlayerReference(c, server.Map.Players[c.Slot]);
|
||||||
}
|
}
|
||||||
|
|
||||||
server.SyncLobbyInfo();
|
server.SyncLobbyInfo();
|
||||||
@@ -234,16 +241,17 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
{ "kick",
|
{ "kick",
|
||||||
s =>
|
s =>
|
||||||
{
|
{
|
||||||
|
|
||||||
if (conn.PlayerIndex != 0)
|
if (conn.PlayerIndex != 0)
|
||||||
{
|
{
|
||||||
server.SendChatTo( conn, "Only the host can kick players" );
|
server.SendChatTo( conn, "Only the host can kick players" );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int slot;
|
int clientID;
|
||||||
int.TryParse( s, out slot );
|
int.TryParse( s, out clientID );
|
||||||
|
|
||||||
var connToKick = server.conns.SingleOrDefault( c => server.GetClient(c) != null && server.GetClient(c).Slot == slot);
|
var connToKick = server.conns.SingleOrDefault( c => server.GetClient(c) != null && server.GetClient(c).Index == clientID);
|
||||||
if (connToKick == null)
|
if (connToKick == null)
|
||||||
{
|
{
|
||||||
server.SendChatTo( conn, "Noone in that slot." );
|
server.SendChatTo( conn, "Noone in that slot." );
|
||||||
@@ -252,9 +260,7 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
|
|
||||||
server.SendOrderTo(connToKick, "ServerError", "You have been kicked from the server");
|
server.SendOrderTo(connToKick, "ServerError", "You have been kicked from the server");
|
||||||
server.DropClient(connToKick);
|
server.DropClient(connToKick);
|
||||||
|
|
||||||
server.SyncLobbyInfo();
|
server.SyncLobbyInfo();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}},
|
}},
|
||||||
};
|
};
|
||||||
@@ -275,9 +281,13 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
if (!pr.Playable) return null;
|
if (!pr.Playable) return null;
|
||||||
return new Session.Slot
|
return new Session.Slot
|
||||||
{
|
{
|
||||||
MapPlayer = pr.Name,
|
PlayerReference = pr.Name,
|
||||||
Bot = null, /* todo: allow the map to specify a bot class? */
|
Bot = null,
|
||||||
Closed = false,
|
Closed = false,
|
||||||
|
AllowBots = pr.AllowBots,
|
||||||
|
LockRace = pr.LockRace,
|
||||||
|
LockColor = pr.LockColor,
|
||||||
|
LockTeam = false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,18 +297,7 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
server.lobbyInfo.Slots = server.Map.Players
|
server.lobbyInfo.Slots = server.Map.Players
|
||||||
.Select(p => MakeSlotFromPlayerReference(p.Value))
|
.Select(p => MakeSlotFromPlayerReference(p.Value))
|
||||||
.Where(s => s != null)
|
.Where(s => s != null)
|
||||||
.Select((s, i) => { s.Index = i; return s; })
|
.ToDictionary(s => s.PlayerReference, s => s);
|
||||||
.ToList();
|
|
||||||
|
|
||||||
// Generate slots for spectators
|
|
||||||
for (int i = 0; i < MaxSpectators; i++)
|
|
||||||
server.lobbyInfo.Slots.Add(new Session.Slot
|
|
||||||
{
|
|
||||||
Spectator = true,
|
|
||||||
Index = server.lobbyInfo.Slots.Count(),
|
|
||||||
MapPlayer = null,
|
|
||||||
Bot = null
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
server.lobbyInfo.Clients.Count,
|
server.lobbyInfo.Clients.Count,
|
||||||
string.Join(",", Game.CurrentMods.Select(f => "{0}@{1}".F(f.Key, f.Value.Version)).ToArray()),
|
string.Join(",", Game.CurrentMods.Select(f => "{0}@{1}".F(f.Key, f.Value.Version)).ToArray()),
|
||||||
server.lobbyInfo.GlobalSettings.Map,
|
server.lobbyInfo.GlobalSettings.Map,
|
||||||
server.lobbyInfo.Slots.Count( s => !s.Spectator )));
|
server.Map.PlayerCount));
|
||||||
|
|
||||||
if (isInitialPing)
|
if (isInitialPing)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace OpenRA.Mods.RA.Server
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server.lobbyInfo.Slots[client.Slot].Spectator)
|
if (client.Slot == null)
|
||||||
{
|
{
|
||||||
server.SendChatTo( conn, "Can't select a spawnpoint as a spectator" );
|
server.SendChatTo( conn, "Can't select a spawnpoint as a spectator" );
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
{
|
{
|
||||||
public class LobbyLogic
|
public class LobbyLogic
|
||||||
{
|
{
|
||||||
Widget lobby, LocalPlayerTemplate, RemotePlayerTemplate, EmptySlotTemplate, EmptySlotTemplateHost;
|
Widget lobby, LocalPlayerTemplate, RemotePlayerTemplate, EmptySlotTemplate, EmptySlotTemplateHost,
|
||||||
|
LocalSpectatorTemplate, RemoteSpectatorTemplate, NewSpectatorTemplate;
|
||||||
|
|
||||||
ScrollPanelWidget Players;
|
ScrollPanelWidget Players;
|
||||||
Dictionary<string, string> CountryNames;
|
Dictionary<string, string> CountryNames;
|
||||||
string MapUid;
|
string MapUid;
|
||||||
@@ -50,6 +52,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
RemotePlayerTemplate = Players.GetWidget("TEMPLATE_REMOTE");
|
RemotePlayerTemplate = Players.GetWidget("TEMPLATE_REMOTE");
|
||||||
EmptySlotTemplate = Players.GetWidget("TEMPLATE_EMPTY");
|
EmptySlotTemplate = Players.GetWidget("TEMPLATE_EMPTY");
|
||||||
EmptySlotTemplateHost = Players.GetWidget("TEMPLATE_EMPTY_HOST");
|
EmptySlotTemplateHost = Players.GetWidget("TEMPLATE_EMPTY_HOST");
|
||||||
|
LocalSpectatorTemplate = Players.GetWidget("TEMPLATE_LOCAL_SPECTATOR");
|
||||||
|
RemoteSpectatorTemplate = Players.GetWidget("TEMPLATE_REMOTE_SPECTATOR");
|
||||||
|
NewSpectatorTemplate = Players.GetWidget("TEMPLATE_NEW_SPECTATOR");
|
||||||
|
|
||||||
var mapPreview = lobby.GetWidget<MapPreviewWidget>("LOBBY_MAP_PREVIEW");
|
var mapPreview = lobby.GetWidget<MapPreviewWidget>("LOBBY_MAP_PREVIEW");
|
||||||
mapPreview.Map = () => Map;
|
mapPreview.Map = () => Map;
|
||||||
@@ -202,11 +207,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
title.Text = "OpenRA Multiplayer Lobby - " + orderManager.LobbyInfo.GlobalSettings.ServerName;
|
title.Text = "OpenRA Multiplayer Lobby - " + orderManager.LobbyInfo.GlobalSettings.ServerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
Session.Client GetClientInSlot(Session.Slot slot)
|
|
||||||
{
|
|
||||||
return orderManager.LobbyInfo.ClientInSlot( slot );
|
|
||||||
}
|
|
||||||
|
|
||||||
class SlotDropDownOption
|
class SlotDropDownOption
|
||||||
{
|
{
|
||||||
public string Title;
|
public string Title;
|
||||||
@@ -221,20 +221,21 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShowSlotDropDown(DropDownButtonWidget dropdown, Session.Slot slot, bool showBotOptions)
|
bool ShowSlotDropDown(DropDownButtonWidget dropdown, Session.Slot slot)
|
||||||
{
|
{
|
||||||
var options = new List<SlotDropDownOption>()
|
var options = new List<SlotDropDownOption>()
|
||||||
{
|
{
|
||||||
new SlotDropDownOption("Open", "slot_open "+slot.Index, () => (!slot.Closed && slot.Bot == null)),
|
new SlotDropDownOption("Open", "slot_open "+slot.PlayerReference, () => (!slot.Closed && slot.Bot == null)),
|
||||||
new SlotDropDownOption("Closed", "slot_close "+slot.Index, () => slot.Closed)
|
new SlotDropDownOption("Closed", "slot_close "+slot.PlayerReference, () => slot.Closed)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (showBotOptions)
|
if (slot.AllowBots)
|
||||||
foreach (var b in Rules.Info["player"].Traits.WithInterface<IBotInfo>().Select(t => t.Name))
|
foreach (var b in Rules.Info["player"].Traits.WithInterface<IBotInfo>().Select(t => t.Name))
|
||||||
{
|
{
|
||||||
var bot = b;
|
var bot = b;
|
||||||
options.Add(new SlotDropDownOption("Bot: {0}".F(bot), "slot_bot {0} {1}".F(slot.Index, bot), () => slot.Bot == bot));
|
options.Add(new SlotDropDownOption("Bot: {0}".F(bot), "slot_bot {0} {1}".F(slot.PlayerReference, bot), () => slot.Bot == bot));
|
||||||
}
|
}
|
||||||
|
|
||||||
Func<SlotDropDownOption, ScrollItemWidget, ScrollItemWidget> setupItem = (o, itemTemplate) =>
|
Func<SlotDropDownOption, ScrollItemWidget, ScrollItemWidget> setupItem = (o, itemTemplate) =>
|
||||||
{
|
{
|
||||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||||
@@ -248,16 +249,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShowRaceDropDown(DropDownButtonWidget dropdown, Session.Slot slot)
|
bool ShowRaceDropDown(DropDownButtonWidget dropdown, Session.Client client)
|
||||||
{
|
{
|
||||||
if (Map.Players[slot.MapPlayer].LockRace)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var sr = GetClientInSlot(slot).Country;
|
|
||||||
Func<string, ScrollItemWidget, ScrollItemWidget> setupItem = (race, itemTemplate) =>
|
Func<string, ScrollItemWidget, ScrollItemWidget> setupItem = (race, itemTemplate) =>
|
||||||
{
|
{
|
||||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||||
() => sr == race,
|
() => client.Country == race,
|
||||||
() => orderManager.IssueOrder(Order.Command("race "+race)));
|
() => orderManager.IssueOrder(Order.Command("race "+race)));
|
||||||
item.GetWidget<LabelWidget>("LABEL").GetText = () => CountryNames[race];
|
item.GetWidget<LabelWidget>("LABEL").GetText = () => CountryNames[race];
|
||||||
var flag = item.GetWidget<ImageWidget>("FLAG");
|
var flag = item.GetWidget<ImageWidget>("FLAG");
|
||||||
@@ -270,13 +267,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShowTeamDropDown(DropDownButtonWidget dropdown, Session.Slot slot)
|
bool ShowTeamDropDown(DropDownButtonWidget dropdown, Session.Client client)
|
||||||
{
|
{
|
||||||
var c = GetClientInSlot(slot);
|
|
||||||
Func<int, ScrollItemWidget, ScrollItemWidget> setupItem = (ii, itemTemplate) =>
|
Func<int, ScrollItemWidget, ScrollItemWidget> setupItem = (ii, itemTemplate) =>
|
||||||
{
|
{
|
||||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||||
() => c.Team == ii,
|
() => client.Team == ii,
|
||||||
() => orderManager.IssueOrder(Order.Command("team "+ii)));
|
() => orderManager.IssueOrder(Order.Command("team "+ii)));
|
||||||
item.GetWidget<LabelWidget>("LABEL").GetText = () => ii == 0 ? "-" : ii.ToString();
|
item.GetWidget<LabelWidget>("LABEL").GetText = () => ii == 0 ? "-" : ii.ToString();
|
||||||
return item;
|
return item;
|
||||||
@@ -287,11 +283,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShowColorDropDown(Session.Slot s, DropDownButtonWidget color)
|
bool ShowColorDropDown(DropDownButtonWidget color, Session.Client client)
|
||||||
{
|
{
|
||||||
if (Map.Players[s.MapPlayer].LockColor)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var colorChooser = Game.modData.WidgetLoader.LoadWidget( new WidgetArgs() { {"worldRenderer", worldRenderer} }, null, "COLOR_CHOOSER" );
|
var colorChooser = Game.modData.WidgetLoader.LoadWidget( new WidgetArgs() { {"worldRenderer", worldRenderer} }, null, "COLOR_CHOOSER" );
|
||||||
var hueSlider = colorChooser.GetWidget<SliderWidget>("HUE_SLIDER");
|
var hueSlider = colorChooser.GetWidget<SliderWidget>("HUE_SLIDER");
|
||||||
hueSlider.SetOffset(orderManager.LocalClient.ColorRamp.H / 255f);
|
hueSlider.SetOffset(orderManager.LocalClient.ColorRamp.H / 255f);
|
||||||
@@ -328,50 +321,32 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
// Todo: handle this nicer
|
// Todo: handle this nicer
|
||||||
Players.RemoveChildren();
|
Players.RemoveChildren();
|
||||||
|
|
||||||
foreach (var slot in orderManager.LobbyInfo.Slots)
|
foreach (var kv in orderManager.LobbyInfo.Slots)
|
||||||
{
|
{
|
||||||
var s = slot;
|
var s = kv.Value;
|
||||||
var c = GetClientInSlot(s);
|
var c = orderManager.LobbyInfo.ClientInSlot(kv.Key);
|
||||||
Widget template;
|
Widget template;
|
||||||
|
|
||||||
if (c == null)
|
if (c == null)
|
||||||
{
|
{
|
||||||
if (Game.IsHost)
|
if (Game.IsHost)
|
||||||
{
|
|
||||||
if (slot.Spectator)
|
|
||||||
{
|
|
||||||
template = EmptySlotTemplateHost.Clone();
|
|
||||||
var name = template.GetWidget<DropDownButtonWidget>("NAME");
|
|
||||||
name.GetText = () => s.Closed ? "Closed" : "Open";
|
|
||||||
name.OnMouseDown = _ => ShowSlotDropDown(name, s, false);
|
|
||||||
var btn = template.GetWidget<ButtonWidget>("JOIN");
|
|
||||||
btn.GetText = () => "Spectate in this slot";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
template = EmptySlotTemplateHost.Clone();
|
template = EmptySlotTemplateHost.Clone();
|
||||||
var name = template.GetWidget<DropDownButtonWidget>("NAME");
|
var name = template.GetWidget<DropDownButtonWidget>("NAME");
|
||||||
name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : s.Bot;
|
name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : s.Bot;
|
||||||
name.OnMouseDown = _ => ShowSlotDropDown(name, s, Map.Players[ s.MapPlayer ].AllowBots);
|
name.OnMouseDown = _ => ShowSlotDropDown(name, s);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
template = EmptySlotTemplate.Clone();
|
template = EmptySlotTemplate.Clone();
|
||||||
var name = template.GetWidget<LabelWidget>("NAME");
|
var name = template.GetWidget<LabelWidget>("NAME");
|
||||||
name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : s.Bot;
|
name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : s.Bot;
|
||||||
|
|
||||||
if (slot.Spectator)
|
|
||||||
{
|
|
||||||
var btn = template.GetWidget<ButtonWidget>("JOIN");
|
|
||||||
btn.GetText = () => "Spectate in this slot";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var join = template.GetWidget<ButtonWidget>("JOIN");
|
var join = template.GetWidget<ButtonWidget>("JOIN");
|
||||||
if (join != null)
|
if (join != null)
|
||||||
{
|
{
|
||||||
join.OnMouseUp = _ => { orderManager.IssueOrder(Order.Command("slot " + s.Index)); return true; };
|
join.OnMouseUp = _ => { orderManager.IssueOrder(Order.Command("slot " + s.PlayerReference)); return true; };
|
||||||
join.IsVisible = () => !s.Closed && s.Bot == null && orderManager.LocalClient.State != Session.ClientState.Ready;
|
join.IsVisible = () => !s.Closed && s.Bot == null && orderManager.LocalClient.State != Session.ClientState.Ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,13 +377,15 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
name.OnLoseFocus = () => name.OnEnterKey();
|
name.OnLoseFocus = () => name.OnEnterKey();
|
||||||
|
|
||||||
var color = template.GetWidget<DropDownButtonWidget>("COLOR");
|
var color = template.GetWidget<DropDownButtonWidget>("COLOR");
|
||||||
color.OnMouseUp = _ => ShowColorDropDown(s, color);
|
color.IsDisabled = () => s.LockColor;
|
||||||
|
color.OnMouseDown = _ => { if (s.LockColor) return true; return ShowColorDropDown(color, c); };
|
||||||
|
|
||||||
var colorBlock = color.GetWidget<ColorBlockWidget>("COLORBLOCK");
|
var colorBlock = color.GetWidget<ColorBlockWidget>("COLORBLOCK");
|
||||||
colorBlock.GetColor = () => c.ColorRamp.GetColor(0);
|
colorBlock.GetColor = () => c.ColorRamp.GetColor(0);
|
||||||
|
|
||||||
var faction = template.GetWidget<DropDownButtonWidget>("FACTION");
|
var faction = template.GetWidget<DropDownButtonWidget>("FACTION");
|
||||||
faction.OnMouseDown = _ => ShowRaceDropDown(faction, s);
|
faction.IsDisabled = () => s.LockRace;
|
||||||
|
faction.OnMouseDown = _ => { if (s.LockRace) return true; return ShowRaceDropDown(faction, c); };
|
||||||
|
|
||||||
var factionname = faction.GetWidget<LabelWidget>("FACTIONNAME");
|
var factionname = faction.GetWidget<LabelWidget>("FACTIONNAME");
|
||||||
factionname.GetText = () => CountryNames[c.Country];
|
factionname.GetText = () => CountryNames[c.Country];
|
||||||
@@ -417,7 +394,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
factionflag.GetImageCollection = () => "flags";
|
factionflag.GetImageCollection = () => "flags";
|
||||||
|
|
||||||
var team = template.GetWidget<DropDownButtonWidget>("TEAM");
|
var team = template.GetWidget<DropDownButtonWidget>("TEAM");
|
||||||
team.OnMouseDown = _ => ShowTeamDropDown(team, s);
|
team.IsDisabled = () => s.LockTeam;
|
||||||
|
team.OnMouseDown = _ => { if (s.LockTeam) return true; return ShowTeamDropDown(team, c); };
|
||||||
team.GetText = () => (c.Team == 0) ? "-" : c.Team.ToString();
|
team.GetText = () => (c.Team == 0) ? "-" : c.Team.ToString();
|
||||||
|
|
||||||
var status = template.GetWidget<CheckboxWidget>("STATUS");
|
var status = template.GetWidget<CheckboxWidget>("STATUS");
|
||||||
@@ -426,14 +404,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
|
|
||||||
var spectator = template.GetWidget<LabelWidget>("SPECTATOR");
|
var spectator = template.GetWidget<LabelWidget>("SPECTATOR");
|
||||||
|
|
||||||
Session.Slot slot1 = slot;
|
Session.Slot ss = s;
|
||||||
color.IsVisible = () => !slot1.Spectator;
|
spectator.IsVisible = () => ss.Bot != null;
|
||||||
colorBlock.IsVisible = () => !slot1.Spectator;
|
|
||||||
faction.IsVisible = () => !slot1.Spectator;
|
|
||||||
factionname.IsVisible = () => !slot1.Spectator;
|
|
||||||
factionflag.IsVisible = () => !slot1.Spectator;
|
|
||||||
team.IsVisible = () => !slot1.Spectator;
|
|
||||||
spectator.IsVisible = () => slot1.Spectator || slot1.Bot != null;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -459,13 +431,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
|
|
||||||
var spectator = template.GetWidget<LabelWidget>("SPECTATOR");
|
var spectator = template.GetWidget<LabelWidget>("SPECTATOR");
|
||||||
|
|
||||||
Session.Slot slot1 = slot;
|
Session.Slot ss = s;
|
||||||
color.IsVisible = () => !slot1.Spectator;
|
spectator.IsVisible = () => ss.Bot != null;
|
||||||
faction.IsVisible = () => !slot1.Spectator;
|
|
||||||
factionname.IsVisible = () => !slot1.Spectator;
|
|
||||||
factionflag.IsVisible = () => !slot1.Spectator;
|
|
||||||
team.IsVisible = () => !slot1.Spectator;
|
|
||||||
spectator.IsVisible = () => slot1.Spectator || slot1.Bot != null;
|
|
||||||
|
|
||||||
var kickButton = template.GetWidget<ButtonWidget>("KICK");
|
var kickButton = template.GetWidget<ButtonWidget>("KICK");
|
||||||
kickButton.IsVisible = () => Game.IsHost && c.Index != orderManager.LocalClient.Index;
|
kickButton.IsVisible = () => Game.IsHost && c.Index != orderManager.LocalClient.Index;
|
||||||
@@ -476,10 +443,82 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template.Id = "SLOT_{0}".F(s.Index);
|
|
||||||
template.IsVisible = () => true;
|
template.IsVisible = () => true;
|
||||||
Players.AddChild(template);
|
Players.AddChild(template);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add spectators
|
||||||
|
foreach (var client in orderManager.LobbyInfo.Clients.Where(client => client.Slot == null))
|
||||||
|
{
|
||||||
|
Widget template;
|
||||||
|
// Editable spectator
|
||||||
|
if (client.Index == orderManager.LocalClient.Index && client.State != Session.ClientState.Ready)
|
||||||
|
{
|
||||||
|
template = LocalSpectatorTemplate.Clone();
|
||||||
|
var name = template.GetWidget<TextFieldWidget>("NAME");
|
||||||
|
name.Text = client.Name;
|
||||||
|
name.OnEnterKey = () =>
|
||||||
|
{
|
||||||
|
name.Text = name.Text.Trim();
|
||||||
|
if (name.Text.Length == 0)
|
||||||
|
name.Text = client.Name;
|
||||||
|
|
||||||
|
name.LoseFocus();
|
||||||
|
if (name.Text == client.Name)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
orderManager.IssueOrder(Order.Command("name " + name.Text));
|
||||||
|
Game.Settings.Player.Name = name.Text;
|
||||||
|
Game.Settings.Save();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
name.OnLoseFocus = () => name.OnEnterKey();
|
||||||
|
|
||||||
|
var color = template.GetWidget<DropDownButtonWidget>("COLOR");
|
||||||
|
color.OnMouseDown = _ => ShowColorDropDown(color, client);
|
||||||
|
|
||||||
|
var colorBlock = color.GetWidget<ColorBlockWidget>("COLORBLOCK");
|
||||||
|
colorBlock.GetColor = () => client.ColorRamp.GetColor(0);
|
||||||
|
|
||||||
|
var status = template.GetWidget<CheckboxWidget>("STATUS");
|
||||||
|
status.IsChecked = () => client.State == Session.ClientState.Ready;
|
||||||
|
status.OnClick += CycleReady;
|
||||||
|
}
|
||||||
|
// Non-editable spectator
|
||||||
|
else
|
||||||
|
{
|
||||||
|
template = RemoteSpectatorTemplate.Clone();
|
||||||
|
template.GetWidget<LabelWidget>("NAME").GetText = () => client.Name;
|
||||||
|
var color = template.GetWidget<ColorBlockWidget>("COLOR");
|
||||||
|
color.GetColor = () => client.ColorRamp.GetColor(0);
|
||||||
|
|
||||||
|
var status = template.GetWidget<CheckboxWidget>("STATUS");
|
||||||
|
status.IsChecked = () => client.State == Session.ClientState.Ready;
|
||||||
|
if (client.Index == orderManager.LocalClient.Index)
|
||||||
|
status.OnClick += CycleReady;
|
||||||
|
|
||||||
|
var kickButton = template.GetWidget<ButtonWidget>("KICK");
|
||||||
|
kickButton.IsVisible = () => Game.IsHost && client.Index != orderManager.LocalClient.Index;
|
||||||
|
kickButton.OnMouseUp = mi =>
|
||||||
|
{
|
||||||
|
orderManager.IssueOrder(Order.Command("kick " + client.Index));
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template.IsVisible = () => true;
|
||||||
|
Players.AddChild(template);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spectate button
|
||||||
|
if (orderManager.LocalClient.Slot != null && orderManager.LocalClient.State != Session.ClientState.Ready)
|
||||||
|
{
|
||||||
|
var spec = NewSpectatorTemplate.Clone();
|
||||||
|
var btn = spec.GetWidget<ButtonWidget>("SPECTATE");
|
||||||
|
btn.OnMouseUp = _ => { orderManager.IssueOrder(Order.Command("spectate")); return true; };
|
||||||
|
spec.IsVisible = () => true;
|
||||||
|
Players.AddChild(spec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpawnPointAvailable(int index) { return (index == 0) || orderManager.LobbyInfo.Clients.All(c => c.SpawnPoint != index); }
|
bool SpawnPointAvailable(int index) { return (index == 0) || orderManager.LobbyInfo.Clients.All(c => c.SpawnPoint != index); }
|
||||||
|
|||||||
@@ -113,15 +113,6 @@ Container@SERVER_LOBBY:
|
|||||||
Y:2
|
Y:2
|
||||||
Width:20
|
Width:20
|
||||||
Height:20
|
Height:20
|
||||||
Label@SPECTATOR:
|
|
||||||
Id:SPECTATOR
|
|
||||||
Text:Spectator
|
|
||||||
Width:278
|
|
||||||
Height:25
|
|
||||||
X:160
|
|
||||||
Y:0
|
|
||||||
Align:Center
|
|
||||||
Font:Bold
|
|
||||||
Container@TEMPLATE_REMOTE:
|
Container@TEMPLATE_REMOTE:
|
||||||
Id:TEMPLATE_REMOTE
|
Id:TEMPLATE_REMOTE
|
||||||
X:5
|
X:5
|
||||||
@@ -185,17 +176,112 @@ Container@SERVER_LOBBY:
|
|||||||
Y:2
|
Y:2
|
||||||
Width:20
|
Width:20
|
||||||
Height:20
|
Height:20
|
||||||
Label@SPECTATOR:
|
Container@TEMPLATE_EMPTY:
|
||||||
Id:SPECTATOR
|
Id:TEMPLATE_EMPTY
|
||||||
Text:Spectator
|
X:5
|
||||||
|
Y:0
|
||||||
|
Width:475
|
||||||
|
Height:25
|
||||||
|
Visible:false
|
||||||
|
Children:
|
||||||
|
DropDownButton@NAME_HOST:
|
||||||
|
Id:NAME_HOST
|
||||||
|
Text:Name
|
||||||
|
Width:150
|
||||||
|
Height:25
|
||||||
|
Font:Regular
|
||||||
|
Visible:false
|
||||||
|
Label@NAME:
|
||||||
|
Id:NAME
|
||||||
|
Text:Name
|
||||||
|
Width:145
|
||||||
|
Height:25
|
||||||
|
X:5
|
||||||
|
Y:0-1
|
||||||
|
Visible:false
|
||||||
|
Button@JOIN:
|
||||||
|
Id:JOIN
|
||||||
|
Text:Play in this slot
|
||||||
|
Font:Regular
|
||||||
|
Width:278
|
||||||
|
Height:25
|
||||||
|
X:160
|
||||||
|
Y:0
|
||||||
|
Container@TEMPLATE_BOT:
|
||||||
|
Id:TEMPLATE_BOT
|
||||||
|
X:5
|
||||||
|
Y:0
|
||||||
|
Width:475
|
||||||
|
Height:25
|
||||||
|
Visible:false
|
||||||
|
Children:
|
||||||
|
DropDownButton@NAME_HOST:
|
||||||
|
Id:NAME_HOST
|
||||||
|
Text:Name
|
||||||
|
Width:150
|
||||||
|
Height:25
|
||||||
|
Font:Regular
|
||||||
|
Visible:false
|
||||||
|
Label@NAME:
|
||||||
|
Id:NAME
|
||||||
|
Text:Name
|
||||||
|
Width:145
|
||||||
|
Height:25
|
||||||
|
X:5
|
||||||
|
Y:0-1
|
||||||
|
Visible:false
|
||||||
|
Label@BOT:
|
||||||
|
Id:BOT
|
||||||
|
Text:Bot
|
||||||
Width:278
|
Width:278
|
||||||
Height:25
|
Height:25
|
||||||
X:160
|
X:160
|
||||||
Y:0
|
Y:0
|
||||||
Align:Center
|
Align:Center
|
||||||
Font:Bold
|
Font:Bold
|
||||||
Container@TEMPLATE_EMPTY:
|
Container@TEMPLATE_LOCAL_SPECTATOR:
|
||||||
Id:TEMPLATE_EMPTY
|
Id:TEMPLATE_LOCAL_SPECTATOR
|
||||||
|
X:5
|
||||||
|
Y:0
|
||||||
|
Width:475
|
||||||
|
Height:25
|
||||||
|
Visible:false
|
||||||
|
Children:
|
||||||
|
TextField@NAME:
|
||||||
|
Id:NAME
|
||||||
|
Text:Name
|
||||||
|
Width:150
|
||||||
|
Height:25
|
||||||
|
MaxLength:16
|
||||||
|
DropDownButton@COLOR:
|
||||||
|
Id:COLOR
|
||||||
|
Width:80
|
||||||
|
Height:25
|
||||||
|
X:160
|
||||||
|
Font:Regular
|
||||||
|
Children:
|
||||||
|
ColorBlock@COLORBLOCK:
|
||||||
|
Id:COLORBLOCK
|
||||||
|
X:5
|
||||||
|
Y:6
|
||||||
|
Width:PARENT_RIGHT-35
|
||||||
|
Height:PARENT_BOTTOM-12
|
||||||
|
Label@SPECTATOR:
|
||||||
|
Text:Spectator
|
||||||
|
Width:198
|
||||||
|
Height:25
|
||||||
|
X:240
|
||||||
|
Y:0
|
||||||
|
Align:Center
|
||||||
|
Font:Bold
|
||||||
|
Checkbox@STATUS:
|
||||||
|
Id:STATUS
|
||||||
|
X:448
|
||||||
|
Y:2
|
||||||
|
Width:20
|
||||||
|
Height:20
|
||||||
|
Container@TEMPLATE_REMOTE_SPECTATOR:
|
||||||
|
Id:TEMPLATE_REMOTE_SPECTATOR
|
||||||
X:5
|
X:5
|
||||||
Y:0
|
Y:0
|
||||||
Width:475
|
Width:475
|
||||||
@@ -209,54 +295,50 @@ Container@SERVER_LOBBY:
|
|||||||
Height:25
|
Height:25
|
||||||
X:5
|
X:5
|
||||||
Y:0-1
|
Y:0-1
|
||||||
Button@JOIN:
|
Button@KICK:
|
||||||
Id:JOIN
|
Id:KICK
|
||||||
Text:Play in this slot
|
Text:X
|
||||||
Font:Regular
|
Width:25
|
||||||
Width:278
|
Height:23
|
||||||
|
X:125
|
||||||
|
Y:2
|
||||||
|
Font:Bold
|
||||||
|
ColorBlock@COLOR:
|
||||||
|
Id:COLOR
|
||||||
|
X:165
|
||||||
|
Y:6
|
||||||
|
Width:45
|
||||||
|
Height:13
|
||||||
|
Label@SPECTATOR:
|
||||||
|
Text:Spectator
|
||||||
|
Width:198
|
||||||
Height:25
|
Height:25
|
||||||
X:160
|
X:240
|
||||||
Y:0
|
|
||||||
Label@BOT:
|
|
||||||
Id:BOT
|
|
||||||
Text:Bot
|
|
||||||
Width:278
|
|
||||||
Height:25
|
|
||||||
X:160
|
|
||||||
Y:0
|
Y:0
|
||||||
Align:Center
|
Align:Center
|
||||||
Font:Bold
|
Font:Bold
|
||||||
Container@TEMPLATE_EMPTY_HOST:
|
Checkbox@STATUS:
|
||||||
Id:TEMPLATE_EMPTY_HOST
|
Id:STATUS
|
||||||
|
X:448
|
||||||
|
Y:2
|
||||||
|
Width:20
|
||||||
|
Height:20
|
||||||
|
Container@TEMPLATE_NEW_SPECTATOR:
|
||||||
|
Id:TEMPLATE_NEW_SPECTATOR
|
||||||
X:5
|
X:5
|
||||||
Y:0
|
Y:0
|
||||||
Width:400
|
Width:475
|
||||||
Height:25
|
Height:25
|
||||||
Visible:false
|
Visible:false
|
||||||
Children:
|
Children:
|
||||||
DropDownButton@NAME:
|
Button@SPECTATE:
|
||||||
Id:NAME
|
Id:SPECTATE
|
||||||
Text:Name
|
Text:Spectate
|
||||||
Width:150
|
|
||||||
Height:25
|
|
||||||
Font:Regular
|
|
||||||
Button@JOIN:
|
|
||||||
Id:JOIN
|
|
||||||
Text:Play in this slot
|
|
||||||
Font:Regular
|
Font:Regular
|
||||||
Width:278
|
Width:278
|
||||||
Height:25
|
Height:25
|
||||||
X:160
|
X:160
|
||||||
Y:0
|
Y:0
|
||||||
Label@BOT:
|
|
||||||
Id:BOT
|
|
||||||
Text:Bot
|
|
||||||
Width:278
|
|
||||||
Height:25
|
|
||||||
X:160
|
|
||||||
Y:0
|
|
||||||
Align:Center
|
|
||||||
Font:Bold
|
|
||||||
Container@LABEL_CONTAINER:
|
Container@LABEL_CONTAINER:
|
||||||
X:25
|
X:25
|
||||||
Y:5
|
Y:5
|
||||||
|
|||||||
@@ -241,6 +241,106 @@ Background@SERVER_LOBBY:
|
|||||||
Y:0
|
Y:0
|
||||||
Align:Center
|
Align:Center
|
||||||
Font:Bold
|
Font:Bold
|
||||||
|
Container@TEMPLATE_LOCAL_SPECTATOR:
|
||||||
|
Id:TEMPLATE_LOCAL_SPECTATOR
|
||||||
|
X:5
|
||||||
|
Y:0
|
||||||
|
Width:475
|
||||||
|
Height:25
|
||||||
|
Visible:false
|
||||||
|
Children:
|
||||||
|
TextField@NAME:
|
||||||
|
Id:NAME
|
||||||
|
Text:Name
|
||||||
|
Width:150
|
||||||
|
Height:25
|
||||||
|
MaxLength:16
|
||||||
|
DropDownButton@COLOR:
|
||||||
|
Id:COLOR
|
||||||
|
Width:80
|
||||||
|
Height:25
|
||||||
|
X:160
|
||||||
|
Font:Regular
|
||||||
|
Children:
|
||||||
|
ColorBlock@COLORBLOCK:
|
||||||
|
Id:COLORBLOCK
|
||||||
|
X:5
|
||||||
|
Y:6
|
||||||
|
Width:PARENT_RIGHT-35
|
||||||
|
Height:PARENT_BOTTOM-12
|
||||||
|
Label@SPECTATOR:
|
||||||
|
Text:Spectator
|
||||||
|
Width:198
|
||||||
|
Height:25
|
||||||
|
X:240
|
||||||
|
Y:0
|
||||||
|
Align:Center
|
||||||
|
Font:Bold
|
||||||
|
Checkbox@STATUS:
|
||||||
|
Id:STATUS
|
||||||
|
X:448
|
||||||
|
Y:2
|
||||||
|
Width:20
|
||||||
|
Height:20
|
||||||
|
Container@TEMPLATE_REMOTE_SPECTATOR:
|
||||||
|
Id:TEMPLATE_REMOTE_SPECTATOR
|
||||||
|
X:5
|
||||||
|
Y:0
|
||||||
|
Width:475
|
||||||
|
Height:25
|
||||||
|
Visible:false
|
||||||
|
Children:
|
||||||
|
Label@NAME:
|
||||||
|
Id:NAME
|
||||||
|
Text:Name
|
||||||
|
Width:145
|
||||||
|
Height:25
|
||||||
|
X:5
|
||||||
|
Y:0-1
|
||||||
|
Button@KICK:
|
||||||
|
Id:KICK
|
||||||
|
Text:X
|
||||||
|
Width:25
|
||||||
|
Height:23
|
||||||
|
X:125
|
||||||
|
Y:2
|
||||||
|
Font:Bold
|
||||||
|
ColorBlock@COLOR:
|
||||||
|
Id:COLOR
|
||||||
|
X:165
|
||||||
|
Y:6
|
||||||
|
Width:45
|
||||||
|
Height:13
|
||||||
|
Label@SPECTATOR:
|
||||||
|
Text:Spectator
|
||||||
|
Width:198
|
||||||
|
Height:25
|
||||||
|
X:240
|
||||||
|
Y:0
|
||||||
|
Align:Center
|
||||||
|
Font:Bold
|
||||||
|
Checkbox@STATUS:
|
||||||
|
Id:STATUS
|
||||||
|
X:448
|
||||||
|
Y:2
|
||||||
|
Width:20
|
||||||
|
Height:20
|
||||||
|
Container@TEMPLATE_NEW_SPECTATOR:
|
||||||
|
Id:TEMPLATE_NEW_SPECTATOR
|
||||||
|
X:5
|
||||||
|
Y:0
|
||||||
|
Width:475
|
||||||
|
Height:25
|
||||||
|
Visible:false
|
||||||
|
Children:
|
||||||
|
Button@SPECTATE:
|
||||||
|
Id:SPECTATE
|
||||||
|
Text:Spectate
|
||||||
|
Font:Regular
|
||||||
|
Width:278
|
||||||
|
Height:25
|
||||||
|
X:160
|
||||||
|
Y:0
|
||||||
Container@LABEL_CONTAINER:
|
Container@LABEL_CONTAINER:
|
||||||
X:25
|
X:25
|
||||||
Y:40
|
Y:40
|
||||||
|
|||||||
Reference in New Issue
Block a user