106 lines
4.0 KiB
C#
106 lines
4.0 KiB
C#
namespace ALttPRandomizer.Serialization {
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using ALttPRandomizer.Model;
|
|
using YamlDotNet.Core;
|
|
using YamlDotNet.Core.Events;
|
|
using YamlDotNet.Serialization;
|
|
|
|
public class RandomizableWeightsYamlConverters : IYamlTypeConverter {
|
|
private readonly Dictionary<Type, IYamlTypeConverter> converters = new();
|
|
|
|
public bool Accepts(Type type) {
|
|
if (this.converters.ContainsKey(type)) {
|
|
return true;
|
|
}
|
|
|
|
if (!type.IsGenericType) {
|
|
return false;
|
|
}
|
|
|
|
if (type.GetGenericTypeDefinition() != typeof(RandomizableWeights<>)) {
|
|
return false;
|
|
}
|
|
|
|
Type itemType = type.GetGenericArguments()[0];
|
|
Type innerType = typeof(RandomizableWeightsYamlConverter<>).MakeGenericType(itemType)!;
|
|
|
|
this.converters[type] = (IYamlTypeConverter) Activator.CreateInstance(innerType)!;
|
|
|
|
return true;
|
|
}
|
|
|
|
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) {
|
|
return this.converters[type].ReadYaml(parser, type, rootDeserializer);
|
|
}
|
|
|
|
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer) {
|
|
this.converters[type].WriteYaml(emitter, value, type, serializer);
|
|
}
|
|
}
|
|
|
|
internal class RandomizableWeightsYamlConverter<T> : IYamlTypeConverter where T : struct, Enum {
|
|
private readonly Type valueType;
|
|
private readonly Type dictionaryType;
|
|
|
|
public RandomizableWeightsYamlConverter() {
|
|
this.valueType = typeof(T);
|
|
this.dictionaryType = typeof(IDictionary<T, int>);
|
|
}
|
|
|
|
public bool Accepts(Type type) {
|
|
return type == typeof(RandomizableWeights<T>);
|
|
}
|
|
|
|
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) {
|
|
if (parser.Accept<Scalar>(out var evt)) {
|
|
if (evt.Value == "null") {
|
|
parser.Consume<Scalar>();
|
|
return RandomizableWeights<T>.EmptyWeights;
|
|
}
|
|
var value = rootDeserializer.Invoke(this.valueType);
|
|
if (value is T t) {
|
|
return RandomizableWeights<T>.ConstantWeights(t);
|
|
} else {
|
|
return RandomizableWeights<T>.EmptyWeights;
|
|
}
|
|
}
|
|
|
|
if (parser.Accept<MappingStart>(out _)) {
|
|
var value = rootDeserializer.Invoke(this.dictionaryType);
|
|
if (value is IDictionary<T, int> dict) {
|
|
return RandomizableWeights<T>.FromDictionary(dict);
|
|
} else {
|
|
return RandomizableWeights<T>.EmptyWeights;
|
|
}
|
|
}
|
|
|
|
throw new YamlException($"Error reading type RandomizableWeights<{typeof(T).Name}>.");
|
|
}
|
|
|
|
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer) {
|
|
if (value is RandomizableWeights<T> weights) {
|
|
switch (weights.Options.Count) {
|
|
case 0:
|
|
emitter.Emit(new Scalar("null"));
|
|
break;
|
|
case 1:
|
|
serializer.Invoke(weights.Options[0].Item, valueType);
|
|
break;
|
|
default:
|
|
emitter.Emit(new MappingStart());
|
|
foreach (var (item, weight) in weights.Options) {
|
|
serializer.Invoke(item, valueType);
|
|
emitter.Emit(new Scalar(weight.ToString()));
|
|
}
|
|
emitter.Emit(new MappingEnd());
|
|
break;
|
|
}
|
|
} else {
|
|
emitter.Emit(new MappingStart());
|
|
emitter.Emit(new MappingEnd());
|
|
}
|
|
}
|
|
}
|
|
}
|