Generic parser that scans a source file for attribute-decorated fields (float, float2/3/4, Texture2D and DynamicCombo) and populates dictionaries of parsed default values. It uses a provided IAttributeTypeSet to parse or supply Particle/Native float and color types, and parses vector defaults from text.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Sandbox;
public class AttributesParser<TFloat, TGradient>
{
private readonly IAttributeTypeSet<TFloat, TGradient> _typeSet;
public AttributesParser(IAttributeTypeSet<TFloat, TGradient> typeSet)
{
if (!((typeof(TFloat) == typeof(ParticleFloat) && typeof(TGradient) == typeof(ParticleGradient)) ||
(typeof(TFloat) == typeof(float) && typeof(TGradient) == typeof(Color))))
{
throw new InvalidOperationException("Only Particle or Native types allowed.");
}
_typeSet = typeSet;
}
public Dictionary<String, TGradient> Colors { get; set; }
public Dictionary<String, TFloat> Floats { get; set; }
public Dictionary<String, Vector2> Floats2 { get; set; }
public Dictionary<String, Vector3> Floats3 { get; set; }
public Dictionary<String, Vector4> Floats4 { get; set; }
public Dictionary<String, Texture> Textures { get; set; }
public Dictionary<String, int> DynamicCombos { get; set; }
private const string AttributesPattern = @"(float(?:[2,3,4])?|Texture2D) +.+ +< *Attribute\(.?""(.+)"".?\)\;(?:[^>]*?Default(?:[1,2,3,4])?\(([^)]*)\))?[^>]*>\;";
private const string DynamicComboPattern = "DynamicCombo\\(([^,]+),.+\\)\\;";
public void ParseAttributes( string filePath )
{
string fileContent = FileSystem.Mounted.ReadAllText( filePath );
var attributeMatches = Regex.Matches(fileContent, AttributesPattern);
var dynamicComboMatches = Regex.Matches(fileContent, DynamicComboPattern);
foreach ( Match match in dynamicComboMatches )
{
var value = match.Groups[1].Value.Trim();
if(!DynamicCombos.ContainsKey(value)) DynamicCombos.Add(value, 0);
}
foreach (Match match in attributeMatches)
{
var type = match.Groups[1].Value;
var value = match.Groups[2].Value;
var defaultValue = match.Groups[3].Value;
SetAttribute(type, value, defaultValue);
}
}
private void SetAttribute( string attributeType, string attributeName, string defaultValue )
{
switch ( attributeType )
{
case "float":
if ( !Floats.ContainsKey( attributeName ) ) SetFloat( attributeName, defaultValue );
break;
case "float2":
if ( !Floats2.ContainsKey( attributeName ) ) SetFloat2( attributeName, defaultValue );
break;
case "float3":
if ( !Floats3.ContainsKey( attributeName ) ) SetFloat3( attributeName, defaultValue );
break;
case "float4":
if ( !Floats4.ContainsKey( attributeName ) && !Colors.ContainsKey( attributeName ) ) SetFloat4( attributeName );
break;
case "Texture2D":
if ( !Textures.ContainsKey( attributeName ) ) Textures.Add( attributeName, Texture.White );
break;
default: break;
}
}
private void SetFloat( string attributeName, string defaultValue )
{
TFloat value = !string.IsNullOrEmpty( defaultValue )
? _typeSet.ParseFloat( defaultValue )
: _typeSet.GetDefaultFloat();
Floats.Add( attributeName, value );
}
private void SetFloat2( string attributeName, string defaultValue )
{
Vector2 value = !string.IsNullOrEmpty( defaultValue )
? ParseVector2( defaultValue )
: new Vector2();
Floats2.Add( attributeName, value );
}
private void SetFloat3( string attributeName, string defaultValue )
{
Vector3 value = !string.IsNullOrEmpty( defaultValue )
? ParseVector3( defaultValue )
: new Vector3();
Floats3.Add( attributeName, value );
}
private static Vector2 ParseVector2( string raw )
{
var p = raw.Split( ',' );
return new Vector2(
float.Parse( p[0].Trim(), System.Globalization.CultureInfo.InvariantCulture ),
float.Parse( p[1].Trim(), System.Globalization.CultureInfo.InvariantCulture )
);
}
private static Vector3 ParseVector3( string raw )
{
var p = raw.Split( ',' );
return new Vector3(
float.Parse( p[0].Trim(), System.Globalization.CultureInfo.InvariantCulture ),
float.Parse( p[1].Trim(), System.Globalization.CultureInfo.InvariantCulture ),
float.Parse( p[2].Trim(), System.Globalization.CultureInfo.InvariantCulture )
);
}
private void SetFloat4( string attributeName)
{
if ( attributeName.ToLower().Contains( "color" ) )
{
Colors.Add( attributeName, _typeSet.GetDefaultColor() );
}
else
{
Floats4.Add( attributeName, new Vector4( ) );
}
}
}