238 lines
10 KiB
C#
238 lines
10 KiB
C#
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);
|
|
if (obj == null)
|
|
throw new InvalidDataException("Species data is empty.");
|
|
var jsonConfig = new JsonSerializerOptions()
|
|
{
|
|
PropertyNameCaseInsensitive = true,
|
|
};
|
|
return obj.Where(x => x.Key != "$schema")
|
|
.ToDictionary(x => x.Key, x => x.Value.Deserialize<SerializedSpecies>(jsonConfig));
|
|
}
|
|
|
|
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)
|
|
{
|
|
return new ImmutableStatisticSet<ushort>(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."),
|
|
};
|
|
}
|
|
} |