Let servers query map details from the resource centre.

This commit is contained in:
Paul Chote
2016-03-28 13:12:44 +01:00
parent 65f7d46025
commit 4ec1369553
3 changed files with 93 additions and 62 deletions

View File

@@ -112,7 +112,7 @@ namespace OpenRA
} }
} }
public void QueryRemoteMapDetails(IEnumerable<string> uids, Action<MapPreview> mapDetailsReceived = null) public void QueryRemoteMapDetails(IEnumerable<string> uids, Action<MapPreview> mapDetailsReceived = null, Action queryFailed = null)
{ {
var maps = uids.Distinct() var maps = uids.Distinct()
.Select(uid => previews[uid]) .Select(uid => previews[uid])
@@ -136,6 +136,9 @@ namespace OpenRA
foreach (var p in maps.Values) foreach (var p in maps.Values)
p.UpdateRemoteSearch(MapStatus.Unavailable, null); p.UpdateRemoteSearch(MapStatus.Unavailable, null);
if (queryFailed != null)
queryFailed();
return; return;
} }
@@ -149,6 +152,8 @@ namespace OpenRA
catch catch
{ {
Log.Write("debug", "Can't parse remote map search data:\n{0}", data); Log.Write("debug", "Can't parse remote map search data:\n{0}", data);
if (queryFailed != null)
queryFailed();
} }
}; };

View File

@@ -74,6 +74,9 @@ namespace OpenRA
[Desc("Disallow games where only one player plays with bots.")] [Desc("Disallow games where only one player plays with bots.")]
public bool DisableSinglePlayer = false; public bool DisableSinglePlayer = false;
[Desc("Query map information from the Resource Center if they are not available locally.")]
public bool QueryMapRepository = true;
public string TimestampFormat = "s"; public string TimestampFormat = "s";
public ServerSettings Clone() public ServerSettings Clone()

View File

@@ -13,6 +13,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Threading;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits; using OpenRA.Mods.Common.Traits;
using OpenRA.Network; using OpenRA.Network;
@@ -338,64 +339,87 @@ namespace OpenRA.Mods.Common.Server
return true; return true;
} }
if (server.ModData.MapCache[s].Status != MapStatus.Available) var lastMap = server.LobbyInfo.GlobalSettings.Map;
Action<MapPreview> selectMap = map =>
{ {
server.SendOrderTo(conn, "Message", "Map was not found on server."); // Make sure the map hasn't changed in the meantime
return true; if (server.LobbyInfo.GlobalSettings.Map != lastMap)
} return;
server.LobbyInfo.GlobalSettings.Map = s; server.LobbyInfo.GlobalSettings.Map = map.Uid;
var oldSlots = server.LobbyInfo.Slots.Keys.ToArray(); var oldSlots = server.LobbyInfo.Slots.Keys.ToArray();
LoadMap(server); server.Map = server.ModData.MapCache[server.LobbyInfo.GlobalSettings.Map];
// Reset client states server.LobbyInfo.Slots = server.Map.Players.Players
foreach (var c in server.LobbyInfo.Clients) .Select(p => MakeSlotFromPlayerReference(p.Value))
c.State = Session.ClientState.Invalid; .Where(ss => ss != null)
.ToDictionary(ss => ss.PlayerReference, ss => ss);
// Reassign players into new slots based on their old slots: LoadMapSettings(server.LobbyInfo.GlobalSettings, server.Map.Rules);
// - Observers remain as observers
// - Players who now lack a slot are made observers
// - Bots who now lack a slot are dropped
// - Bots who are not defined in the map rules are dropped
var botNames = server.Map.Rules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Name);
var slots = server.LobbyInfo.Slots.Keys.ToArray();
var i = 0;
foreach (var os in oldSlots)
{
var c = server.LobbyInfo.ClientInSlot(os);
if (c == null)
continue;
c.SpawnPoint = 0; // Reset client states
c.Slot = i < slots.Length ? slots[i++] : null; foreach (var c in server.LobbyInfo.Clients)
if (c.Slot != null) c.State = Session.ClientState.Invalid;
// Reassign players into new slots based on their old slots:
// - Observers remain as observers
// - Players who now lack a slot are made observers
// - Bots who now lack a slot are dropped
// - Bots who are not defined in the map rules are dropped
var botNames = server.Map.Rules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Name);
var slots = server.LobbyInfo.Slots.Keys.ToArray();
var i = 0;
foreach (var os in oldSlots)
{ {
// Remove Bot from slot if slot forbids bots var c = server.LobbyInfo.ClientInSlot(os);
if (c.Bot != null && (!server.Map.Players.Players[c.Slot].AllowBots || !botNames.Contains(c.Bot))) if (c == null)
continue;
c.SpawnPoint = 0;
c.Slot = i < slots.Length ? slots[i++] : null;
if (c.Slot != null)
{
// Remove Bot from slot if slot forbids bots
if (c.Bot != null && (!server.Map.Players.Players[c.Slot].AllowBots || !botNames.Contains(c.Bot)))
server.LobbyInfo.Clients.Remove(c);
S.SyncClientToPlayerReference(c, server.Map.Players.Players[c.Slot]);
}
else if (c.Bot != null)
server.LobbyInfo.Clients.Remove(c); server.LobbyInfo.Clients.Remove(c);
S.SyncClientToPlayerReference(c, server.Map.Players.Players[c.Slot]);
} }
else if (c.Bot != null)
server.LobbyInfo.Clients.Remove(c); // Validate if color is allowed and get an alternative it isn't
foreach (var c in server.LobbyInfo.Clients)
if (c.Slot == null || (c.Slot != null && !server.LobbyInfo.Slots[c.Slot].LockColor))
c.Color = c.PreferredColor = SanitizePlayerColor(server, c.Color, c.Index, conn);
server.SyncLobbyInfo();
server.SendMessage("{0} changed the map to {1}.".F(client.Name, server.Map.Title));
if (server.Map.Rules.Actors != server.ModData.DefaultRules.Actors)
server.SendMessage("This map contains custom rules. Game experience may change.");
if (server.Settings.DisableSinglePlayer)
server.SendMessage("Singleplayer games have been disabled on this server.");
else if (server.Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots))
server.SendMessage("Bots have been disabled on this map.");
};
Action queryFailed = () =>
server.SendOrderTo(conn, "Message", "Map was not found on server.");
var m = server.ModData.MapCache[s];
if (m.Status == MapStatus.Available || m.Status == MapStatus.DownloadAvailable)
selectMap(m);
else if (server.Settings.QueryMapRepository)
{
server.SendOrderTo(conn, "Message", "Searching for map on the Resource Center...");
server.ModData.MapCache.QueryRemoteMapDetails(new[] { s }, selectMap, queryFailed);
} }
else
// Validate if color is allowed and get an alternative it isn't queryFailed();
foreach (var c in server.LobbyInfo.Clients)
if (c.Slot == null || (c.Slot != null && !server.LobbyInfo.Slots[c.Slot].LockColor))
c.Color = c.PreferredColor = SanitizePlayerColor(server, c.Color, c.Index, conn);
server.SyncLobbyInfo();
server.SendMessage("{0} changed the map to {1}.".F(client.Name, server.Map.Title));
if (server.Map.Rules.Actors != server.ModData.DefaultRules.Actors)
server.SendMessage("This map contains custom rules. Game experience may change.");
if (server.Settings.DisableSinglePlayer)
server.SendMessage("Singleplayer games have been disabled on this server.");
else if (server.Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots))
server.SendMessage("Bots have been disabled on this map.");
return true; return true;
} }
@@ -996,7 +1020,18 @@ namespace OpenRA.Mods.Common.Server
public void ServerStarted(S server) public void ServerStarted(S server)
{ {
LoadMap(server); // Remote maps are not supported for the initial map
var uid = server.LobbyInfo.GlobalSettings.Map;
server.Map = server.ModData.MapCache[uid];
if (server.Map.Status != MapStatus.Available)
throw new Exception("Map {0} not found".F(uid));
server.LobbyInfo.Slots = server.Map.Players.Players
.Select(p => MakeSlotFromPlayerReference(p.Value))
.Where(s => s != null)
.ToDictionary(s => s.PlayerReference, s => s);
LoadMapSettings(server.LobbyInfo.GlobalSettings, server.Map.Rules);
} }
static Session.Slot MakeSlotFromPlayerReference(PlayerReference pr) static Session.Slot MakeSlotFromPlayerReference(PlayerReference pr)
@@ -1042,18 +1077,6 @@ namespace OpenRA.Mods.Common.Server
gs.Difficulty = mapOptions.Difficulty ?? mapOptions.Difficulties.FirstOrDefault(); gs.Difficulty = mapOptions.Difficulty ?? mapOptions.Difficulties.FirstOrDefault();
} }
static void LoadMap(S server)
{
server.Map = server.ModData.MapCache[server.LobbyInfo.GlobalSettings.Map];
server.LobbyInfo.Slots = server.Map.Players.Players
.Select(p => MakeSlotFromPlayerReference(p.Value))
.Where(s => s != null)
.ToDictionary(s => s.PlayerReference, s => s);
LoadMapSettings(server.LobbyInfo.GlobalSettings, server.Map.Rules);
}
static HSLColor SanitizePlayerColor(S server, HSLColor askedColor, int playerIndex, Connection connectionToEcho = null) static HSLColor SanitizePlayerColor(S server, HSLColor askedColor, int playerIndex, Connection connectionToEcho = null)
{ {
var validator = server.ModData.Manifest.Get<ColorValidator>(); var validator = server.ModData.Manifest.Get<ColorValidator>();