Core: Added basic support for Spectators
TODO: Someone modify the files for cnc (chrome / rules)
This commit is contained in:
@@ -56,7 +56,7 @@ namespace OpenRA.Network
|
||||
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 string MapPlayer; // playerReference to bind against.
|
||||
|
||||
public bool Spectator = false; // Spectating or not
|
||||
// todo: more stuff?
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace OpenRA
|
||||
PlayerName = client.Name;
|
||||
InternalName = pr.Name;
|
||||
Country = world.GetCountries()
|
||||
.FirstOrDefault(c => client != null && client.Country == c.Race)
|
||||
.FirstOrDefault(c => client != null && client.Country == c.Race )
|
||||
?? world.GetCountries().Random(world.SharedRandom);
|
||||
|
||||
ClientIndex = client.Index;
|
||||
|
||||
@@ -40,6 +40,9 @@ namespace OpenRA.Server
|
||||
|
||||
const int MasterPingInterval = 60 * 3; // 3 minutes. server has a 5 minute TTL for games, so give ourselves a bit
|
||||
// of leeway.
|
||||
|
||||
public static int MaxSpectators = 4; // How many spectators to allow // @todo Expose this as an option
|
||||
|
||||
static int lastPing = 0;
|
||||
static bool isInternetServer;
|
||||
static string masterServerUrl;
|
||||
@@ -135,6 +138,12 @@ namespace OpenRA.Server
|
||||
.Where(s => s != null)
|
||||
.Select((s, i) => { s.Index = i; return s; })
|
||||
.ToList();
|
||||
|
||||
// Generate slots for spectators
|
||||
for (int i = 0; i < MaxSpectators; i++)
|
||||
{
|
||||
lobbyInfo.Slots.Add(new Session.Slot { Spectator = true, Index = lobbyInfo.Slots.Count(), MapPlayer = null, Bot = null});
|
||||
}
|
||||
}
|
||||
|
||||
/* lobby rework todo:
|
||||
@@ -283,6 +292,8 @@ namespace OpenRA.Server
|
||||
|
||||
static void SyncClientToPlayerReference(Session.Client c, PlayerReference pr)
|
||||
{
|
||||
if (pr == null)
|
||||
return;
|
||||
if (pr.LockColor)
|
||||
{
|
||||
c.Color1 = pr.Color;
|
||||
@@ -358,6 +369,13 @@ namespace OpenRA.Server
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "spectator",
|
||||
s =>
|
||||
{
|
||||
// GetClient(conn).Slot = -1; /* observer */
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "team",
|
||||
s =>
|
||||
{
|
||||
@@ -411,7 +429,7 @@ namespace OpenRA.Server
|
||||
var cl = GetClient(conn);
|
||||
cl.Slot = slot;
|
||||
|
||||
SyncClientToPlayerReference(cl, Map.Players[slotData.MapPlayer]);
|
||||
SyncClientToPlayerReference(cl, slotData.MapPlayer != null ? Map.Players[slotData.MapPlayer] : null);
|
||||
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace OpenRA.Traits
|
||||
|
||||
void DrawUnitPath(Actor self)
|
||||
{
|
||||
if (!self.World.LocalPlayer.PlayerActor.Trait<DeveloperMode>().PathDebug) return;
|
||||
if (self.World.LocalPlayer == null ||!self.World.LocalPlayer.PlayerActor.Trait<DeveloperMode>().PathDebug) return;
|
||||
|
||||
var activity = self.GetCurrentActivity();
|
||||
var mobile = self.TraitOrDefault<IMove>();
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace OpenRA.Widgets.Delegates
|
||||
{
|
||||
public class LobbyDelegate : IWidgetDelegate
|
||||
{
|
||||
Widget Players, LocalPlayerTemplate, RemotePlayerTemplate, EmptySlotTemplate, EmptySlotTemplateHost;
|
||||
Widget Players, LocalPlayerTemplate, RemotePlayerTemplate, EmptySlotTemplate, EmptySlotTemplateHost, EmptySpectatorSlotTemplateHost;
|
||||
|
||||
Dictionary<string, string> CountryNames;
|
||||
string MapUid;
|
||||
@@ -44,6 +44,7 @@ namespace OpenRA.Widgets.Delegates
|
||||
RemotePlayerTemplate = Players.GetWidget("TEMPLATE_REMOTE");
|
||||
EmptySlotTemplate = Players.GetWidget("TEMPLATE_EMPTY");
|
||||
EmptySlotTemplateHost = Players.GetWidget("TEMPLATE_EMPTY_HOST");
|
||||
EmptySpectatorSlotTemplateHost = Players.GetWidget("TEMPLATE_EMPTY_SPECTATOR");
|
||||
|
||||
var mapPreview = lobby.GetWidget<MapPreviewWidget>("LOBBY_MAP_PREVIEW");
|
||||
mapPreview.Map = () => Map;
|
||||
@@ -71,6 +72,7 @@ namespace OpenRA.Widgets.Delegates
|
||||
};
|
||||
|
||||
CountryNames = Rules.Info["world"].Traits.WithInterface<OpenRA.Traits.CountryInfo>().ToDictionary(a => a.Race, a => a.Name);
|
||||
|
||||
CountryNames.Add("random", "Random");
|
||||
|
||||
var mapButton = lobby.GetWidget("CHANGEMAP_BUTTON");
|
||||
@@ -232,25 +234,48 @@ namespace OpenRA.Widgets.Delegates
|
||||
{
|
||||
if (Game.IsHost)
|
||||
{
|
||||
template = EmptySlotTemplateHost.Clone();
|
||||
var name = template.GetWidget<ButtonWidget>("NAME");
|
||||
name.GetText = () => s.Closed ? "Closed" : (s.Bot == null)? "Open" : "Bot: " + s.Bot;
|
||||
name.OnMouseUp = _ =>
|
||||
if (slot.Spectator)
|
||||
{
|
||||
if (s.Closed)
|
||||
template = EmptySlotTemplateHost.Clone();
|
||||
var btn = template.GetWidget<ButtonWidget>("JOIN");
|
||||
var name = template.GetWidget<ButtonWidget>("NAME");
|
||||
btn.GetText = () => "Spectate in this slot";
|
||||
name.GetText = () => s.Closed ? "Closed" : "Open";
|
||||
name.OnMouseUp = _ =>
|
||||
{
|
||||
s.Bot = null;
|
||||
orderManager.IssueOrder(Order.Command("slot_open " + s.Index));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s.Bot == null && Map.Players[s.MapPlayer].AllowBots)
|
||||
orderManager.IssueOrder(Order.Command("slot_bot {0} HackyAI".F(s.Index)));
|
||||
if (s.Closed)
|
||||
{
|
||||
orderManager.IssueOrder(Order.Command("slot_open " + s.Index));
|
||||
}
|
||||
else
|
||||
{
|
||||
orderManager.IssueOrder(Order.Command("slot_close " + s.Index));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
template = EmptySlotTemplateHost.Clone();
|
||||
var name = template.GetWidget<ButtonWidget>("NAME");
|
||||
name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : "Bot: " + s.Bot;
|
||||
name.OnMouseUp = _ =>
|
||||
{
|
||||
if (s.Closed)
|
||||
{
|
||||
s.Bot = null;
|
||||
orderManager.IssueOrder(Order.Command("slot_open " + s.Index));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s.Bot == null && Map.Players[s.MapPlayer].AllowBots)
|
||||
orderManager.IssueOrder(Order.Command("slot_bot {0} HackyAI".F(s.Index)));
|
||||
else
|
||||
orderManager.IssueOrder(Order.Command("slot_close " + s.Index));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -330,6 +355,14 @@ namespace OpenRA.Widgets.Delegates
|
||||
var status = template.GetWidget<CheckboxWidget>("STATUS");
|
||||
status.Checked = () => c.State == Session.ClientState.Ready;
|
||||
status.OnMouseDown = CycleReady;
|
||||
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace OpenRA
|
||||
|
||||
public void AddPlayer(Player p) { players[p.Index] = p; }
|
||||
|
||||
int localPlayerIndex;
|
||||
int localPlayerIndex = -999;
|
||||
public Player LocalPlayer
|
||||
{
|
||||
get { return players.ContainsKey(localPlayerIndex) ? players[localPlayerIndex] : null; }
|
||||
|
||||
@@ -103,6 +103,7 @@ namespace OpenRA
|
||||
|
||||
public static bool IsVisible(this Actor a, Player byPlayer) /* must never be relied on in synced code! */
|
||||
{
|
||||
if (byPlayer == null) return true; // Observer
|
||||
if (a.World.LocalPlayer != null && a.World.LocalPlayer.Shroud.Disabled)
|
||||
return true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user