Move data and data loading to plugin libraries.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-05-16 13:01:23 +02:00
parent b6ff51c9df
commit 810cdbb15a
46 changed files with 108405 additions and 155 deletions

View File

@@ -1,69 +0,0 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using PkmnLib.Dataloader.Models;
using PkmnLib.Static.Libraries;
using PkmnLib.Static.Species;
using PkmnLib.Static.Utils;
namespace PkmnLib.Dataloader;
public static class AbilityDataLoader
{
private static Dictionary<string, SerializedAbility> LoadAbilitiesData(Stream stream)
{
var obj = JsonSerializer.Deserialize<JsonObject>(stream, JsonOptions.DefaultOptions);
if (obj == null)
throw new InvalidDataException("Ability data is empty.");
obj.Remove("$schema");
var cleanedString = obj.ToJsonString();
var objects =
JsonSerializer.Deserialize<Dictionary<string, SerializedAbility>>(cleanedString,
JsonOptions.DefaultOptions);
if (objects == null)
throw new InvalidDataException("Ability data is empty.");
return objects;
}
public static AbilityLibrary LoadAbilities(Stream[] streams)
{
var library = new AbilityLibrary();
var objects = streams.SelectMany(LoadAbilitiesData);
if (objects == null)
throw new InvalidDataException("Ability data is empty.");
var abilities = objects.Select(x => DeserializeAbility(x.Key, x.Value));
foreach (var a in abilities)
library.Add(a);
return library;
}
public static AbilityLibrary LoadAbilities(Stream stream)
{
var library = new AbilityLibrary();
var objects = LoadAbilitiesData(stream);
if (objects == null)
throw new InvalidDataException("Ability data is empty.");
var abilities = objects.Select(x => DeserializeAbility(x.Key, x.Value));
foreach (var a in abilities)
library.Add(a);
return library;
}
private static AbilityImpl DeserializeAbility(string name, SerializedAbility serialized)
{
var effect = serialized.Effect;
var parameters = serialized.Parameters.ToDictionary(x => (StringKey)x.Key, x => x.Value.ToParameter());
StringKey? effectName = effect == null ? null! : new StringKey(effect);
var flags = serialized.Flags.Select(x => new StringKey(x)).ToImmutableHashSet();
var ability = new AbilityImpl(name, effectName, parameters, flags);
return ability;
}
}

View File

@@ -1,21 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using PkmnLib.Dataloader.Models;
using PkmnLib.Static.Moves;
using PkmnLib.Static.Utils;
namespace PkmnLib.Dataloader;
internal static class CommonDataLoaderHelper
{
internal static ISecondaryEffect? ParseEffect(this SerializedMoveEffect? effect)
{
if (effect == null)
return null;
var name = effect.Name;
var chance = effect.Chance ?? -1;
var parameters = effect.Parameters?.ToDictionary(x => (StringKey)x.Key, x => x.Value.ToParameter()) ??
new Dictionary<StringKey, object?>();
return new SecondaryEffectImpl(chance, name, parameters);
}
}

View File

@@ -1,22 +0,0 @@
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using PkmnLib.Static;
using PkmnLib.Static.Libraries;
namespace PkmnLib.Dataloader;
public static class GrowthRateDataLoader
{
public static GrowthRateLibrary LoadGrowthRates(Stream stream)
{
var objects = JsonSerializer.Deserialize<Dictionary<string, uint[]>>(stream, JsonOptions.DefaultOptions)!;
var library = new GrowthRateLibrary();
foreach (var (key, value) in objects)
{
var growthRate = new LookupGrowthRate(key, value);
library.Add(growthRate);
}
return library;
}
}

View File

@@ -1,54 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text.Json;
using JetBrains.Annotations;
using PkmnLib.Dataloader.Models;
using PkmnLib.Static;
using PkmnLib.Static.Libraries;
using PkmnLib.Static.Moves;
using PkmnLib.Static.Utils;
namespace PkmnLib.Dataloader;
public static class ItemDataLoader
{
public static ItemLibrary LoadItems(Stream stream)
{
var library = new ItemLibrary();
var obj = JsonSerializer.Deserialize<SerializedItem[]>(stream, JsonOptions.DefaultOptions);
if (obj == null)
throw new InvalidDataException("Item data is empty.");
var items = obj.Select(DeserializeItem);
foreach (var i in items)
library.Add(i);
return library;
}
public delegate IItem ItemFactoryDelegate(SerializedItem serialized, StringKey name, ItemCategory type,
BattleItemCategory battleType, int price, ImmutableHashSet<StringKey> flags, ISecondaryEffect? effect,
ISecondaryEffect? battleTriggerEffect, Dictionary<StringKey, object?> additionalData);
[PublicAPI]
public static ItemFactoryDelegate ItemConstructor { get; set; } =
(_, name, type, battleType, price, flags, effect, battleTriggerEffect, additionalData) => new ItemImpl(name,
type, battleType, price, flags, effect, battleTriggerEffect, additionalData);
private static IItem DeserializeItem(SerializedItem serialized)
{
if (!Enum.TryParse<ItemCategory>(serialized.ItemType, true, out var itemType))
throw new InvalidDataException($"Item type {serialized.ItemType} is not valid for item {serialized.Name}.");
Enum.TryParse(serialized.BattleType, true, out BattleItemCategory battleType);
var effect = serialized.Effect?.ParseEffect();
var battleTriggerEffect = serialized.BattleEffect?.ParseEffect();
var additionalData =
serialized.AdditionalData?.ToDictionary(x => (StringKey)x.Key, x => x.Value.ToParameter()) ??
new Dictionary<StringKey, object?>();
return ItemConstructor(serialized, serialized.Name, itemType, battleType, serialized.Price,
serialized.Flags.Select(x => (StringKey)x).ToImmutableHashSet(), effect, battleTriggerEffect,
additionalData);
}
}

View File

@@ -1,13 +0,0 @@
using System.Text.Json;
namespace PkmnLib.Dataloader;
internal static class JsonOptions
{
public static JsonSerializerOptions DefaultOptions => new()
{
PropertyNameCaseInsensitive = true,
AllowTrailingCommas = true,
ReadCommentHandling = JsonCommentHandling.Skip,
};
}

View File

@@ -1,40 +0,0 @@
using System;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using PkmnLib.Static.Utils;
namespace PkmnLib.Dataloader;
internal static class JsonParameterLoader
{
internal static object? ToParameter(this JsonNode node)
{
switch (node.GetValueKind())
{
case JsonValueKind.Undefined:
throw new InvalidOperationException("Undefined value.");
case JsonValueKind.Object:
return node.AsObject().ToDictionary(x => (StringKey)x.Key, x => x.Value?.ToParameter());
case JsonValueKind.Array:
return node.AsArray().Select(x => x?.ToParameter()).ToList();
case JsonValueKind.String:
return node.GetValue<string>();
case JsonValueKind.Number:
var element = node.GetValue<JsonElement>();
if (element.TryGetInt32(out var v))
return v;
if (element.TryGetSingle(out var f))
return f;
throw new InvalidOperationException("Number is not an integer or a float.");
case JsonValueKind.True:
return true;
case JsonValueKind.False:
return false;
case JsonValueKind.Null:
return null;
default:
throw new ArgumentOutOfRangeException();
}
}
}

View File

@@ -1,11 +0,0 @@
using System.Collections.Generic;
using System.Text.Json.Nodes;
namespace PkmnLib.Dataloader.Models;
public class SerializedAbility
{
public string? Effect { get; set; }
public Dictionary<string, JsonNode> Parameters { get; set; } = new();
public string[] Flags { get; set; } = [];
}

View File

@@ -1,21 +0,0 @@
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace PkmnLib.Dataloader.Models;
public class SerializedItem
{
public string Name { get; set; } = null!;
public string ItemType { get; set; } = null!;
public string BattleType { get; set; } = null!;
public string[] Flags { get; set; } = null!;
public int Price { get; set; }
public SerializedMoveEffect? Effect { get; set; }
public SerializedMoveEffect? BattleEffect { get; set; }
public Dictionary<string, JsonNode>? AdditionalData { get; set; } = null!;
[JsonExtensionData] public Dictionary<string, JsonElement>? ExtensionData { get; set; }
}

View File

@@ -1,34 +0,0 @@
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace PkmnLib.Dataloader.Models;
public class SerializedMoveDataWrapper
{
public SerializedMove[] Data { get; set; } = null!;
}
public class SerializedMove
{
public string Name { get; set; } = null!;
public string Type { get; set; } = null!;
public byte Power { get; set; }
public byte PP { get; set; }
public byte Accuracy { get; set; }
public sbyte Priority { get; set; }
public string Target { get; set; } = null!;
public string Category { get; set; } = null!;
public string[] Flags { get; set; } = null!;
public SerializedMoveEffect? Effect { get; set; }
[JsonExtensionData] public Dictionary<string, JsonElement>? ExtensionData { get; set; }
}
public class SerializedMoveEffect
{
public string Name { get; set; } = null!;
public float? Chance { get; set; }
public Dictionary<string, JsonNode>? Parameters { get; set; } = null!;
}

View File

@@ -1,73 +0,0 @@
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace PkmnLib.Dataloader.Models;
public class SerializedSpecies
{
public string Species { get; set; } = null!;
public ushort Id { get; set; }
public float GenderRatio { get; set; }
public string GrowthRate { get; set; } = null!;
public byte BaseHappiness { get; set; }
public byte CatchRate { get; set; }
public string Color { get; set; } = null!;
public bool GenderDifference { get; set; }
public string[] EggGroups { get; set; } = null!;
public int EggCycles { get; set; }
public string[] Flags { get; set; } = [];
public Dictionary<string, SerializedForm> Formes { get; set; } = null!;
public SerializedEvolution[] Evolutions { get; set; } = [];
[JsonExtensionData] public Dictionary<string, JsonElement>? ExtensionData { get; set; }
}
public class SerializedForm
{
public string[] Abilities { get; set; } = null!;
public string[] HiddenAbilities { get; set; } = [];
public SerializedStats BaseStats { get; set; } = null!;
public SerializedStats EVReward { get; set; } = null!;
public string[] Types { get; set; } = null!;
public float Height { get; set; }
public float Weight { get; set; }
public uint BaseExp { get; set; }
public bool IsMega { get; set; }
public SerializedMoves Moves { get; set; } = null!;
public string[] Flags { get; set; } = [];
[JsonExtensionData] public Dictionary<string, JsonElement>? ExtensionData { get; set; }
}
public class SerializedEvolution
{
public string Species { get; set; } = null!;
public string Method { get; set; } = null!;
public JsonNode Data { get; set; } = null!;
}
public class SerializedStats
{
public ushort Hp { get; set; }
public ushort Attack { get; set; }
public ushort Defense { get; set; }
public ushort SpecialAttack { get; set; }
public ushort SpecialDefense { get; set; }
public ushort Speed { get; set; }
}
public class SerializedLevelMove
{
public string Name { get; set; } = null!;
public uint Level { get; set; }
}
public class SerializedMoves
{
public SerializedLevelMove[]? LevelMoves { get; set; } = null!;
public string[]? EggMoves { get; set; } = null!;
public string[]? TutorMoves { get; set; } = null!;
public string[]? Machine { get; set; } = null!;
}

View File

@@ -1,66 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text.Json;
using JetBrains.Annotations;
using PkmnLib.Dataloader.Models;
using PkmnLib.Static;
using PkmnLib.Static.Libraries;
using PkmnLib.Static.Moves;
using PkmnLib.Static.Utils;
namespace PkmnLib.Dataloader;
public static class MoveDataLoader
{
public static MoveLibrary LoadMoves(Stream stream, TypeLibrary typeLibrary)
{
var library = new MoveLibrary();
var objects = JsonSerializer.Deserialize<SerializedMoveDataWrapper>(stream, JsonOptions.DefaultOptions);
if (objects == null)
throw new InvalidDataException("Move data is empty.");
var moves = objects.Data.Select(x => DeserializeMove(x, typeLibrary));
foreach (var m in moves)
library.Add(m);
return library;
}
[PublicAPI]
public static
Func<SerializedMove, StringKey, TypeIdentifier, MoveCategory, byte, byte, byte, MoveTarget, sbyte,
ISecondaryEffect?
, IEnumerable<StringKey>, MoveDataImpl> MoveConstructor =
(_, name, moveType, category, basePower, accuracy, baseUsages, target, priority, secondaryEffect, flags) =>
new MoveDataImpl(name, moveType, category, basePower, accuracy, baseUsages, target, priority,
secondaryEffect, flags);
private static MoveDataImpl DeserializeMove(SerializedMove serialized, TypeLibrary typeLibrary)
{
var type = serialized.Type;
var power = serialized.Power;
var pp = serialized.PP;
var accuracy = serialized.Accuracy;
var priority = serialized.Priority;
var target = serialized.Target;
var category = serialized.Category;
var flags = serialized.Flags;
var effect = serialized.Effect;
if (target.Equals("self", StringComparison.InvariantCultureIgnoreCase))
target = "selfUse";
if (!typeLibrary.TryGetTypeIdentifier(type, out var typeIdentifier))
throw new InvalidDataException($"Type {type} is not a valid type.");
if (!Enum.TryParse<MoveCategory>(category, true, out var categoryEnum))
throw new InvalidDataException($"Category {category} is not a valid category.");
if (!Enum.TryParse<MoveTarget>(target, true, out var targetEnum))
throw new InvalidDataException($"Target {target} is not a valid target.");
var secondaryEffect = effect.ParseEffect();
var move = MoveConstructor(serialized, serialized.Name, typeIdentifier, categoryEnum, power, accuracy, pp,
targetEnum, priority, secondaryEffect, flags.Select(x => (StringKey)x).ToImmutableHashSet());
return move;
}
}

View File

@@ -1,60 +0,0 @@
using System;
using System.IO;
using System.Linq;
using PkmnLib.Static;
using PkmnLib.Static.Libraries;
namespace PkmnLib.Dataloader;
public static class NatureDataLoader
{
private static readonly char[] CommonCsvDelimiters = ['|', ','];
public static NatureLibrary LoadNatureLibrary(Stream stream)
{
var library = new NatureLibrary();
using var reader = new StreamReader(stream);
var header = reader.ReadLine();
if (header == null)
throw new InvalidDataException("Type data is empty.");
var delimiter = CommonCsvDelimiters.FirstOrDefault(header.Contains);
if (delimiter == default)
throw new InvalidDataException("No valid delimiter found in type data.");
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (line == null)
break;
var values = line.Split(delimiter)!;
var nature = values[0];
var increasedStat = values[1];
var decreasedStat = values[2];
var increasedModifier = 1.1f;
var decreasedModifier = 0.9f;
if (increasedStat == string.Empty)
{
increasedStat = "Hp";
increasedModifier = 1.0f;
}
if (decreasedStat == string.Empty)
{
decreasedStat = "Hp";
decreasedModifier = 1.0f;
}
if (!Enum.TryParse<Statistic>(increasedStat, out var increasedStatEnum))
throw new InvalidDataException($"Increased stat {increasedStat} is not a valid stat.");
if (!Enum.TryParse<Statistic>(decreasedStat, out var decreasedStatEnum))
throw new InvalidDataException($"Decreased stat {decreasedStat} is not a valid stat.");
library.Add(new Nature(nature, increasedStatEnum, decreasedStatEnum, increasedModifier, decreasedModifier));
}
return library;
}
}

View File

@@ -7,17 +7,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Text.Json" Version="8.0.5" />
<PackageReference Include="System.Text.Json" Version="8.0.5"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PkmnLib.Static\PkmnLib.Static.csproj" />
<ProjectReference Include="..\PkmnLib.Static\PkmnLib.Static.csproj"/>
</ItemGroup>
<ItemGroup>
<Reference Include="JetBrains.Annotations">
<HintPath>..\..\..\..\.nuget\packages\jetbrains.annotations\2024.2.0\lib\netstandard2.0\JetBrains.Annotations.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@@ -1,241 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using PkmnLib.Dataloader.Models;
using PkmnLib.Static;
using PkmnLib.Static.Libraries;
using PkmnLib.Static.Species;
using PkmnLib.Static.Utils;
namespace PkmnLib.Dataloader;
public static class SpeciesDataLoader
{
private static Dictionary<string, SerializedSpecies> LoadSpeciesData(Stream stream)
{
var obj = JsonSerializer.Deserialize<JsonObject>(stream, JsonOptions.DefaultOptions);
if (obj == null)
throw new InvalidDataException("Species data is empty.");
return obj.Where(x => x.Key != "$schema").ToDictionary(x => x.Key,
x => x.Value.Deserialize<SerializedSpecies>(JsonOptions.DefaultOptions))!;
}
public static SpeciesLibrary LoadSpecies(Stream[] streams, IReadOnlyTypeLibrary typeLibrary)
{
var library = new SpeciesLibrary();
var objects = streams.SelectMany(LoadSpeciesData);
if (objects == null)
throw new InvalidDataException("Species data is empty.");
var species = objects.Select(x => DeserializeSpecies(x.Value, typeLibrary));
foreach (var s in species)
library.Add(s);
return library;
}
public static SpeciesLibrary LoadSpecies(Stream stream, IReadOnlyTypeLibrary typeLibrary)
{
var library = new SpeciesLibrary();
var objects = LoadSpeciesData(stream);
if (objects == null)
throw new InvalidDataException("Species data is empty.");
var species = objects.Select(x => DeserializeSpecies(x.Value, typeLibrary));
foreach (var s in species)
library.Add(s);
return library;
}
public static
Func<SerializedSpecies, ushort, StringKey, float, StringKey, byte, byte, IReadOnlyDictionary<StringKey, IForm>,
IEnumerable<StringKey>, IReadOnlyList<IEvolution>, IEnumerable<StringKey>, SpeciesImpl> SpeciesConstructor =
(_, id, name, genderRate, growthRate, captureRate, baseHappiness, forms, flags, evolutionData, eggGroups) =>
{
return new SpeciesImpl(id, name, genderRate, growthRate, captureRate, baseHappiness, forms, flags,
evolutionData, eggGroups);
};
private static SpeciesImpl DeserializeSpecies(SerializedSpecies serialized, IReadOnlyTypeLibrary typeLibrary)
{
var id = serialized.Id;
var genderRate = serialized.GenderRatio;
if (genderRate < -1.0 || genderRate > 100.0)
{
throw new InvalidDataException(
$"Gender rate for species {id} is invalid: {genderRate}. Must be between -1.0 and 100.0.");
}
if (serialized.EggCycles < 0)
{
throw new InvalidDataException(
$"Egg cycles for species {id} is invalid: {serialized.EggCycles}. Must be greater than or equal to 0.");
}
var forms = serialized.Formes.ToDictionary(x => (StringKey)x.Key,
x => DeserializeForm(x.Key, x.Value, typeLibrary));
var evolutions = serialized.Evolutions.Select(DeserializeEvolution).ToList();
var species = SpeciesConstructor(serialized, serialized.Id, serialized.Species, genderRate,
serialized.GrowthRate, serialized.CatchRate, serialized.BaseHappiness, forms,
serialized.Flags.Select(x => new StringKey(x)), evolutions, serialized.EggGroups.Select(x => (StringKey)x));
return species;
}
private static IForm DeserializeForm(string name, SerializedForm form, IReadOnlyTypeLibrary typeLibrary)
{
if (form == null)
throw new ArgumentException("Form data is null.", nameof(form));
if (form.Height < 0.0)
{
throw new InvalidDataException(
$"Height for form {name} is invalid: {form.Height}. Must be greater than or equal to 0.0.");
}
if (form.Weight < 0.0)
{
throw new InvalidDataException(
$"Weight for form {name} is invalid: {form.Weight}. Must be greater than or equal to 0.0.");
}
var types = form.Types.Select(x =>
typeLibrary.TryGetTypeIdentifier(new StringKey(x), out var t)
? t
: throw new InvalidDataException($"Type {x} for form {name} is invalid.")).ToList();
return new FormImpl(name, form.Height, form.Weight, form.BaseExp, types, DeserializeStats(form.BaseStats),
form.Abilities.Select(x => new StringKey(x)).ToList(),
form.HiddenAbilities.Select(x => new StringKey(x)).ToList(), DeserializeMoves(form.Moves),
form.Flags.Select(x => new StringKey(x)).ToImmutableHashSet());
}
private static ILearnableMoves DeserializeMoves(SerializedMoves moves)
{
var learnableMoves = new LearnableMovesImpl();
if (moves.LevelMoves != null)
{
foreach (var levelMove in moves.LevelMoves)
{
learnableMoves.AddLevelMove((byte)levelMove.Level, new StringKey(levelMove.Name));
}
}
if (moves.EggMoves != null)
{
foreach (var eggMove in moves.EggMoves)
{
learnableMoves.AddEggMove(new StringKey(eggMove));
}
}
return learnableMoves;
}
private static ImmutableStatisticSet<ushort> DeserializeStats(SerializedStats stats) =>
new(stats.Hp, stats.Attack, stats.Defense, stats.SpecialAttack, stats.SpecialDefense, stats.Speed);
private static IEvolution DeserializeEvolution(SerializedEvolution evolution)
{
return evolution.Method.ToLowerInvariant() switch
{
"level" => new LevelEvolution
{
Level = evolution.Data.GetValue<byte>(),
ToSpecies = evolution.Species,
},
"levelfemale" => new LevelGenderEvolution
{
Level = evolution.Data.GetValue<byte>(),
Gender = Gender.Female,
ToSpecies = evolution.Species,
},
"levelmale" => new LevelGenderEvolution
{
Level = evolution.Data.GetValue<byte>(),
Gender = Gender.Male,
ToSpecies = evolution.Species,
},
"happiness" => new HappinessEvolution
{
Happiness = evolution.Data.GetValue<byte>(),
ToSpecies = evolution.Species,
},
"happinessday" => new HappinessDayEvolution
{
Happiness = evolution.Data.GetValue<byte>(),
ToSpecies = evolution.Species,
},
"happinessnight" => new HappinessNightEvolution
{
Happiness = evolution.Data.GetValue<byte>(),
ToSpecies = evolution.Species,
},
"item" => new ItemUseEvolution
{
Item = evolution.Data.GetValue<string>() ?? throw new InvalidDataException("Item is null."),
ToSpecies = evolution.Species,
},
"itemmale" => new ItemGenderEvolution
{
Item = evolution.Data.GetValue<string>() ?? throw new InvalidDataException("Item is null."),
ToSpecies = evolution.Species,
},
"itemfemale" => new ItemGenderEvolution
{
Item = evolution.Data.GetValue<string>() ?? throw new InvalidDataException("Item is null."),
ToSpecies = evolution.Species,
},
"holditem" => new HoldItemEvolution
{
Item = evolution.Data.GetValue<string>() ?? throw new InvalidDataException("Item is null."),
ToSpecies = evolution.Species,
},
"dayholditem" => new DayHoldItemEvolution
{
Item = evolution.Data.GetValue<string>() ?? throw new InvalidDataException("Item is null."),
ToSpecies = evolution.Species,
},
"nightholditem" => new NightHoldItemEvolution
{
Item = evolution.Data.GetValue<string>() ?? throw new InvalidDataException("Item is null."),
ToSpecies = evolution.Species,
},
"hasmove" => new HasMoveEvolution
{
MoveName = evolution.Data.GetValue<string>() ?? throw new InvalidDataException("Move is null."),
ToSpecies = evolution.Species,
},
"trade" => new TradeEvolution
{
ToSpecies = evolution.Species,
},
"tradespecies" => new TradeSpeciesEvolution
{
WithSpecies = evolution.Data.GetValue<string>() ?? throw new InvalidDataException("Species is null."),
ToSpecies = evolution.Species,
},
"tradeitem" => new TradeItemEvolution
{
Item = evolution.Data.GetValue<string>() ?? throw new InvalidDataException("Item is null."),
ToSpecies = evolution.Species,
},
"location" => new CustomEvolution
{
Name = "location",
Parameters = new Dictionary<StringKey, object?>
{
["location"] = evolution.Data.ToString() ?? throw new InvalidDataException("Location is null."),
},
ToSpecies = evolution.Species,
},
"custom" => new CustomEvolution
{
Name = evolution.Data.AsObject()["type"]?.GetValue<string>() ??
throw new InvalidDataException("Type is null."),
Parameters = evolution.Data.AsObject().Where(x => x.Key != "type")
.ToDictionary(x => new StringKey(x.Key), x => x.Value!.ToParameter()),
ToSpecies = evolution.Species,
},
_ => throw new InvalidDataException($"Evolution type {evolution.Method} is invalid."),
};
}
}

View File

@@ -1,55 +0,0 @@
using System;
using System.IO;
using System.Linq;
using PkmnLib.Static.Libraries;
namespace PkmnLib.Dataloader;
public static class TypeDataLoader
{
private static readonly char[] CommonCsvDelimiters = ['|', ','];
public static TypeLibrary LoadTypeLibrary(Stream stream)
{
var library = new TypeLibrary();
using var reader = new StreamReader(stream);
var header = reader.ReadLine();
if (header == null)
throw new InvalidDataException("Type data is empty.");
var delimiter = CommonCsvDelimiters.FirstOrDefault(header.Contains);
if (delimiter == default)
throw new InvalidDataException("No valid delimiter found in type data.");
var types = header.Split(delimiter, StringSplitOptions.RemoveEmptyEntries)!;
if (!types.Any())
throw new InvalidDataException("No types found in type data.");
foreach (var type in types.Skip(1))
library.RegisterType(type);
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (line == null)
break;
var values = line.Split(delimiter, StringSplitOptions.RemoveEmptyEntries)!;
var type = values[0];
if (!library.TryGetTypeIdentifier(type, out var typeId))
throw new InvalidDataException($"Type {type} not found in type library.");
for (var i = 1; i < values.Length; i++)
{
var effectiveness = float.Parse(values[i]);
if (effectiveness < 0.0)
{
throw new InvalidDataException(
$"Effectiveness for {type} against {types[i]} is invalid: {effectiveness}. Must be greater than or equal to 0.0.");
}
library.TryGetTypeIdentifier(types[i], out var defendingTypeId);
library.SetEffectiveness(typeId, defendingTypeId, effectiveness);
}
}
return library;
}
}