Support map-defined AI in the lobby.

This commit is contained in:
Paul Chote
2016-03-12 21:59:04 +00:00
parent ab6a9597bb
commit d40bff3fd9
4 changed files with 25 additions and 19 deletions

View File

@@ -210,6 +210,9 @@ namespace OpenRA
Status = MapStatus.Unavailable; Status = MapStatus.Unavailable;
} }
// Note: multiple threads may try to access the value at the same time
// We rely on the thread-safety guarantees given by Lazy<T> to prevent race conitions.
// If you're thinking about replacing this, then you must be careful to keep this safe.
rules = Exts.Lazy(() => rules = Exts.Lazy(() =>
{ {
try try

View File

@@ -249,8 +249,6 @@ namespace OpenRA.Widgets
return trimmed; return trimmed;
} }
public static Action Once(Action a) { return () => { if (a != null) { a(); a = null; } }; }
public static string ChooseInitialMap(string initialUid) public static string ChooseInitialMap(string initialUid)
{ {
if (string.IsNullOrEmpty(initialUid) || Game.ModData.MapCache[initialUid].Status != MapStatus.Available) if (string.IsNullOrEmpty(initialUid) || Game.ModData.MapCache[initialUid].Status != MapStatus.Available)

View File

@@ -65,6 +65,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
readonly LabelWidget chatLabel; readonly LabelWidget chatLabel;
bool teamChat; bool teamChat;
bool addBotOnMapLoad;
int lobbyChatUnreadMessages; int lobbyChatUnreadMessages;
int globalChatLastReadMessages; int globalChatLastReadMessages;
int globalChatUnreadMessages; int globalChatUnreadMessages;
@@ -201,9 +203,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
(orderManager.LobbyInfo.Slots.Values.All(s => !s.AllowBots) && (orderManager.LobbyInfo.Slots.Values.All(s => !s.AllowBots) &&
orderManager.LobbyInfo.Slots.Count(s => !s.Value.LockTeam && orderManager.LobbyInfo.ClientInSlot(s.Key) != null) == 0); orderManager.LobbyInfo.Slots.Count(s => !s.Value.LockTeam && orderManager.LobbyInfo.ClientInSlot(s.Key) != null) == 0);
var botNames = modRules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Name);
slotsButton.OnMouseDown = _ => slotsButton.OnMouseDown = _ =>
{ {
var botNames = Map.Rules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Name);
var options = new Dictionary<string, IEnumerable<DropDownOption>>(); var options = new Dictionary<string, IEnumerable<DropDownOption>>();
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin); var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
@@ -711,16 +713,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
// Add a bot on the first lobbyinfo update // Add a bot on the first lobbyinfo update
if (skirmishMode) if (skirmishMode)
{ addBotOnMapLoad = true;
Game.LobbyInfoChanged += WidgetUtils.Once(() =>
{
var slot = orderManager.LobbyInfo.FirstEmptyBotSlot();
var bot = modRules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Name).FirstOrDefault();
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
if (slot != null && bot != null)
orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot, botController.Index, bot)));
});
}
} }
public override void Tick() public override void Tick()
@@ -796,6 +789,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var currentMap = Map; var currentMap = Map;
new Task(() => new Task(() =>
{ {
// Force map rules to be loaded on this background thread
var unused = currentMap.Rules; var unused = currentMap.Rules;
Game.RunAfterTick(() => Game.RunAfterTick(() =>
{ {
@@ -806,6 +800,17 @@ namespace OpenRA.Mods.Common.Widgets.Logic
// Tell the server that we have the map // Tell the server that we have the map
if (!currentMap.InvalidCustomRules) if (!currentMap.InvalidCustomRules)
orderManager.IssueOrder(Order.Command("state {0}".F(Session.ClientState.NotReady))); orderManager.IssueOrder(Order.Command("state {0}".F(Session.ClientState.NotReady)));
if (addBotOnMapLoad)
{
var slot = orderManager.LobbyInfo.FirstEmptyBotSlot();
var bot = currentMap.Rules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Name).FirstOrDefault();
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
if (slot != null && bot != null)
orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot, botController.Index, bot)));
addBotOnMapLoad = false;
}
}); });
}).Start(); }).Start();
} }
@@ -837,7 +842,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
template = emptySlotTemplate.Clone(); template = emptySlotTemplate.Clone();
if (Game.IsHost) if (Game.IsHost)
LobbyUtils.SetupEditableSlotWidget(template, slot, client, orderManager, modRules); LobbyUtils.SetupEditableSlotWidget(this, template, slot, client, orderManager);
else else
LobbyUtils.SetupSlotWidget(template, slot, client); LobbyUtils.SetupSlotWidget(template, slot, client);
@@ -856,7 +861,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
LobbyUtils.SetupClientWidget(template, client, orderManager, client.Bot == null); LobbyUtils.SetupClientWidget(template, client, orderManager, client.Bot == null);
if (client.Bot != null) if (client.Bot != null)
LobbyUtils.SetupEditableSlotWidget(template, slot, client, orderManager, modRules); LobbyUtils.SetupEditableSlotWidget(this, template, slot, client, orderManager);
else else
LobbyUtils.SetupEditableNameWidget(template, slot, client, orderManager); LobbyUtils.SetupEditableNameWidget(template, slot, client, orderManager);

View File

@@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
} }
} }
public static void ShowSlotDropDown(Ruleset rules, DropDownButtonWidget dropdown, Session.Slot slot, public static void ShowSlotDropDown(LobbyLogic logic, DropDownButtonWidget dropdown, Session.Slot slot,
Session.Client client, OrderManager orderManager) Session.Client client, OrderManager orderManager)
{ {
var options = new Dictionary<string, IEnumerable<SlotDropDownOption>>() { { "Slot", new List<SlotDropDownOption>() var options = new Dictionary<string, IEnumerable<SlotDropDownOption>>() { { "Slot", new List<SlotDropDownOption>()
@@ -50,7 +50,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var bots = new List<SlotDropDownOption>(); var bots = new List<SlotDropDownOption>();
if (slot.AllowBots) if (slot.AllowBots)
{ {
foreach (var b in rules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Name)) foreach (var b in logic.Map.Rules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Name))
{ {
var bot = b; var bot = b;
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin); var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
@@ -303,13 +303,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
name.GetText = () => label; name.GetText = () => label;
} }
public static void SetupEditableSlotWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager, Ruleset rules) public static void SetupEditableSlotWidget(LobbyLogic logic, Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager)
{ {
var slot = parent.Get<DropDownButtonWidget>("SLOT_OPTIONS"); var slot = parent.Get<DropDownButtonWidget>("SLOT_OPTIONS");
slot.IsVisible = () => true; slot.IsVisible = () => true;
slot.IsDisabled = () => orderManager.LocalClient.IsReady; slot.IsDisabled = () => orderManager.LocalClient.IsReady;
slot.GetText = () => c != null ? c.Name : s.Closed ? "Closed" : "Open"; slot.GetText = () => c != null ? c.Name : s.Closed ? "Closed" : "Open";
slot.OnMouseDown = _ => ShowSlotDropDown(rules, slot, s, c, orderManager); slot.OnMouseDown = _ => ShowSlotDropDown(logic, slot, s, c, orderManager);
// Ensure Name selector (if present) is hidden // Ensure Name selector (if present) is hidden
var name = parent.GetOrNull("NAME"); var name = parent.GetOrNull("NAME");