From 553c9d552be2f3ab62671e8b43a434086b29165f Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Wed, 5 Mar 2025 00:07:25 -0600 Subject: [PATCH] feat: human ids --- .../src/protos/legacy_game_definitions.ts | 2 +- packages/core/src/protos/legacy_i18n.ts | 2 +- .../src/protos/legacy_tank_definitions.ts | 2 +- packages/core/src/protos/tank.proto | 3 +- packages/core/src/protos/tank.ts | 21 +- packages/core/src/protos/tanks.proto | 1 - packages/core/src/protos/tanks.ts | 23 +-- packages/i18n/locales.json | 14 ++ src/BlitzKit.CLI/BlitzKit.CLI.csproj | 1 + src/BlitzKit.CLI/Functions/Mangler.cs | 180 ++++++++++-------- src/BlitzKit.CLI/Functions/Unpacker.cs | 6 +- src/BlitzKit.CLI/Protos/Tank.cs | 64 ++++++- src/BlitzKit.CLI/Protos/Tanks.cs | 55 +----- src/BlitzKit.CLI/Quicktype/DLCManifest.cs | 6 +- src/BlitzKit.CLI/Quicktype/Locales.cs | 176 +++++++++++++++++ submodules/blitzkit-closed | 2 +- 16 files changed, 381 insertions(+), 177 deletions(-) create mode 100644 packages/i18n/locales.json create mode 100644 src/BlitzKit.CLI/Quicktype/Locales.cs diff --git a/packages/core/src/protos/legacy_game_definitions.ts b/packages/core/src/protos/legacy_game_definitions.ts index 71762e823..17b87dea1 100644 --- a/packages/core/src/protos/legacy_game_definitions.ts +++ b/packages/core/src/protos/legacy_game_definitions.ts @@ -6,7 +6,7 @@ /* eslint-disable */ import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; -import { I18nString, createBaseI18nString } from "./legacy_i18n"; +import { I18nString } from "./legacy_i18n"; export const protobufPackage = "blitzkit"; diff --git a/packages/core/src/protos/legacy_i18n.ts b/packages/core/src/protos/legacy_i18n.ts index bc7203097..1faf016f7 100644 --- a/packages/core/src/protos/legacy_i18n.ts +++ b/packages/core/src/protos/legacy_i18n.ts @@ -18,7 +18,7 @@ export interface I18nString_LocalesEntry { value: string; } -export function createBaseI18nString(): I18nString { +function createBaseI18nString(): I18nString { return { locales: {} }; } diff --git a/packages/core/src/protos/legacy_tank_definitions.ts b/packages/core/src/protos/legacy_tank_definitions.ts index 664b00f74..ff622dff0 100644 --- a/packages/core/src/protos/legacy_tank_definitions.ts +++ b/packages/core/src/protos/legacy_tank_definitions.ts @@ -6,7 +6,7 @@ /* eslint-disable */ import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; -import { I18nString, createBaseI18nString } from "./legacy_i18n"; +import { I18nString } from "./legacy_i18n"; export const protobufPackage = "blitzkit"; diff --git a/packages/core/src/protos/tank.proto b/packages/core/src/protos/tank.proto index f198d5c9e..0ca01f268 100644 --- a/packages/core/src/protos/tank.proto +++ b/packages/core/src/protos/tank.proto @@ -6,5 +6,6 @@ package blitzkit; message Tank { required string id = 1; - required I18n name = 2; + required string seo_id = 2; + required I18n name = 3; } \ No newline at end of file diff --git a/packages/core/src/protos/tank.ts b/packages/core/src/protos/tank.ts index 0f074d05b..612dc1113 100644 --- a/packages/core/src/protos/tank.ts +++ b/packages/core/src/protos/tank.ts @@ -12,11 +12,12 @@ export const protobufPackage = "blitzkit"; export interface Tank { id: string; + seo_id: string; name: I18n; } function createBaseTank(): Tank { - return { id: "", name: createBaseI18n() }; + return { id: "", seo_id: "", name: createBaseI18n() }; } export const Tank: MessageFns = { @@ -24,8 +25,11 @@ export const Tank: MessageFns = { if (message.id !== "") { writer.uint32(10).string(message.id); } + if (message.seo_id !== "") { + writer.uint32(18).string(message.seo_id); + } if (message.name !== undefined) { - I18n.encode(message.name, writer.uint32(18).fork()).join(); + I18n.encode(message.name, writer.uint32(26).fork()).join(); } return writer; }, @@ -50,6 +54,14 @@ export const Tank: MessageFns = { break; } + message.seo_id = reader.string(); + continue; + } + case 3: { + if (tag !== 26) { + break; + } + message.name = I18n.decode(reader, reader.uint32()); continue; } @@ -65,6 +77,7 @@ export const Tank: MessageFns = { fromJSON(object: any): Tank { return { id: globalThis.String(assertSet("Tank.id", object.id)), + seo_id: globalThis.String(assertSet("Tank.seo_id", object.seo_id)), name: I18n.fromJSON(assertSet("Tank.name", object.name)), }; }, @@ -74,6 +87,9 @@ export const Tank: MessageFns = { if (message.id !== "") { obj.id = message.id; } + if (message.seo_id !== "") { + obj.seo_id = message.seo_id; + } if (message.name !== undefined) { obj.name = I18n.toJSON(message.name); } @@ -86,6 +102,7 @@ export const Tank: MessageFns = { fromPartial, I>>(object: I): Tank { const message = createBaseTank(); message.id = object.id ?? ""; + message.seo_id = object.seo_id ?? ""; message.name = (object.name !== undefined && object.name !== null) ? I18n.fromPartial(object.name) : createBaseI18n(); diff --git a/packages/core/src/protos/tanks.proto b/packages/core/src/protos/tanks.proto index d343924a4..2db0a5ad9 100644 --- a/packages/core/src/protos/tanks.proto +++ b/packages/core/src/protos/tanks.proto @@ -8,5 +8,4 @@ message Tanks { message TankMeta { required string id = 1; - required string seo_id = 2; } \ No newline at end of file diff --git a/packages/core/src/protos/tanks.ts b/packages/core/src/protos/tanks.ts index 157095201..03e63963d 100644 --- a/packages/core/src/protos/tanks.ts +++ b/packages/core/src/protos/tanks.ts @@ -15,7 +15,6 @@ export interface Tanks { export interface TankMeta { id: string; - seo_id: string; } function createBaseTanks(): Tanks { @@ -77,7 +76,7 @@ export const Tanks: MessageFns = { }; function createBaseTankMeta(): TankMeta { - return { id: "", seo_id: "" }; + return { id: "" }; } export const TankMeta: MessageFns = { @@ -85,9 +84,6 @@ export const TankMeta: MessageFns = { if (message.id !== "") { writer.uint32(10).string(message.id); } - if (message.seo_id !== "") { - writer.uint32(18).string(message.seo_id); - } return writer; }, @@ -106,14 +102,6 @@ export const TankMeta: MessageFns = { message.id = reader.string(); continue; } - case 2: { - if (tag !== 18) { - break; - } - - message.seo_id = reader.string(); - continue; - } } if ((tag & 7) === 4 || tag === 0) { break; @@ -124,10 +112,7 @@ export const TankMeta: MessageFns = { }, fromJSON(object: any): TankMeta { - return { - id: globalThis.String(assertSet("TankMeta.id", object.id)), - seo_id: globalThis.String(assertSet("TankMeta.seo_id", object.seo_id)), - }; + return { id: globalThis.String(assertSet("TankMeta.id", object.id)) }; }, toJSON(message: TankMeta): unknown { @@ -135,9 +120,6 @@ export const TankMeta: MessageFns = { if (message.id !== "") { obj.id = message.id; } - if (message.seo_id !== "") { - obj.seo_id = message.seo_id; - } return obj; }, @@ -147,7 +129,6 @@ export const TankMeta: MessageFns = { fromPartial, I>>(object: I): TankMeta { const message = createBaseTankMeta(); message.id = object.id ?? ""; - message.seo_id = object.seo_id ?? ""; return message; }, }; diff --git a/packages/i18n/locales.json b/packages/i18n/locales.json new file mode 100644 index 000000000..488c43563 --- /dev/null +++ b/packages/i18n/locales.json @@ -0,0 +1,14 @@ +{ + "default": "en", + "supported": [ + { "locale": "en" }, + { "locale": "es" }, + { "locale": "fr" }, + { "locale": "ja" }, + { "locale": "pl" }, + { "locale": "pt" }, + { "locale": "ru" }, + { "locale": "uk" }, + { "locale": "zh", "blitz": "zh_Hans_SG" } + ] +} diff --git a/src/BlitzKit.CLI/BlitzKit.CLI.csproj b/src/BlitzKit.CLI/BlitzKit.CLI.csproj index d50d97098..decec886e 100644 --- a/src/BlitzKit.CLI/BlitzKit.CLI.csproj +++ b/src/BlitzKit.CLI/BlitzKit.CLI.csproj @@ -16,5 +16,6 @@ + diff --git a/src/BlitzKit.CLI/Functions/Mangler.cs b/src/BlitzKit.CLI/Functions/Mangler.cs index d8b740347..731b17513 100644 --- a/src/BlitzKit.CLI/Functions/Mangler.cs +++ b/src/BlitzKit.CLI/Functions/Mangler.cs @@ -1,9 +1,12 @@ using System.Data; using System.Text; +using System.Text.Json; using System.Text.RegularExpressions; using System.Text.Unicode; +using System.Threading.Tasks; using Blitzkit; using BlitzKit.CLI.Models; +using BlitzKit.CLI.Quicktype.Locales; using BlitzKit.CLI.Utils; using CUE4Parse.UE4.Assets.Exports; using CUE4Parse.UE4.Assets.Exports.Engine; @@ -14,27 +17,86 @@ using CUE4Parse.UE4.Pak.Objects; using Google.Protobuf; using Google.Protobuf.Collections; using Newtonsoft.Json.Linq; +using YamlDotNet.Serialization; namespace BlitzKit.CLI.Functions { public class Mangler(string[] args) { readonly BlitzProvider provider = new(args.Contains("--depot")); + Locales? locales; readonly List changes = []; + readonly Dictionary> strings = []; public async Task Mangle() { - var nationDirs = provider.RootDirectory.GetDirectory("Blitz/Content/Tanks").Directories; + await FetchStrings(); + MangleNations(); + // await BlitzKitAssets.CommitAssets("ue assets", changes); + } - foreach (var nationDir in nationDirs) + I18n GetString(string name) + { + I18n i18n = new(); + + if (strings[locales!.Default].TryGetValue(name, out var defaultString)) { - if (nationDir.Key == "TankStub") - continue; - - MangleNation(nationDir.Value); + foreach (var locale in locales!.Supported) + { + if (strings[locale.Locale].TryGetValue(name, out var localeString)) + { + if (locale.Locale == locales.Default || localeString != defaultString) + { + i18n.Locales[locale.Locale] = localeString; + } + } + else + { + PrettyLog.Warn($"String missing from {locale.Locale} locale: {name}"); + } + } + } + else + { + PrettyLog.Warn($"String missing from default locale: {name}"); + i18n.Locales[locales!.Default] = name; } - await BlitzKitAssets.CommitAssets("ue assets", changes); + return i18n; + } + + async Task FetchStrings() + { + using var client = new HttpClient(); + var text = File.ReadAllText("../../packages/i18n/locales.json"); + this.locales = + JsonSerializer.Deserialize(text) + ?? throw new Exception("Failed to deserialize locales"); + + foreach (var locale in locales.Supported) + { + var blitzLocale = locale.Blitz ?? locale.Locale; + var url = + $"{Unpacker.WG_DLC_DOMAIN}/dlc/{Unpacker.CONTENT_GROUP}/ue_localizations/development/general/{blitzLocale}.yaml"; + var yaml = await client.GetStringAsync(url); + var deserializer = new DeserializerBuilder().Build(); + var parsedYaml = deserializer.Deserialize>(yaml); + + strings[locale.Locale] = parsedYaml; + } + } + + void MangleNations() + { + var dirs = provider.RootDirectory.GetDirectory("Blitz/Content/Tanks").Directories; + + foreach (var dir in dirs) + { + if (dir.Key == "TankStub") + continue; + + MangleNation(dir.Value); + } } void MangleNation(VFS nation) @@ -48,25 +110,12 @@ namespace BlitzKit.CLI.Functions var tank = MangleTank(tankDir.Value); - if (!tank.Name.Locales.TryGetValue("en", out var nameEn)) - { - throw new Exception($"Failed to get name for {tankDir.Value.Name}"); - } - - var seoId = Diacritics.Remove(nameEn).ToLower(); - seoId = Regex.Replace(seoId, "[^a-z0-9]", "-"); - seoId = Regex.Replace(seoId, "--+", "-"); - seoId = Regex.Replace(seoId, "-$", ""); - - Console.WriteLine($"{nameEn} -> {seoId}"); - - TankMeta tankMeta = new() { Id = tank.Id, SeoId = seoId }; + TankMeta tankMeta = new() { Id = tank.Id }; tanks.Tanks_.Add(tankMeta); } - FileChange change = new("definitions/tanks.pb", tanks.ToByteArray()); - changes.Add(change); + changes.Add(new("definitions/tanks.pb", tanks.ToByteArray())); } Tank MangleTank(VFS tankDir) @@ -74,9 +123,33 @@ namespace BlitzKit.CLI.Functions var pdaName = $"PDA_{tankDir.Name}"; var pda = provider.LoadObject($"{tankDir.Path}/{pdaName}.{pdaName}"); - var tankId = PropertyUtil.Get(pda, "TankId").Text; - Console.WriteLine($"Mangling {tankId}..."); + var id = PropertyUtil.Get(pda, "TankId").Text; + var name = GetString($"{id}_SHORT_NAME"); + + var seoId = Diacritics.Remove(name.Locales["en"]).ToLower(); + seoId = Regex.Replace(seoId, "[^a-z0-9]", "-"); + seoId = Regex.Replace(seoId, "--+", "-"); + seoId = Regex.Replace(seoId, "-$", ""); + + // MangleHull(id, pda); + + Console.WriteLine(seoId); + + Tank tank = new() + { + Id = id, + Name = name, + SeoId = seoId, + }; + + changes.Add(new($"definitions/tanks/{id}.pb", tank.ToByteArray())); + + return tank; + } + + void MangleHull(string tankId, UObject pda) + { var hulls = PropertyUtil.Get(pda, "DT_Hulls"); UDataTableUtility.TryGetDataTableRow(hulls, "hull", StringComparison.Ordinal, out var hull); var hullVisualData = PropertyUtil.Get(hull, "VisualData"); @@ -85,65 +158,6 @@ namespace BlitzKit.CLI.Functions MonoGltf hullCollisionGltf = new(hullCollision); changes.Add(new($"tanks/{tankId}/collision/hull.glb", hullCollisionGltf.Write())); - - I18n Name = new(); - Name.Locales.Add("en", tankId); - - return new() { Id = tankId, Name = Name }; - } - - Dictionary CrewTypes = new() - { - { "EModuleOrTankmen::Commander", CrewType.Commander }, - { "EModuleOrTankmen::Driver", CrewType.Driver }, - { "EModuleOrTankmen::Gunner1", CrewType.Gunner1 }, - { "EModuleOrTankmen::Gunner2", CrewType.Gunner2 }, - { "EModuleOrTankmen::Loader1", CrewType.Loader1 }, - { "EModuleOrTankmen::Loader2", CrewType.Loader2 }, - }; - - void MangleCrewHealth(RepeatedField map, JArray array) - { - foreach (var member in array.Cast()) - { - var key = member["Key"]!.Value()!; - - if (CrewTypes.TryGetValue(key, out var crewType)) - { - CrewHealth crewHealth = new() - { - Type = crewType, - MaxHealth = member["Value"]!["MaxHealth"]!.Value(), - }; - map.Add(crewHealth); - } - else - { - throw new Exception($"Unrecognized CrewType: {key}"); - } - } - } - - ModuleHealth MangleModuleHealth(JObject obj) - { - ModuleHealth moduleHealth = new() - { - MaxHealth = obj["MaxHealth"]!.Value(), - MaxRegenHealth = obj["MaxRegenHealth"]!.Value(), - HealthRegenPerSec = obj["HealthRegenPerSec"]!.Value(), - }; - - if (obj.TryGetValue("HysteresisHealth", out var hysteresis)) - { - moduleHealth.HysteresisHealth = hysteresis.Value(); - } - - if (obj.TryGetValue("HealthBurnPerSec", out var burn)) - { - moduleHealth.HealthBurnPerSec = burn.Value(); - } - - return moduleHealth; } } } diff --git a/src/BlitzKit.CLI/Functions/Unpacker.cs b/src/BlitzKit.CLI/Functions/Unpacker.cs index 371fb0d31..5f8f37685 100644 --- a/src/BlitzKit.CLI/Functions/Unpacker.cs +++ b/src/BlitzKit.CLI/Functions/Unpacker.cs @@ -1,7 +1,7 @@ using System.Text; using System.Text.Json; using BlitzKit.CLI.Models; -using BlitzKit.CLI.Quicktype; +using BlitzKit.CLI.Quicktype.DLCManifest; using BlitzKit.CLI.Utils; using CUE4Parse.FileProvider; using CUE4Parse.FileProvider.Objects; @@ -15,13 +15,13 @@ namespace BlitzKit.CLI.Functions { public static class Unpacker { - private const string CONTENT_GROUP = "p14y73c7_p5e_b10gg3RS_big_play"; + public const string CONTENT_GROUP = "p14y73c7_p5e_b10gg3RS_big_play"; private const string CONTAINERS_PATH = "../../temp/containers/"; // this may be different from the one provided in args so check this and not args[1] // we don't wanna delete my local installation of the game when debugging haha! private const string TEMP_DEPOT_DIR = "../../temp/depot/"; - private const string WG_DLC_DOMAIN = "http://dl-wotblitz-gc.wargaming.net"; + public const string WG_DLC_DOMAIN = "http://dl-wotblitz-gc.wargaming.net"; private const string BUILD_MANIFEST_OS = "Windows"; public static async Task Unpack(string[] args) diff --git a/src/BlitzKit.CLI/Protos/Tank.cs b/src/BlitzKit.CLI/Protos/Tank.cs index 68ca72ce8..4fcca79a0 100644 --- a/src/BlitzKit.CLI/Protos/Tank.cs +++ b/src/BlitzKit.CLI/Protos/Tank.cs @@ -25,12 +25,13 @@ namespace Blitzkit { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "CiNwYWNrYWdlcy9jb3JlL3NyYy9wcm90b3MvdGFuay5wcm90bxIIYmxpdHpr", - "aXQaI3BhY2thZ2VzL2NvcmUvc3JjL3Byb3Rvcy9pMThuLnByb3RvIjAKBFRh", - "bmsSCgoCaWQYASACKAkSHAoEbmFtZRgCIAIoCzIOLmJsaXR6a2l0LkkxOG4=")); + "aXQaI3BhY2thZ2VzL2NvcmUvc3JjL3Byb3Rvcy9pMThuLnByb3RvIkAKBFRh", + "bmsSCgoCaWQYASACKAkSDgoGc2VvX2lkGAIgAigJEhwKBG5hbWUYAyACKAsy", + "Di5ibGl0emtpdC5JMThu")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { global::Blitzkit.I18NReflection.Descriptor, }, new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { - new pbr::GeneratedClrTypeInfo(typeof(global::Blitzkit.Tank), global::Blitzkit.Tank.Parser, new[]{ "Id", "Name" }, null, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::Blitzkit.Tank), global::Blitzkit.Tank.Parser, new[]{ "Id", "SeoId", "Name" }, null, null, null, null) })); } #endregion @@ -73,6 +74,7 @@ namespace Blitzkit { [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public Tank(Tank other) : this() { id_ = other.id_; + seoId_ = other.seoId_; name_ = other.name_ != null ? other.name_.Clone() : null; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } @@ -109,8 +111,34 @@ namespace Blitzkit { id_ = null; } + /// Field number for the "seo_id" field. + public const int SeoIdFieldNumber = 2; + private readonly static string SeoIdDefaultValue = ""; + + private string seoId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string SeoId { + get { return seoId_ ?? SeoIdDefaultValue; } + set { + seoId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + /// Gets whether the "seo_id" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasSeoId { + get { return seoId_ != null; } + } + /// Clears the value of the "seo_id" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearSeoId() { + seoId_ = null; + } + /// Field number for the "name" field. - public const int NameFieldNumber = 2; + public const int NameFieldNumber = 3; private global::Blitzkit.I18n name_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] @@ -137,6 +165,7 @@ namespace Blitzkit { return true; } if (Id != other.Id) return false; + if (SeoId != other.SeoId) return false; if (!object.Equals(Name, other.Name)) return false; return Equals(_unknownFields, other._unknownFields); } @@ -146,6 +175,7 @@ namespace Blitzkit { public override int GetHashCode() { int hash = 1; if (HasId) hash ^= Id.GetHashCode(); + if (HasSeoId) hash ^= SeoId.GetHashCode(); if (name_ != null) hash ^= Name.GetHashCode(); if (_unknownFields != null) { hash ^= _unknownFields.GetHashCode(); @@ -169,8 +199,12 @@ namespace Blitzkit { output.WriteRawTag(10); output.WriteString(Id); } - if (name_ != null) { + if (HasSeoId) { output.WriteRawTag(18); + output.WriteString(SeoId); + } + if (name_ != null) { + output.WriteRawTag(26); output.WriteMessage(Name); } if (_unknownFields != null) { @@ -187,8 +221,12 @@ namespace Blitzkit { output.WriteRawTag(10); output.WriteString(Id); } - if (name_ != null) { + if (HasSeoId) { output.WriteRawTag(18); + output.WriteString(SeoId); + } + if (name_ != null) { + output.WriteRawTag(26); output.WriteMessage(Name); } if (_unknownFields != null) { @@ -204,6 +242,9 @@ namespace Blitzkit { if (HasId) { size += 1 + pb::CodedOutputStream.ComputeStringSize(Id); } + if (HasSeoId) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SeoId); + } if (name_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Name); } @@ -222,6 +263,9 @@ namespace Blitzkit { if (other.HasId) { Id = other.Id; } + if (other.HasSeoId) { + SeoId = other.SeoId; + } if (other.name_ != null) { if (name_ == null) { Name = new global::Blitzkit.I18n(); @@ -252,6 +296,10 @@ namespace Blitzkit { break; } case 18: { + SeoId = input.ReadString(); + break; + } + case 26: { if (name_ == null) { Name = new global::Blitzkit.I18n(); } @@ -282,6 +330,10 @@ namespace Blitzkit { break; } case 18: { + SeoId = input.ReadString(); + break; + } + case 26: { if (name_ == null) { Name = new global::Blitzkit.I18n(); } diff --git a/src/BlitzKit.CLI/Protos/Tanks.cs b/src/BlitzKit.CLI/Protos/Tanks.cs index dc025f781..a3d65ef13 100644 --- a/src/BlitzKit.CLI/Protos/Tanks.cs +++ b/src/BlitzKit.CLI/Protos/Tanks.cs @@ -26,12 +26,12 @@ namespace Blitzkit { string.Concat( "CiRwYWNrYWdlcy9jb3JlL3NyYy9wcm90b3MvdGFua3MucHJvdG8SCGJsaXR6", "a2l0IioKBVRhbmtzEiEKBXRhbmtzGAEgAygLMhIuYmxpdHpraXQuVGFua01l", - "dGEiJgoIVGFua01ldGESCgoCaWQYASACKAkSDgoGc2VvX2lkGAIgAigJ")); + "dGEiFgoIVGFua01ldGESCgoCaWQYASACKAk=")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Blitzkit.Tanks), global::Blitzkit.Tanks.Parser, new[]{ "Tanks_" }, null, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Blitzkit.TankMeta), global::Blitzkit.TankMeta.Parser, new[]{ "Id", "SeoId" }, null, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::Blitzkit.TankMeta), global::Blitzkit.TankMeta.Parser, new[]{ "Id" }, null, null, null, null) })); } #endregion @@ -261,7 +261,6 @@ namespace Blitzkit { [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public TankMeta(TankMeta other) : this() { id_ = other.id_; - seoId_ = other.seoId_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } @@ -297,32 +296,6 @@ namespace Blitzkit { id_ = null; } - /// Field number for the "seo_id" field. - public const int SeoIdFieldNumber = 2; - private readonly static string SeoIdDefaultValue = ""; - - private string seoId_; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string SeoId { - get { return seoId_ ?? SeoIdDefaultValue; } - set { - seoId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - /// Gets whether the "seo_id" field is set - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasSeoId { - get { return seoId_ != null; } - } - /// Clears the value of the "seo_id" field - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearSeoId() { - seoId_ = null; - } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public override bool Equals(object other) { @@ -339,7 +312,6 @@ namespace Blitzkit { return true; } if (Id != other.Id) return false; - if (SeoId != other.SeoId) return false; return Equals(_unknownFields, other._unknownFields); } @@ -348,7 +320,6 @@ namespace Blitzkit { public override int GetHashCode() { int hash = 1; if (HasId) hash ^= Id.GetHashCode(); - if (HasSeoId) hash ^= SeoId.GetHashCode(); if (_unknownFields != null) { hash ^= _unknownFields.GetHashCode(); } @@ -371,10 +342,6 @@ namespace Blitzkit { output.WriteRawTag(10); output.WriteString(Id); } - if (HasSeoId) { - output.WriteRawTag(18); - output.WriteString(SeoId); - } if (_unknownFields != null) { _unknownFields.WriteTo(output); } @@ -389,10 +356,6 @@ namespace Blitzkit { output.WriteRawTag(10); output.WriteString(Id); } - if (HasSeoId) { - output.WriteRawTag(18); - output.WriteString(SeoId); - } if (_unknownFields != null) { _unknownFields.WriteTo(ref output); } @@ -406,9 +369,6 @@ namespace Blitzkit { if (HasId) { size += 1 + pb::CodedOutputStream.ComputeStringSize(Id); } - if (HasSeoId) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(SeoId); - } if (_unknownFields != null) { size += _unknownFields.CalculateSize(); } @@ -424,9 +384,6 @@ namespace Blitzkit { if (other.HasId) { Id = other.Id; } - if (other.HasSeoId) { - SeoId = other.SeoId; - } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); } @@ -450,10 +407,6 @@ namespace Blitzkit { Id = input.ReadString(); break; } - case 18: { - SeoId = input.ReadString(); - break; - } } } #endif @@ -477,10 +430,6 @@ namespace Blitzkit { Id = input.ReadString(); break; } - case 18: { - SeoId = input.ReadString(); - break; - } } } } diff --git a/src/BlitzKit.CLI/Quicktype/DLCManifest.cs b/src/BlitzKit.CLI/Quicktype/DLCManifest.cs index d048e0742..77aa0b600 100644 --- a/src/BlitzKit.CLI/Quicktype/DLCManifest.cs +++ b/src/BlitzKit.CLI/Quicktype/DLCManifest.cs @@ -10,7 +10,7 @@ #pragma warning disable CS8601 #pragma warning disable CS8603 -namespace BlitzKit.CLI.Quicktype +namespace BlitzKit.CLI.Quicktype.DLCManifest { using System; using System.Collections.Generic; @@ -75,12 +75,12 @@ namespace BlitzKit.CLI.Quicktype public partial class DlcManifest { - public static DlcManifest FromJson(string json) => JsonSerializer.Deserialize(json, BlitzKit.CLI.Quicktype.Converter.Settings); + public static DlcManifest FromJson(string json) => JsonSerializer.Deserialize(json, BlitzKit.CLI.Quicktype.DLCManifest.Converter.Settings); } public static class Serialize { - public static string ToJson(this DlcManifest self) => JsonSerializer.Serialize(self, BlitzKit.CLI.Quicktype.Converter.Settings); + public static string ToJson(this DlcManifest self) => JsonSerializer.Serialize(self, BlitzKit.CLI.Quicktype.DLCManifest.Converter.Settings); } internal static class Converter diff --git a/src/BlitzKit.CLI/Quicktype/Locales.cs b/src/BlitzKit.CLI/Quicktype/Locales.cs new file mode 100644 index 000000000..3ee95df37 --- /dev/null +++ b/src/BlitzKit.CLI/Quicktype/Locales.cs @@ -0,0 +1,176 @@ +// +// +// To parse this JSON data, add NuGet 'System.Text.Json' then do: +// +// using BlitzKit.CLI.Quicktype.Locales; +// +// var locales = Locales.FromJson(jsonString); +#nullable enable +#pragma warning disable CS8618 +#pragma warning disable CS8601 +#pragma warning disable CS8603 + +namespace BlitzKit.CLI.Quicktype.Locales +{ + using System; + using System.Collections.Generic; + + using System.Text.Json; + using System.Text.Json.Serialization; + using System.Globalization; + + public partial class Locales + { + [JsonPropertyName("default")] + public string Default { get; set; } + + [JsonPropertyName("supported")] + public List Supported { get; set; } + } + + public partial class Supported + { + [JsonPropertyName("locale")] + public string Locale { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("blitz")] + public string Blitz { get; set; } + } + + public partial class Locales + { + public static Locales FromJson(string json) => JsonSerializer.Deserialize(json, BlitzKit.CLI.Quicktype.Locales.Converter.Settings); + } + + public static class Serialize + { + public static string ToJson(this Locales self) => JsonSerializer.Serialize(self, BlitzKit.CLI.Quicktype.Locales.Converter.Settings); + } + + internal static class Converter + { + public static readonly JsonSerializerOptions Settings = new(JsonSerializerDefaults.General) + { + Converters = + { + new DateOnlyConverter(), + new TimeOnlyConverter(), + IsoDateTimeOffsetConverter.Singleton + }, + }; + } + + public class DateOnlyConverter : JsonConverter + { + private readonly string serializationFormat; + public DateOnlyConverter() : this(null) { } + + public DateOnlyConverter(string? serializationFormat) + { + this.serializationFormat = serializationFormat ?? "yyyy-MM-dd"; + } + + public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var value = reader.GetString(); + return DateOnly.Parse(value!); + } + + public override void Write(Utf8JsonWriter writer, DateOnly value, JsonSerializerOptions options) + => writer.WriteStringValue(value.ToString(serializationFormat)); + } + + public class TimeOnlyConverter : JsonConverter + { + private readonly string serializationFormat; + + public TimeOnlyConverter() : this(null) { } + + public TimeOnlyConverter(string? serializationFormat) + { + this.serializationFormat = serializationFormat ?? "HH:mm:ss.fff"; + } + + public override TimeOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var value = reader.GetString(); + return TimeOnly.Parse(value!); + } + + public override void Write(Utf8JsonWriter writer, TimeOnly value, JsonSerializerOptions options) + => writer.WriteStringValue(value.ToString(serializationFormat)); + } + + internal class IsoDateTimeOffsetConverter : JsonConverter + { + public override bool CanConvert(Type t) => t == typeof(DateTimeOffset); + + private const string DefaultDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; + + private DateTimeStyles _dateTimeStyles = DateTimeStyles.RoundtripKind; + private string? _dateTimeFormat; + private CultureInfo? _culture; + + public DateTimeStyles DateTimeStyles + { + get => _dateTimeStyles; + set => _dateTimeStyles = value; + } + + public string? DateTimeFormat + { + get => _dateTimeFormat ?? string.Empty; + set => _dateTimeFormat = (string.IsNullOrEmpty(value)) ? null : value; + } + + public CultureInfo Culture + { + get => _culture ?? CultureInfo.CurrentCulture; + set => _culture = value; + } + + public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) + { + string text; + + + if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal + || (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal) + { + value = value.ToUniversalTime(); + } + + text = value.ToString(_dateTimeFormat ?? DefaultDateTimeFormat, Culture); + + writer.WriteStringValue(text); + } + + public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + string? dateText = reader.GetString(); + + if (string.IsNullOrEmpty(dateText) == false) + { + if (!string.IsNullOrEmpty(_dateTimeFormat)) + { + return DateTimeOffset.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles); + } + else + { + return DateTimeOffset.Parse(dateText, Culture, _dateTimeStyles); + } + } + else + { + return default(DateTimeOffset); + } + } + + + public static readonly IsoDateTimeOffsetConverter Singleton = new IsoDateTimeOffsetConverter(); + } +} +#pragma warning restore CS8618 +#pragma warning restore CS8601 +#pragma warning restore CS8603 diff --git a/submodules/blitzkit-closed b/submodules/blitzkit-closed index c1d631764..31937a9f1 160000 --- a/submodules/blitzkit-closed +++ b/submodules/blitzkit-closed @@ -1 +1 @@ -Subproject commit c1d631764f74f8050660aa95c1da071baaadde43 +Subproject commit 31937a9f1e83e588d84a2ce1616870a442d2a7a4