示例#1
0
        /// <summary>Validate that the provided values are valid for the input argument (regardless of whether they match).</summary>
        /// <param name="input">The input argument, if applicable.</param>
        /// <param name="values">The values to validate.</param>
        /// <param name="error">The validation error, if any.</param>
        /// <returns>Returns whether validation succeeded.</returns>
        public bool TryValidateValues(ITokenString input, InvariantHashSet values, out string error)
        {
            if (!this.TryValidateInput(input, out error))
            {
                return(false);
            }

            // default validation
            {
                InvariantHashSet validValues = this.GetAllowedValues(input);
                if (validValues?.Any() == true)
                {
                    string[] invalidValues = values
                                             .Where(p => !validValues.Contains(p))
                                             .Distinct()
                                             .ToArray();
                    if (invalidValues.Any())
                    {
                        error = $"invalid values ({string.Join(", ", invalidValues)}); expected one of {string.Join(", ", validValues)}";
                        return(false);
                    }
                }
            }

            // custom validation
            foreach (string value in values)
            {
                if (!this.TryValidate(input, value, out error))
                {
                    return(false);
                }
            }

            // no issues found
            error = null;
            return(true);
        }
示例#2
0
        /*********
        ** Public methods
        *********/
        /// <summary>Construct an instance.</summary>
        /// <param name="position">The tile position to edit, relative to the top-left corner.</param>
        /// <param name="layer">The map layer name to edit.</param>
        /// <param name="setIndex">The tilesheet index to apply, the string <c>false</c> to remove it, or null to leave it as-is.</param>
        /// <param name="setTilesheet">The tilesheet ID to set.</param>
        /// <param name="setProperties">The tile properties to set.</param>
        /// <param name="remove">Whether to remove the current tile and all its properties.</param>
        public EditMapPatchTile(TokenPosition position, IManagedTokenString layer, IManagedTokenString setIndex, IManagedTokenString setTilesheet, IDictionary <IManagedTokenString, IManagedTokenString> setProperties, IManagedTokenString remove)
        {
            this.Position      = position;
            this.Layer         = layer;
            this.SetIndex      = setIndex;
            this.SetTilesheet  = setTilesheet;
            this.SetProperties = setProperties?.ToDictionary(p => (ITokenString)p.Key, p => (ITokenString)p.Value);
            this.Remove        = remove;

            this.Contextuals = new AggregateContextual()
                               .Add(position)
                               .Add(layer)
                               .Add(setIndex)
                               .Add(setTilesheet)
                               .Add(remove);

            if (setProperties != null)
            {
                foreach (var pair in setProperties)
                {
                    this.Contextuals.Add(pair.Key).Add(pair.Value);
                }
            }
        }
 /// <summary>Get whether the token always chooses from a set of known values for the given input. Mutually exclusive with <see cref="IValueProvider.HasBoundedRangeValues"/>.</summary>
 /// <param name="input">The input argument, if applicable.</param>
 /// <param name="allowedValues">The possible values for the input.</param>
 /// <exception cref="InvalidOperationException">The input argument doesn't match this value provider, or does not respect <see cref="IValueProvider.AllowsInput"/> or <see cref="IValueProvider.RequiresInput"/>.</exception>
 public override bool HasBoundedValues(ITokenString input, out InvariantHashSet allowedValues)
 {
     allowedValues = new InvariantHashSet(this.GetValues(input));
     return(true);
 }
示例#4
0
 /*********
 ** Public methods
 *********/
 /// <summary>Construct an instance.</summary>
 /// <param name="logName">A unique name for this patch shown in log messages.</param>
 /// <param name="contentPack">The content pack which requested the patch.</param>
 /// <param name="assetName">The normalised asset name to intercept.</param>
 /// <param name="conditions">The conditions which determine whether this patch should be applied.</param>
 /// <param name="fromAsset">The asset key to load from the content pack instead.</param>
 /// <param name="fromArea">The map area from which to read tiles.</param>
 /// <param name="toArea">The map area to overwrite.</param>
 /// <param name="monitor">Encapsulates monitoring and logging.</param>
 /// <param name="normaliseAssetName">Normalise an asset name.</param>
 public EditMapPatch(string logName, ManagedContentPack contentPack, ITokenString assetName, IEnumerable <Condition> conditions, ITokenString fromAsset, Rectangle fromArea, Rectangle toArea, IMonitor monitor, Func <string, string> normaliseAssetName)
     : base(logName, PatchType.EditMap, contentPack, assetName, conditions, normaliseAssetName, fromAsset: fromAsset)
 {
     this.FromArea = fromArea != Rectangle.Empty ? fromArea : null as Rectangle?;
     this.ToArea   = toArea != Rectangle.Empty ? toArea : null as Rectangle?;
     this.Monitor  = monitor;
 }
示例#5
0
 /// <summary>Whether the value provider may return multiple values for the given input.</summary>
 /// <param name="input">The input argument, if applicable.</param>
 public bool CanHaveMultipleValues(ITokenString input = null)
 {
     return(input.IsMeaningful()
         ? this.CanHaveMultipleValuesForInput
         : this.CanHaveMultipleValuesForRoot);
 }
示例#6
0
 /// <summary>Get the current values.</summary>
 /// <param name="input">The input argument, if applicable.</param>
 /// <exception cref="InvalidOperationException">The input argument doesn't match this value provider, or does not respect <see cref="IValueProvider.AllowsInput"/> or <see cref="IValueProvider.RequiresInput"/>.</exception>
 public virtual IEnumerable <string> GetValues(ITokenString input)
 {
     this.AssertInputArgument(input);
     yield break;
 }
 /// <summary>Set the current values.</summary>
 /// <param name="values">The values to set.</param>
 public void SetValue(ITokenString values)
 {
     this.DynamicValues.SetValue(values);
 }
示例#8
0
 /// <summary>Validate that the provided input argument is valid.</summary>
 /// <param name="input">The input argument, if applicable.</param>
 /// <param name="error">The validation error, if any.</param>
 /// <returns>Returns whether validation succeeded.</returns>
 public bool TryValidateInput(ITokenString input, out string error)
 {
     return(this.Values.TryValidateInput(input, out error));
 }
示例#9
0
 /// <summary>Get unique comma-separated values from a token string.</summary>
 /// <param name="tokenStr">The token string to parse.</param>
 /// <exception cref="InvalidOperationException">The token string is not ready (<see cref="IContextual.IsReady"/> is false).</exception>
 public static InvariantHashSet SplitValuesUnique(this ITokenString tokenStr)
 {
     return(new InvariantHashSet(tokenStr.SplitValuesNonUnique()));
 }
示例#10
0
 /// <summary>Get the allowed values for an input argument (or <c>null</c> if any value is allowed).</summary>
 /// <param name="input">The input argument, if any.</param>
 /// <exception cref="InvalidOperationException">The input does not respect <see cref="IToken.CanHaveInput"/> or <see cref="IToken.RequiresInput"/>.</exception>
 public virtual InvariantHashSet GetAllowedValues(ITokenString input)
 {
     return(this.Values.GetAllowedValues(input));
 }
示例#11
0
        /// <summary>Prepare a local asset file for a patch to use.</summary>
        /// <param name="pack">The content pack being loaded.</param>
        /// <param name="path">The asset path in the content patch.</param>
        /// <param name="tokenContext">The tokens available for this content pack.</param>
        /// <param name="migrator">The migrator which validates and migrates content pack data.</param>
        /// <param name="error">The error reason if preparing the asset fails.</param>
        /// <param name="tokenedPath">The parsed value.</param>
        /// <returns>Returns whether the local asset was successfully prepared.</returns>
        private bool TryPrepareLocalAsset(ManagedContentPack pack, string path, IContext tokenContext, IMigration migrator, out string error, out ITokenString tokenedPath)
        {
            // normalise raw value
            path = this.NormaliseLocalAssetPath(pack, path);
            if (path == null)
            {
                error       = $"must set the {nameof(PatchConfig.FromFile)} field for this action type.";
                tokenedPath = null;
                return(false);
            }

            // tokenise
            if (!this.TryParseStringTokens(path, tokenContext, migrator, out string tokenError, out tokenedPath))
            {
                error       = $"the {nameof(PatchConfig.FromFile)} is invalid: {tokenError}";
                tokenedPath = null;
                return(false);
            }

            // looks OK
            error = null;
            return(true);
        }
示例#12
0
        /// <summary>Parse a string which can contain tokens, and validate that it's valid.</summary>
        /// <param name="rawValue">The raw string which may contain tokens.</param>
        /// <param name="tokenContext">The tokens available for this content pack.</param>
        /// <param name="migrator">The migrator which validates and migrates content pack data.</param>
        /// <param name="error">An error phrase indicating why parsing failed (if applicable).</param>
        /// <param name="parsed">The parsed value.</param>
        private bool TryParseStringTokens(string rawValue, IContext tokenContext, IMigration migrator, out string error, out ITokenString parsed)
        {
            // parse
            parsed = new TokenString(rawValue, tokenContext);
            if (!migrator.TryMigrate(parsed, out error))
            {
                return(false);
            }

            // validate unknown tokens
            IContextualState state = parsed.GetDiagnosticState();

            if (state.InvalidTokens.Any())
            {
                error  = $"found unknown tokens ({string.Join(", ", state.InvalidTokens.OrderBy(p => p))})";
                parsed = null;
                return(false);
            }

            // validate tokens
            foreach (LexTokenToken lexToken in parsed.GetTokenPlaceholders(recursive: false))
            {
                IToken token = tokenContext.GetToken(lexToken.Name, enforceContext: false);
                if (token == null)
                {
                    error  = $"'{lexToken}' can't be used as a token because that token could not be found."; // should never happen
                    parsed = null;
                    return(false);
                }
            }

            // looks OK
            error = null;
            return(true);
        }
示例#13
0
 /*********
 ** Public methods
 *********/
 /// <summary>Construct an instance.</summary>
 /// <param name="tokenString">The underlying tokenized string.</param>
 public InputArguments(ITokenString tokenString)
 {
     this.TokenString = tokenString;
 }
示例#14
0
        /// <summary>Get the current values of the given token for comparison.</summary>
        /// <param name="name">The token name.</param>
        /// <param name="input">The input argument, if any.</param>
        /// <param name="enforceContext">Whether to only consider tokens that are available in the context.</param>
        /// <returns>Return the values of the matching token, or an empty list if the token doesn't exist.</returns>
        /// <exception cref="ArgumentNullException">The specified key is null.</exception>
        public IEnumerable <string> GetValues(string name, ITokenString input, bool enforceContext)
        {
            IToken token = this.GetToken(name, enforceContext);

            return(token?.GetValues(input) ?? new string[0]);
        }
示例#15
0
 /*********
 ** Public methods
 *********/
 /// <summary>Construct an instance.</summary>
 /// <param name="logName">A unique name for this patch shown in log messages.</param>
 /// <param name="contentPack">The content pack which requested the patch.</param>
 /// <param name="assetName">The normalised asset name to intercept.</param>
 /// <param name="conditions">The conditions which determine whether this patch should be applied.</param>
 /// <param name="localAsset">The asset key to load from the content pack instead.</param>
 /// <param name="normaliseAssetName">Normalise an asset name.</param>
 public LoadPatch(string logName, ManagedContentPack contentPack, ITokenString assetName, IEnumerable <Condition> conditions, ITokenString localAsset, Func <string, string> normaliseAssetName)
     : base(logName, PatchType.Load, contentPack, assetName, conditions, normaliseAssetName, fromAsset: localAsset)
 {
 }
示例#16
0
 /// <summary>Get the current token values.</summary>
 /// <param name="input">The input to check, if any.</param>
 /// <exception cref="InvalidOperationException">The input does not respect <see cref="IToken.CanHaveInput"/> or <see cref="IToken.RequiresInput"/>.</exception>
 public virtual IEnumerable <string> GetValues(ITokenString input)
 {
     this.AssertInput(input);
     return(this.Values.GetValues(input));
 }
示例#17
0
 /// <summary>Whether the token may return multiple values for the given name.</summary>
 /// <param name="input">The input argument, if any.</param>
 public bool CanHaveMultipleValues(ITokenString input)
 {
     return(this.Values.CanHaveMultipleValues(input));
 }
示例#18
0
        /*********
        ** Protected methods
        *********/
        /// <summary>Construct an instance.</summary>
        /// <param name="logName">A unique name for this patch shown in log messages.</param>
        /// <param name="type">The patch type.</param>
        /// <param name="contentPack">The content pack which requested the patch.</param>
        /// <param name="assetName">The normalized asset name to intercept.</param>
        /// <param name="conditions">The conditions which determine whether this patch should be applied.</param>
        /// <param name="normalizeAssetName">Normalize an asset name.</param>
        /// <param name="fromAsset">The normalized asset key from which to load the local asset (if applicable), including tokens.</param>
        protected Patch(string logName, PatchType type, ManagedContentPack contentPack, ITokenString assetName, IEnumerable <Condition> conditions, Func <string, string> normalizeAssetName, ITokenString fromAsset = null)
        {
            this.LogName                = logName;
            this.Type                   = type;
            this.ContentPack            = contentPack;
            this.RawTargetAsset         = assetName;
            this.Conditions             = conditions.ToArray();
            this.NormalizeAssetNameImpl = normalizeAssetName;
            this.PrivateContext         = new LocalContext(scope: this.ContentPack.Manifest.UniqueID);
            this.RawFromAsset           = fromAsset;

            this.Contextuals
            .Add(this.Conditions)
            .Add(this.RawTargetAsset)
            .Add(this.RawFromAsset);
        }
示例#19
0
 /// <summary>Add a set of possible values.</summary>
 /// <param name="possibleValues">The possible values to add.</param>
 public void AddAllowedValues(ITokenString possibleValues)
 {
     this.DynamicValues.AddAllowedValues(possibleValues);
     this.CanHaveMultipleRootValues = this.DynamicValues.CanHaveMultipleValues();
 }
示例#20
0
 /// <summary>Validate that the provided input argument is valid.</summary>
 /// <param name="input">The input argument, if applicable.</param>
 /// <param name="error">The validation error, if any.</param>
 /// <returns>Returns whether validation succeeded.</returns>
 public override bool TryValidateInput(ITokenString input, out string error)
 {
     return(this.TryCalculate(input, out _, out error));
 }
 /// <summary>Validate that the provided input argument is valid.</summary>
 /// <param name="input">The input argument, if applicable.</param>
 /// <param name="error">The validation error, if any.</param>
 /// <returns>Returns whether validation succeeded.</returns>
 public override bool TryValidateInput(ITokenString input, out string error)
 {
     return
         (base.TryValidateInput(input, out error) &&
          this.TryParseRange(input, out _, out _, out error));
 }
 /****
 ** Tokens
 ****/
 /// <summary>Get whether a token string has a meaningful value.</summary>
 /// <param name="str">The token string.</param>
 public static bool IsMeaningful(this ITokenString str)
 {
     return(!string.IsNullOrWhiteSpace(str?.Value));
 }
示例#23
0
 /// <summary>Get the allowed values for an input argument (or <c>null</c> if any value is allowed).</summary>
 /// <param name="input">The input argument, if applicable.</param>
 /// <exception cref="InvalidOperationException">The input argument doesn't match this value provider, or does not respect <see cref="IValueProvider.AllowsInput"/> or <see cref="IValueProvider.RequiresInput"/>.</exception>
 public virtual InvariantHashSet GetAllowedValues(ITokenString input)
 {
     return(null);
 }
 /// <summary>Get unique comma-separated values from a token string.</summary>
 /// <param name="tokenStr">The token string to parse.</param>
 /// <param name="normalize">Normalize a value.</param>
 /// <exception cref="InvalidOperationException">The token string is not ready (<see cref="IContextual.IsReady"/> is false).</exception>
 public static InvariantHashSet SplitValuesUnique(this ITokenString tokenStr, Func <string, string> normalize = null)
 {
     return(new InvariantHashSet(tokenStr.SplitValuesNonUnique(normalize)));
 }
示例#25
0
 /// <summary>Validate that the provided value is valid for an input argument (regardless of whether they match).</summary>
 /// <param name="input">The input argument, if applicable.</param>
 /// <param name="value">The value to validate.</param>
 /// <param name="error">The validation error, if any.</param>
 /// <returns>Returns whether validation succeeded.</returns>
 protected virtual bool TryValidate(ITokenString input, string value, out string error)
 {
     error = null;
     return(true);
 }
示例#26
0
 /// <summary>Get the current values of the given token for comparison.</summary>
 /// <param name="name">The token name.</param>
 /// <param name="input">The input argument, if any.</param>
 /// <param name="enforceContext">Whether to only consider tokens that are available in the context.</param>
 /// <returns>Return the values of the matching token, or an empty list if the token doesn't exist.</returns>
 /// <exception cref="ArgumentNullException">The specified key is null.</exception>
 public IEnumerable <string> GetValues(string name, ITokenString input, bool enforceContext)
 {
     return(this.GlobalContext.GetValues(name, input, enforceContext));
 }
 /// <summary>Get the allowed values for an input argument (or <c>null</c> if any value is allowed).</summary>
 /// <param name="input">The input argument, if applicable.</param>
 /// <exception cref="InvalidOperationException">The input argument doesn't match this value provider, or does not respect <see cref="IValueProvider.AllowsInput"/> or <see cref="IValueProvider.RequiresInput"/>.</exception>
 public override InvariantHashSet GetAllowedValues(ITokenString input)
 {
     return(input.IsMeaningful()
         ? InvariantHashSet.Boolean()
         : this.AllowedRootValues);
 }
示例#28
0
 /// <summary>Get whether the token always chooses from a set of known values for the given input. Mutually exclusive with <see cref="IToken.HasBoundedRangeValues"/>.</summary>
 /// <param name="input">The input argument, if applicable.</param>
 /// <param name="allowedValues">The possible values for the input.</param>
 /// <exception cref="InvalidOperationException">The input argument doesn't match this value provider, or does not respect <see cref="IToken.CanHaveInput"/> or <see cref="IToken.RequiresInput"/>.</exception>
 public bool HasBoundedValues(ITokenString input, out InvariantHashSet allowedValues)
 {
     return(this.Values.HasBoundedValues(input, out allowedValues));
 }
示例#29
0
 /// <summary>Set the current values.</summary>
 /// <param name="values">The values to set.</param>
 public void SetValue(ITokenString values)
 {
     this.Values = values.SplitValuesUnique();
 }
示例#30
0
 /// <summary>Get whether the token always returns a value within a bounded numeric range for the given input. Mutually exclusive with <see cref="IToken.HasBoundedValues"/>.</summary>
 /// <param name="input">The input argument, if any.</param>
 /// <param name="min">The minimum value this token may return.</param>
 /// <param name="max">The maximum value this token may return.</param>
 /// <exception cref="InvalidOperationException">The input argument doesn't match this value provider, or does not respect <see cref="IToken.CanHaveInput"/> or <see cref="IToken.RequiresInput"/>.</exception>
 public bool HasBoundedRangeValues(ITokenString input, out int min, out int max)
 {
     return(this.Values.HasBoundedRangeValues(input, out min, out max));
 }