2025-01-29 19:14:46 -06:00
|
|
|
using Blitzkit;
|
2025-01-28 12:59:59 -06:00
|
|
|
using BlitzKit.CLI.Models;
|
2025-01-28 19:52:49 -06:00
|
|
|
using BlitzKit.CLI.Utils;
|
|
|
|
|
using CUE4Parse.FileProvider.Objects;
|
2025-01-30 12:49:15 -06:00
|
|
|
using Google.Protobuf.Collections;
|
2025-01-29 19:14:46 -06:00
|
|
|
using Newtonsoft.Json.Linq;
|
2025-01-27 22:17:13 -06:00
|
|
|
|
2025-01-28 12:59:59 -06:00
|
|
|
namespace BlitzKit.CLI.Functions
|
2025-01-26 21:17:25 -06:00
|
|
|
{
|
|
|
|
|
public static class Mangler
|
|
|
|
|
{
|
2025-01-27 22:17:13 -06:00
|
|
|
public static void Mangle()
|
|
|
|
|
{
|
2025-01-29 19:14:46 -06:00
|
|
|
Tanks tanks = new();
|
2025-01-27 22:17:13 -06:00
|
|
|
BlitzProvider provider = new();
|
|
|
|
|
|
2025-01-30 11:31:55 -06:00
|
|
|
foreach (
|
|
|
|
|
var nationDir in provider.RootDirectory.GetDirectory("Blitz/Content/Tanks").Directories
|
|
|
|
|
)
|
2025-01-27 22:17:13 -06:00
|
|
|
{
|
2025-01-30 11:31:55 -06:00
|
|
|
if (nationDir.Key == "TankStub")
|
2025-01-27 22:17:13 -06:00
|
|
|
continue;
|
|
|
|
|
|
2025-01-30 11:31:55 -06:00
|
|
|
foreach (var tankDir in nationDir.Value.Directories)
|
2025-01-27 22:17:13 -06:00
|
|
|
{
|
2025-01-30 12:54:37 -06:00
|
|
|
var id = tankDir.Key;
|
|
|
|
|
|
|
|
|
|
if (id != "R90_IS_4")
|
2025-01-28 19:52:49 -06:00
|
|
|
continue;
|
|
|
|
|
|
2025-01-30 12:54:37 -06:00
|
|
|
var attributeFileName = $"DA_{id}_Attributes.uasset";
|
2025-01-30 11:31:55 -06:00
|
|
|
var hasAttributesFile = tankDir.Value.HasFile(attributeFileName);
|
2025-01-29 19:14:46 -06:00
|
|
|
GameFile? attributesFile = null;
|
2025-01-28 19:52:49 -06:00
|
|
|
|
|
|
|
|
if (hasAttributesFile)
|
2025-01-28 12:55:02 -06:00
|
|
|
{
|
2025-01-30 11:31:55 -06:00
|
|
|
attributesFile = tankDir.Value.GetFile(attributeFileName);
|
2025-01-28 19:52:49 -06:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PrettyLog.Warn(
|
2025-01-30 12:54:37 -06:00
|
|
|
$"No attributes file found for {nationDir.Key}/{id}, it may be misspelled; finding any attributes file..."
|
2025-01-28 19:52:49 -06:00
|
|
|
);
|
|
|
|
|
|
2025-01-30 11:31:55 -06:00
|
|
|
foreach (var file in tankDir.Value.Files)
|
2025-01-28 19:52:49 -06:00
|
|
|
{
|
|
|
|
|
if (file.Key.EndsWith("_Attributes.uasset"))
|
|
|
|
|
{
|
2025-01-29 19:14:46 -06:00
|
|
|
attributesFile = file.Value;
|
2025-01-28 19:52:49 -06:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-29 19:14:46 -06:00
|
|
|
if (attributesFile == null)
|
2025-01-28 19:52:49 -06:00
|
|
|
{
|
|
|
|
|
PrettyLog.Error(
|
2025-01-30 12:54:37 -06:00
|
|
|
$"No suffixed attributes file found for {nationDir.Key}/{id}; skipping..."
|
2025-01-28 19:52:49 -06:00
|
|
|
);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-29 19:14:46 -06:00
|
|
|
var exports = provider.LoadAllObjects(attributesFile.Path);
|
2025-01-28 19:52:49 -06:00
|
|
|
|
2025-01-29 19:14:46 -06:00
|
|
|
var tankAttributesDataAsset =
|
|
|
|
|
exports.First((export) => export.ExportType == "TankAttributesDataAsset")
|
|
|
|
|
?? throw new Exception("TankAttributesDataAsset not found");
|
|
|
|
|
var attr = JObject.FromObject(tankAttributesDataAsset);
|
2025-01-28 19:52:49 -06:00
|
|
|
|
2025-01-30 12:54:37 -06:00
|
|
|
if (attr["Properties"] is not JObject props || props["MaxHealth"] == null)
|
2025-01-30 11:31:55 -06:00
|
|
|
{
|
2025-01-30 12:54:37 -06:00
|
|
|
PrettyLog.Warn($"{nationDir.Key}/{id} has not migrated to Reforged; skipping...");
|
2025-01-30 11:31:55 -06:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-30 12:54:37 -06:00
|
|
|
var tank = MangleTank(id, props);
|
2025-01-30 11:31:55 -06:00
|
|
|
|
|
|
|
|
tanks.Tanks_.Add(tank.Id);
|
|
|
|
|
|
2025-01-30 12:54:37 -06:00
|
|
|
Console.WriteLine($"Mangled {nationDir.Key}/{id}");
|
2025-01-27 22:17:13 -06:00
|
|
|
}
|
|
|
|
|
}
|
2025-01-30 12:54:37 -06:00
|
|
|
}
|
2025-01-29 19:14:46 -06:00
|
|
|
|
2025-01-30 12:54:37 -06:00
|
|
|
public static Tank MangleTank(string id, JObject props)
|
|
|
|
|
{
|
|
|
|
|
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)!),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
MangleCrewHealth(tank.CrewHealth, (props["CrewHealth"] as JArray)!);
|
|
|
|
|
|
|
|
|
|
return tank;
|
2025-01-26 21:17:25 -06:00
|
|
|
}
|
2025-01-30 11:31:55 -06:00
|
|
|
|
2025-01-30 12:49:15 -06:00
|
|
|
public static Dictionary<string, CrewType> 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 },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public static void MangleCrewHealth(RepeatedField<CrewHealth> map, JArray array)
|
|
|
|
|
{
|
|
|
|
|
foreach (var member in array.Cast<JObject>())
|
|
|
|
|
{
|
|
|
|
|
var key = member["Key"]!.Value<string>()!;
|
|
|
|
|
|
|
|
|
|
if (CrewTypes.TryGetValue(key, out var crewType))
|
|
|
|
|
{
|
|
|
|
|
CrewHealth crewHealth = new()
|
|
|
|
|
{
|
|
|
|
|
Type = crewType,
|
|
|
|
|
MaxHealth = member["Value"]!["MaxHealth"]!.Value<float>(),
|
|
|
|
|
};
|
|
|
|
|
map.Add(crewHealth);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new Exception($"Unrecognized CrewType: {key}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-30 11:31:55 -06:00
|
|
|
public static ModuleHealth MangleModuleHealth(JObject obj)
|
|
|
|
|
{
|
|
|
|
|
ModuleHealth moduleHealth = new()
|
|
|
|
|
{
|
|
|
|
|
MaxHealth = obj["MaxHealth"]!.Value<float>(),
|
|
|
|
|
MaxRegenHealth = obj["MaxRegenHealth"]!.Value<float>(),
|
|
|
|
|
HealthRegenPerSec = obj["HealthRegenPerSec"]!.Value<float>(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (obj.TryGetValue("HysteresisHealth", out var hysteresis))
|
|
|
|
|
{
|
|
|
|
|
moduleHealth.HysteresisHealth = hysteresis.Value<float>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (obj.TryGetValue("HealthBurnPerSec", out var burn))
|
|
|
|
|
{
|
|
|
|
|
moduleHealth.HealthBurnPerSec = burn.Value<float>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return moduleHealth;
|
|
|
|
|
}
|
2025-01-26 21:17:25 -06:00
|
|
|
}
|
|
|
|
|
}
|