Even further seperating the parser from having hardcoded values
This commit is contained in:
parent
d12474c01e
commit
22cce4257d
@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace SessionZero.Data;
|
namespace SessionZero.Data;
|
||||||
|
|
||||||
|
[SzfObject(SzfObjectType.CharacterTemplate, "character_template")]
|
||||||
public class CharacterTemplate : SzfObject
|
public class CharacterTemplate : SzfObject
|
||||||
{
|
{
|
||||||
public string GameSystem { get; set; } = string.Empty;
|
public string GameSystem { get; set; } = string.Empty;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
namespace SessionZero.Data;
|
namespace SessionZero.Data;
|
||||||
|
|
||||||
|
[SzfObject(SzfObjectType.Dataset, "dataset")]
|
||||||
public class Dataset : SzfObject
|
public class Dataset : SzfObject
|
||||||
{
|
{
|
||||||
public string DatasetType { get; set; } = string.Empty;
|
public string DatasetType { get; set; } = string.Empty;
|
||||||
|
18
SessionZero/Data/SzfObjectAttribute.cs
Normal file
18
SessionZero/Data/SzfObjectAttribute.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// SzfObjectAttribute.cs
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace SessionZero.Data;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||||
|
public class SzfObjectAttribute : Attribute
|
||||||
|
{
|
||||||
|
public SzfObjectType ObjectType { get; }
|
||||||
|
public string TypeString { get; }
|
||||||
|
|
||||||
|
public SzfObjectAttribute(SzfObjectType objectType, string typeString)
|
||||||
|
{
|
||||||
|
ObjectType = objectType;
|
||||||
|
TypeString = typeString;
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Reflection;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace SessionZero.Data;
|
namespace SessionZero.Data;
|
||||||
@ -8,6 +9,32 @@ public class SzfParser
|
|||||||
private static readonly Regex SectionRegex = new(@"^\[([^\]]+)\]$", RegexOptions.Compiled);
|
private static readonly Regex SectionRegex = new(@"^\[([^\]]+)\]$", RegexOptions.Compiled);
|
||||||
private static readonly Regex FieldRegex = new(@"^(\w+)\s*\(([^)]+)\)\s*=\s*(.*)$", RegexOptions.Compiled);
|
private static readonly Regex FieldRegex = new(@"^(\w+)\s*\(([^)]+)\)\s*=\s*(.*)$", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
// Static dictionaries to store type mappings, initialized once
|
||||||
|
private static readonly Dictionary<SzfObjectType, Type> s_objectTypeToClassMap;
|
||||||
|
private static readonly Dictionary<string, SzfObjectType> s_stringToObjectTypeMap;
|
||||||
|
|
||||||
|
static SzfParser()
|
||||||
|
{
|
||||||
|
s_objectTypeToClassMap = new Dictionary<SzfObjectType, Type>();
|
||||||
|
s_stringToObjectTypeMap = new Dictionary<string, SzfObjectType>();
|
||||||
|
|
||||||
|
// Discover types with SzfObjectAttribute in the current assembly
|
||||||
|
var szfObjectTypes = Assembly.GetExecutingAssembly().GetTypes()
|
||||||
|
.Where(type => typeof(SzfObject).IsAssignableFrom(type) && !type.IsAbstract)
|
||||||
|
.Select(type => new
|
||||||
|
{
|
||||||
|
Type = type,
|
||||||
|
Attribute = type.GetCustomAttribute<SzfObjectAttribute>()
|
||||||
|
})
|
||||||
|
.Where(x => x.Attribute != null);
|
||||||
|
|
||||||
|
foreach (var item in szfObjectTypes)
|
||||||
|
{
|
||||||
|
s_objectTypeToClassMap[item.Attribute!.ObjectType] = item.Type;
|
||||||
|
s_stringToObjectTypeMap[item.Attribute.TypeString.ToLower()] = item.Attribute.ObjectType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parse a SZF file content and return the appropriate SzfObject type
|
/// Parse a SZF file content and return the appropriate SzfObject type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -66,18 +93,16 @@ public class SzfParser
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create an instance based on the object type
|
/// Create an instance based on the object type using the dynamically built map
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private SzfObject CreateInstanceFromType(SzfObjectType objectType)
|
private SzfObject CreateInstanceFromType(SzfObjectType objectType)
|
||||||
{
|
{
|
||||||
return objectType switch
|
if (s_objectTypeToClassMap.TryGetValue(objectType, out var type))
|
||||||
{
|
{
|
||||||
SzfObjectType.Dataset => new Dataset(),
|
return (SzfObject)Activator.CreateInstance(type)!;
|
||||||
SzfObjectType.CharacterTemplate => new CharacterTemplate(), // UNCOMMENTED THIS LINE
|
}
|
||||||
// SzfObjectType.Character => new Character(),
|
|
||||||
// SzfObjectType.Session => new Session(),
|
throw new SzfParseException($"Unsupported object type: {objectType}");
|
||||||
_ => throw new SzfParseException($"Unsupported object type: {objectType}")
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -231,35 +256,34 @@ public class SzfParser
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parse object type from string
|
/// Parse object type from string using the dynamically built map
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private SzfObjectType ParseObjectType(string typeString)
|
private SzfObjectType ParseObjectType(string typeString)
|
||||||
{
|
{
|
||||||
return typeString.ToLower() switch
|
if (s_stringToObjectTypeMap.TryGetValue(typeString.ToLower(), out var objectType))
|
||||||
{
|
{
|
||||||
"dataset" => SzfObjectType.Dataset,
|
return objectType;
|
||||||
"character_template" => SzfObjectType.CharacterTemplate,
|
}
|
||||||
"character" => SzfObjectType.Character,
|
|
||||||
"session" => SzfObjectType.Session,
|
throw new SzfParseException($"Unknown object type: {typeString}");
|
||||||
_ => throw new SzfParseException($"Unknown object type: {typeString}")
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Validate that the parsed type matches the requested generic type
|
/// Validate that the parsed type matches the requested generic type using the attribute
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void ValidateObjectType<T>(SzfObjectType parsedType) where T : SzfObject
|
private void ValidateObjectType<T>(SzfObjectType parsedType) where T : SzfObject
|
||||||
{
|
{
|
||||||
var expectedType = typeof(T).Name switch
|
var targetType = typeof(T);
|
||||||
{
|
var attribute = targetType.GetCustomAttribute<SzfObjectAttribute>();
|
||||||
nameof(Dataset) => SzfObjectType.Dataset,
|
|
||||||
nameof(CharacterTemplate) => SzfObjectType.CharacterTemplate,
|
|
||||||
_ => throw new SzfParseException($"Unsupported SzfObject type: {typeof(T).Name}")
|
|
||||||
};
|
|
||||||
|
|
||||||
if (parsedType != expectedType)
|
if (attribute == null)
|
||||||
{
|
{
|
||||||
throw new SzfParseException($"Type mismatch: Expected {expectedType}, found {parsedType}");
|
throw new SzfParseException($"Type {targetType.Name} does not have SzfObjectAttribute.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedType != attribute.ObjectType)
|
||||||
|
{
|
||||||
|
throw new SzfParseException($"Type mismatch: Expected {attribute.ObjectType}, found {parsedType}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user