diff --git a/build.ps1 b/build.ps1 deleted file mode 100644 index 3e6c468..0000000 --- a/build.ps1 +++ /dev/null @@ -1,901 +0,0 @@ -#requires -Version 5.1 -<# - BadWolf 过滤器构建脚本 build.ps1 v1.2 - ------------------------------------------------------------------ - 用途:把模块目录下的 txt 按文件名排序拼接成 BadWolf-LootFilter.txt, - 并完成一致性校验与行号换算。纯 PowerShell,无需安装任何软件。 - - v1.2 相对 v1.1 的变化 - ------------------------------------------------------------------ - · 自检新增:孤立 % / 未闭合 % 扫描(半截百分号会吞颜色或漏出明文) - 判定:先整体屏蔽合法占位符 %NAME%,剩下的 % 只放行四种写字面百分号的情形 - (数值后 40%ED / 右括号后 [4-6]%物理减伤 / 夹在两个占位符之间 / - 「物理减伤%」「魔法减伤%」后的百分比示意符) - - v1.1 相对 v1.0 的变化 - ------------------------------------------------------------------ - · 模块白名单:只拼 NN-*.txt,其它 txt 一律跳过并黄字警告(不再静默混入) - · 备份轮转:build 只保留最近 2 份 .bak,可用 -KeepBackups N 调整 - · 临时文件:写盘失败也会清理 .tmp - · 自检新增:物品代码白名单(item_codes.txt)/ 死规则 / Formula 引用完整性 - · 版本行联动:版本行日期落后于最晚模块改动时间时提示 - - 用法(二选一) - ------------------------------------------------------------------ - A. 双击 build.bat → 直接校验(窗口不关) - B. 命令行: - powershell -NoProfile -ExecutionPolicy Bypass -File build.ps1 - powershell -NoProfile -ExecutionPolicy Bypass -File build.ps1 build - powershell -NoProfile -ExecutionPolicy Bypass -File build.ps1 map 1939 - powershell -NoProfile -ExecutionPolicy Bypass -File build.ps1 map 16:139 - powershell -NoProfile -ExecutionPolicy Bypass -File build.ps1 export - - 命令 - ------------------------------------------------------------------ - check 校验(默认,不写任何文件) - build 重建合并版(自动备份 .bak,只保留最近 2 份;-NoBackup 关闭备份) - map 行号换算: 1939(合并→模块) 或 16:139(模块→合并) - export 导出行号映射表 - - 参数 - ------------------------------------------------------------------ - -NoBackup build 时不备份原文件 - -KeepBackups N 备份保留份数,默认 2 - -Strict 有提示项也算不通过(退出码 1) - - 退出码:0 一致 / 1 有问题 / 2 环境问题 -#> -param( - [Parameter(Position = 0)][string]$Command = 'check', - [Parameter(Position = 1)][string]$Arg = '', - [switch]$NoBackup, - [switch]$Strict, - [int]$KeepBackups = 2 -) - -$ErrorActionPreference = 'Stop' - -# ---------------------------------------------------------------- 基础路径 -$Root = $PSScriptRoot -$MergedName = 'BadWolf-LootFilter.txt' -$MergedPath = Join-Path $Root $MergedName -$MapName = [char]0x884C + [char]0x53F7 + [char]0x6620 + [char]0x5C04 + [char]0x8868 + '.md' - -function Write-Line([string]$s) { Write-Host $s } -function Format-N([long]$n) { return $n.ToString('N0', [System.Globalization.CultureInfo]::InvariantCulture) } -function Get-Bar { return ('=' * 74) } -function Write-Head([string]$t) { Write-Host ""; Write-Host "[$t]"; Write-Host ('-' * 74) } - -function Get-Md5Hex([byte[]]$Bytes) { - $md5 = [System.Security.Cryptography.MD5]::Create() - try { $h = $md5.ComputeHash($Bytes) } finally { $md5.Dispose() } - return (-join ($h | ForEach-Object { $_.ToString('x2') })) -} - -# ---------------------------------------------------------------- 模块目录 -# 只认「≥10 个 数字-xxx.txt」的目录;多个候选直接报错,绝不猜 -function Get-ModuleDir { - $cands = @() - foreach ($d in @(Get-ChildItem -LiteralPath $Root -Directory -ErrorAction SilentlyContinue)) { - $n = @(Get-ChildItem -LiteralPath $d.FullName -Filter '*.txt' -File -ErrorAction SilentlyContinue | - Where-Object { $_.Name -match '^\d{2}-' }).Count - if ($n -gt 0) { $cands += [pscustomobject]@{ Path = $d.FullName; Count = $n } } - } - $good = @($cands | Where-Object { $_.Count -ge 10 } | Sort-Object -Descending Count) - - # 兼容「模块与脚本平铺在同一目录」的布局(仓库里可能没有子文件夹) - $flat = @(Get-ChildItem -LiteralPath $Root -Filter '*.txt' -File -ErrorAction SilentlyContinue | - Where-Object { $_.Name -match '^\d{2}-' }).Count - if ($flat -ge 10) { return $Root } - if ($good.Count -eq 0) { - $tip = '' - if ($cands.Count -gt 0) { - $tip = ';候选目录(文件数不足):' + (($cands | ForEach-Object { "$($_.Path)($($_.Count)个)" }) -join ',') - } - throw "找不到模块目录:$Root 下没有包含 ≥10 个 `00-xxx.txt` 形式文件的文件夹$tip" - } - if ($good.Count -gt 1) { - $list = ($good | ForEach-Object { "$($_.Path)($($_.Count) 个)" }) -join ';' - throw "检测到多个可能的模块目录,为避免用错目录构建,已停止:$list。请把多余的移走或改名。" - } - return $good[0].Path -} - -# ---------------------------------------------------------------- 载入模块 -# 白名单:只认「NN-名称.txt」;名字里带 副本/备份/copy/bak/(1) 的视为复制品,同样跳过 -$script:SkippedModules = @() -$CopyNameRe = '副本|备份|复制|copy|bak|backup|\(\d+\)' - -function Get-Modules([string]$Dir) { - $allTxt = @(Get-ChildItem -LiteralPath $Dir -Filter '*.txt' -File) - $files = @($allTxt | Where-Object { - $_.Name -match '^\d{2}-.*\.txt$' -and $_.Name -notmatch $CopyNameRe - } | Sort-Object Name) - $script:SkippedModules = @($allTxt | Where-Object { - -not ($_.Name -match '^\d{2}-.*\.txt$') -or ($_.Name -match $CopyNameRe) - } | Sort-Object Name | ForEach-Object { $_.Name }) - $list = New-Object System.Collections.ArrayList - $cursor = 1 - $strict = [System.Text.UTF8Encoding]::new($false, $true) - - foreach ($f in $files) { - $bytes = [System.IO.File]::ReadAllBytes($f.FullName) - $text = [System.Text.Encoding]::UTF8.GetString($bytes) - $errors = New-Object System.Collections.ArrayList - - try { [void]$strict.GetString($bytes) } - catch { [void]$errors.Add('不是合法的 UTF-8 编码') } - - if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) { - [void]$errors.Add('含 UTF-8 BOM') - } - $lfOnly = ([regex]::Matches($text, "(?.bak(文件名时间戳可直接按名倒序) -function Remove-OldBackup([int]$Keep) { - $dir = Split-Path -Parent $MergedPath - $pat = (Split-Path -Leaf $MergedPath) + '.*.bak' - $all = @(Get-ChildItem -LiteralPath $dir -Filter $pat -File -ErrorAction SilentlyContinue | - Sort-Object Name -Descending) - if ($all.Count -le $Keep) { return @() } - $gone = @($all | Select-Object -Skip $Keep) - foreach ($g in $gone) { Remove-Item -LiteralPath $g.FullName -Force -ErrorAction SilentlyContinue } - return $gone -} - -# ---------------------------------------------------------------- build -function Invoke-Build($Mods) { - Write-Line (Get-Bar) - Write-Line " BadWolf 过滤器 构建" - Write-Line (Get-Bar) - - $bad = @($Mods | Where-Object { $_.Errors.Count -gt 0 }) - if ($bad.Count -gt 0) { - Write-Line " [中止] 以下模块存在编码/换行问题:" - foreach ($m in $bad) { - Write-Line " $($m.Name)" - foreach ($e in $m.Errors) { Write-Line " ! $e" } - } - return 1 - } - - $cat = Join-Bytes $Mods - $old = @() - if (Test-Path -LiteralPath $MergedPath) { $old = [System.IO.File]::ReadAllBytes($MergedPath) } - - $same = $false - if ($old.Length -eq $cat.Length) { - $same = $true - for ($i = 0; $i -lt $cat.Length; $i++) { if ($cat[$i] -ne $old[$i]) { $same = $false; break } } - } - if ($same) { - Write-Line " 合并版已是最新,无需重建。" - Write-Line "" - return Invoke-Check $Mods - } - - if (-not $NoBackup -and (Test-Path -LiteralPath $MergedPath)) { - $stamp = Get-Date -Format 'yyyyMMdd-HHmmss' - $bak = "$MergedPath.$stamp.bak" - Copy-Item -LiteralPath $MergedPath -Destination $bak -Force - Write-Line " 已备份 → $(Split-Path -Leaf $bak)" - if ($KeepBackups -gt 0) { - $gone = @(Remove-OldBackup $KeepBackups) - if ($gone.Count -gt 0) { - Write-Line " 轮转 删除旧备份 $($gone.Count) 份(保留最近 $KeepBackups 份):$(($gone | ForEach-Object { $_.Name }) -join ', ')" - } else { - Write-Line " 轮转 现有备份未超过 $KeepBackups 份,无需删除" - } - } - } - - $tmp = "$MergedPath.tmp" - try { - [System.IO.File]::WriteAllBytes($tmp, $cat) - Move-Item -LiteralPath $tmp -Destination $MergedPath -Force - } finally { - if (Test-Path -LiteralPath $tmp) { Remove-Item -LiteralPath $tmp -Force -ErrorAction SilentlyContinue } - } - - $new = [System.IO.File]::ReadAllBytes($MergedPath) - $lineN = ([regex]::Matches([System.Text.Encoding]::UTF8.GetString($new), "\n")).Count - Write-Line " 已写入 $(Format-N $new.Length) B / $(Format-N $lineN) 行 MD5 $(Get-Md5Hex $new)" - - $okWrite = $false - if ($new.Length -eq $cat.Length) { - $okWrite = $true - for ($i = 0; $i -lt $cat.Length; $i++) { if ($new[$i] -ne $cat[$i]) { $okWrite = $false; break } } - } - if ($okWrite) { Write-Line " 写入校验通过(逐字节一致)" } else { Write-Line " [错误] 写入校验失败"; return 1 } - - Write-Line "" - return Invoke-Check $Mods -} - -# ---------------------------------------------------------------- map -function Invoke-Map($Mods, [string]$Q) { - if ($Q -match ':') { - $parts = $Q.Split(':') - $code = $parts[0]; $ln = 0 - if (-not [int]::TryParse($parts[1], [ref]$ln)) { Write-Line "无法解析行号:$Q"; return 1 } - $m = $Mods | Where-Object { $_.Code -eq $code -or $_.Name.StartsWith($code) } | Select-Object -First 1 - if ($null -eq $m) { Write-Line "找不到模块:$code"; return 1 } - if ($ln -lt 1 -or $ln -gt $m.LineCount) { Write-Line "$($m.Name) 只有 $($m.LineCount) 行"; return 1 } - $merged = $m.Start + $ln - 1 - Write-Line "$($m.Name) 第 $ln 行 → 合并版 L$merged" - $lines = Get-Lines $m.Text - if ($ln -le $lines.Count) { Write-Line " $($lines[$ln - 1])" } - return 0 - } - - $ln = 0 - if (-not [int]::TryParse($Q, [ref]$ln)) { Write-Line "无法解析行号:$Q"; return 1 } - $m = Find-ModuleOfLine $Mods $ln - if ($null -eq $m) { Write-Line "L$ln 超出范围(1-$($Mods[$Mods.Count-1].End))"; return 1 } - Write-Line "合并版 L$ln → $($m.Name) 第 $($ln - $m.Start + 1) 行" - return 0 -} - -# ---------------------------------------------------------------- export -function Invoke-Export($Mods) { - $cat = Join-Bytes $Mods - $end = $Mods[$Mods.Count - 1].End - $sb = New-Object System.Text.StringBuilder - [void]$sb.AppendLine('# BadWolf 过滤器行号映射表') - [void]$sb.AppendLine('') - [void]$sb.AppendLine("- 生成时间:$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')") - [void]$sb.AppendLine("- 模块数:$($Mods.Count)") - [void]$sb.AppendLine("- 模块拼接:$(Format-N $cat.Length) 字节 / $(Format-N $end) 行 / MD5 ``$(Get-Md5Hex $cat)``") - [void]$sb.AppendLine('- 换算:`合并行 = 模块起始行 + 模块行 - 1`') - [void]$sb.AppendLine('') - [void]$sb.AppendLine('| 模块 | 合并版起 | 合并版止 | 行数 | 字节 |') - [void]$sb.AppendLine('|---|---:|---:|---:|---:|') - foreach ($m in $Mods) { - [void]$sb.AppendLine("| $($m.Name) | $($m.Start) | $($m.End) | $($m.LineCount) | $(Format-N $m.ByteLen) |") - } - [void]$sb.AppendLine("| **合计** | 1 | $end | $end | $(Format-N $cat.Length) |") - [void]$sb.AppendLine('') - [void]$sb.AppendLine('## 常用锚点') - [void]$sb.AppendLine('') - foreach ($m in $Mods) { - if (@('00','09','16','22','28','37','39') -contains $m.Code) { - [void]$sb.AppendLine("- ``$($m.Code)`` $($m.Name) → L$($m.Start)–L$($m.End)") - } - } - $path = Join-Path $Root $MapName - [System.IO.File]::WriteAllText($path, $sb.ToString(), (New-Object System.Text.UTF8Encoding($false))) - Write-Line "已导出 $path" - return 0 -} - -# ---------------------------------------------------------------- 主流程 -try { - $moduleDir = Get-ModuleDir -} catch { - Write-Line "[错误] $($_.Exception.Message)" - exit 2 -} - -Write-Line (Get-Bar) -Write-Line " BadWolf 过滤器构建工具(PowerShell 版)" -Write-Line (Get-Bar) -Write-Line " 脚本位置 $PSCommandPath" -Write-Line " 模块目录 $moduleDir" -Write-Line " 合并版 $MergedPath" - -$mods = Get-Modules $moduleDir -if ($mods.Count -eq 0) { Write-Line "[错误] 模块目录里没有 NN-*.txt 模块文件"; exit 2 } - -if ($script:SkippedModules.Count -gt 0) { - Write-Host "" - Write-Host " [警告] 以下 txt 不符合「NN-名称.txt」,已跳过(不会进入合并版):" -ForegroundColor Yellow - foreach ($n in $script:SkippedModules) { Write-Host " - $n" -ForegroundColor Yellow } - Write-Host " 若是正式模块,请改名成 40-xxx.txt 这种形式。" -ForegroundColor Yellow -} - -# 编号必须唯一:两个 16-xxx.txt 会让合并版多出一整段,且顺序取决于文件名,必须人工处理 -$dupCodes = @($mods | Group-Object Code | Where-Object { $_.Count -gt 1 }) -if ($dupCodes.Count -gt 0) { - Write-Line "" - Write-Line "[错误] 模块编号重复,已停止(避免把两份内容都拼进合并版):" - foreach ($g in $dupCodes) { - $names = ($g.Group | ForEach-Object { $_.Name }) -join ' / ' - Write-Line (" [$($g.Name)] $names") - } - Write-Line " 处理办法:把多余的那份移出模块目录,或改成未占用的编号。" - exit 2 -} - -switch ($Command.ToLowerInvariant()) { - 'build' { exit (Invoke-Build $mods) } - 'map' { if ([string]::IsNullOrWhiteSpace($Arg)) { Write-Line "用法:build.bat map 1939 或 build.bat map 16:139"; exit 2 }; exit (Invoke-Map $mods $Arg) } - 'export' { exit (Invoke-Export $mods) } - 'check' { exit (Invoke-Check $mods) } - default { Write-Line "[错误] 未知命令:$Command(可用 check / build / map / export)"; exit 2 } -}