feat(expansions): Adds expansion.json and loads expansions dynamically (#798)

Moves hardcoded expansion settings to the file Data\expansion.json.
This commit is contained in:
Michael Whelehan 2021-09-24 05:28:43 +02:00 committed by GitHub
parent a0c3158675
commit 2f5b26ae68
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 1084 additions and 99 deletions

View file

@ -0,0 +1,794 @@
[
{
"Name": "None",
"ClientVersion": null,
"ClientFlags": null,
"FeatureFlags": {
"None": true,
"T2A": false,
"UOR": false,
"UOTD": false,
"LBR": false,
"AOS": false,
"SixthCharacterSlot": false,
"SE": false,
"ML": false,
"EigthAge": false,
"NinthAge": false,
"TenthAge": false,
"IncreasedStorage": false,
"SeventhCharacterSlot": false,
"RoleplayFaces": false,
"TrialAccount": false,
"LiveAccount": false,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
},
"CharacterListFlags": {
"None": true,
"Unk1": false,
"OverwriteConfigButton": false,
"OneCharacterSlot": false,
"ContextMenus": false,
"SlotLimit": false,
"AOS": false,
"SixthCharacterSlot": false,
"SE": false,
"ML": false,
"Unk2": false,
"UO3DClientType": false,
"Unk3": false,
"SeventhCharacterSlot": false,
"Unk4": false,
"NewMovementSystem": false,
"NewFeluccaAreas": false
},
"HousingFlags": {
"None": true,
"AOS": false,
"SE": false,
"ML": false,
"Crystal": false,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
}
},
{
"Name": "The Second Age",
"ClientVersion": null,
"ClientFlags": "Felucca",
"FeatureFlags": {
"None": false,
"T2A": true,
"UOR": false,
"UOTD": false,
"LBR": false,
"AOS": false,
"SixthCharacterSlot": false,
"SE": false,
"ML": false,
"EigthAge": false,
"NinthAge": false,
"TenthAge": false,
"IncreasedStorage": false,
"SeventhCharacterSlot": false,
"RoleplayFaces": false,
"TrialAccount": false,
"LiveAccount": false,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
},
"CharacterListFlags": {
"None": false,
"Unk1": false,
"OverwriteConfigButton": false,
"OneCharacterSlot": false,
"ContextMenus": true,
"SlotLimit": false,
"AOS": false,
"SixthCharacterSlot": false,
"SE": false,
"ML": false,
"Unk2": false,
"UO3DClientType": false,
"Unk3": false,
"SeventhCharacterSlot": false,
"Unk4": false,
"NewMovementSystem": false,
"NewFeluccaAreas": false
},
"HousingFlags": {
"None": true,
"AOS": false,
"SE": false,
"ML": false,
"Crystal": false,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
}
},
{
"Name": "Renaissance",
"ClientVersion": null,
"ClientFlags": "Trammel",
"FeatureFlags": {
"None": false,
"T2A": true,
"UOR": true,
"UOTD": false,
"LBR": false,
"AOS": false,
"SixthCharacterSlot": false,
"SE": false,
"ML": false,
"EigthAge": false,
"NinthAge": false,
"TenthAge": false,
"IncreasedStorage": false,
"SeventhCharacterSlot": false,
"RoleplayFaces": false,
"TrialAccount": false,
"LiveAccount": false,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
},
"CharacterListFlags": {
"None": false,
"Unk1": false,
"OverwriteConfigButton": false,
"OneCharacterSlot": false,
"ContextMenus": true,
"SlotLimit": false,
"AOS": false,
"SixthCharacterSlot": false,
"SE": false,
"ML": false,
"Unk2": false,
"UO3DClientType": false,
"Unk3": false,
"SeventhCharacterSlot": false,
"Unk4": false,
"NewMovementSystem": false,
"NewFeluccaAreas": false
},
"HousingFlags": {
"None": true,
"AOS": false,
"SE": false,
"ML": false,
"Crystal": false,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
}
},
{
"Name": "Third Dawn",
"ClientVersion": null,
"ClientFlags": "Ilshenar",
"FeatureFlags": {
"None": false,
"T2A": true,
"UOR": true,
"UOTD": true,
"LBR": false,
"AOS": false,
"SixthCharacterSlot": false,
"SE": false,
"ML": false,
"EigthAge": false,
"NinthAge": false,
"TenthAge": false,
"IncreasedStorage": false,
"SeventhCharacterSlot": false,
"RoleplayFaces": false,
"TrialAccount": false,
"LiveAccount": false,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
},
"CharacterListFlags": {
"None": false,
"Unk1": false,
"OverwriteConfigButton": false,
"OneCharacterSlot": false,
"ContextMenus": true,
"SlotLimit": false,
"AOS": false,
"SixthCharacterSlot": false,
"SE": false,
"ML": false,
"Unk2": false,
"UO3DClientType": false,
"Unk3": false,
"SeventhCharacterSlot": false,
"Unk4": false,
"NewMovementSystem": false,
"NewFeluccaAreas": false
},
"HousingFlags": {
"None": true,
"AOS": false,
"SE": false,
"ML": false,
"Crystal": false,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
}
},
{
"Name": "Blackthorn's Revenge",
"ClientVersion": null,
"ClientFlags": "Ilshenar",
"FeatureFlags": {
"None": false,
"T2A": true,
"UOR": true,
"UOTD": true,
"LBR": true,
"AOS": false,
"SixthCharacterSlot": false,
"SE": false,
"ML": false,
"EigthAge": false,
"NinthAge": false,
"TenthAge": false,
"IncreasedStorage": false,
"SeventhCharacterSlot": false,
"RoleplayFaces": false,
"TrialAccount": false,
"LiveAccount": false,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
},
"CharacterListFlags": {
"None": false,
"Unk1": false,
"OverwriteConfigButton": false,
"OneCharacterSlot": false,
"ContextMenus": true,
"SlotLimit": false,
"AOS": false,
"SixthCharacterSlot": false,
"SE": false,
"ML": false,
"Unk2": false,
"UO3DClientType": false,
"Unk3": false,
"SeventhCharacterSlot": false,
"Unk4": false,
"NewMovementSystem": false,
"NewFeluccaAreas": false
},
"HousingFlags": {
"None": true,
"AOS": false,
"SE": false,
"ML": false,
"Crystal": false,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
}
},
{
"Name": "Age of Shadows",
"ClientVersion": null,
"ClientFlags": "Malas",
"FeatureFlags": {
"None": false,
"T2A": true,
"UOR": true,
"UOTD": true,
"LBR": true,
"AOS": true,
"SixthCharacterSlot": false,
"SE": false,
"ML": false,
"EigthAge": false,
"NinthAge": false,
"TenthAge": false,
"IncreasedStorage": false,
"SeventhCharacterSlot": false,
"RoleplayFaces": false,
"TrialAccount": false,
"LiveAccount": true,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
},
"CharacterListFlags": {
"None": false,
"Unk1": false,
"OverwriteConfigButton": false,
"OneCharacterSlot": false,
"ContextMenus": true,
"SlotLimit": false,
"AOS": true,
"SixthCharacterSlot": false,
"SE": false,
"ML": false,
"Unk2": false,
"UO3DClientType": false,
"Unk3": false,
"SeventhCharacterSlot": false,
"Unk4": false,
"NewMovementSystem": false,
"NewFeluccaAreas": false
},
"HousingFlags": {
"None": false,
"AOS": true,
"SE": false,
"ML": false,
"Crystal": false,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
}
},
{
"Name": "Samurai Empire",
"ClientVersion": null,
"ClientFlags": "Tokuno",
"FeatureFlags": {
"None": false,
"T2A": true,
"UOR": true,
"UOTD": true,
"LBR": true,
"AOS": true,
"SixthCharacterSlot": false,
"SE": true,
"ML": false,
"EigthAge": false,
"NinthAge": false,
"TenthAge": false,
"IncreasedStorage": false,
"SeventhCharacterSlot": false,
"RoleplayFaces": false,
"TrialAccount": false,
"LiveAccount": true,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
},
"CharacterListFlags": {
"None": false,
"Unk1": false,
"OverwriteConfigButton": false,
"OneCharacterSlot": false,
"ContextMenus": true,
"SlotLimit": false,
"AOS": true,
"SixthCharacterSlot": false,
"SE": true,
"ML": false,
"Unk2": false,
"UO3DClientType": false,
"Unk3": false,
"SeventhCharacterSlot": false,
"Unk4": false,
"NewMovementSystem": false,
"NewFeluccaAreas": false
},
"HousingFlags": {
"None": false,
"AOS": true,
"SE": true,
"ML": false,
"Crystal": false,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
}
},
{
"Name": "Mondain's Legacy",
"ClientVersion": "5.0.0a",
"ClientFlags": null,
"FeatureFlags": {
"None": false,
"T2A": true,
"UOR": true,
"UOTD": true,
"LBR": true,
"AOS": true,
"SixthCharacterSlot": false,
"SE": true,
"ML": true,
"EigthAge": false,
"NinthAge": true,
"TenthAge": false,
"IncreasedStorage": false,
"SeventhCharacterSlot": false,
"RoleplayFaces": false,
"TrialAccount": false,
"LiveAccount": true,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
},
"CharacterListFlags": {
"None": false,
"Unk1": false,
"OverwriteConfigButton": false,
"OneCharacterSlot": false,
"ContextMenus": true,
"SlotLimit": false,
"AOS": true,
"SixthCharacterSlot": false,
"SE": true,
"ML": true,
"Unk2": false,
"UO3DClientType": false,
"Unk3": false,
"SeventhCharacterSlot": false,
"Unk4": false,
"NewMovementSystem": false,
"NewFeluccaAreas": false
},
"HousingFlags": {
"None": false,
"AOS": true,
"SE": true,
"ML": true,
"Crystal": true,
"SA": false,
"HS": false,
"Gothic": false,
"Rustic": false,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
}
},
{
"Name": "Stygian Abyss",
"ClientVersion": null,
"ClientFlags": "TerMur",
"FeatureFlags": {
"None": false,
"T2A": true,
"UOR": true,
"UOTD": true,
"LBR": true,
"AOS": true,
"SixthCharacterSlot": false,
"SE": true,
"ML": true,
"EigthAge": false,
"NinthAge": true,
"TenthAge": false,
"IncreasedStorage": false,
"SeventhCharacterSlot": false,
"RoleplayFaces": false,
"TrialAccount": false,
"LiveAccount": true,
"SA": true,
"HS": false,
"Gothic": true,
"Rustic": true,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
},
"CharacterListFlags": {
"None": false,
"Unk1": false,
"OverwriteConfigButton": false,
"OneCharacterSlot": false,
"ContextMenus": true,
"SlotLimit": false,
"AOS": true,
"SixthCharacterSlot": false,
"SE": true,
"ML": true,
"Unk2": false,
"UO3DClientType": false,
"Unk3": false,
"SeventhCharacterSlot": false,
"Unk4": false,
"NewMovementSystem": false,
"NewFeluccaAreas": false
},
"HousingFlags": {
"None": false,
"AOS": true,
"SE": true,
"ML": true,
"Crystal": true,
"SA": true,
"HS": false,
"Gothic": true,
"Rustic": true,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
}
},
{
"Name": "High Seas",
"ClientVersion": "7.0.9.0",
"ClientFlags": null,
"FeatureFlags": {
"None": false,
"T2A": true,
"UOR": true,
"UOTD": true,
"LBR": true,
"AOS": true,
"SixthCharacterSlot": false,
"SE": true,
"ML": true,
"EigthAge": false,
"NinthAge": true,
"TenthAge": false,
"IncreasedStorage": false,
"SeventhCharacterSlot": false,
"RoleplayFaces": false,
"TrialAccount": false,
"LiveAccount": true,
"SA": true,
"HS": true,
"Gothic": true,
"Rustic": true,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
},
"CharacterListFlags": {
"None": false,
"Unk1": false,
"OverwriteConfigButton": false,
"OneCharacterSlot": false,
"ContextMenus": true,
"SlotLimit": false,
"AOS": true,
"SixthCharacterSlot": false,
"SE": true,
"ML": true,
"Unk2": false,
"UO3DClientType": false,
"Unk3": false,
"SeventhCharacterSlot": false,
"Unk4": false,
"NewMovementSystem": false,
"NewFeluccaAreas": false
},
"HousingFlags": {
"None": false,
"AOS": true,
"SE": true,
"ML": true,
"Crystal": true,
"SA": true,
"HS": true,
"Gothic": true,
"Rustic": true,
"Jungle": false,
"Shadowguard": false,
"TOL": false,
"EJ": false
}
},
{
"Name": "Time of Legends",
"ClientVersion": "7.0.45.65",
"ClientFlags": null,
"FeatureFlags": {
"None": false,
"T2A": true,
"UOR": true,
"UOTD": true,
"LBR": true,
"AOS": true,
"SixthCharacterSlot": false,
"SE": true,
"ML": true,
"EigthAge": false,
"NinthAge": true,
"TenthAge": false,
"IncreasedStorage": false,
"SeventhCharacterSlot": false,
"RoleplayFaces": false,
"TrialAccount": false,
"LiveAccount": true,
"SA": true,
"HS": true,
"Gothic": true,
"Rustic": true,
"Jungle": true,
"Shadowguard": true,
"TOL": true,
"EJ": false
},
"CharacterListFlags": {
"None": false,
"Unk1": false,
"OverwriteConfigButton": false,
"OneCharacterSlot": false,
"ContextMenus": true,
"SlotLimit": false,
"AOS": true,
"SixthCharacterSlot": false,
"SE": true,
"ML": true,
"Unk2": false,
"UO3DClientType": false,
"Unk3": false,
"SeventhCharacterSlot": false,
"Unk4": false,
"NewMovementSystem": false,
"NewFeluccaAreas": false
},
"HousingFlags": {
"None": false,
"AOS": true,
"SE": true,
"ML": true,
"Crystal": true,
"SA": true,
"HS": true,
"Gothic": true,
"Rustic": true,
"Jungle": true,
"Shadowguard": true,
"TOL": true,
"EJ": false
}
},
{
"Name": "Endless Journey",
"ClientVersion": "7.0.61.0",
"ClientFlags": null,
"FeatureFlags": {
"None": false,
"T2A": true,
"UOR": true,
"UOTD": true,
"LBR": true,
"AOS": true,
"SixthCharacterSlot": false,
"SE": true,
"ML": true,
"EigthAge": false,
"NinthAge": true,
"TenthAge": false,
"IncreasedStorage": false,
"SeventhCharacterSlot": false,
"RoleplayFaces": false,
"TrialAccount": false,
"LiveAccount": true,
"SA": true,
"HS": true,
"Gothic": true,
"Rustic": true,
"Jungle": true,
"Shadowguard": true,
"TOL": true,
"EJ": true
},
"CharacterListFlags": {
"None": false,
"Unk1": false,
"OverwriteConfigButton": false,
"OneCharacterSlot": false,
"ContextMenus": true,
"SlotLimit": false,
"AOS": true,
"SixthCharacterSlot": false,
"SE": true,
"ML": true,
"Unk2": false,
"UO3DClientType": false,
"Unk3": false,
"SeventhCharacterSlot": false,
"Unk4": false,
"NewMovementSystem": false,
"NewFeluccaAreas": false
},
"HousingFlags": {
"None": false,
"AOS": true,
"SE": true,
"ML": true,
"Crystal": true,
"SA": true,
"HS": true,
"Gothic": true,
"Rustic": true,
"Jungle": true,
"Shadowguard": true,
"TOL": true,
"EJ": true
}
}
]

View file

@ -1,4 +1,5 @@
using System;
using System.Reflection;
namespace Server.Tests
{
@ -7,8 +8,8 @@ namespace Server.Tests
// Global setup
static ServerFixture()
{
Core.Assembly = Assembly.GetExecutingAssembly();
Core.LoopContext = new EventLoopContext();
Core.Expansion = Expansion.EJ;
// Load Configurations

View file

@ -10,5 +10,9 @@
<PackageReference Include="Zlib.Bindings" Version="1.5.0" />
<ProjectReference Include="..\Server\Server.csproj" />
<ProjectReference Include="..\UOContent\UOContent.csproj" />
<DataFiles Include="$(SolutionDir)\Distribution\Data\**" />
</ItemGroup>
<Target Name="CopyData" AfterTargets="AfterBuild">
<Copy SourceFiles="@(DataFiles)" DestinationFolder="$(OutDir)\Data\%(RecursiveDir)" />
</Target>
</Project>

View file

@ -1,4 +1,23 @@
/*************************************************************************
* ModernUO *
* Copyright 2019-2021 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: ExpansionInfo.cs *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json.Serialization;
using Server.Json;
namespace Server
{
@ -141,105 +160,37 @@ namespace Server
{
static ExpansionInfo()
{
Table = new[]
var path = Path.Combine(Core.BaseDirectory, "Data/expansion.json");
var expansions = JsonConfig.Deserialize<List<ExpansionConfig>>(path);
Table = new ExpansionInfo[expansions.Count];
for (var i = 0; i < expansions.Count; i++)
{
new ExpansionInfo(
0,
"None",
ClientFlags.None,
FeatureFlags.ExpansionNone,
CharacterListFlags.ExpansionNone,
HousingFlags.None
),
new ExpansionInfo(
1,
"The Second Age",
ClientFlags.Felucca,
FeatureFlags.ExpansionT2A,
CharacterListFlags.ExpansionT2A,
HousingFlags.None
),
new ExpansionInfo(
2,
"Renaissance",
ClientFlags.Trammel,
FeatureFlags.ExpansionUOR,
CharacterListFlags.ExpansionUOR,
HousingFlags.None
),
new ExpansionInfo(
3,
"Third Dawn",
ClientFlags.Ilshenar,
FeatureFlags.ExpansionUOTD,
CharacterListFlags.ExpansionUOTD,
HousingFlags.None
),
new ExpansionInfo(
4,
"Blackthorn's Revenge",
ClientFlags.Ilshenar,
FeatureFlags.ExpansionLBR,
CharacterListFlags.ExpansionLBR,
HousingFlags.None
),
new ExpansionInfo(
5,
"Age of Shadows",
ClientFlags.Malas,
FeatureFlags.ExpansionAOS,
CharacterListFlags.ExpansionAOS,
HousingFlags.HousingAOS
),
new ExpansionInfo(
6,
"Samurai Empire",
ClientFlags.Tokuno,
FeatureFlags.ExpansionSE,
CharacterListFlags.ExpansionSE,
HousingFlags.HousingSE
),
new ExpansionInfo(
7,
"Mondain's Legacy",
new ClientVersion("5.0.0a"),
FeatureFlags.ExpansionML,
CharacterListFlags.ExpansionML,
HousingFlags.HousingML
),
new ExpansionInfo(
8,
"Stygian Abyss",
ClientFlags.TerMur,
FeatureFlags.ExpansionSA,
CharacterListFlags.ExpansionSA,
HousingFlags.HousingSA
),
new ExpansionInfo(
9,
"High Seas",
new ClientVersion("7.0.9.0"),
FeatureFlags.ExpansionHS,
CharacterListFlags.ExpansionHS,
HousingFlags.HousingHS
),
new ExpansionInfo(
10,
"Time of Legends",
new ClientVersion("7.0.45.65"),
FeatureFlags.ExpansionTOL,
CharacterListFlags.ExpansionTOL,
HousingFlags.HousingTOL
),
new ExpansionInfo(
11,
"Endless Journey",
new ClientVersion("7.0.61.0"),
FeatureFlags.ExpansionEJ,
CharacterListFlags.ExpansionEJ,
HousingFlags.HousingEJ
)
};
var expansion = expansions[i];
if (expansion.ClientVersion != null)
{
Table[i] = new ExpansionInfo(
i,
expansion.Name,
expansion.ClientVersion,
expansion.FeatureFlags,
expansion.CharacterListFlags,
expansion.HousingFlags
);
}
else
{
Table[i] = new ExpansionInfo(
i,
expansion.Name,
expansion.ClientFlags ?? ClientFlags.None,
expansion.FeatureFlags,
expansion.CharacterListFlags,
expansion.HousingFlags
);
}
}
}
public ExpansionInfo(
@ -331,4 +282,22 @@ namespace Server
public override string ToString() => Name;
}
public record ExpansionConfig
{
public string Name { get; init; }
public ClientVersion? ClientVersion { get; init; }
public ClientFlags? ClientFlags { get; init; }
[JsonConverter(typeof(FlagsConverter<FeatureFlags>))]
public FeatureFlags FeatureFlags { get; init; }
[JsonConverter(typeof(FlagsConverter<CharacterListFlags>))]
public CharacterListFlags CharacterListFlags { get; init; }
[JsonConverter(typeof(FlagsConverter<HousingFlags>))]
public HousingFlags HousingFlags { get; init; }
}
}

View file

@ -0,0 +1,37 @@
/*************************************************************************
* ModernUO *
* Copyright 2021 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: ClientVersionConverter.cs *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Server.Json
{
public class ClientVersionConverter : JsonConverter<ClientVersion>
{
public override ClientVersion Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
{
return new ClientVersion(reader.GetString());
}
throw new JsonException($"Value must be a string");
}
public override void Write(Utf8JsonWriter writer, ClientVersion value, JsonSerializerOptions options) =>
writer.WriteStringValue(value.ToString());
}
}

View file

@ -0,0 +1,30 @@
/*************************************************************************
* ModernUO *
* Copyright 2019-2021 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: ClientVersionConverterFactory.cs *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
using System.Net;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Server.Json
{
public class ClientVersionConverterFactory : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(ClientVersion);
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) =>
new ClientVersionConverter();
}
}

View file

@ -0,0 +1,149 @@
/*************************************************************************
* ModernUO *
* Copyright 2021 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: FlagsConverter.cs *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Server.Json
{
public class FlagsConverter<T> : JsonConverter<T> where T : struct, Enum
{
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var flags = 0ul;
var underlyingType = Enum.GetUnderlyingType(typeof(T));
while (true)
{
reader.Read();
if (reader.TokenType == JsonTokenType.EndObject)
{
break;
}
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException("Invalid Json structure for Flag object");
}
var key = reader.GetString();
reader.Read();
if (!reader.GetBoolean() || !Enum.TryParse<T>(key, out var val))
{
continue;
}
flags |= ConvertToUInt64(underlyingType, val);
}
switch (Type.GetTypeCode(underlyingType))
{
case TypeCode.SByte:
{
var num = (sbyte)flags;
return Unsafe.As<sbyte, T>(ref num);
}
case TypeCode.Byte:
{
var num = (byte)flags;
return Unsafe.As<byte, T>(ref num);
}
case TypeCode.Int16:
{
var num = (short)flags;
return Unsafe.As<short, T>(ref num);
}
case TypeCode.UInt16:
{
var num = (ushort)flags;
return Unsafe.As<ushort, T>(ref num);
}
case TypeCode.UInt32:
{
var num = (uint)flags;
return Unsafe.As<uint, T>(ref num);
}
case TypeCode.Int64:
{
var num = (long)flags;
return Unsafe.As<long, T>(ref num);
}
case TypeCode.UInt64:
{
return Unsafe.As<ulong, T>(ref flags);
}
default:
{
var num = (int)flags;
return Unsafe.As<int, T>(ref num);
}
}
}
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
writer.WriteStartObject();
var underlyingType = Enum.GetUnderlyingType(typeof(T));
var size = GetUnderlyingTypeLength(Type.GetTypeCode(underlyingType)) - 1;
var intValue = ConvertToUInt64(underlyingType, value);
foreach (var flagName in Enum.GetNames(typeof(T)))
{
var flagValue = Enum.Parse<T>(flagName, false);
var flag = ConvertToUInt64(underlyingType, flagValue);
if (flag == 0 || (flag & size) == 0)
{
writer.WriteBoolean(flagName, (intValue & flag) != 0);
}
}
writer.WriteEndObject();
}
private static ulong ConvertToUInt64(Type underlyingType, object value) =>
Type.GetTypeCode(underlyingType) switch
{
TypeCode.SByte => (ulong)(sbyte)value,
TypeCode.Byte => (byte)value,
TypeCode.Int16 => (ulong)(short)value,
TypeCode.UInt16 => (ushort)value,
TypeCode.Int32 => (ulong)(int)value,
TypeCode.UInt32 => (uint)value,
TypeCode.Int64 => (ulong)(long)value,
TypeCode.UInt64 => (ulong)value,
_ => throw new InvalidOperationException()
};
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong GetUnderlyingTypeLength(TypeCode typeCode) =>
typeCode switch
{
TypeCode.Byte => 8,
TypeCode.SByte => 8,
TypeCode.Int16 => 16,
TypeCode.UInt16 => 16,
TypeCode.Char => 16,
TypeCode.Int32 => 32,
TypeCode.UInt32 => 32,
TypeCode.Int64 => 64,
TypeCode.UInt64 => 64,
_ => 64
};
}
}

View file

@ -39,6 +39,7 @@ namespace Server.Json
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
options.Converters.Add(new ClientVersionConverterFactory());
options.Converters.Add(new GuidConverterFactory());
options.Converters.Add(new JsonStringEnumConverter());
options.Converters.Add(new MapConverterFactory());