diff --git a/packages/core/src/protos/tank.proto b/packages/core/src/protos/tank.proto index 17c26017f..c45c02345 100644 --- a/packages/core/src/protos/tank.proto +++ b/packages/core/src/protos/tank.proto @@ -21,12 +21,12 @@ message Tank { required ModuleHealth fuel_tank_health = 12; repeated CrewHealth crew_health = 13; required float max_health = 14; - required float health_burn_per_second = 15; + required float health_burn_per_sec = 15; required float fire_starting_chance = 16; required float concealment_stationary = 17; required float concealment_moving = 18; - required float concealment_factor_on_shot = 19; + required float concealment_factor_at_shot = 19; required float turret_turn_rate = 20; required float circular_vision_radius = 21; @@ -46,7 +46,6 @@ message Tank { required float rotation_speed = 33; required float terrain_resistance_hard = 34; required float brake_force = 35; - required bool b_rotation_is_around_center = 36; } enum CrewType { diff --git a/packages/core/src/protos/tank.ts b/packages/core/src/protos/tank.ts index 0e42c31b9..4df74dfbd 100644 --- a/packages/core/src/protos/tank.ts +++ b/packages/core/src/protos/tank.ts @@ -79,11 +79,11 @@ export interface Tank { fuel_tank_health: ModuleHealth; crew_health: CrewHealth[]; max_health: number; - health_burn_per_second: number; + health_burn_per_sec: number; fire_starting_chance: number; concealment_stationary: number; concealment_moving: number; - concealment_factor_on_shot: number; + concealment_factor_at_shot: number; turret_turn_rate: number; circular_vision_radius: number; shells: Shell[]; @@ -100,7 +100,6 @@ export interface Tank { rotation_speed: number; terrain_resistance_hard: number; brake_force: number; - b_rotation_is_around_center: boolean; } export interface CrewHealth { @@ -165,11 +164,11 @@ function createBaseTank(): Tank { fuel_tank_health: createBaseModuleHealth(), crew_health: [], max_health: 0, - health_burn_per_second: 0, + health_burn_per_sec: 0, fire_starting_chance: 0, concealment_stationary: 0, concealment_moving: 0, - concealment_factor_on_shot: 0, + concealment_factor_at_shot: 0, turret_turn_rate: 0, circular_vision_radius: 0, shells: [], @@ -186,7 +185,6 @@ function createBaseTank(): Tank { rotation_speed: 0, terrain_resistance_hard: 0, brake_force: 0, - b_rotation_is_around_center: false, }; } @@ -234,8 +232,8 @@ export const Tank: MessageFns = { if (message.max_health !== 0) { writer.uint32(117).float(message.max_health); } - if (message.health_burn_per_second !== 0) { - writer.uint32(125).float(message.health_burn_per_second); + if (message.health_burn_per_sec !== 0) { + writer.uint32(125).float(message.health_burn_per_sec); } if (message.fire_starting_chance !== 0) { writer.uint32(133).float(message.fire_starting_chance); @@ -246,8 +244,8 @@ export const Tank: MessageFns = { if (message.concealment_moving !== 0) { writer.uint32(149).float(message.concealment_moving); } - if (message.concealment_factor_on_shot !== 0) { - writer.uint32(157).float(message.concealment_factor_on_shot); + if (message.concealment_factor_at_shot !== 0) { + writer.uint32(157).float(message.concealment_factor_at_shot); } if (message.turret_turn_rate !== 0) { writer.uint32(165).float(message.turret_turn_rate); @@ -297,9 +295,6 @@ export const Tank: MessageFns = { if (message.brake_force !== 0) { writer.uint32(285).float(message.brake_force); } - if (message.b_rotation_is_around_center !== false) { - writer.uint32(288).bool(message.b_rotation_is_around_center); - } return writer; }, @@ -427,7 +422,7 @@ export const Tank: MessageFns = { break; } - message.health_burn_per_second = reader.float(); + message.health_burn_per_sec = reader.float(); continue; } case 16: { @@ -459,7 +454,7 @@ export const Tank: MessageFns = { break; } - message.concealment_factor_on_shot = reader.float(); + message.concealment_factor_at_shot = reader.float(); continue; } case 20: { @@ -590,14 +585,6 @@ export const Tank: MessageFns = { message.brake_force = reader.float(); continue; } - case 36: { - if (tag !== 288) { - break; - } - - message.b_rotation_is_around_center = reader.bool(); - continue; - } } if ((tag & 7) === 4 || tag === 0) { break; @@ -629,16 +616,14 @@ export const Tank: MessageFns = { ? object.crew_health.map((e: any) => CrewHealth.fromJSON(e)) : [], max_health: globalThis.Number(assertSet("Tank.max_health", object.max_health)), - health_burn_per_second: globalThis.Number( - assertSet("Tank.health_burn_per_second", object.health_burn_per_second), - ), + health_burn_per_sec: globalThis.Number(assertSet("Tank.health_burn_per_sec", object.health_burn_per_sec)), fire_starting_chance: globalThis.Number(assertSet("Tank.fire_starting_chance", object.fire_starting_chance)), concealment_stationary: globalThis.Number( assertSet("Tank.concealment_stationary", object.concealment_stationary), ), concealment_moving: globalThis.Number(assertSet("Tank.concealment_moving", object.concealment_moving)), - concealment_factor_on_shot: globalThis.Number( - assertSet("Tank.concealment_factor_on_shot", object.concealment_factor_on_shot), + concealment_factor_at_shot: globalThis.Number( + assertSet("Tank.concealment_factor_at_shot", object.concealment_factor_at_shot), ), turret_turn_rate: globalThis.Number(assertSet("Tank.turret_turn_rate", object.turret_turn_rate)), circular_vision_radius: globalThis.Number( @@ -664,9 +649,6 @@ export const Tank: MessageFns = { assertSet("Tank.terrain_resistance_hard", object.terrain_resistance_hard), ), brake_force: globalThis.Number(assertSet("Tank.brake_force", object.brake_force)), - b_rotation_is_around_center: globalThis.Boolean( - assertSet("Tank.b_rotation_is_around_center", object.b_rotation_is_around_center), - ), }; }, @@ -714,8 +696,8 @@ export const Tank: MessageFns = { if (message.max_health !== 0) { obj.max_health = message.max_health; } - if (message.health_burn_per_second !== 0) { - obj.health_burn_per_second = message.health_burn_per_second; + if (message.health_burn_per_sec !== 0) { + obj.health_burn_per_sec = message.health_burn_per_sec; } if (message.fire_starting_chance !== 0) { obj.fire_starting_chance = message.fire_starting_chance; @@ -726,8 +708,8 @@ export const Tank: MessageFns = { if (message.concealment_moving !== 0) { obj.concealment_moving = message.concealment_moving; } - if (message.concealment_factor_on_shot !== 0) { - obj.concealment_factor_on_shot = message.concealment_factor_on_shot; + if (message.concealment_factor_at_shot !== 0) { + obj.concealment_factor_at_shot = message.concealment_factor_at_shot; } if (message.turret_turn_rate !== 0) { obj.turret_turn_rate = message.turret_turn_rate; @@ -777,9 +759,6 @@ export const Tank: MessageFns = { if (message.brake_force !== 0) { obj.brake_force = message.brake_force; } - if (message.b_rotation_is_around_center !== false) { - obj.b_rotation_is_around_center = message.b_rotation_is_around_center; - } return obj; }, @@ -820,11 +799,11 @@ export const Tank: MessageFns = { : createBaseModuleHealth(); message.crew_health = object.crew_health?.map((e) => CrewHealth.fromPartial(e)) || []; message.max_health = object.max_health ?? 0; - message.health_burn_per_second = object.health_burn_per_second ?? 0; + message.health_burn_per_sec = object.health_burn_per_sec ?? 0; message.fire_starting_chance = object.fire_starting_chance ?? 0; message.concealment_stationary = object.concealment_stationary ?? 0; message.concealment_moving = object.concealment_moving ?? 0; - message.concealment_factor_on_shot = object.concealment_factor_on_shot ?? 0; + message.concealment_factor_at_shot = object.concealment_factor_at_shot ?? 0; message.turret_turn_rate = object.turret_turn_rate ?? 0; message.circular_vision_radius = object.circular_vision_radius ?? 0; message.shells = object.shells?.map((e) => Shell.fromPartial(e)) || []; @@ -841,7 +820,6 @@ export const Tank: MessageFns = { message.rotation_speed = object.rotation_speed ?? 0; message.terrain_resistance_hard = object.terrain_resistance_hard ?? 0; message.brake_force = object.brake_force ?? 0; - message.b_rotation_is_around_center = object.b_rotation_is_around_center ?? false; return message; }, }; diff --git a/src/BlitzKit.CLI/Functions/Mangler.cs b/src/BlitzKit.CLI/Functions/Mangler.cs index 2dddfcd14..5be7726e0 100644 --- a/src/BlitzKit.CLI/Functions/Mangler.cs +++ b/src/BlitzKit.CLI/Functions/Mangler.cs @@ -1,112 +1,52 @@ using Blitzkit; using BlitzKit.CLI.Models; -using BlitzKit.CLI.Utils; -using CUE4Parse.FileProvider.Objects; using Google.Protobuf.Collections; using Newtonsoft.Json.Linq; namespace BlitzKit.CLI.Functions { - public static class Mangler + public class Mangler { - public static void Mangle() + readonly Tanks tanks = new(); + readonly BlitzProvider provider = new(); + + public void Mangle() { - Tanks tanks = new(); - BlitzProvider provider = new(); + var nationDirs = provider.RootDirectory.GetDirectory("Blitz/Content/Tanks").Directories; - foreach ( - var nationDir in provider.RootDirectory.GetDirectory("Blitz/Content/Tanks").Directories - ) + foreach (var nationDir in nationDirs) { if (nationDir.Key == "TankStub") continue; - foreach (var tankDir in nationDir.Value.Directories) - { - var id = tankDir.Key; - - if (id != "R90_IS_4") - continue; - - var attributeFileName = $"DA_{id}_Attributes.uasset"; - var hasAttributesFile = tankDir.Value.HasFile(attributeFileName); - GameFile? attributesFile = null; - - if (hasAttributesFile) - { - attributesFile = tankDir.Value.GetFile(attributeFileName); - } - else - { - PrettyLog.Warn( - $"No attributes file found for {nationDir.Key}/{id}, it may be misspelled; finding any attributes file..." - ); - - foreach (var file in tankDir.Value.Files) - { - if (file.Key.EndsWith("_Attributes.uasset")) - { - attributesFile = file.Value; - break; - } - } - - if (attributesFile == null) - { - PrettyLog.Error( - $"No suffixed attributes file found for {nationDir.Key}/{id}; skipping..." - ); - continue; - } - } - - var exports = provider.LoadAllObjects(attributesFile.Path); - - var tankAttributesDataAsset = - exports.First((export) => export.ExportType == "TankAttributesDataAsset") - ?? throw new Exception("TankAttributesDataAsset not found"); - var attr = JObject.FromObject(tankAttributesDataAsset); - - if (attr["Properties"] is not JObject props || props["MaxHealth"] == null) - { - PrettyLog.Warn($"{nationDir.Key}/{id} has not migrated to Reforged; skipping..."); - continue; - } + MangleNation(nationDir.Value); + } + } - var tank = MangleTank(id, props); + void MangleNation(VfsDirectory nation) + { + foreach (var tankDir in nation.Directories) + { + if (tankDir.Value.Name != "R90_IS_4") + continue; - tanks.Tanks_.Add(tank.Id); + var tank = MangleTank(tankDir.Value); - Console.WriteLine($"Mangled {nationDir.Key}/{id}"); - } + tanks.Tanks_.Add(tank.Id); } } - public static Tank MangleTank(string id, JObject props) + Tank MangleTank(VfsDirectory tankDir) { - Tank tank = new() - { - Id = id, - // TODO: Name - // TODO: Set - // TODO: Class - // TODO: Faction - - TurretRotatorHealth = MangleModuleHealth((props["TurretRotatorHealth"] as JObject)!), - SurveyingDeviceHealth = MangleModuleHealth((props["SurveyingDeviceHealth"] as JObject)!), - GunHealth = MangleModuleHealth((props["GunHealth"] as JObject)!), - ChassisHealth = MangleModuleHealth((props["ChassisHealth"] as JObject)!), - AmmoBayHealth = MangleModuleHealth((props["AmmoBayHealth"] as JObject)!), - EngineHealth = MangleModuleHealth((props["EngineHealth"] as JObject)!), - FuelTankHealth = MangleModuleHealth((props["FuelTankHealth"] as JObject)!), - }; + var pdaName = $"PDA_{tankDir.Name}"; + var pda = tankDir.GetUasset($"{pdaName}.uasset").Get(pdaName); - MangleCrewHealth(tank.CrewHealth, (props["CrewHealth"] as JArray)!); + Console.WriteLine(pda); - return tank; + return new(); } - public static Dictionary CrewTypes = new() + Dictionary CrewTypes = new() { { "EModuleOrTankmen::Commander", CrewType.Commander }, { "EModuleOrTankmen::Driver", CrewType.Driver }, @@ -116,7 +56,7 @@ public static Tank MangleTank(string id, JObject props) { "EModuleOrTankmen::Loader2", CrewType.Loader2 }, }; - public static void MangleCrewHealth(RepeatedField map, JArray array) + void MangleCrewHealth(RepeatedField map, JArray array) { foreach (var member in array.Cast()) { @@ -138,7 +78,7 @@ public static void MangleCrewHealth(RepeatedField map, JArray array) } } - public static ModuleHealth MangleModuleHealth(JObject obj) + ModuleHealth MangleModuleHealth(JObject obj) { ModuleHealth moduleHealth = new() { diff --git a/src/BlitzKit.CLI/Models/BlitzProvider.cs b/src/BlitzKit.CLI/Models/BlitzProvider.cs index 978b029e3..e3ee8e042 100644 --- a/src/BlitzKit.CLI/Models/BlitzProvider.cs +++ b/src/BlitzKit.CLI/Models/BlitzProvider.cs @@ -15,7 +15,7 @@ public class BlitzProvider : DefaultFileProvider private static readonly string LOCAL_MAPPINGS_PATH = "../../submodules/blitzkit-closed/blitz.usmap"; - public readonly VfsDirectory RootDirectory = new(); + public readonly VfsDirectory RootDirectory; public BlitzProvider() : base( @@ -25,6 +25,7 @@ public BlitzProvider() versions: new(EGame.GAME_UE5_3) ) { + RootDirectory = new() { Name = "", provider = this }; MappingsContainer = new FileUsmapTypeMappingsProvider(LOCAL_MAPPINGS_PATH); Initialize(); @@ -51,7 +52,7 @@ public BlitzProvider() } else { - VfsDirectory newDirectory = new(); + VfsDirectory newDirectory = new() { Name = segment, provider = this }; directory.AddDirectory(segment, newDirectory); directory = newDirectory; } @@ -59,42 +60,4 @@ public BlitzProvider() } } } - - public class VfsDirectory - { - public Dictionary Directories = []; - public Dictionary Files = []; - - public void AddFile(string name, GameFile file) => Files.TryAdd(name, file); - - public bool HasFile(string name) => Files.ContainsKey(name); - - public GameFile GetFile(string name) - { - var directoryPath = Path.GetDirectoryName(name); - var fileName = Path.GetFileName(name); - var directory = - directoryPath == null || directoryPath.Length == 0 ? this : GetDirectory(directoryPath); - - return directory.Files[fileName]; - } - - public bool HasDirectory(string name) => Directories.ContainsKey(name); - - public VfsDirectory GetDirectory(string name) - { - var segments = name.Split('/'); - var directory = this; - - foreach (var segment in segments) - { - directory = directory.Directories[segment]; - } - - return directory; - } - - public void AddDirectory(string name, VfsDirectory directory) => - Directories.Add(name, directory); - } } diff --git a/src/BlitzKit.CLI/Models/Uasset.cs b/src/BlitzKit.CLI/Models/Uasset.cs new file mode 100644 index 000000000..c234cfbd1 --- /dev/null +++ b/src/BlitzKit.CLI/Models/Uasset.cs @@ -0,0 +1,25 @@ +using CUE4Parse.FileProvider; +using CUE4Parse.FileProvider.Objects; +using CUE4Parse.UE4.Assets.Exports; + +namespace BlitzKit.CLI.Models +{ + public class Uasset + { + readonly GameFile file; + readonly Dictionary objects = []; + + public Uasset(GameFile file, AbstractFileProvider provider) + { + this.file = file; + var objects = provider.LoadAllObjects(file.Path); + + foreach (var obj in objects) + { + this.objects.Add(obj.Name, obj); + } + } + + public UObject Get(string name) => objects[name]; + } +} diff --git a/src/BlitzKit.CLI/Models/VfsDirectory.cs b/src/BlitzKit.CLI/Models/VfsDirectory.cs new file mode 100644 index 000000000..8cdf36a3e --- /dev/null +++ b/src/BlitzKit.CLI/Models/VfsDirectory.cs @@ -0,0 +1,47 @@ +using CUE4Parse.FileProvider; +using CUE4Parse.FileProvider.Objects; + +namespace BlitzKit.CLI.Models +{ + public class VfsDirectory + { + public Dictionary Directories = []; + public Dictionary Files = []; + public required string Name; + public required AbstractFileProvider provider; + + public void AddFile(string name, GameFile file) => Files.TryAdd(name, file); + + public bool HasFile(string name) => Files.ContainsKey(name); + + public Uasset GetUasset(string name) => new(GetFile(name), provider); + + public GameFile GetFile(string name) + { + var directoryPath = Path.GetDirectoryName(name); + var fileName = Path.GetFileName(name); + var directory = + directoryPath == null || directoryPath.Length == 0 ? this : GetDirectory(directoryPath); + + return directory.Files[fileName]; + } + + public bool HasDirectory(string name) => Directories.ContainsKey(name); + + public VfsDirectory GetDirectory(string name) + { + var segments = name.Split('/'); + var directory = this; + + foreach (var segment in segments) + { + directory = directory.Directories[segment]; + } + + return directory; + } + + public void AddDirectory(string name, VfsDirectory directory) => + Directories.Add(name, directory); + } +} diff --git a/src/BlitzKit.CLI/Program.cs b/src/BlitzKit.CLI/Program.cs index 262a562ea..940572cf1 100644 --- a/src/BlitzKit.CLI/Program.cs +++ b/src/BlitzKit.CLI/Program.cs @@ -19,7 +19,10 @@ static async Task Main(string[] args) case "mangle": { - Mangler.Mangle(); + Mangler mangler = new(); + + mangler.Mangle(); + break; }