TH1/Tools/CheckCultureUpgradeUnitConfig.ps1

241 lines
7.0 KiB
PowerShell

param(
[string]$AssetPath = "Unity/Assets/BundleResources/DataAssets/UnitTypeDataAssets.asset",
[string]$ExportPath = "Unity/Assets/BundleResources/Export/UnitTypeDataAssets.asset",
[switch]$CheckExport
)
$ErrorActionPreference = "Stop"
$repoRoot = git rev-parse --show-toplevel 2>$null
if (-not $repoRoot) {
throw "Not inside a git repository."
}
$repoRoot = [System.IO.Path]::GetFullPath($repoRoot.Trim())
$prepareOfficerSkillHex = @(
"b6000000", # SkillType.OFFICER
"b3000000" # SkillType.JUNKEROFFICER
)
$cultureUpgradeChessTypes = @{
6 = "PawnWarrior"
7 = "PawnArcher"
8 = "PawnDefender"
9 = "PawnRider"
10 = "PawnKnight"
12 = "PawnCatapult"
13 = "PawnSword"
}
$explicitExemptions = @{
"20/0/0" = "KaguyaFrenchAnimalWarrior is an animal-resource conversion unit, not a normal Feudal Fief upgrade target."
}
function Resolve-RepoPath([string]$Path) {
if ([System.IO.Path]::IsPathRooted($Path)) {
return [System.IO.Path]::GetFullPath($Path)
}
return [System.IO.Path]::GetFullPath((Join-Path $repoRoot $Path))
}
function Get-UnitKey($Unit) {
return "$($Unit.UnitType)/$($Unit.GiantType)/$($Unit.UnitLevel)"
}
function Read-UnitTypeEntries([string]$Path) {
$fullPath = Resolve-RepoPath $Path
if (-not (Test-Path -LiteralPath $fullPath)) {
throw "UnitTypeDataAssets file not found: $fullPath"
}
$lines = Get-Content -LiteralPath $fullPath
$entries = @()
$current = $null
for ($i = 0; $i -lt $lines.Count; $i++) {
$line = $lines[$i]
if ($line -match '^ - UnitType: (\d+)') {
if ($current) {
$entries += [pscustomobject]$current
}
$current = [ordered]@{
SourcePath = $Path
Line = $i + 1
UnitType = [int]$Matches[1]
GiantType = $null
UnitLevel = $null
ChessType = $null
Civ = $null
Force = $null
Name = ""
LandType = $null
Cost = $null
Skills = ""
}
continue
}
if (-not $current) {
continue
}
if ($line -match '^ GiantType: (\d+)') {
$current.GiantType = [int]$Matches[1]
continue
}
if ($line -match '^ UnitLevel: (\d+)') {
$current.UnitLevel = [int]$Matches[1]
continue
}
if ($line -match '^ ChessType: (\d+)') {
$current.ChessType = [int]$Matches[1]
continue
}
if ($line -match '^ Civ: (\d+)') {
$current.Civ = [int]$Matches[1]
continue
}
if ($line -match '^ Force: (\d+)') {
$current.Force = [int]$Matches[1]
continue
}
if ($line -match '^ Name: (.*)$') {
$current.Name = $Matches[1]
continue
}
if ($line -match '^ LandType: (\d+)') {
$current.LandType = [int]$Matches[1]
continue
}
if ($line -match '^ Cost: ([\d\.]+)') {
$current.Cost = [double]$Matches[1]
continue
}
if ($line -match '^ Skills: ?(.*)$') {
$current.Skills = $Matches[1].ToLowerInvariant()
continue
}
}
if ($current) {
$entries += [pscustomobject]$current
}
return $entries
}
function Test-HasPrepareOfficerSkill($Unit) {
foreach ($skillHex in $prepareOfficerSkillHex) {
if ($Unit.Skills -match $skillHex) {
return $true
}
}
return $false
}
function Test-IsExpectedCultureUpgradeTarget($Unit) {
if ($null -eq $Unit.GiantType -or $Unit.GiantType -ne 0) {
return $false
}
if ($null -eq $Unit.UnitLevel -or $Unit.UnitLevel -ne 0) {
return $false
}
if ($null -eq $Unit.Cost -or $Unit.Cost -le 0) {
return $false
}
if ($null -eq $Unit.LandType -or $Unit.LandType -ne 1) {
return $false
}
if ($null -eq $Unit.ChessType -or -not $cultureUpgradeChessTypes.ContainsKey([int]$Unit.ChessType)) {
return $false
}
if ($explicitExemptions.ContainsKey((Get-UnitKey $Unit))) {
return $false
}
return $true
}
function Get-MissingPrepareOfficerUnits($Units) {
foreach ($unit in $Units) {
if (-not (Test-IsExpectedCultureUpgradeTarget $unit)) {
continue
}
if (Test-HasPrepareOfficerSkill $unit) {
continue
}
[pscustomobject]@{
Path = $unit.SourcePath
Line = $unit.Line
UnitKey = Get-UnitKey $unit
Name = $unit.Name
ChessType = $cultureUpgradeChessTypes[[int]$unit.ChessType]
Skills = $unit.Skills
}
}
}
function Assert-NoMissingPrepareOfficer([string]$Label, $Units) {
$expected = @($Units | Where-Object { Test-IsExpectedCultureUpgradeTarget $_ })
$missing = @(Get-MissingPrepareOfficerUnits $Units)
if ($missing.Count -gt 0) {
Write-Host "$Label culture upgrade config errors:"
$missing | Format-Table -AutoSize
throw "$Label has $($missing.Count) ordinary culture-upgrade unit(s) missing prepare-officer skill."
}
Write-Host "$Label culture upgrade config OK: checked $($expected.Count) ordinary culture-upgrade unit(s)."
}
$sourceUnits = Read-UnitTypeEntries $AssetPath
Assert-NoMissingPrepareOfficer "Source" $sourceUnits
if ($CheckExport) {
$exportUnits = Read-UnitTypeEntries $ExportPath
Assert-NoMissingPrepareOfficer "Export" $exportUnits
$exportByKey = @{}
foreach ($unit in $exportUnits) {
$exportByKey[(Get-UnitKey $unit)] = $unit
}
$staleExportUnits = @()
foreach ($sourceUnit in $sourceUnits) {
if (-not (Test-IsExpectedCultureUpgradeTarget $sourceUnit)) {
continue
}
if (-not (Test-HasPrepareOfficerSkill $sourceUnit)) {
continue
}
$key = Get-UnitKey $sourceUnit
if (-not $exportByKey.ContainsKey($key)) {
$staleExportUnits += [pscustomobject]@{
UnitKey = $key
SourceLine = $sourceUnit.Line
ExportLine = ""
Problem = "missing in export"
}
continue
}
$exportUnit = $exportByKey[$key]
if (-not (Test-HasPrepareOfficerSkill $exportUnit)) {
$staleExportUnits += [pscustomobject]@{
UnitKey = $key
SourceLine = $sourceUnit.Line
ExportLine = $exportUnit.Line
Problem = "export lacks prepare-officer skill"
}
}
}
if ($staleExportUnits.Count -gt 0) {
Write-Host "Export culture upgrade sync errors:"
$staleExportUnits | Format-Table -AutoSize
throw "Export UnitTypeDataAssets is stale for $($staleExportUnits.Count) culture-upgrade unit(s). Refresh export through the normal Unity workflow."
}
Write-Host "Export culture upgrade config is in sync with source."
}