Add plumbing for trait-defined lobby options.
This commit is contained in:
@@ -173,6 +173,17 @@ namespace OpenRA.Network
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class LobbyOptionState
|
||||||
|
{
|
||||||
|
public bool Locked;
|
||||||
|
public string Value;
|
||||||
|
public string PreferredValue;
|
||||||
|
|
||||||
|
public LobbyOptionState() { }
|
||||||
|
|
||||||
|
public bool Enabled { get { return Value == "True"; } }
|
||||||
|
}
|
||||||
|
|
||||||
public class Global
|
public class Global
|
||||||
{
|
{
|
||||||
public string ServerName;
|
public string ServerName;
|
||||||
@@ -198,14 +209,45 @@ namespace OpenRA.Network
|
|||||||
public string GameUid;
|
public string GameUid;
|
||||||
public bool DisableSingleplayer;
|
public bool DisableSingleplayer;
|
||||||
|
|
||||||
|
[FieldLoader.Ignore]
|
||||||
|
public Dictionary<string, LobbyOptionState> LobbyOptions = new Dictionary<string, LobbyOptionState>();
|
||||||
|
|
||||||
public static Global Deserialize(MiniYaml data)
|
public static Global Deserialize(MiniYaml data)
|
||||||
{
|
{
|
||||||
return FieldLoader.Load<Global>(data);
|
var gs = FieldLoader.Load<Global>(data);
|
||||||
|
|
||||||
|
var optionsNode = data.Nodes.FirstOrDefault(n => n.Key == "Options");
|
||||||
|
if (optionsNode != null)
|
||||||
|
foreach (var n in optionsNode.Value.Nodes)
|
||||||
|
gs.LobbyOptions[n.Key] = FieldLoader.Load<LobbyOptionState>(n.Value);
|
||||||
|
|
||||||
|
return gs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MiniYamlNode Serialize()
|
public MiniYamlNode Serialize()
|
||||||
{
|
{
|
||||||
return new MiniYamlNode("GlobalSettings", FieldSaver.Save(this));
|
var data = new MiniYamlNode("GlobalSettings", FieldSaver.Save(this));
|
||||||
|
var options = LobbyOptions.Select(kv => new MiniYamlNode(kv.Key, FieldSaver.Save(kv.Value))).ToList();
|
||||||
|
data.Value.Nodes.Add(new MiniYamlNode("Options", new MiniYaml(null, options)));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OptionOrDefault(string id, bool def)
|
||||||
|
{
|
||||||
|
LobbyOptionState option;
|
||||||
|
if (LobbyOptions.TryGetValue(id, out option))
|
||||||
|
return option.Enabled;
|
||||||
|
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string OptionOrDefault(string id, string def)
|
||||||
|
{
|
||||||
|
LobbyOptionState option;
|
||||||
|
if (LobbyOptions.TryGetValue(id, out option))
|
||||||
|
return option.Value;
|
||||||
|
|
||||||
|
return def;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -412,4 +412,50 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
public interface IRulesetLoaded<TInfo> { void RulesetLoaded(Ruleset rules, TInfo info); }
|
public interface IRulesetLoaded<TInfo> { void RulesetLoaded(Ruleset rules, TInfo info); }
|
||||||
public interface IRulesetLoaded : IRulesetLoaded<ActorInfo>, ITraitInfoInterface { }
|
public interface IRulesetLoaded : IRulesetLoaded<ActorInfo>, ITraitInfoInterface { }
|
||||||
|
|
||||||
|
[RequireExplicitImplementation]
|
||||||
|
public interface ILobbyOptions : ITraitInfoInterface
|
||||||
|
{
|
||||||
|
IEnumerable<LobbyOption> LobbyOptions(Ruleset rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LobbyOption
|
||||||
|
{
|
||||||
|
public readonly string Id;
|
||||||
|
public readonly string Name;
|
||||||
|
public readonly IReadOnlyDictionary<string, string> Values;
|
||||||
|
public readonly string DefaultValue;
|
||||||
|
public readonly bool Locked;
|
||||||
|
|
||||||
|
public LobbyOption(string id, string name, IReadOnlyDictionary<string, string> values, string defaultValue, bool locked)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Name = name;
|
||||||
|
Values = values;
|
||||||
|
DefaultValue = defaultValue;
|
||||||
|
Locked = locked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string ValueChangedMessage(string playerName, string newValue)
|
||||||
|
{
|
||||||
|
return playerName + " changed " + Name + " to " + Values[newValue] + ".";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LobbyBooleanOption : LobbyOption
|
||||||
|
{
|
||||||
|
static readonly Dictionary<string, string> BoolValues = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{ true.ToString(), "enabled" },
|
||||||
|
{ false.ToString(), "disabled" }
|
||||||
|
};
|
||||||
|
|
||||||
|
public LobbyBooleanOption(string id, string name, bool defaultValue, bool locked)
|
||||||
|
: base(id, name, new ReadOnlyDictionary<string, string>(BoolValues), defaultValue.ToString(), locked) { }
|
||||||
|
|
||||||
|
public override string ValueChangedMessage(string playerName, string newValue)
|
||||||
|
{
|
||||||
|
return playerName + " " + BoolValues[newValue] + " " + Name + ".";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -424,6 +424,47 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{ "option",
|
||||||
|
s =>
|
||||||
|
{
|
||||||
|
if (!client.IsAdmin)
|
||||||
|
{
|
||||||
|
server.SendOrderTo(conn, "Message", "Only the host can change the configuration.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = server.Map.Rules.Actors["player"].TraitInfos<ILobbyOptions>()
|
||||||
|
.Concat(server.Map.Rules.Actors["world"].TraitInfos<ILobbyOptions>())
|
||||||
|
.SelectMany(t => t.LobbyOptions(server.Map.Rules))
|
||||||
|
.ToDictionary(o => o.Id, o => o);
|
||||||
|
|
||||||
|
var split = s.Split(' ');
|
||||||
|
LobbyOption option;
|
||||||
|
if (split.Length < 2 || !options.TryGetValue(split[0], out option) ||
|
||||||
|
!option.Values.ContainsKey(split[1]))
|
||||||
|
{
|
||||||
|
server.SendOrderTo(conn, "Message", "Invalid configuration command.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option.Locked)
|
||||||
|
{
|
||||||
|
server.SendOrderTo(conn, "Message", "{0} cannot be changed.".F(option.Name));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var oo = server.LobbyInfo.GlobalSettings.LobbyOptions[option.Id];
|
||||||
|
if (oo.Value == split[1])
|
||||||
|
return true;
|
||||||
|
|
||||||
|
oo.Value = oo.PreferredValue = split[1];
|
||||||
|
|
||||||
|
server.SyncLobbyGlobalSettings();
|
||||||
|
server.SendMessage(option.ValueChangedMessage(client.Name, split[1]));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
{ "allowcheats",
|
{ "allowcheats",
|
||||||
s =>
|
s =>
|
||||||
{
|
{
|
||||||
@@ -1067,6 +1108,37 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
|
|
||||||
public static void LoadMapSettings(Session.Global gs, Ruleset rules)
|
public static void LoadMapSettings(Session.Global gs, Ruleset rules)
|
||||||
{
|
{
|
||||||
|
var options = rules.Actors["player"].TraitInfos<ILobbyOptions>()
|
||||||
|
.Concat(rules.Actors["world"].TraitInfos<ILobbyOptions>())
|
||||||
|
.SelectMany(t => t.LobbyOptions(rules));
|
||||||
|
|
||||||
|
foreach (var o in options)
|
||||||
|
{
|
||||||
|
var value = o.DefaultValue;
|
||||||
|
var preferredValue = o.DefaultValue;
|
||||||
|
Session.LobbyOptionState state;
|
||||||
|
if (gs.LobbyOptions.TryGetValue(o.Id, out state))
|
||||||
|
{
|
||||||
|
// Propagate old state on map change
|
||||||
|
if (!o.Locked)
|
||||||
|
{
|
||||||
|
if (o.Values.Keys.Contains(state.PreferredValue))
|
||||||
|
value = state.PreferredValue;
|
||||||
|
else if (o.Values.Keys.Contains(state.Value))
|
||||||
|
value = state.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
preferredValue = state.PreferredValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
state = new Session.LobbyOptionState();
|
||||||
|
|
||||||
|
state.Locked = o.Locked;
|
||||||
|
state.Value = value;
|
||||||
|
state.PreferredValue = preferredValue;
|
||||||
|
gs.LobbyOptions[o.Id] = state;
|
||||||
|
}
|
||||||
|
|
||||||
var devMode = rules.Actors["player"].TraitInfo<DeveloperModeInfo>();
|
var devMode = rules.Actors["player"].TraitInfo<DeveloperModeInfo>();
|
||||||
gs.AllowCheats = devMode.Enabled;
|
gs.AllowCheats = devMode.Enabled;
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using System.Linq;
|
|||||||
using OpenRA.Mods.Common.Traits;
|
using OpenRA.Mods.Common.Traits;
|
||||||
using OpenRA.Network;
|
using OpenRA.Network;
|
||||||
using OpenRA.Server;
|
using OpenRA.Server;
|
||||||
|
using OpenRA.Traits;
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.Server
|
namespace OpenRA.Mods.Common.Server
|
||||||
{
|
{
|
||||||
@@ -26,6 +27,18 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
var defaults = new Session.Global();
|
var defaults = new Session.Global();
|
||||||
LobbyCommands.LoadMapSettings(defaults, server.Map.Rules);
|
LobbyCommands.LoadMapSettings(defaults, server.Map.Rules);
|
||||||
|
|
||||||
|
var options = server.Map.Rules.Actors["player"].TraitInfos<ILobbyOptions>()
|
||||||
|
.Concat(server.Map.Rules.Actors["world"].TraitInfos<ILobbyOptions>())
|
||||||
|
.SelectMany(t => t.LobbyOptions(server.Map.Rules))
|
||||||
|
.ToDictionary(o => o.Id, o => o);
|
||||||
|
|
||||||
|
foreach (var kv in server.LobbyInfo.GlobalSettings.LobbyOptions)
|
||||||
|
{
|
||||||
|
Session.LobbyOptionState def;
|
||||||
|
if (!defaults.LobbyOptions.TryGetValue(kv.Key, out def) || kv.Value.Value != def.Value)
|
||||||
|
server.SendOrderTo(conn, "Message", options[kv.Key].Name + ": " + kv.Value.Value);
|
||||||
|
}
|
||||||
|
|
||||||
if (server.LobbyInfo.GlobalSettings.AllowCheats != defaults.AllowCheats)
|
if (server.LobbyInfo.GlobalSettings.AllowCheats != defaults.AllowCheats)
|
||||||
server.SendOrderTo(conn, "Message", "Allow Cheats: {0}".F(server.LobbyInfo.GlobalSettings.AllowCheats));
|
server.SendOrderTo(conn, "Message", "Allow Cheats: {0}".F(server.LobbyInfo.GlobalSettings.AllowCheats));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user