Skip to content

Commit 7588680

Browse files
committed
Added default value parsing
1 parent 5e0b0f0 commit 7588680

File tree

5 files changed

+164
-44
lines changed

5 files changed

+164
-44
lines changed
Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
1+
using System.Text.Json.Nodes;
12
using Microsoft.Data.Sqlite;
23

34
namespace TreeHouse.OtherParams.JsonConverter;
45

56
public class ContentDbJsonConverter : DbJsonConverterBase
67
{
7-
public ContentDbJsonConverter(ParamSetJsonConverter converter, bool validateClasses = true)
8-
: base(converter, "guid", "data", validateClasses ? "ixClass" : null)
8+
private readonly DefaultValueProvider<int>? defaultValueProvider;
9+
10+
public ContentDbJsonConverter(ParamSetJsonConverter converter, DefaultValueProvider<int>? defaultValueProvider, bool validateClasses = true) : base(
11+
converter: converter,
12+
keyColumn: "guid",
13+
dataColumn: "data",
14+
extraColumns: validateClasses || defaultValueProvider != null ? [ "ixClass" ] : [],
15+
ordClassIdColumn: validateClasses ? OrdExtraOffset + 0 : null
16+
)
917
{
18+
this.defaultValueProvider = defaultValueProvider;
1019
}
1120

21+
protected override JsonObject GetDefaultJson(string table, SqliteDataReader reader) =>
22+
defaultValueProvider != null ? defaultValueProvider.GetDefault(reader.GetInt32(OrdExtraOffset + 0)) : new JsonObject();
23+
1224
public void ReadParamSets(SqliteConnection connection, Model.Table table) =>
1325
ReadParamSetsForTable(connection, table.Name);
1426
}

TreeHouse.OtherParams/JsonConverter/DbJsonConverterBase.cs

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,43 +13,33 @@ namespace TreeHouse.OtherParams.JsonConverter;
1313

1414
public abstract class DbJsonConverterBase
1515
{
16-
private readonly ParamSetJsonConverter converter;
16+
protected const int OrdKeyColumn = 0;
17+
protected const int OrdDataColumn = 1;
18+
protected const int OrdExtraOffset = 2;
1719

18-
private readonly string keyColumn;
19-
private readonly string dataColumn;
20-
private readonly string? classIdColumn;
21-
private readonly string? extraColumn;
20+
protected readonly ParamSetJsonConverter converter;
21+
22+
private readonly string columns;
23+
protected readonly string keyColumn;
24+
protected readonly int? ordClassIdColumn;
2225

2326
private readonly Dictionary<string, Dictionary<Guid, JsonObject>> paramSetsJson = new();
2427

2528
private readonly byte[] commonBlobBuffer = new byte[100 * 2^10];
2629

27-
protected DbJsonConverterBase(ParamSetJsonConverter converter, string keyColumn, string dataColumn, string? classIdColumn, string? extraColumn = null)
30+
protected DbJsonConverterBase(ParamSetJsonConverter converter, string keyColumn, string dataColumn, IEnumerable<string> extraColumns, int? ordClassIdColumn)
2831
{
2932
this.converter = converter;
3033
this.keyColumn = keyColumn;
31-
this.dataColumn = dataColumn;
32-
this.classIdColumn = classIdColumn;
33-
this.extraColumn = extraColumn;
34+
this.ordClassIdColumn = ordClassIdColumn;
35+
36+
columns = string.Join(", ", new[] { keyColumn, dataColumn }.Concat(extraColumns));
3437
}
3538

3639
protected void ReadParamSetsForTable(SqliteConnection connection, string table)
3740
{
38-
int extraOrd = 2;
39-
40-
StringBuilder commandBuilder = new();
41-
commandBuilder.Append($"SELECT {keyColumn}, {dataColumn}");
42-
if (classIdColumn != null)
43-
{
44-
commandBuilder.Append($", {classIdColumn}");
45-
extraOrd = 3;
46-
}
47-
if (extraColumn != null)
48-
commandBuilder.Append($", {extraColumn}");
49-
commandBuilder.Append($" FROM {table}");
50-
5141
using SqliteCommand command = connection.CreateCommand();
52-
command.CommandText = commandBuilder.ToString();
42+
command.CommandText = $"SELECT {columns} FROM {table}";
5343

5444
using SqliteDataReader reader = command.ExecuteReader();
5545

@@ -59,12 +49,13 @@ protected void ReadParamSetsForTable(SqliteConnection connection, string table)
5949

6050
try
6151
{
62-
key = Guid.Parse(reader.GetString(0));
63-
int? classId = classIdColumn != null ? reader.GetInt32(2) : null;
64-
string? extra = extraColumn != null ? reader.GetString(extraOrd) : null;
52+
key = Guid.Parse(reader.GetString(OrdKeyColumn));
53+
int? classId = ordClassIdColumn != null ? reader.GetInt32(ordClassIdColumn.Value) : null;
6554

66-
using Stream dataBlob = reader.GetStream(1);
67-
ReadFromBlob(table, key, dataBlob, classId, extra);
55+
JsonObject json = GetDefaultJson(table, reader);
56+
57+
using Stream dataBlob = reader.GetStream(OrdDataColumn);
58+
ReadFromBlob(json, table, key, dataBlob, classId);
6859
}
6960
catch (Exception e)
7061
{
@@ -73,12 +64,10 @@ protected void ReadParamSetsForTable(SqliteConnection connection, string table)
7364
}
7465
}
7566

76-
protected virtual JsonObject GetDefaultJson(string table, Guid key, int? classId, string? extra) => new JsonObject();
67+
protected virtual JsonObject GetDefaultJson(string table, SqliteDataReader reader) => new JsonObject();
7768

78-
private void ReadFromBlob(string table, Guid key, Stream blob, int? classId, string? extra)
69+
private void ReadFromBlob(JsonObject json, string table, Guid key, Stream blob, int? classId)
7970
{
80-
JsonObject json = GetDefaultJson(table, key, classId, extra);
81-
8271
byte[] blobBuffer = commonBlobBuffer;
8372

8473
int blobLength = (int)blob.Length;
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text.Json.Nodes;
5+
using System.Threading.Tasks;
6+
using Microsoft.EntityFrameworkCore;
7+
8+
namespace TreeHouse.OtherParams.JsonConverter;
9+
10+
public static class DefaultValueParser
11+
{
12+
private delegate JsonNode? JsonParser(string s);
13+
14+
private static readonly Dictionary<ParamType, JsonParser> JsonReaders = new()
15+
{
16+
[ParamType.Float] = ReadFloat,
17+
[ParamType.String] = ReadString,
18+
[ParamType.JSON] = s => JsonNode.Parse(s.Replace("\\\"", "\"")),
19+
[ParamType.ContentRef] = ReadString,
20+
[ParamType.ContentRefAndInt] = ReadString,
21+
[ParamType.ContentRefList] = ReadString,
22+
[ParamType.InstanceGroup] = ReadString,
23+
[ParamType.Int] = ReadInt,
24+
[ParamType.Int64] = s => JsonValue.Create(long.Parse(s)),
25+
[ParamType.AvatarID] = s => s == "#0" ? JsonValue.Create(0) : throw new FormatException($"Don't know how to parse non-zero AvatarID"),
26+
[ParamType.Bool] = s => JsonValue.Create(bool.Parse(s)),
27+
[ParamType.Guid] = ReadGuid,
28+
[ParamType.LocalizedString] = ReadGuid,
29+
[ParamType.FloatRange] = s => ReadArray(s, ReadFloat),
30+
[ParamType.Vector3] = s => ReadArray(s, ReadFloat, ' '),
31+
[ParamType.IntVector] = s => ReadArray(s, ReadInt),
32+
[ParamType.StringVector] = s => ReadArray(s, ReadString),
33+
[ParamType.LocalizedStringVector] = s => ReadArray(s, ReadGuid),
34+
[ParamType.BitSetFilter] = s => s.All(x => x == '0') ? JsonValue.Create(0) : throw new FormatException($"Don't know how to parse non-zero BitSetFilter")
35+
};
36+
37+
private static JsonValue ReadString(string s) => JsonValue.Create(s);
38+
39+
private static JsonValue ReadFloat(string s) => JsonValue.Create(float.Parse(s));
40+
41+
private static JsonValue ReadInt(string s) => JsonValue.Create(int.Parse(s));
42+
43+
private static JsonValue ReadGuid(string s) => JsonValue.Create(Guid.Parse(s));
44+
45+
private static JsonArray ReadArray(string s, Func<string, JsonValue> readItem, char separator = ',') => new JsonArray(s
46+
.Split(separator, StringSplitOptions.RemoveEmptyEntries)
47+
.Select(x =>
48+
readItem(x.Trim(' ', '[', ']'))
49+
)
50+
.ToArray()
51+
);
52+
53+
private static JsonNode? ParseDefaultValue(int paramId, ParamType type, string defaultValue)
54+
{
55+
try
56+
{
57+
if (!JsonReaders.TryGetValue(type, out JsonParser? parser))
58+
throw new FormatException($"Don't know how to parse default value of type {type}");
59+
60+
return parser(defaultValue);
61+
}
62+
catch (Exception e)
63+
{
64+
throw new FormatException($"Failed to parse default value for param definition {paramId} of type {type}: {defaultValue}", e);
65+
}
66+
}
67+
68+
public static async Task<DefaultValueProvider<int>> CreateProvider(ParamDb db) => new DefaultValueProvider<int>(
69+
await db.Classes
70+
.Include(x => x.DeclaredParams)
71+
.ThenInclude(x => x.Definition)
72+
.ToDictionaryAsync(
73+
x => x.UniqueId,
74+
x => new JsonObject(
75+
x.DeclaredParams
76+
.Where(p => p.Definition.Default != null)
77+
.Select(p => new KeyValuePair<string, JsonNode?>(
78+
p.Definition.Name,
79+
ParseDefaultValue(p.ParamId, p.Definition.TypeId, p.Definition.Default!)
80+
))
81+
)
82+
)
83+
);
84+
}
Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,41 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text.Json.Nodes;
14
using Microsoft.Data.Sqlite;
25

36
namespace TreeHouse.OtherParams.JsonConverter;
47

58
public class InstanceDbJsonConverter : DbJsonConverterBase
69
{
7-
public InstanceDbJsonConverter(ParamSetJsonConverter converter, bool validateClasses = true)
8-
: base(converter, "uxInstanceGuid", "data", validateClasses ? "ixClass" : null)
10+
private readonly DefaultValueProvider<Guid>? defaultValueProvider;
11+
12+
public InstanceDbJsonConverter(ParamSetJsonConverter converter, DefaultValueProvider<Guid>? defaultValueProvider, bool validateClasses = true) : base(
13+
converter: converter,
14+
keyColumn: "uxInstanceGuid",
15+
dataColumn: "data",
16+
ExtraColumns(validateClasses, defaultValueProvider != null),
17+
validateClasses ? OrdExtraOffset + 0 : null
18+
)
919
{
20+
this.defaultValueProvider = defaultValueProvider;
1021
}
1122

23+
private static IEnumerable<string> ExtraColumns(bool validateClasses, bool provideDefaults)
24+
{
25+
if (validateClasses)
26+
yield return "ixClass";
27+
if (provideDefaults)
28+
yield return "uxContentGuid";
29+
}
30+
31+
protected override JsonObject GetDefaultJson(string table, SqliteDataReader reader) =>
32+
defaultValueProvider != null
33+
? defaultValueProvider.GetDefault(
34+
Guid.Parse(reader.GetString(
35+
ordClassIdColumn == null ? OrdExtraOffset + 0 : OrdExtraOffset + 1
36+
))
37+
)
38+
: new JsonObject();
39+
1240
public void ReadParamSets(SqliteConnection connection) => ReadParamSetsForTable(connection, "Instance");
1341
}

TreeHouse.OtherParams/Program.cs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
new Option<FileInfo>(["--instance-db", "-i"]).ExistingOnly(),
3030
new Option<bool>("--write-jsonb"),
3131
new Option<bool>("--write-unformatted"),
32-
new Option<bool>("--no-write-json")
32+
new Option<bool>("--no-write-json"),
33+
new Option<bool>("--no-defaults")
3334
}.WithHandler(JsonConvertHandler)
3435
}
3536
.InvokeAsync(args);
@@ -55,7 +56,7 @@ async Task PrintHandler(FileInfo paramDb, FileInfo output)
5556
await template.RenderAsync(writer);
5657
}
5758

58-
async Task JsonConvertHandler(FileInfo paramDb, FileInfo? contentDb, FileInfo? instanceDb, bool writeJsonb, bool writeUnformatted, bool noWriteJson)
59+
async Task JsonConvertHandler(FileInfo paramDb, FileInfo? contentDb, FileInfo? instanceDb, bool writeJsonb, bool writeUnformatted, bool noWriteJson, bool noDefaults)
5960
{
6061
if (contentDb == null && instanceDb == null)
6162
{
@@ -66,22 +67,26 @@ async Task JsonConvertHandler(FileInfo paramDb, FileInfo? contentDb, FileInfo? i
6667
using ParamDb db = ParamDb.Open(paramDb.FullName);
6768
ParamSetJsonConverter converter = await ParamSetJsonConverter.CreateInstance(db);
6869

70+
ContentDbJsonConverter? contentDbConverter = null;
71+
6972
if (contentDb != null)
7073
{
74+
DefaultValueProvider<int>? paramDefaultsProvider = noDefaults ? null : await DefaultValueParser.CreateProvider(db);
75+
7176
using SqliteConnection connection = SqliteUtils.Open(contentDb.FullName, write: true);
72-
ContentDbJsonConverter dbConverter = new(converter);
77+
contentDbConverter = new(converter, paramDefaultsProvider);
7378

7479
Console.WriteLine("Reading content db...");
7580

7681
foreach (Table table in await db.Tables.ToListAsync())
7782
{
7883
Console.WriteLine($"Reading table {table.Name}...");
79-
dbConverter.ReadParamSets(connection, table);
84+
contentDbConverter.ReadParamSets(connection, table);
8085
}
8186

8287
Console.WriteLine("Writing json to content db...");
8388

84-
dbConverter.WriteParamSetsJson(
89+
contentDbConverter.WriteParamSetsJson(
8590
connection: connection,
8691
writeJson: !noWriteJson,
8792
formatJson: !writeUnformatted,
@@ -91,16 +96,18 @@ async Task JsonConvertHandler(FileInfo paramDb, FileInfo? contentDb, FileInfo? i
9196

9297
if (instanceDb != null)
9398
{
99+
DefaultValueProvider<Guid>? contentDefaultsProvider = noDefaults ? null : contentDbConverter?.GetDefaultValueProvider();
100+
94101
using SqliteConnection connection = SqliteUtils.Open(instanceDb.FullName, write: true);
95-
InstanceDbJsonConverter dbConverter = new(converter);
102+
InstanceDbJsonConverter instanceDbConverter = new(converter, contentDefaultsProvider);
96103

97104
Console.WriteLine("Reading instance db...");
98105

99-
dbConverter.ReadParamSets(connection);
106+
instanceDbConverter.ReadParamSets(connection);
100107

101108
Console.WriteLine("Writing json to instance db...");
102109

103-
dbConverter.WriteParamSetsJson(
110+
instanceDbConverter.WriteParamSetsJson(
104111
connection: connection,
105112
writeJson: !noWriteJson,
106113
formatJson: !writeUnformatted,

0 commit comments

Comments
 (0)