Compare commits
13 Commits
v0.0.5
...
4148e8b861
| Author | SHA1 | Date | |
|---|---|---|---|
| 4148e8b861 | |||
| 3c893cd0d9 | |||
| 2a7b6d9395 | |||
| 4bb64d35da | |||
| cb92587449 | |||
| 84c9baa2d5 | |||
| a60aa56477 | |||
| 6d1186b60a | |||
| 83dcb77425 | |||
| e67c7e6093 | |||
| 6030d10069 | |||
| 05259e1f26 | |||
| 3476112815 |
@@ -2,9 +2,6 @@ name: Build Mod Package
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
tags:
|
||||
- "v*"
|
||||
workflow_dispatch:
|
||||
@@ -68,23 +65,6 @@ jobs:
|
||||
- name: Build .pak
|
||||
run: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
$workspace = "${{ gitea.workspace }}"
|
||||
$refName = "${{ gitea.ref_name }}"
|
||||
$archiveBaseName = "DnD 5.5e AIO Russian"
|
||||
$modName = "DnD 5.5e All-in-One BEYOND Russian Localization"
|
||||
$modFolder = "DnD 5.5e AIO Russian"
|
||||
$modUuid = "6401e84d-daf2-416d-adeb-99c03a2487a6"
|
||||
$modDescription = "Русская локализация мода DnD 5.5e All-in-One BEYOND."
|
||||
$modAuthor = "MikhailRaw"
|
||||
$modVersion64 = "36028797018963968"
|
||||
$modGroup = "6401e84d-daf2-416d-adeb-99c03a2487a6"
|
||||
if ($refName -and $refName -like "v*") {
|
||||
$archiveBaseName = "DnD 5.5e AIO Russian $refName"
|
||||
}
|
||||
$modsPath = [System.IO.Path]::GetFullPath((Join-Path $workspace "Mods"))
|
||||
$packagePath = [System.IO.Path]::GetFullPath((Join-Path $workspace "build/DnD 5.5e AIO Russian.pak"))
|
||||
$zipPath = [System.IO.Path]::GetFullPath((Join-Path $workspace "build/$archiveBaseName.zip"))
|
||||
$infoJsonPath = [System.IO.Path]::GetFullPath((Join-Path $workspace "build/info.json"))
|
||||
$divine = Get-ChildItem -Path ".tools/lslib" -Recurse -File |
|
||||
Where-Object { $_.Name -ieq "Divine.exe" } |
|
||||
Select-Object -First 1
|
||||
@@ -93,48 +73,7 @@ jobs:
|
||||
throw "Divine.exe was not found in the downloaded LSLib release."
|
||||
}
|
||||
|
||||
& $divine.FullName -a pack -g bg3 -s $modsPath -d $packagePath
|
||||
|
||||
if (-not (Test-Path -LiteralPath "build/DnD 5.5e AIO Russian.pak")) {
|
||||
throw "Package was not created."
|
||||
}
|
||||
|
||||
$packageFile = Get-Item -LiteralPath $packagePath
|
||||
if ($packageFile.Length -lt 1024) {
|
||||
throw "Package looks invalid: '$packagePath' is only $($packageFile.Length) bytes."
|
||||
}
|
||||
|
||||
if (Test-Path -LiteralPath $zipPath) {
|
||||
Remove-Item -LiteralPath $zipPath -Force
|
||||
}
|
||||
|
||||
$packageMd5 = (Get-FileHash -LiteralPath $packagePath -Algorithm MD5).Hash.ToLowerInvariant()
|
||||
$createdAt = (Get-Date).ToString("o")
|
||||
|
||||
$infoJson = [ordered]@{
|
||||
Mods = @(
|
||||
[ordered]@{
|
||||
Author = $modAuthor
|
||||
Name = $modName
|
||||
Folder = $modFolder
|
||||
Version = $modVersion64
|
||||
Description = $modDescription
|
||||
UUID = $modUuid
|
||||
Created = $createdAt
|
||||
Dependencies = @()
|
||||
Group = $modGroup
|
||||
}
|
||||
)
|
||||
MD5 = $packageMd5
|
||||
} | ConvertTo-Json -Depth 4
|
||||
|
||||
Set-Content -LiteralPath $infoJsonPath -Value $infoJson -Encoding utf8
|
||||
|
||||
Compress-Archive -LiteralPath @($packagePath, $infoJsonPath) -DestinationPath $zipPath -CompressionLevel Optimal
|
||||
|
||||
if (-not (Test-Path -LiteralPath $zipPath)) {
|
||||
throw "ZIP archive was not created."
|
||||
}
|
||||
& ".\\scripts\\build.ps1" -DivinePath $divine.FullName -Workspace "${{ gitea.workspace }}" -VersionTag "${{ gitea.ref_name }}"
|
||||
|
||||
- name: Show build result
|
||||
run: |
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,4 +1,6 @@
|
||||
build/
|
||||
build-stage*
|
||||
.tools/
|
||||
*.pak
|
||||
*.tmp
|
||||
*.temp
|
||||
|
||||
152
AGENTS.md
Normal file
152
AGENTS.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# AGENTS.md
|
||||
|
||||
## Project Overview
|
||||
|
||||
This repository contains a standalone Russian localization mod for **Baldur's Gate 3**:
|
||||
|
||||
- Mod name: `DnD 5.5e All-in-One BEYOND Russian Localization`
|
||||
- Mod folder: `Mods/DnD 5.5e AIO Russian`
|
||||
- Base/original mod dependency: `DnD 5.5e All-in-One BEYOND`
|
||||
- Original mod repository: `https://github.com/Yoonmoonsik/dnd55e`
|
||||
- Original dependency UUID: `897914ef-5c96-053c-44af-0be823f895fe`
|
||||
|
||||
This repository is for the localization mod only. It must not gain gameplay logic, Script Extender files, or unrelated assets.
|
||||
|
||||
## Repository Rules
|
||||
|
||||
- Keep the repository source-only.
|
||||
- Do not commit `.pak` artifacts.
|
||||
- Do not commit temporary build outputs.
|
||||
- Do not add gameplay or script content unrelated to localization/release packaging.
|
||||
- Keep the localization folder and metadata consistent with the packaged mod.
|
||||
|
||||
## Current Important Paths
|
||||
|
||||
- Mod sources: `Mods/DnD 5.5e AIO Russian`
|
||||
- Localization XML: `Mods/DnD 5.5e AIO Russian/Localization/Russian/russian.xml`
|
||||
- Mod metadata: `Mods/DnD 5.5e AIO Russian/meta.lsx`
|
||||
- CI workflow: `.gitea/workflows/build.yml`
|
||||
- Main build script: `scripts/build.ps1`
|
||||
|
||||
## Build And Release Model
|
||||
|
||||
The authoritative build logic lives in:
|
||||
|
||||
- `scripts/build.ps1`
|
||||
|
||||
The Gitea workflow should stay thin and only:
|
||||
|
||||
1. prepare the workspace
|
||||
2. download `Divine`
|
||||
3. call `scripts/build.ps1`
|
||||
4. publish the release zip for tag builds
|
||||
|
||||
### Current Build Outputs
|
||||
|
||||
The build script produces:
|
||||
|
||||
- `build/DnD 5.5e AIO Russian.pak`
|
||||
- `build/info.json`
|
||||
- `build/DnD 5.5e AIO Russian <tag>.zip` for tagged builds
|
||||
|
||||
The release zip is expected to contain:
|
||||
|
||||
- the built `.pak`
|
||||
- `info.json`
|
||||
|
||||
## Packaging Notes
|
||||
|
||||
The package must contain only the BG3 mod structure under `Mods/...`.
|
||||
|
||||
Verified expected extracted `.pak` structure:
|
||||
|
||||
- `Mods/DnD 5.5e AIO Russian/meta.lsx`
|
||||
- `Mods/DnD 5.5e AIO Russian/Localization/Russian/russian.xml`
|
||||
|
||||
Do not allow `.git`, `.gitea`, `scripts`, `tools`, `.tools`, `build`, or staging directories into the `.pak`.
|
||||
|
||||
## Important Packaging Behavior
|
||||
|
||||
There is a runner-specific packaging quirk:
|
||||
|
||||
- `Divine` can produce a broken 48-byte `.pak` on the CI runner depending on the source path.
|
||||
- Current mitigation is implemented in `scripts/build.ps1`.
|
||||
- The script uses staged sources and fallback packaging attempts.
|
||||
- Staging is performed in `%TEMP%`, not in a dot-prefixed directory inside the repo.
|
||||
|
||||
If packaging breaks again, debug the source path and unpack the resulting `.pak` locally to verify actual contents.
|
||||
|
||||
## Versioning
|
||||
|
||||
Version displayed by BG3ModManager should be derived from the release tag.
|
||||
|
||||
Current behavior:
|
||||
|
||||
- `scripts/build.ps1` derives `Version64` from tags like `v0.1.0`
|
||||
- the computed version is written into:
|
||||
- generated `info.json`
|
||||
- staged `meta.lsx` before packaging
|
||||
|
||||
Do not manually hardcode release versions in the committed `meta.lsx` for each release if CI can derive them from tags.
|
||||
|
||||
## info.json Expectations
|
||||
|
||||
`info.json` is generated during build and should remain aligned with BG3/BG3ModManager expectations.
|
||||
|
||||
Current expected shape:
|
||||
|
||||
- top-level `Mods`
|
||||
- top-level `MD5`
|
||||
- per-mod fields:
|
||||
- `Author`
|
||||
- `Name`
|
||||
- `Folder`
|
||||
- `Version`
|
||||
- `Description`
|
||||
- `UUID`
|
||||
- `Created`
|
||||
- `Dependencies`
|
||||
- `Group`
|
||||
|
||||
Current dependency model:
|
||||
|
||||
- `Dependencies` is an array of dependency UUIDs
|
||||
- current dependency UUID:
|
||||
- `897914ef-5c96-053c-44af-0be823f895fe`
|
||||
|
||||
## CI Trigger Policy
|
||||
|
||||
Current workflow policy:
|
||||
|
||||
- run on tags `v*`
|
||||
- run on manual dispatch
|
||||
- do not run on every push to `main`
|
||||
|
||||
## Git / Collaboration Preferences
|
||||
|
||||
User preference:
|
||||
|
||||
- after making changes, ask for permission before committing
|
||||
- if the user approves, commit and push immediately
|
||||
- for significant changes, propose moving work into a separate branch
|
||||
- feature/fix branches must use the prefix `feat/` or `fix/`
|
||||
- after finishing work in a `feat/` or `fix/` branch, propose merging it back into `main`
|
||||
- comments and commit messages should be written in Russian
|
||||
- commit messages should describe what was done, not what should be done
|
||||
- if changes affect files that go into the final `.pak`, or change the build/release process, propose releasing the next version
|
||||
- if push fails, retry up to two more times with a 3-second pause between attempts
|
||||
|
||||
Do not auto-commit or auto-push without explicit user approval.
|
||||
|
||||
## Cleanup Expectations
|
||||
|
||||
Temporary directories and debug artifacts should not remain in the repository.
|
||||
|
||||
Ignored paths currently include:
|
||||
|
||||
- `build/`
|
||||
- `build-stage*`
|
||||
- `.tools/`
|
||||
- `*.pak`
|
||||
|
||||
If local debugging creates additional temporary folders, remove them when done unless the user explicitly wants to keep them.
|
||||
133
glossary/glossary.normalized.json
Normal file
133
glossary/glossary.normalized.json
Normal file
@@ -0,0 +1,133 @@
|
||||
{
|
||||
"Ability Check": "проверка характеристики",
|
||||
"Advantage": "преимущество",
|
||||
"Aid": "Подмога",
|
||||
"Armor Class": "класс доспеха",
|
||||
"Attack Action": "действие «Атака»",
|
||||
"Attack Roll": "бросок атаки",
|
||||
"Bardic Inspiration": "Вдохновение барда",
|
||||
"Bardic Inspiration die": "кубик Вдохновения барда",
|
||||
"Beguiling Magic": "Чарующая магия",
|
||||
"Blessed Healer": "Благословенный целитель",
|
||||
"Blessed Strikes": "Благословенные удары",
|
||||
"Bonus Action": "бонусное действие",
|
||||
"Bonus Unarmed Strike": "Бонусная безоружная атака",
|
||||
"Brutal Strike": "Жестокий удар",
|
||||
"Cantrip": "заговор",
|
||||
"Cantrips": "заговоры",
|
||||
"Channel Divinity": "Направление божественной энергии",
|
||||
"Circle Forms": "Облики круга",
|
||||
"Circle of the Moon Spells": "Заклинания круга Луны",
|
||||
"Cleave": "Рассечение",
|
||||
"Concentration": "концентрация",
|
||||
"Countercharm": "Контрочарование",
|
||||
"Cutting Words": "Едкие слова",
|
||||
"D20 Test": "проверка к20",
|
||||
"Danger Sense": "Чувство опасности",
|
||||
"Dash": "Рывок",
|
||||
"Deflect Attacks": "Отклонение атак",
|
||||
"Disadvantage": "помеха",
|
||||
"Disciple of Life": "Ученик жизни",
|
||||
"Disengage": "Отход",
|
||||
"Divine Order": "Божественный порядок",
|
||||
"Divine Spark": "Божественная искра",
|
||||
"Druidic": "Друидический",
|
||||
"Eldritch Strike": "Мистический удар",
|
||||
"Elemental Fury": "Стихийная ярость",
|
||||
"Empowered Strikes": "Усиленные удары",
|
||||
"Evasion": "Ускользание",
|
||||
"Extra Attack": "Дополнительная атака",
|
||||
"Font of Inspiration": "Источник вдохновения",
|
||||
"Forceful Blow": "Мощный удар",
|
||||
"Fount of Moonlight": "Фонтан лунного света",
|
||||
"Frenzy": "Неистовство",
|
||||
"Graze": "Задевание",
|
||||
"Guidance": "Наставление",
|
||||
"Hamstring Blow": "Удар по сухожилиям",
|
||||
"Heavy Armor": "тяжёлые доспехи",
|
||||
"Heightened Focus": "Обострённый фокус",
|
||||
"Heroic Inspiration": "Героическое вдохновение",
|
||||
"Heroic Warrior": "Героический воин",
|
||||
"Hit Points": "очки здоровья",
|
||||
"Improved Combat Superiority": "Усовершенствованное превосходство в бою",
|
||||
"Improved Warding Flare": "Улучшенная защитная вспышка",
|
||||
"Indomitable": "Несгибаемая воля",
|
||||
"Instinctive Pounce": "Интуитивный рывок",
|
||||
"Invoke Duplicity": "Призыв двойника",
|
||||
"Light": "Свет",
|
||||
"Long Rest": "длительный отдых",
|
||||
"Magic Action": "действие «Магия»",
|
||||
"Magician": "Маг",
|
||||
"Mantle of Inspiration": "Мантия вдохновения",
|
||||
"Martial Arts": "Боевые искусства",
|
||||
"Martial weapons": "воинское оружие",
|
||||
"Mastery Properties": "свойства мастерства",
|
||||
"Medium Armor": "средние доспехи",
|
||||
"Mind Magic": "Магия разума",
|
||||
"Mindless Rage": "Безрассудная ярость",
|
||||
"Moonlight Step": "Лунный шаг",
|
||||
"Moonlight Step Charge": "заряд «Лунного шага»",
|
||||
"Necrotic Damage": "урон некротической энергией",
|
||||
"Nick": "Надрез",
|
||||
"Opportunity Attack": "атака по возможности",
|
||||
"Opportunity Attacks": "атаки по возможности",
|
||||
"Patient Defense": "Выжидательная оборона",
|
||||
"Poison Spray": "Брызги яда",
|
||||
"Potent Spellcasting": "Мощное заклинание",
|
||||
"Preserve Life": "Сохранение жизни",
|
||||
"Primal Knowledge": "Первозданное знание",
|
||||
"Primal Order": "Первозданный уклад",
|
||||
"Primal Strike": "Первобытный удар",
|
||||
"Produce Flame": "Создание пламени",
|
||||
"Proficiency Bonus": "бонус мастерства",
|
||||
"Proficient": "владение",
|
||||
"Protector": "Защитник",
|
||||
"Purity of Body": "Чистота тела",
|
||||
"Push": "Отталкивание",
|
||||
"Radiant Damage": "урон излучением",
|
||||
"Rage": "Ярость",
|
||||
"Reaction": "реакция",
|
||||
"Reckless Attack": "Безрассудная атака",
|
||||
"Redirect Attacks": "Перенаправление атак",
|
||||
"Relentless Rage": "Неудержимая ярость",
|
||||
"Remarkable Athlete": "Выдающийся атлет",
|
||||
"Resistance": "Сопротивление",
|
||||
"Retaliation": "Возмездие",
|
||||
"Sacred Flame": "Священное пламя",
|
||||
"Sap": "Утомление",
|
||||
"Saving Throw": "спасбросок",
|
||||
"Sear Undead": "Выжигание нежити",
|
||||
"Second Wind": "Второе дыхание",
|
||||
"Self-Restoration": "Самоисцеление",
|
||||
"Shillelagh": "Дубинка",
|
||||
"Short Rest": "короткий отдых",
|
||||
"Slow": "Замедление",
|
||||
"Slow Fall": "Замедление падения",
|
||||
"Spare the Dying": "Пощада умирающему",
|
||||
"Spell Slot": "ячейка заклинаний",
|
||||
"Starry Wisp": "Звёздная искра",
|
||||
"Step of the Wind": "Шаг ветра",
|
||||
"Tactical Master": "Мастер тактики",
|
||||
"Tactical Mind": "Тактический ум",
|
||||
"Tactical Shift": "Тактический манёвр",
|
||||
"Temporary Hit Points": "временные очки здоровья",
|
||||
"Thaumaturge": "Чудотворец",
|
||||
"Thaumaturgy": "Чудотворство",
|
||||
"Thorn Whip": "Колючий бич",
|
||||
"Thunderclap": "Раскат грома",
|
||||
"Toll the Dead": "Погребальный звон",
|
||||
"Topple": "Опрокидывание",
|
||||
"Trickster’s Transposition": "Перемещение обманщика",
|
||||
"Unarmored Defense": "Защита без доспехов",
|
||||
"Unarmored Movement": "Бездоспешное передвижение",
|
||||
"Uncanny Metabolism": "Необычный метаболизм",
|
||||
"Unfettered Mind": "Свободный разум",
|
||||
"Vex": "Досада",
|
||||
"Warden": "Страж",
|
||||
"Warding Flare": "Защитная вспышка",
|
||||
"Weapon Mastery": "мастерство владения оружием",
|
||||
"Wild Resurgence": "Возрождение дикого облика",
|
||||
"Wild Shape": "Дикий облик",
|
||||
"Wild Shape Charge": "заряд «Дикого облика»",
|
||||
"Word of Radiance": "Сияющее слово"
|
||||
}
|
||||
@@ -1,7 +1,189 @@
|
||||
param(
|
||||
[string]$DivinePath = "Divine",
|
||||
[string]$Workspace = (Get-Location).Path,
|
||||
[string]$VersionTag = "",
|
||||
[string]$ModFolder = "DnD 5.5e AIO Russian",
|
||||
[string]$PackageName = "DnD 5.5e AIO Russian.pak",
|
||||
[string]$ArchiveBaseName = "DnD 5.5e AIO Russian",
|
||||
[string]$ModName = "DnD 5.5e All-in-One BEYOND Russian Localization",
|
||||
[string]$ModUuid = "6401e84d-daf2-416d-adeb-99c03a2487a6",
|
||||
[string]$ModAuthor = "MikhailRaw",
|
||||
[string]$ModDescription = "Russian Localization",
|
||||
[string]$ModVersion64 = "36028797018963968",
|
||||
[string]$ModGroup = "6401e84d-daf2-416d-adeb-99c03a2487a6",
|
||||
[string]$DependencyUuid = "897914ef-5c96-053c-44af-0be823f895fe",
|
||||
[string]$DependencyVersion64 = "36028797018963968"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
if (-not (Test-Path -LiteralPath "build")) {
|
||||
New-Item -ItemType Directory -Path "build" | Out-Null
|
||||
function Convert-VersionTagToVersion64 {
|
||||
param(
|
||||
[string]$Tag,
|
||||
[string]$FallbackVersion64
|
||||
)
|
||||
|
||||
if (-not $Tag) {
|
||||
return [int64]$FallbackVersion64
|
||||
}
|
||||
|
||||
Divine -a pack -s Mods -d "build/DnD 5.5e AIO Russian.pak"
|
||||
$normalized = $Tag
|
||||
if ($normalized.StartsWith("v")) {
|
||||
$normalized = $normalized.Substring(1)
|
||||
}
|
||||
|
||||
if ($normalized -notmatch '^\d+(\.\d+){0,3}$') {
|
||||
return [int64]$FallbackVersion64
|
||||
}
|
||||
|
||||
$parts = $normalized.Split(".")
|
||||
$numbers = @(0, 0, 0, 0)
|
||||
for ($i = 0; $i -lt $parts.Length; $i++) {
|
||||
$numbers[$i] = [int]$parts[$i]
|
||||
}
|
||||
|
||||
return ([int64]$numbers[0] -shl 55) -bor ([int64]$numbers[1] -shl 47) -bor ([int64]$numbers[2] -shl 31) -bor [int64]$numbers[3]
|
||||
}
|
||||
|
||||
$workspacePath = [System.IO.Path]::GetFullPath($Workspace)
|
||||
$modsPath = Join-Path $workspacePath "Mods"
|
||||
$modPath = Join-Path $modsPath $ModFolder
|
||||
$buildPath = Join-Path $workspacePath "build"
|
||||
$stagingRoot = Join-Path $env:TEMP "bg3-dnd55e-russian-localization-stage"
|
||||
$stagingPath = Join-Path $stagingRoot "build-stage"
|
||||
$packagePath = Join-Path $buildPath $PackageName
|
||||
$tempPackagePath = Join-Path $env:TEMP $PackageName
|
||||
$archiveName = $ArchiveBaseName
|
||||
if ($VersionTag) {
|
||||
$archiveName = "$ArchiveBaseName $VersionTag"
|
||||
}
|
||||
$zipPath = Join-Path $buildPath "$archiveName.zip"
|
||||
$infoJsonPath = Join-Path $buildPath "info.json"
|
||||
$resolvedVersion64 = Convert-VersionTagToVersion64 -Tag $VersionTag -FallbackVersion64 $ModVersion64
|
||||
|
||||
if (-not (Test-Path -LiteralPath $DivinePath)) {
|
||||
$resolvedCommand = Get-Command $DivinePath -ErrorAction SilentlyContinue
|
||||
if (-not $resolvedCommand) {
|
||||
throw "Divine executable was not found: '$DivinePath'."
|
||||
}
|
||||
$DivinePath = $resolvedCommand.Source
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $modPath)) {
|
||||
throw "Mod folder was not found: '$modPath'."
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath (Join-Path $modPath "Localization\\Russian\\russian.xml"))) {
|
||||
throw "Localization file was not found under '$modPath'."
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $buildPath -Force | Out-Null
|
||||
|
||||
foreach ($path in @($stagingPath, $tempPackagePath, $packagePath, $zipPath, $infoJsonPath)) {
|
||||
if (Test-Path -LiteralPath $path) {
|
||||
if ((Get-Item -LiteralPath $path).PSIsContainer) {
|
||||
Remove-Item -LiteralPath $path -Recurse -Force
|
||||
} else {
|
||||
Remove-Item -LiteralPath $path -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Test-Path -LiteralPath $stagingRoot) {
|
||||
Remove-Item -LiteralPath $stagingRoot -Recurse -Force
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $stagingPath -Force | Out-Null
|
||||
Copy-Item -LiteralPath $modsPath -Destination $stagingPath -Recurse
|
||||
|
||||
$stagedMetaPath = Join-Path $stagingPath "Mods\\$ModFolder\\meta.lsx"
|
||||
if (-not (Test-Path -LiteralPath $stagedMetaPath)) {
|
||||
throw "Staged meta.lsx was not found: '$stagedMetaPath'."
|
||||
}
|
||||
|
||||
$stagedMetaContent = Get-Content -LiteralPath $stagedMetaPath -Raw
|
||||
$stagedMetaContent = $stagedMetaContent -replace '(<attribute id="Version64" type="int64" value=")\d+("/>)', "`${1}$resolvedVersion64`${2}"
|
||||
Set-Content -LiteralPath $stagedMetaPath -Value $stagedMetaContent -Encoding utf8
|
||||
|
||||
Write-Host "[build.ps1] Staged source tree:"
|
||||
Get-ChildItem -Recurse $stagingPath | Select-Object FullName, Length | Format-Table -AutoSize
|
||||
|
||||
if (Test-Path -LiteralPath $tempPackagePath) {
|
||||
Remove-Item -LiteralPath $tempPackagePath -Force
|
||||
}
|
||||
|
||||
$packageAttempts = @(
|
||||
[ordered]@{ Name = "staging-root"; Source = $stagingPath },
|
||||
[ordered]@{ Name = "mods-root"; Source = $modsPath },
|
||||
[ordered]@{ Name = "workspace-root"; Source = $workspacePath }
|
||||
)
|
||||
|
||||
$successfulAttempt = $null
|
||||
foreach ($attempt in $packageAttempts) {
|
||||
if (Test-Path -LiteralPath $tempPackagePath) {
|
||||
Remove-Item -LiteralPath $tempPackagePath -Force
|
||||
}
|
||||
|
||||
Write-Host "[build.ps1] Trying Divine source '$($attempt.Name)': $($attempt.Source)"
|
||||
& $DivinePath -a create-package -g bg3 -s $attempt.Source -d $tempPackagePath
|
||||
|
||||
if (-not (Test-Path -LiteralPath $tempPackagePath)) {
|
||||
Write-Host "[build.ps1] No package created for attempt '$($attempt.Name)'."
|
||||
continue
|
||||
}
|
||||
|
||||
$attemptPackage = Get-Item -LiteralPath $tempPackagePath
|
||||
Write-Host "[build.ps1] Attempt '$($attempt.Name)' produced $($attemptPackage.Length) bytes."
|
||||
|
||||
if ($attemptPackage.Length -ge 1024) {
|
||||
$successfulAttempt = $attempt
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $successfulAttempt) {
|
||||
$lastSize = "missing"
|
||||
if (Test-Path -LiteralPath $tempPackagePath) {
|
||||
$lastSize = (Get-Item -LiteralPath $tempPackagePath).Length
|
||||
}
|
||||
throw "Package looks invalid after all attempts. Last output '$tempPackagePath' size: $lastSize bytes."
|
||||
}
|
||||
|
||||
Move-Item -LiteralPath $tempPackagePath -Destination $packagePath
|
||||
|
||||
if (-not (Test-Path -LiteralPath $packagePath)) {
|
||||
throw "Package was not created."
|
||||
}
|
||||
|
||||
$packageFile = Get-Item -LiteralPath $packagePath
|
||||
Write-Host "[build.ps1] Using package from attempt '$($successfulAttempt.Name)'."
|
||||
|
||||
$packageMd5 = (Get-FileHash -LiteralPath $packagePath -Algorithm MD5).Hash.ToLowerInvariant()
|
||||
$createdAt = (Get-Date).ToString("o")
|
||||
|
||||
$infoJson = [ordered]@{
|
||||
Mods = @(
|
||||
[ordered]@{
|
||||
Author = $ModAuthor
|
||||
Name = $ModName
|
||||
Folder = $ModFolder
|
||||
Version = [string]$resolvedVersion64
|
||||
Description = $ModDescription
|
||||
UUID = $ModUuid
|
||||
Created = $createdAt
|
||||
Dependencies = @($DependencyUuid)
|
||||
Group = $ModGroup
|
||||
}
|
||||
)
|
||||
MD5 = $packageMd5
|
||||
} | ConvertTo-Json -Depth 4
|
||||
|
||||
Set-Content -LiteralPath $infoJsonPath -Value $infoJson -Encoding utf8
|
||||
Compress-Archive -LiteralPath @($packagePath, $infoJsonPath) -DestinationPath $zipPath -CompressionLevel Optimal
|
||||
|
||||
if (-not (Test-Path -LiteralPath $zipPath)) {
|
||||
throw "ZIP archive was not created."
|
||||
}
|
||||
|
||||
Get-ChildItem -LiteralPath $packagePath, $infoJsonPath, $zipPath |
|
||||
Select-Object FullName, Length, LastWriteTime
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
mkdir -p build
|
||||
Divine -a pack -s Mods -d "build/DnD 5.5e AIO Russian.pak"
|
||||
Reference in New Issue
Block a user