Merge pull request #11082 from pchote/custom-rule-detection
Fix and improve lobby custom rules warning.
This commit is contained in:
@@ -200,5 +200,55 @@ namespace OpenRA
|
||||
|
||||
return ruleset;
|
||||
}
|
||||
|
||||
static bool AnyCustomYaml(MiniYaml yaml)
|
||||
{
|
||||
return yaml != null && (yaml.Value != null || yaml.Nodes.Any());
|
||||
}
|
||||
|
||||
static bool AnyFlaggedTraits(ModData modData, List<MiniYamlNode> actors)
|
||||
{
|
||||
foreach (var actorNode in actors)
|
||||
{
|
||||
foreach (var traitNode in actorNode.Value.Nodes)
|
||||
{
|
||||
try
|
||||
{
|
||||
var traitName = traitNode.Key.Split('@')[0];
|
||||
var traitType = modData.ObjectCreator.FindType(traitName + "Info");
|
||||
if (traitType.GetInterface("ILobbyCustomRulesIgnore") == null)
|
||||
return true;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool DefinesUnsafeCustomRules(ModData modData, IReadOnlyFileSystem fileSystem,
|
||||
MiniYaml mapRules, MiniYaml mapWeapons, MiniYaml mapVoices, MiniYaml mapNotifications, MiniYaml mapSequences)
|
||||
{
|
||||
// Maps that define any weapon, voice, notification, or sequence overrides are always flagged
|
||||
if (AnyCustomYaml(mapWeapons) || AnyCustomYaml(mapVoices) || AnyCustomYaml(mapNotifications) || AnyCustomYaml(mapSequences))
|
||||
return true;
|
||||
|
||||
// Any trait overrides that aren't explicitly whitelisted are flagged
|
||||
if (mapRules != null)
|
||||
{
|
||||
if (AnyFlaggedTraits(modData, mapRules.Nodes))
|
||||
return true;
|
||||
|
||||
if (mapRules.Value != null)
|
||||
{
|
||||
var mapFiles = FieldLoader.GetValue<string[]>("value", mapRules.Value);
|
||||
foreach (var f in mapFiles)
|
||||
if (AnyFlaggedTraits(modData, MiniYaml.FromStream(fileSystem.Open(f))))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
@@ -80,12 +81,14 @@ namespace OpenRA
|
||||
Lazy<Ruleset> rules;
|
||||
public Ruleset Rules { get { return rules != null ? rules.Value : null; } }
|
||||
public bool InvalidCustomRules { get; private set; }
|
||||
public bool DefinesUnsafeCustomRules { get; private set; }
|
||||
public bool RulesLoaded { get; private set; }
|
||||
|
||||
public void SetRulesetGenerator(ModData modData, Func<Ruleset> generator)
|
||||
public void SetRulesetGenerator(ModData modData, Func<Pair<Ruleset, bool>> generator)
|
||||
{
|
||||
InvalidCustomRules = false;
|
||||
RulesLoaded = false;
|
||||
DefinesUnsafeCustomRules = false;
|
||||
|
||||
// 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.
|
||||
@@ -97,7 +100,9 @@ namespace OpenRA
|
||||
|
||||
try
|
||||
{
|
||||
return generator();
|
||||
var ret = generator();
|
||||
DefinesUnsafeCustomRules = ret.Second;
|
||||
return ret.First;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -146,6 +151,15 @@ namespace OpenRA
|
||||
public Ruleset Rules { get { return innerData.Rules; } }
|
||||
public bool InvalidCustomRules { get { return innerData.InvalidCustomRules; } }
|
||||
public bool RulesLoaded { get { return innerData.RulesLoaded; } }
|
||||
public bool DefinesUnsafeCustomRules
|
||||
{
|
||||
get
|
||||
{
|
||||
// Force lazy rules to be evaluated
|
||||
var force = innerData.Rules;
|
||||
return innerData.DefinesUnsafeCustomRules;
|
||||
}
|
||||
}
|
||||
|
||||
Download download;
|
||||
public long DownloadBytes { get; private set; }
|
||||
@@ -297,8 +311,11 @@ namespace OpenRA
|
||||
var musicDefinitions = LoadRuleSection(yaml, "Music");
|
||||
var notificationDefinitions = LoadRuleSection(yaml, "Notifications");
|
||||
var sequenceDefinitions = LoadRuleSection(yaml, "Sequences");
|
||||
return Ruleset.Load(modData, this, TileSet, ruleDefinitions, weaponDefinitions,
|
||||
var rules = Ruleset.Load(modData, this, TileSet, ruleDefinitions, weaponDefinitions,
|
||||
voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions);
|
||||
var flagged = Ruleset.DefinesUnsafeCustomRules(modData, this, ruleDefinitions,
|
||||
weaponDefinitions, voiceDefinitions, notificationDefinitions, sequenceDefinitions);
|
||||
return Pair.New(rules, flagged);
|
||||
});
|
||||
|
||||
if (p.Contains("map.png"))
|
||||
@@ -384,8 +401,11 @@ namespace OpenRA
|
||||
var musicDefinitions = LoadRuleSection(rulesYaml, "Music");
|
||||
var notificationDefinitions = LoadRuleSection(rulesYaml, "Notifications");
|
||||
var sequenceDefinitions = LoadRuleSection(rulesYaml, "Sequences");
|
||||
return Ruleset.Load(modData, this, TileSet, ruleDefinitions, weaponDefinitions,
|
||||
var rules = Ruleset.Load(modData, this, TileSet, ruleDefinitions, weaponDefinitions,
|
||||
voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions);
|
||||
var flagged = Ruleset.DefinesUnsafeCustomRules(modData, this, ruleDefinitions,
|
||||
weaponDefinitions, voiceDefinitions, notificationDefinitions, sequenceDefinitions);
|
||||
return Pair.New(rules, flagged);
|
||||
});
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
@@ -392,7 +392,7 @@ namespace OpenRA.Server
|
||||
SendOrderTo(newConn, "Message", motd);
|
||||
}
|
||||
|
||||
if (Map.Rules != ModData.DefaultRules && !LobbyInfo.IsSinglePlayer)
|
||||
if (!LobbyInfo.IsSinglePlayer && Map.DefinesUnsafeCustomRules)
|
||||
SendOrderTo(newConn, "Message", "This map contains custom rules. Game experience may change.");
|
||||
|
||||
if (Settings.DisableSinglePlayer)
|
||||
|
||||
@@ -319,6 +319,7 @@ namespace OpenRA.Traits
|
||||
public interface ITraitInfo : ITraitInfoInterface { object Create(ActorInitializer init); }
|
||||
|
||||
public class TraitInfo<T> : ITraitInfo where T : new() { public virtual object Create(ActorInitializer init) { return new T(); } }
|
||||
public interface ILobbyCustomRulesIgnore { }
|
||||
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1302:InterfaceNamesMustBeginWithI", Justification = "Not a real interface, but more like a tag.")]
|
||||
public interface Requires<T> where T : class, ITraitInfoInterface { }
|
||||
|
||||
@@ -398,7 +398,7 @@ namespace OpenRA.Mods.Common.Server
|
||||
|
||||
server.SendMessage("{0} changed the map to {1}.".F(client.Name, server.Map.Title));
|
||||
|
||||
if (server.Map.Rules.Actors != server.ModData.DefaultRules.Actors)
|
||||
if (server.Map.DefinesUnsafeCustomRules)
|
||||
server.SendMessage("This map contains custom rules. Game experience may change.");
|
||||
|
||||
if (server.Settings.DisableSinglePlayer)
|
||||
|
||||
@@ -17,7 +17,7 @@ using OpenRA.Traits;
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
[Desc("Used for day/night effects.")]
|
||||
class GlobalLightingPaletteEffectInfo : ITraitInfo
|
||||
class GlobalLightingPaletteEffectInfo : ITraitInfo, ILobbyCustomRulesIgnore
|
||||
{
|
||||
[Desc("Do not modify graphics that use any palette in this list.")]
|
||||
public readonly HashSet<string> ExcludePalettes = new HashSet<string> { "cursor", "chrome", "colorpicker", "fog", "shroud", "alpha" };
|
||||
|
||||
@@ -17,7 +17,7 @@ using OpenRA.Traits;
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
[Desc("Adds a particle-based overlay.")]
|
||||
public class WeatherOverlayInfo : ITraitInfo
|
||||
public class WeatherOverlayInfo : ITraitInfo, ILobbyCustomRulesIgnore
|
||||
{
|
||||
[Desc("Factor for particle density. As higher as more particles will get spawned.")]
|
||||
public readonly float ParticleDensityFactor = 0.0007625f;
|
||||
|
||||
Reference in New Issue
Block a user