コード例 #1
0
 public override sealed object DoConvert(ConfigField value, Type targetType, object parameter, CultureInfo culture)
 {
     if (!value.IsString)
         return "";
     var res = SqfProperty.GetSqfPropertySectionArg(this.Tag.PropertyObject as SqfProperty, value.String, (int)this.Tag.Extra);
     return this.DoConvertFromString(res, targetType, parameter, culture);
 }
コード例 #2
0
 public ConfigFieldReference(ConfigField referencedField, string thisKey)
     : base(true)
 {
     this.IsReference = true;
     this.ReferencedConfigField = referencedField;
     this.ParentalReference = null;
     this._Key = thisKey;
 }
コード例 #3
0
 public ConfigFieldReference(string thisKey, ConfigField parent)
     : base(true)
 {
     this.IsReference = true;
     this.ReferencedConfigField = null;
     this.ParentalReference = parent;
     this._Key = thisKey;
 }
コード例 #4
0
ファイル: NumberType.cs プロジェクト: X39/ArmA-UI-Editor
 public override object DoConvert(ConfigField value, Type targetType, object parameter, CultureInfo culture)
 {
     Logger.Trace(string.Format("{0} args: {1}", GetTraceInfo(), string.Join(", ", value, targetType, parameter, culture)));
     ConverterPropertyData data = (ConverterPropertyData)parameter;
     switch (data.Conversion)
     {
         default:
             return value.IsNumber ? value.Number : -1;
         case "SCREENX":
             return value.IsNumber ? value.Number : value.IsString && !string.IsNullOrWhiteSpace(value.String) ? data.Window.FromSqfString(EditingSnap.FieldTypeEnum.XField, value.String) : -1;
         case "SCREENY":
             return value.IsNumber ? value.Number : value.IsString && !string.IsNullOrWhiteSpace(value.String) ? data.Window.FromSqfString(EditingSnap.FieldTypeEnum.YField, value.String) : -1;
         case "SCREENW":
             return value.IsNumber ? value.Number : value.IsString && !string.IsNullOrWhiteSpace(value.String) ? data.Window.FromSqfString(EditingSnap.FieldTypeEnum.WField, value.String) : -1;
         case "SCREENH":
             return value.IsNumber ? value.Number : value.IsString && !string.IsNullOrWhiteSpace(value.String) ? data.Window.FromSqfString(EditingSnap.FieldTypeEnum.HField, value.String) : -1;
     }
 }
コード例 #5
0
 public override object DoConvert(ConfigField value, Type targetType, object parameter, CultureInfo culture)
 {
     if (value.IsClass || value.IsString && string.IsNullOrWhiteSpace(value.String))
         return null;
     var output = value.Value;
     EditingSnap snap;
     if (this.EditingSnapWeak.TryGetTarget(out snap))
     {
         if (parameter is FieldTypeEnum)
         {
             output = value.IsNumber ? value.Number : snap.FromSqfString((FieldTypeEnum)parameter, value.String);
         }
     }
     return output;
 }
コード例 #6
0
ファイル: BooleanType.cs プロジェクト: X39/ArmA-UI-Editor
 public override object DoConvert(ConfigField value, Type targetType, object parameter, CultureInfo culture)
 {
     return value.IsBoolean ? value.Boolean ? 1 : 0 : -1;
 }
コード例 #7
0
ファイル: ListboxType.cs プロジェクト: X39/ArmA-UI-Editor
 public override object DoConvert(ConfigField value, Type targetType, object parameter, CultureInfo culture)
 {
     var str = string.Format(CultureInfo.InvariantCulture, "{0}", value.Value);
     for (int i = 0; i < this.DataList.Count; i++)
     {
         if (this.DataList[i].Value == str)
         {
             return i;
         }
     }
     return -1;
 }
コード例 #8
0
ファイル: CoronaGameBuilder.cs プロジェクト: slagusev/Krea
        public void CreateConfigLua(bool isCustomBuild, float XRatio, float YRatio)
        {
            string path = this.project.BuildFolderPath + "\\config.lua";

            this.project.updateConfigFields(XRatio, YRatio);

            StringBuilder sb = new StringBuilder();

            //Application Section
            String contentToWrite = "application =\n";

            contentToWrite += "{\n";
            //Content SubSection
            contentToWrite += "\tcontent =\n";
            contentToWrite += "\t{\n";

            ////Write Parameters
            //contentToWrite += "\t\twidth = " + (this.project.width * XRatio).ToString().Replace(",", ".") + ",\n";
            //contentToWrite += "\t\theight = " + (this.project.height * YRatio).ToString().Replace(",", ".") + ",\n";
            //contentToWrite += "\t\tscale = \"" + this.project.scale + "\",\n";
            //contentToWrite += "\t\txAlign =  \"" + this.project.ScreenXAlign.ToString() + "\",\n";
            //contentToWrite += "\t\tyAlign = \"" + this.project.ScreenYAlign.ToString() + "\",\n";
            //contentToWrite += "\t\tfps = " + this.project.fps.ToString() + ",\n";
            //contentToWrite += "\t\tantialias = " + this.project.antialias.ToString().ToLower() + ",\n";
            ConfigField contentField = this.project.getFieldByName(this.project.CustomConfigFields, "content");

            int indentCount = 2;

            for (int i = 0; i < contentField.Children.Count; i++)
            {
                ConfigField contentChild = contentField.Children[i];
                contentToWrite += contentChild.ToLua(indentCount);
            }

            if (isCustomBuild == false)
            {
                //ImageSuffix SubSection
                if (this.project.ImageSuffix.Count > 0)
                {
                    contentToWrite += "\t\timageSuffix =\n";
                    contentToWrite += "\t\t{\n";
                    for (int i = 0; i < this.project.ImageSuffix.Count; i++)
                    {
                        contentToWrite += "\t\t\t" + this.project.ImageSuffix[i].ToString() + ",\n";
                    }
                    //Close ImageSuffix SubSection
                    contentToWrite += "\t\t},\n";
                }
            }



            //Close Content SubSection
            contentToWrite += "\t},\n";

            indentCount = 1;
            ConfigField applicationField = this.project.getFieldByName(this.project.CustomConfigFields, "application");

            for (int i = 0; i < applicationField.Children.Count; i++)
            {
                ConfigField applicationChild = applicationField.Children[i];

                if (!applicationChild.Name.Equals("content"))
                {
                    contentToWrite += applicationChild.ToLua(indentCount);
                }
            }
            //Application Content SubSection
            contentToWrite += "}\n";

            sb.Append(contentToWrite);

            FileStream fs = File.Create(path);

            fs.Close();

            File.AppendAllText(path, sb.ToString());
            sb.Clear();
            sb = null;
        }
コード例 #9
0
        private void CreateField()
        {
            if (!this.IsReference)
                return;
            ConfigField field = null;
            if (this.ReferencedConfigField != null)
            {
                field = this.ReferencedConfigField.TreeRoot;
            }
            if (this.ParentalReference != null)
            {
                field = this.ParentalReference.TreeRoot;
                this.ParentalReference = null;
            }

            field = field.GetKey(this.Key, KeyMode.CreateNew);
            this.ReferencedConfigField = field;
            this.IsReference = false;
        }
コード例 #10
0
 public abstract object DoConvert(ConfigField value, Type targetType, object parameter, CultureInfo culture);
コード例 #11
0
ファイル: ArrayType.cs プロジェクト: X39/ArmA-UI-Editor
 public override object DoConvert(ConfigField value, Type targetType, object parameter, CultureInfo culture)
 {
     Logger.Trace(string.Format("{0} args: {1}", GetTraceInfo(), string.Join(", ", value, targetType, parameter, culture)));
     if (!value.IsArray)
         return null;
     StringBuilder builder = new StringBuilder();
     foreach(var val in value.Array)
     {
         builder.Append(string.Format(CultureInfo.InvariantCulture, "{0}, ", val));
     }
     return builder.ToString().TrimEnd(',', ' ');
 }
コード例 #12
0
ファイル: CoronaGameBuilder.cs プロジェクト: slagusev/Krea
        public void CreateBuildSettings()
        {
            string path = this.project.BuildFolderPath + "\\build.settings";

            this.project.updateBuildFields();


            StringBuilder sb = new StringBuilder();

            sb.AppendLine("settings  =");
            sb.AppendLine("{\n");

            ConfigField settingsField = this.project.getFieldByName(this.project.CustomBuildFields, "settings");

            int indentCount = 1;

            for (int i = 0; i < settingsField.Children.Count; i++)
            {
                ConfigField settingsChild = settingsField.Children[i];
                sb.Append(settingsChild.ToLua(indentCount));
            }

            sb.AppendLine("}");
            ////settings Section
            //String contentToWrite = "settings  = \n";
            //contentToWrite += "{\n";

            //contentToWrite += "\tiphone = \n";
            //contentToWrite += "\t{\n";
            //     contentToWrite += "\t\tcomponents = {}\n";
            //contentToWrite += "\t},\n";

            ////android SubSection
            //if (this.project.AndroidVersionCode != null)
            //{
            //    contentToWrite += "\tandroid = \n";
            //    contentToWrite += "\t{\n";

            //    contentToWrite += "\t\tVersionCode = \"" + this.project.AndroidVersionCode + "\"\n";

            //    //close android SubSection
            //    contentToWrite += "\t},\n";
            //}

            ////androidPermissions SubSection
            //if (this.project.AndroidPermissions.Count > 0)
            //{
            //    contentToWrite += "\tandroidPermissions  = " + "\n";
            //    contentToWrite += "\t{\n";

            //    for (int i = 0; i < this.project.AndroidPermissions.Count; i++)
            //    {
            //        contentToWrite += "\t\t\"" + this.project.AndroidPermissions[i] + "\"";
            //        if (i != this.project.AndroidPermissions.Count - 1)
            //        {
            //            contentToWrite += ",";
            //        }
            //        contentToWrite += "\n";
            //    }
            //    //close androidPermissions SubSection
            //    contentToWrite += "\t},\n";
            //}

            ////orientation SubSection
            //contentToWrite += "\torientation  = " + "\n";
            //contentToWrite += "\t{\n";

            //contentToWrite += "\t\tdefault = \"" + this.project.Orientation.ToString().ToLower() + "\",\n";
            //contentToWrite += "\t\tcontent = \"" + this.project.Orientation.ToString().ToLower() + "\",\n";

            ////orientation supported SubSection
            //if (this.project.SupportedOrientation.Count > 0)
            //{
            //    contentToWrite += "\t\tsupported   = " + "\n";
            //    contentToWrite += "\t\t{\n";

            //    for (int i = 0; i < this.project.SupportedOrientation.Count; i++)
            //    {
            //        contentToWrite += "\t\t\t\"" + this.project.SupportedOrientation[i] + "\",";
            //    }
            //    contentToWrite += "\n";
            //    // close orientation supported SubSection
            //    contentToWrite += "\t\t},\n";
            //}
            ////close orientation SubSection
            //contentToWrite += "\t},\n";

            ////Builds Fonts
            //contentToWrite += this.GenerateIphoneFontsProperties(this.project.AvailableFont);

            ////build  SubSection
            //if (this.project.CustomBuildName != null)
            //{
            //    contentToWrite += "\tbuild  = \n";
            //    contentToWrite += "\t{\n";

            //    contentToWrite += "\t\tcustom  = \"" + this.project.CustomBuildName + "\",\n";

            //    //Close build  SubSection
            //    contentToWrite += "\t},\n";
            //}
            ////settings Content SubSection
            //contentToWrite += "}\n";


            FileStream fs = File.Create(path);

            fs.Close();

            File.AppendAllText(path, sb.ToString());
            sb.Clear();
            sb = null;
        }
コード例 #13
0
 private void Parent_PropertyChanged(object sender, PropertyChangedEventArgs e)
 {
     if (e.PropertyName != "Children")
         return;
     var field = sender as ConfigField;
     field = field.GetKey(this.Key.Remove(0, field.Key.Length), KeyMode.HighestMatchAvailable);
     this.ParentalReference.PropertyChanged -= Parent_PropertyChanged;
     if (field.Key == this.Key)
     {
         this.ParentalReference = null;
         this.IsReference = false;
         this.ReferencedConfigField = field;
     }
     else
     {
         this.ParentalReference = field;
     }
 }
コード例 #14
0
ファイル: Parser.cs プロジェクト: notjuliee/Daybreak.Config
        internal static bool ParseConfig <T>(T inst, string config, string filename = "[string]") where T : BaseConfig
        {
            var t = (BaseConfig)inst;

            t.Config = config;

            var nullField = new ConfigField();

            var rootSection   = true;
            var stringBuf     = new List <char>();
            var currentField  = nullField;
            var section       = nullField;
            var hasField      = false;
            var updatedFields = new List <ConfigField>();
            var i             = 0;

            while (i < t.Config.Length)
            {
                while (char.IsWhiteSpace(t.Config[i]) || t.Config[i] == '\n')
                {
                    i++;
                }

                if (i == t.Config.Length)
                {
                    break;
                }

                if (t.Config[i] == '/' && t.Config[i + 1] == '/')
                {
                    i += 2;
                    while (t.Config[i] != '\n' && i < t.Config.Length)
                    {
                        i++;
                    }

                    continue;
                }

                if (t.Config[i] == '[')
                {
                    i++;
                    stringBuf.Clear();
                    while (true)
                    {
                        if (t.Config[i] == ']')
                        {
                            break;
                        }
                        if (!IsValidIdentifier(t.Config[i]))
                        {
                            throw new Exceptions.InvalidTokenException(filename, t.Config, i, t.Config[i]);
                        }
                        stringBuf.Add(t.Config[i]);
                        i++;
                    }

                    i++;

                    var sectionName = new string(stringBuf.ToArray());
                    try
                    {
                        section = t._fields.First(x =>
                                                  x.IsSection && x.FieldAttr.FieldName == sectionName);
                    }
                    catch (InvalidOperationException)
                    {
                        throw new Exceptions.InvalidSectionException(filename, t.Config, i - sectionName.Length - 1,
                                                                     sectionName);
                    }


                    rootSection = false;
                }

                while (char.IsWhiteSpace(t.Config[i]))
                {
                    i++;
                }

                if (!hasField)
                {
                    if (!rootSection && section.Position == -1)
                    {
                        section.Position = i;
                        updatedFields.Add(section);
                    }

                    stringBuf.Clear();
                    while (!char.IsWhiteSpace(t.Config[i]) && t.Config[i] != '=')
                    {
                        if (!IsValidIdentifier(t.Config[i]))
                        {
                            throw new Exceptions.InvalidTokenException(filename, t.Config, i, t.Config[i]);
                        }

                        stringBuf.Add(t.Config[i]);
                        i++;
                    }

                    var fieldName = new string(stringBuf.ToArray());
                    try
                    {
                        if (rootSection)
                        {
                            currentField = t._fields.First(x => x.FieldAttr.FieldName == fieldName);
                        }
                        else
                        {
                            currentField = section.SubFields.First(x => x.FieldAttr.FieldName == fieldName);
                        }
                    }
                    catch (InvalidOperationException)
                    {
                        throw new Exceptions.InvalidFieldException(fieldName);
                    }

                    while (char.IsWhiteSpace(t.Config[i]))
                    {
                        i++;
                    }

                    if (t.Config[i] != '=')
                    {
                        throw new Exceptions.InvalidTokenException(filename, t.Config, i, t.Config[i]);
                    }

                    i++;
                    while (char.IsWhiteSpace(t.Config[i]))
                    {
                        i++;
                    }

                    hasField = true;
                }
                else
                {
                    stringBuf.Clear();
                    currentField.Position = i;
                    if (t.Config[i] == '"')
                    {
                        i++;
                        while (t.Config[i] != '"')
                        {
                            if (currentField.FieldInfo.FieldType != typeof(string))
                            {
                                throw new InvalidCastException("Don't quote non string fields");
                            }

                            if (t.Config[i] == '\n')
                            {
                                throw new Exceptions.InvalidTokenException(filename, t.Config, i, '\n');
                            }

                            if (i >= t.Config.Length)
                            {
                                throw new Exception(); // TODO: Write exception type for unexpected EOF
                            }

                            stringBuf.Add(t.Config[i]);
                            i++;
                        }

                        i++;
                    }
                    else
                    {
                        while (i < t.Config.Length && !char.IsWhiteSpace(t.Config[i]) && t.Config[i] != '\n')
                        {
                            stringBuf.Add(t.Config[i]);
                            i++;
                        }
                    }


                    currentField.Length = i - currentField.Position;

                    var    fieldVal = new string(stringBuf.ToArray());
                    object val      = null;
                    try
                    {
                        val = Conversion.ConvertTo(currentField.FieldInfo.FieldType, fieldVal);
                        if (currentField.Validators.Any(validator =>
                                                        !validator.Validate(val, currentField.FieldInfo.FieldType)))
                        {
                            throw new Exceptions.InternalInvalidValueException(val.GetType(), $"{val}");
                        }
                    }
                    catch (Exceptions.InternalInvalidValueException e)
                    {
                        throw new Exceptions.InvalidValueException(filename, t.Config, i - fieldVal.Length, e.Message);
                    }

                    currentField.FieldInfo.SetValue(rootSection ? t : section.FieldInfo.GetValue(t), val);
                    updatedFields.Add(currentField);

                    i++;
                    hasField = false;
                }
            }

            foreach (var field in updatedFields)
            {
                for (var x = 0; x < t._fields.Count; x++)
                {
                    if (field.Id == t._fields[x].Id)
                    {
                        t._fields[x] = field;
                        goto NEXTFIELD;
                    }

                    if (t._fields[x].IsSection)
                    {
                        for (var y = 0; y < t._fields[x].SubFields.Count; y++)
                        {
                            if (field.Id == t._fields[x].SubFields[y].Id)
                            {
                                t._fields[x].SubFields[y] = field;
                                goto NEXTFIELD;
                            }
                        }
                    }
                }

                NEXTFIELD :;
            }

            return(true);
        }
コード例 #15
0
ファイル: Parser.cs プロジェクト: notjuliee/Daybreak.Config
        private static void AddField <T>(ref StringBuilder builder, T obj, string doc, ConfigField field, ref int i)
        {
            if (field.IsSection)
            {
                foreach (var ifield in field.SubFields)
                {
                    AddField(ref builder, ifield.FieldInfo.GetValue(obj), doc, ifield, ref i);
                }
            }
            else
            {
                if (field.Position < 0)
                {
                    return;
                }
                builder.Append(doc.Substring(i, field.Position - i));
                i = field.Position + field.Length;
                if (field.FieldInfo.FieldType == typeof(string))
                {
                    builder.Append('"');
                }

                builder.Append(Conversion.ConvertFrom(field.FieldInfo.FieldType, obj));

                if (field.FieldInfo.FieldType == typeof(string))
                {
                    builder.Append('"');
                }
            }
        }
コード例 #16
0
ファイル: ConfigDialog.cs プロジェクト: flopik3-5/SmartMirror
 public ConfigDialog(ConfigField field)
 {
     _field = field;
 }
コード例 #17
0
        private void LoadContentPacks(IEnumerable <RawContentPack> contentPacks)
        {
            // load content packs
            ConfigFileHandler configFileHandler = new ConfigFileHandler(this.ConfigFileName, this.ParseCommaDelimitedField, (pack, label, reason) => this.Monitor.Log($"Ignored {pack.Manifest.Name} > {label}: {reason}"));

            foreach (RawContentPack current in contentPacks)
            {
                this.Monitor.VerboseLog($"Loading content pack '{current.Manifest.Name}'...");

                try
                {
                    ContentConfig content = current.Content;

                    // load tokens
                    ModTokenContext tokenContext = this.TokenManager.TrackLocalTokens(current.ManagedPack.Pack);
                    {
                        // load config.json
                        InvariantDictionary <ConfigField> config = configFileHandler.Read(current.ManagedPack, content.ConfigSchema);
                        configFileHandler.Save(current.ManagedPack, config, this.Helper);
                        if (config.Any())
                        {
                            this.Monitor.VerboseLog($"   found config.json with {config.Count} fields...");
                        }

                        // load config tokens
                        foreach (KeyValuePair <string, ConfigField> pair in config)
                        {
                            ConfigField field = pair.Value;
                            tokenContext.Add(new ImmutableToken(pair.Key, field.Value, allowedValues: field.AllowValues, canHaveMultipleValues: field.AllowMultiple));
                        }

                        // load dynamic tokens
                        foreach (DynamicTokenConfig entry in content.DynamicTokens ?? new DynamicTokenConfig[0])
                        {
                            void LogSkip(string reason) => this.Monitor.Log($"Ignored {current.Manifest.Name} > dynamic token '{entry.Name}': {reason}", LogLevel.Warn);

                            // validate token key
                            if (!TokenName.TryParse(entry.Name, out TokenName name))
                            {
                                LogSkip("the name could not be parsed as a token key.");
                                continue;
                            }
                            if (name.HasSubkey())
                            {
                                LogSkip("the token name cannot contain a subkey (:).");
                                continue;
                            }
                            if (name.TryGetConditionType(out ConditionType conflictingType))
                            {
                                LogSkip($"conflicts with global token '{conflictingType}'.");
                                continue;
                            }
                            if (config.ContainsKey(name.Key))
                            {
                                LogSkip($"conflicts with player config token '{conflictingType}'.");
                                continue;
                            }

                            // parse values
                            InvariantHashSet values = entry.Value != null?this.ParseCommaDelimitedField(entry.Value) : new InvariantHashSet();

                            // parse conditions
                            ConditionDictionary conditions;
                            {
                                if (!this.TryParseConditions(entry.When, tokenContext, current.Migrator, out conditions, out string error))
                                {
                                    this.Monitor.Log($"Ignored {current.Manifest.Name} > '{entry.Name}' token: its {nameof(DynamicTokenConfig.When)} field is invalid: {error}.", LogLevel.Warn);
                                    continue;
                                }
                            }

                            // add token
                            tokenContext.Add(new DynamicTokenValue(name, values, conditions));
                        }
                    }

                    // load patches
                    content.Changes = this.SplitPatches(content.Changes).ToArray();
                    this.NamePatches(current.ManagedPack, content.Changes);
                    foreach (PatchConfig patch in content.Changes)
                    {
                        this.Monitor.VerboseLog($"   loading {patch.LogName}...");
                        this.LoadPatch(current.ManagedPack, patch, tokenContext, current.Migrator, logSkip: reasonPhrase => this.Monitor.Log($"Ignored {patch.LogName}: {reasonPhrase}", LogLevel.Warn));
                    }
                }
                catch (Exception ex)
                {
                    this.Monitor.Log($"Error loading content pack '{current.Manifest.Name}'. Technical details:\n{ex}", LogLevel.Error);
                    continue;
                }
            }
        }
コード例 #18
0
ファイル: StringType.cs プロジェクト: X39/ArmA-UI-Editor
 public override object DoConvert(ConfigField value, Type targetType, object parameter, CultureInfo culture)
 {
     Logger.Trace(string.Format("{0} args: {1}", GetTraceInfo(), string.Join(", ", value, targetType, parameter, culture)));
     return value.IsString ? value.String : string.Empty;
 }
コード例 #19
0
        /*********
        ** Private methods
        *********/
        /// <summary>Parse a raw config schema for a content pack.</summary>
        /// <param name="rawSchema">The raw config schema.</param>
        /// <param name="logWarning">The callback to invoke on each validation warning, passed the field name and reason respectively.</param>
        /// <param name="formatVersion">The content format version.</param>
        private InvariantDictionary <ConfigField> LoadConfigSchema(InvariantDictionary <ConfigSchemaFieldConfig> rawSchema, Action <string, string> logWarning, ISemanticVersion formatVersion)
        {
            InvariantDictionary <ConfigField> schema = new InvariantDictionary <ConfigField>();

            if (rawSchema == null || !rawSchema.Any())
            {
                return(schema);
            }

            foreach (string rawKey in rawSchema.Keys)
            {
                ConfigSchemaFieldConfig field = rawSchema[rawKey];

                // validate format
                if (string.IsNullOrWhiteSpace(rawKey))
                {
                    logWarning(rawKey, "the config field name can't be empty.");
                    continue;
                }
                if (rawKey.Contains(InternalConstants.InputArgSeparator))
                {
                    logWarning(rawKey, $"the name '{rawKey}' can't have an input argument ({InternalConstants.InputArgSeparator} character).");
                    continue;
                }

                // validate reserved keys
                if (Enum.TryParse <ConditionType>(rawKey, true, out _))
                {
                    logWarning(rawKey, $"can't use {rawKey} as a config field, because it's a reserved condition key.");
                    continue;
                }

                // read allowed/default values
                InvariantHashSet allowValues   = this.ParseCommaDelimitedField(field.AllowValues);
                InvariantHashSet defaultValues = this.ParseCommaDelimitedField(field.Default);

                // pre-1.7 behaviour
                if (formatVersion.IsOlderThan("1.7"))
                {
                    // allowed values are required
                    if (!allowValues.Any())
                    {
                        logWarning(rawKey, $"no {nameof(ConfigSchemaFieldConfig.AllowValues)} specified (and format version is less than 1.7).");
                        continue;
                    }

                    // inject default if needed
                    if (!defaultValues.Any() && !field.AllowBlank)
                    {
                        defaultValues = new InvariantHashSet(allowValues.First());
                    }
                }

                // validate allowed values
                if (!field.AllowBlank && !defaultValues.Any())
                {
                    logWarning(rawKey, $"if {nameof(field.AllowBlank)} is false, you must specify {nameof(field.Default)}.");
                    continue;
                }
                if (allowValues.Any() && defaultValues.Any())
                {
                    string[] invalidValues = defaultValues.ExceptIgnoreCase(allowValues).ToArray();
                    if (invalidValues.Any())
                    {
                        logWarning(rawKey, $"default values '{string.Join(", ", invalidValues)}' are not allowed according to {nameof(ConfigSchemaFieldConfig.AllowValues)}.");
                        continue;
                    }
                }

                // validate allow multiple
                if (!field.AllowMultiple && defaultValues.Count > 1)
                {
                    logWarning(rawKey, $"can't have multiple default values because {nameof(ConfigSchemaFieldConfig.AllowMultiple)} is false.");
                    continue;
                }

                // add to schema
                schema[rawKey] = new ConfigField(allowValues, defaultValues, field.AllowBlank, field.AllowMultiple);
            }

            return(schema);
        }