diff --git a/.editorconfig b/.editorconfig index 21516d51c5..8719cf43c5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,6 +14,10 @@ end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true +[*.rc] +# rc.exe assumes the system ANSI codepage without a BOM, which would mangle non-ASCII strings like the copyright symbol. +charset = utf-8-bom + [.gitattributes] charset = utf-8 end_of_line = unset diff --git a/.github/actions/build-phobos/action.yml b/.github/actions/build-phobos/action.yml index 380228e08e..44c78314db 100644 --- a/.github/actions/build-phobos/action.yml +++ b/.github/actions/build-phobos/action.yml @@ -8,6 +8,10 @@ inputs: build-config: description: 'Configuration to build' required: true + build-type: + description: 'Build type: NIGHTLY or RELEASE' + required: true + default: 'NIGHTLY' syringeex-tag: description: 'SyringeEx release tag to bundle (empty for the latest release)' required: false @@ -26,7 +30,7 @@ runs: working-directory: ${{env.GITHUB_WORKSPACE}} # Add additional options to the MSBuild command line here (like platform or verbosity level). # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference - run: msbuild /m /p:Configuration=${{inputs.build-config}} /p:GitCommit=${{github.sha}} /p:GitBranch=${{github.ref}} ${{inputs.sln-path}} + run: msbuild /m /p:Configuration=${{inputs.build-config}} /p:BuildType=${{inputs.build-type}} ${{inputs.sln-path}} shell: cmd - name: Stage exception database diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index be74b16347..4e8f02ed5f 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -23,17 +23,18 @@ git submodule update --init --recursive | Config | Command | Output | |--------|---------|--------| | Debug (recommended for dev) | `scripts\build_debug.bat` | `Debug\Phobos.dll` + `.pdb` | -| DevBuild (CI nightly) | `scripts\build_devbuild.bat` | `DevBuild\Phobos.dll` + `.pdb` | | Release | `scripts\build_release.bat` | `Release\Phobos.dll` + `.pdb` | +There are only two build configurations, `Debug` and `Release`. What kind of build is produced (nightly or stable release) is a separate axis, set by the `BuildType` MSBuild property (`NIGHTLY` or `RELEASE`), which defines the preprocessor macro of the same name; an unset `BuildType` means a plain local build. A pre-release is a `RELEASE` build whose `PRERELEASE_SUFFIX` (hardcoded in `src/Phobos.version.h`) is still defined; remove the suffix there to build a stable release. + These scripts invoke `scripts\run_msbuild.bat`, which locates the VS Developer Command Prompt via `vswhere.exe` (bundled in `scripts/`), then runs `msbuild`. **VS 2022 or VS Build Tools 2022** with the components listed in `.vsconfig` must be installed: - `Microsoft.VisualStudio.Component.VC.Tools.x86.x64` - `Microsoft.VisualStudio.Component.Windows10SDK.20348` - `Microsoft.VisualStudio.Component.VC.ATL` -**In VS Code**, prefer the pre-configured build tasks over running scripts directly unless there are issues. The workspace defines a **"Build Phobos"** task (default build task) that prompts for Debug/DevBuild/Release. Run it via `Ctrl+Shift+B` or the `Tasks: Run Build Task` command. A **"Cleanup build folders"** task is also available. +**In VS Code**, prefer the pre-configured build tasks over running scripts directly unless there are issues. The workspace defines a **"Build Phobos"** task (default build task) that prompts for Debug/Release. Run it via `Ctrl+Shift+B` or the `Tasks: Run Build Task` command. A **"Cleanup build folders"** task is also available. -**In Visual Studio 2022**, most contributors build directly from the IDE using `Build > Build Solution` (`Ctrl+Shift+B`) with the solution configuration dropdown (Debug/DevBuild/Release). The batch scripts are not needed when building from VS. +**In Visual Studio 2022**, most contributors build directly from the IDE using `Build > Build Solution` (`Ctrl+Shift+B`) with the solution configuration dropdown (Debug/Release). The batch scripts are not needed when building from VS. The build takes roughly 1–3 minutes for a full rebuild. Incremental builds are much faster. To clean: ``` @@ -42,19 +43,17 @@ scripts\clean.bat ### CI build (GitHub Actions) -The CI workflow (`.github/actions/build-phobos/action.yml`) builds the **DevBuild** config with MSBuild, passing `/p:GitCommit= /p:GitBranch=` for version stamping. The agent should replicate the CI as: +The release workflow (`.github/workflows/release.yml`) builds the **Release** config with MSBuild, passing `/p:BuildType=RELEASE`; whether that build is a pre-release is decided by `PRERELEASE_SUFFIX` in `src/Phobos.version.h`, not by the workflow. Nightly builds (`.github/workflows/nightly.yml` and the PR nightly) pass `/p:BuildType=NIGHTLY`. Git commit/ref info is not passed from CI in either case: `Phobos.props` runs a `ComputeGitInfo` target that derives the short commit SHA, the ref (e.g. `refs/heads/develop`) and a dirty marker straight from the repository, so local builds are stamped identically. The agent should replicate a nightly CI build as: ``` -msbuild /m /p:Configuration=DevBuild Phobos.sln +msbuild /m /p:Configuration=Release /p:BuildType=NIGHTLY Phobos.sln ``` ## Tests & Validation There is **no automated test suite**. Validation is: 1. **Successful compilation** with zero errors (warning level 4, but not treated as errors). -2. **PR CI checks** - the `Pull Request Nightly Build` workflow must pass (builds DevBuild config). -3. **PR doc checker** (`.github/workflows/pr-doc-checker.yml`) - unless the PR has the `No Documentation Needed` label, these files must be modified: - - `docs/Whats-New.md` (changelog entry) - - `CREDITS.md` (credit entry; skipped if the `Bugfix` label is set) +2. **PR CI checks** - the `Pull Request Nightly Build` workflow must pass (builds the Release config as a nightly). +3. **PR doc checker** (`.github/workflows/pr-doc-checker.yml`) - its three checks (changelog, credits, docs) each pass when the corresponding file is modified, and are skipped individually when the matching label is applied (`Skip Changelog`, `Skip Docs`, `Skip Credits`). Labels are applied by maintainers; see the table in `docs/Contributing.md` for what each kind of change is expected to cover. Always verify your changes compile by running `scripts\build_debug.bat` before committing. @@ -373,6 +372,8 @@ scripts\build_docs.bat Output goes to `docs/_build/html/`. Pull requests are automatically built and served by Read the Docs - check the PR status checks for a preview link. +**Local extension `docs/_ext/`**: a small local Sphinx extension (`sanitize_system_messages`, registered as `_ext.sanitize_system_messages` in `docs/conf.py`) strips docutils `system_message` nodes and repairs the `rawsource` that Sphinx's `ApplySourceWorkaround` pollutes with them. Without it, the "Duplicate implicit target name" warnings caused by repeated sub-headings (e.g. the many `#### Vanilla fixes:` blocks inside `{dropdown}`s in `Whats-New.md`) leak into the gettext `.pot`/`.po` files as bogus translatable strings. Do not remove it or drop `sys.path.insert(0, os.path.abspath('.'))` from `conf.py` - the extension is only importable because of that path insert. A standalone reproduction of the underlying Sphinx/MyST bug is in this [gist](https://gist.github.com/Metadorius/ee435861903ba132cd70563c2bdffec1). + ### Translations The project uses Sphinx internationalization with `.po` files. Currently only **zh_CN** (Chinese) is maintained. The translation workflow: @@ -401,12 +402,12 @@ Many contributors are non-native English speakers, so the existing documentation ## PR Checklist -For non-trivial changes (unless labeled `No Documentation Needed`): +For non-trivial changes: 1. Update `docs/Whats-New.md` with a changelog entry. 2. Update `CREDITS.md` with your contribution. 3. Update relevant documentation pages in `docs/`. -Use `[Minor]` in the PR title for small changes that don't need documentation updates. +If one of these doesn't apply to your change, ask a maintainer to apply the matching label (`Skip Changelog`, `Skip Docs` or `Skip Credits`) so the corresponding check is skipped. See the table in `docs/Contributing.md` for what each kind of change is expected to cover. ## Trust These Instructions diff --git a/.github/labeler.yml b/.github/labeler.yml deleted file mode 100644 index 3d1afafe8e..0000000000 --- a/.github/labeler.yml +++ /dev/null @@ -1,26 +0,0 @@ -# https://github.com/marketplace/actions/auto-labeler -# labeler "full" schema - -# enable labeler on issues, prs, or both. -enable: - issues: false - prs: true -# comments object allows you to specify a different message for issues and prs - -# Labels is an object where: -# - keys are labels -# - values are objects of { include: [ pattern ], exclude: [ pattern ] } -# - pattern must be a valid regex, and is applied globally to -# title + description of issues and/or prs (see enabled config above) -# - 'include' patterns will associate a label if any of these patterns match -# - 'exclude' patterns will ignore this label if any of these patterns match -labels: - 'Minor': - include: - - '(?i)\[minor\]' - exclude: [] - - 'No Documentation Needed': - include: - - '(?i)\[no documentation needed\]' - exclude: [] diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index fe85615ca1..969e5e7158 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,2 +1,17 @@ - + + +## What kind of change is this? + + + +- [ ] **New feature, vanilla bugfix or enhancement of a released feature** - changelog, docs and credits entries are needed. +- [ ] **Improvement to a new (unreleased) feature** - docs and credits entries are needed; no changelog entry (`Skip Changelog`). +- [ ] **Bugfix to a new (unreleased) feature** - credits entry is needed; no changelog or docs entries (`Skip Changelog`, `Skip Docs`). +- [ ] **Bugfix to an old (released) feature** - changelog and credits entries are needed; no docs entry (`Skip Docs`). +- [ ] **Completely minor change (e.g. a typo fix)** - no entries are needed (`Skip Changelog`, `Skip Docs`, `Skip Credits`). + +## Description + + diff --git a/.github/workflows/labeler-action.yml b/.github/workflows/labeler-action.yml deleted file mode 100644 index 2448ff159c..0000000000 --- a/.github/workflows/labeler-action.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Labeler Action -on: - pull_request_target: - types: [opened, edited] - -jobs: - - labeler: - runs-on: ubuntu-latest - - steps: - - name: Label - id: labeler - uses: jimschubert/labeler-action@v2 - with: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 78abf91f6c..cb27d97e15 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -3,8 +3,6 @@ name: Nightly Build on: push: branches: - - master - - main - develop env: @@ -14,9 +12,7 @@ env: # Configuration type to build. # You can convert this to a build matrix if you need coverage of multiple configuration types. # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix - BUILD_CONFIGURATION: DevBuild - # GIT_COMMIT: $(git rev-parse --short "$GITHUB_SHA") - # GIT_BRANCH: ${GITHUB_REF#refs/heads/} + BUILD_CONFIGURATION: Release jobs: build: @@ -32,3 +28,4 @@ jobs: with: sln-path: ${{env.SOLUTION_FILE_PATH}} build-config: ${{env.BUILD_CONFIGURATION}} + build-type: NIGHTLY diff --git a/.github/workflows/pr-doc-checker.yml b/.github/workflows/pr-doc-checker.yml index 1795c07167..58ad0778d0 100644 --- a/.github/workflows/pr-doc-checker.yml +++ b/.github/workflows/pr-doc-checker.yml @@ -14,8 +14,8 @@ env: jobs: Changelog-Check: name: Changelog Mention - # If the No Documentation Needed label is set, then workflow will not be executed - if: ${{ !contains(github.event.pull_request.labels.*.name, 'No Documentation Needed') }} + # If the Skip Changelog label is set, then workflow will not be executed + if: ${{ !contains(github.event.pull_request.labels.*.name, 'Skip Changelog') }} runs-on: ubuntu-latest steps: @@ -31,14 +31,14 @@ jobs: exit 0 else echo "It looks like you forgot to update the Changelog! ðŸ§" - echo "Please, mention your changes in 'docs/Whats-New.md' or use [No Documentation Needed] label for your Pull Request." + echo "Please, mention your changes in 'docs/Whats-New.md' or ask a maintainer to apply the Skip Changelog label for your Pull Request." exit 1 fi Credits-Check: name: Credits List Mention - # If the No Documentation Needed or Bugfix label is set, then workflow will not be executed - if: ${{ !contains(github.event.pull_request.labels.*.name, 'No Documentation Needed') && !contains(github.event.pull_request.labels.*.name, 'Bugfix') }} + # If the Skip Credits label is set, then workflow will not be executed + if: ${{ !contains(github.event.pull_request.labels.*.name, 'Skip Credits') }} runs-on: ubuntu-latest steps: @@ -54,14 +54,14 @@ jobs: exit 0 else echo "It looks like you forgot to update the Credits List! ðŸ§" - echo "Please, mention your contribution in 'CREDITS.md' or use [No Documentation Needed] label for your Pull Request." + echo "Please, mention your contribution in 'CREDITS.md' or ask a maintainer to apply the Skip Credits label for your Pull Request." exit 1 fi Documentation-Check: name: Documentation for Changes - # If the No Documentation Needed or Bugfix label is set, then workflow will not be executed - if: ${{ !contains(github.event.pull_request.labels.*.name, 'No Documentation Needed') && !contains(github.event.pull_request.labels.*.name, 'Bugfix') }} + # If the Skip Docs label is set, then workflow will not be executed + if: ${{ !contains(github.event.pull_request.labels.*.name, 'Skip Docs') }} runs-on: ubuntu-latest steps: @@ -85,14 +85,12 @@ jobs: exit 0 else echo "It looks like you forgot to add your changes to the docs! ðŸ§" - echo "Please, document your changes or use [No Documentation Needed] label for your Pull Request." + echo "Please, document your changes or ask a maintainer to apply the Skip Docs label for your Pull Request." exit 1 fi Interop-Version-Check: name: Interop API Version Updated - # If the No Documentation Needed label is set, then workflow will not be executed - if: ${{ !contains(github.event.pull_request.labels.*.name, 'No Documentation Needed') }} runs-on: ubuntu-latest steps: @@ -104,12 +102,12 @@ jobs: # Check if any files in src/Interop/ were modified (excluding Version.h itself for initial checks) CHANGED_FILES=$(git diff --name-only $(git merge-base origin/$BASE_BRANCH HEAD)) INTEROP_MODIFIED=$(echo "$CHANGED_FILES" | grep -E "^src/Interop/.*\.(h|cpp)$" | grep -v "^src/Interop/Version\." || true) - + if [ -z "$INTEROP_MODIFIED" ]; then echo "No Interop files modified. Skipping version check." exit 0 fi - + # If Interop files were modified, check if Version.h was also modified if echo "$CHANGED_FILES" | grep -q "^src/Interop/Version\.h$"; then echo "Thank you for updating the Interop API version! 😋" diff --git a/.github/workflows/pr-nightly.yml b/.github/workflows/pr-nightly.yml index 4eb9b53ec9..10354fe56f 100644 --- a/.github/workflows/pr-nightly.yml +++ b/.github/workflows/pr-nightly.yml @@ -10,9 +10,7 @@ env: # Configuration type to build. # You can convert this to a build matrix if you need coverage of multiple configuration types. # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix - BUILD_CONFIGURATION: DevBuild - # GIT_COMMIT: $(git rev-parse --short "$GITHUB_SHA") - # GIT_BRANCH: ${GITHUB_REF#refs/heads/} + BUILD_CONFIGURATION: Release jobs: build: @@ -30,3 +28,5 @@ jobs: with: sln-path: ${{env.SOLUTION_FILE_PATH}} build-config: ${{env.BUILD_CONFIGURATION}} + build-type: NIGHTLY + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..64d7467385 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,87 @@ +name: Release Build + +on: + release: + types: [published] + +env: + SOLUTION_FILE_PATH: . + BUILD_CONFIGURATION: Release + +permissions: + contents: write + +jobs: + build: + runs-on: windows-2022 + + steps: + - uses: actions/checkout@v7 + with: + submodules: recursive + + - name: Determine Build Type and Version Info + id: info + shell: pwsh + run: | + $tag = "${{ github.ref_name }}" + $version = $tag.TrimStart('v') + $isPrerelease = "${{ github.event.release.prerelease }}" + # Whether the build is a pre-release is decided by Phobos.version.h's PRERELEASE_SUFFIX; + # here we only build a release-family build and keep the display name distinct. + if ($isPrerelease -eq "true") { + $releaseName = "Phobos $tag (Pre-release)" + } else { + $releaseName = "Phobos $tag" + } + echo "build-type=RELEASE" >> $env:GITHUB_OUTPUT + echo "version=$version" >> $env:GITHUB_OUTPUT + echo "release-name=$releaseName" >> $env:GITHUB_OUTPUT + + - name: Build Phobos + uses: ./.github/actions/build-phobos + with: + sln-path: ${{env.SOLUTION_FILE_PATH}} + build-config: ${{ env.BUILD_CONFIGURATION }} + build-type: ${{ steps.info.outputs.build-type }} + + - name: Extract Release Notes + shell: pwsh + run: | + .\scripts\extract_changelog.ps1 ` + -Tag "${{ github.ref_name }}" ` + -WhatsNewPath docs\Whats-New.md ` + -OutputPath RELEASE_NOTES.md ` + -LinkBase "https://github.com/${{ github.repository }}/blob/${{ github.ref_name }}/docs" + + - name: Append Changelog to the Release Notes + shell: pwsh + env: + GH_TOKEN: ${{ github.token }} + run: | + $tag = "${{ github.ref_name }}" + # Fetch the text the release author wrote, so the changelog can be appended to it + # instead of replacing it. Re-running the workflow must not append a second copy, + # so the changelog is wrapped in a marker block that is stripped before re-appending. + $existing = (gh api "repos/${{ github.repository }}/releases/tags/$tag" --jq '.body // ""' 2>$null) -join "`n" + if ($LASTEXITCODE -ne 0) { $existing = '' } + $changelog = (Get-Content -Raw -Path RELEASE_NOTES.md).Trim() + $markerStart = '' + $markerEnd = '' + $block = "$markerStart`n$changelog`n$markerEnd" + # Drop any previously appended changelog block so re-runs replace rather than duplicate + $existing = [regex]::Replace($existing, "(?s)$markerStart.*$markerEnd", '').TrimEnd("`r", "`n") + $combined = if ([string]::IsNullOrWhiteSpace($existing)) { $block } else { "$existing`n`n$block" } + Set-Content -Path RELEASE_NOTES.md -Value $combined -Encoding utf8 + + - name: Upload Release Assets + uses: softprops/action-gh-release@v2 + with: + name: ${{ steps.info.outputs.release-name }} + files: | + ${{ env.BUILD_CONFIGURATION }}/Phobos.dll + ${{ env.BUILD_CONFIGURATION }}/Phobos.pdb + ${{ env.BUILD_CONFIGURATION }}/gamemd.edb + ${{ env.BUILD_CONFIGURATION }}/Syringe.exe + ${{ env.BUILD_CONFIGURATION }}/Syringe.LICENSE.txt + body_path: RELEASE_NOTES.md diff --git a/.gitignore b/.gitignore index 8591b8d397..2f2b9c2dde 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,7 @@ out # Python virtual environment for docs .venv/ + +# Python bytecode caches +__pycache__/ +*.py[cod] diff --git a/.vscode/c_cpp_properties.example.json b/.vscode/c_cpp_properties.example.json index cbea9e2a8e..dcd5039162 100644 --- a/.vscode/c_cpp_properties.example.json +++ b/.vscode/c_cpp_properties.example.json @@ -20,12 +20,19 @@ "${workspaceFolder}/YRpp/**", "${workspaceFolder}/lib", "${workspaceFolder}/lib/**", + "${workspaceFolder}/Debug/IntDir/Generated", + "${workspaceFolder}/Debug/IntDir/Generated/**", + "${workspaceFolder}/Release/IntDir/Generated", + "${workspaceFolder}/Release/IntDir/Generated/**", ], "defines": [ "SYR_VER=2", "HAS_EXCEPTIONS=0", "NOMINMAX", "_CRT_SECURE_NO_WARNINGS", + "_WIN32_WINNT=0x0601", + "NTDDI_VERSION=0x06010000", + "PHOBOS_DLL=\"Phobos.dll\"", "_WINDLL" ], "compilerPath": "${vsPath}/VC/Tools/MSVC/14.29.30133/bin/HostX86/x86/cl.exe", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index c441998e81..7a64122948 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -77,9 +77,6 @@ { "value": "Debug" }, - { - "value": "DevBuild" - }, { "value": "Release" } diff --git a/Phobos.props b/Phobos.props index bee83b6da5..9cf1e017d8 100644 --- a/Phobos.props +++ b/Phobos.props @@ -5,10 +5,6 @@ Debug Win32 - - DevBuild - Win32 - Release Win32 @@ -25,10 +21,10 @@ false - $(ExpandedIncludePath);$(MSBuildThisFileDirectory)src\;$(YRppDir);$(VC_IncludePath) + $(Configuration)\IntDir\ + $(ExpandedIncludePath);$(MSBuildThisFileDirectory)src\;$(YRppDir);$(IntDir)Generated;$(VC_IncludePath) false $(Configuration)\ - $(Configuration)\IntDir\ dbghelp.lib;onecore.lib @@ -70,21 +66,6 @@ - - IS_RELEASE_VER;%(PreprocessorDefinitions) - MaxSpeed - true - - - - - - - IS_RELEASE_VER;%(PreprocessorDefinitions) - - - - MaxSpeed true @@ -106,22 +87,71 @@ DEBUG;%(PreprocessorDefinitions) - - + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + - /DGIT_COMMIT="$(GitCommit)" %(AdditionalOptions) + NIGHTLY;%(PreprocessorDefinitions) - /DGIT_COMMIT="$(GitCommit)" %(AdditionalOptions) + NIGHTLY;%(PreprocessorDefinitions) - - + - /DGIT_BRANCH="$(GitBranch)" %(AdditionalOptions) + RELEASE;%(PreprocessorDefinitions) - /DGIT_BRANCH="$(GitBranch)" %(AdditionalOptions) + RELEASE;%(PreprocessorDefinitions) diff --git a/Phobos.sln b/Phobos.sln index cb404798b9..d5ed44ff6f 100644 --- a/Phobos.sln +++ b/Phobos.sln @@ -1,21 +1,18 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29209.62 +# Visual Studio Version 18 +VisualStudioVersion = 18.4.11626.88 stable MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Phobos", "Phobos.vcxproj", "{3FAF7126-F38C-4D1E-9973-C21A37870F60}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 - DevBuild|x86 = DevBuild|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {3FAF7126-F38C-4D1E-9973-C21A37870F60}.Debug|x86.ActiveCfg = Debug|Win32 {3FAF7126-F38C-4D1E-9973-C21A37870F60}.Debug|x86.Build.0 = Debug|Win32 - {3FAF7126-F38C-4D1E-9973-C21A37870F60}.DevBuild|x86.ActiveCfg = DevBuild|Win32 - {3FAF7126-F38C-4D1E-9973-C21A37870F60}.DevBuild|x86.Build.0 = DevBuild|Win32 {3FAF7126-F38C-4D1E-9973-C21A37870F60}.Release|x86.ActiveCfg = Release|Win32 {3FAF7126-F38C-4D1E-9973-C21A37870F60}.Release|x86.Build.0 = Release|Win32 EndGlobalSection diff --git a/Phobos.vcxproj b/Phobos.vcxproj index 781debeb8a..b848a70513 100644 --- a/Phobos.vcxproj +++ b/Phobos.vcxproj @@ -1,23 +1,5 @@ - - true - - - - true - - - - - true - - - - - true - - Phobos Phobos diff --git a/README.md b/README.md index 6b3de732df..37c16cdc20 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,12 @@ Downloads You can choose one of the following: - [Latest stable branch build](https://github.com/Phobos-developers/Phobos/releases/latest) (most bug-free release but very slow on new features) -- [Latest development branch builds](https://github.com/Phobos-developers/Phobos/releases) (a bit less bug-free releases, devbuilds get new features when they are finished) -- [Latest development branch nightly](https://nightly.link/Phobos-developers/Phobos/blob/develop/.github/workflows/nightly.yml) (added unreleased features that will be in next devbuild) +- [Latest pre-release builds](https://github.com/Phobos-developers/Phobos/releases) (a bit less bug-free releases, pre-releases get new features when they are finished) +- [Latest development branch nightly](https://nightly.link/Phobos-developers/Phobos/blob/develop/.github/workflows/nightly.yml) (added unreleased features that will be in the next pre-release) - Individual new feature nightly builds for testing can be found in [pull requests](https://github.com/Phobos-developers/Phobos/pulls) +To learn how these build types relate to each other and how versioning works, see the [release model and version lifecycle](docs/Project-guidelines-and-policies.md#git-branching-model-version-lifecycle-and-release-strategy). + ### Note on nightly builds Last two listed versions are bleeding edge (don't redistribute them outside of testing!) and have build information (commit and branch/tag) in them which is displayed ingame and can't be turned off. You can get a build for development branch (link above) any up-to-date pull request via an automatic bot comment that would appear in it and would contain the most recent successfully compiled version of Phobos for that feature branch. Please note that the build is produced *only if the PR has no merge conflicts*. Alternatively, you can get an artifact manually from GitHub Actions runs. You can get an artifact for a specific commit which is built automatically with a GitHub Actions workflow, just press on a green tick, open the workflow, find and download the build artifact. This is limited to authorized users only. @@ -46,6 +48,8 @@ Installation and Usage 2. Place those files in the game folder (where your `gamemd.exe` is located), replacing any existing `Syringe.exe` (for example the one shipped with Ares). 3. To launch the game with Phobos (and all other installed Syringe-compatible engine extensions including Ares) you need to execute `Syringe.exe "gamemd.exe" [command line arguments for gamemd.exe]` in command line (omit arguments if you don't need any). `RunAres.bat` from Ares package does the same so you may use that as well. +Be sure to read [migration and breaking changes](docs/Whats-New.md#migration-breaking-changes) to know if you need to adjust something in your mod after Phobos installation (or update). + If you already use Ares in your mod, you just need to drop Phobos files mentioned above in your game folder, Syringe will load Phobos automatically. This also applies to mods using XNA client with Syringe; if your mod doesn't use Syringe and Ares (or you just haven't set up the client) yet we recommend to use [CnCNet client mod base by Starkku](https://github.com/Starkku/cncnet-client-mod-base) which is compatible with Ares and Phobos out of the box. Additional files and tools that you may need are located at [Phobos supplementaries repo](https://github.com/Phobos-developers/PhobosSupplementaries). @@ -97,7 +101,7 @@ This project was founded by [@Belonit](https://github.com/Belonit) (Gluk-v48) an ### Interoperability -Phobos has opened the external interfaces of some key components. If you are also developing your own engine extension and wish to use Phobos at the same time, please check out [Interoperability](Interoperability.md). +Phobos has opened the external interfaces of some key components. If you are also developing your own engine extension and wish to use Phobos at the same time, please check out [Interoperability](docs/Interoperability.md). ### Maintenance crew diff --git a/docs/Contributing.md b/docs/Contributing.md index 9fc7527616..60dcec2858 100644 --- a/docs/Contributing.md +++ b/docs/Contributing.md @@ -41,7 +41,22 @@ If you contribute something, please make sure: - you mention the change in the changelog and migration sections in the [what's new page](Whats-New.md); - you mention your contribution in the [credits page](CREDITS.md). -If your change does not fit in standard criteria or too small that it doesn't need the above - add `[Minor]` to your pull request's title, so the CI won't yell at you for no reason. +Not every change needs all of the above. The table below shows what each kind of change is expected to cover (a checkmark means that kind of entry is required): + +| Change type | Changelog | Docs | Credits | +|----------------------------------------------------------------|-----------|------|---------| +| New feature, vanilla bugfix, enhancement of a released feature | ✓ | ✓ | ✓ | +| Improvement to a new (unreleased) feature | ✗ | ✓ | ✓ | +| Bugfix to a new (unreleased) feature | ✗ | ✗ | ✓ | +| Bugfix to an old (released) feature | ✓ | ✗ | ✓ | +| Completely minor change (e.g. a typo fix) | ✗ | ✗ | ✗ | + +```{warning} +If editing this table - also edit the PR template. +``` + +The checks for changelog, docs and credits are skipped individually when a maintainer applies the matching label - `Skip Changelog`, `Skip Docs` or `Skip Credits`. If one of the requirements does not apply to your change, say so in the pull request and ask for the corresponding label. + ```{hint} Every pull request push trigger a nightly build for the latest pushed commit, so you can check the build status at the bottom of PR page, press `Show all checks`, go to details of a build run and get the zip containing built DLL and PDB (for your testers, f. ex.), or download a build from an automatically posted comment. diff --git a/docs/General-Info.md b/docs/General-Info.md index 7797bb6ba3..e70dfe46c9 100644 --- a/docs/General-Info.md +++ b/docs/General-Info.md @@ -6,22 +6,24 @@ This page lists general info that should be known about the project. There are three main types of Phobos builds: - *stable builds* - those are numbered like your regular versions (something close to semantic versioning, e.g. version 1.2.3 for example) and ideally should contain no bugs, therefore are safe to use in mods; -- *development builds* - those are the builds which contain functionality that needs to be tested. They are numbered plainly starting from 0 and incrementing the number on each release. Mod authors still can include those versions with their mods if they want latest features, though we can't guarantee lack of bugs; +- *pre-release builds* - previously known as *development builds*, these builds mark the start of a new release branch and are used for testing new features before they are finalized. They are numbered with a version and a pre-release suffix (e.g., 0.5-beta1, 0.5-rc2). Mod authors can include these versions with their mods to access the latest features, but we cannot guarantee the absence of bugs; - *nightly builds* - bleeding edge versions which can include prototypes, proofs of concepts, scrapped features etc., in other words - we can't guarantee anything in those builds and they absolutely should NOT be used in mod releases and should only be used to help with development and testing. +Besides the published builds above, any build you make locally (from Visual Studio, VS Code or the build scripts) is marked as a *local build*: like nightly, it is stamped with the git commit and ref it was built from (plus a `-dirty` marker when the working tree has uncommitted changes) and shows a hideable "please test" warning. + ```{hint} You can find the downloads for these versions on the document's [main page](index.md#downloads). ``` -### Disabling development build warning +### Disabling pre-release build warning -**DISCLAIMER:** We understand that everyone wants to try and use the new features as soon as they're released, but we can't do all the testing ourselves, so we only test the functionality on a basic level. We ask everyone who uses the new development build first to **test the new changes in every possible way first before disabling the development build warning** and proceeding to include the build in your mod release. This would allow us to concentrate on implementing the actual features, which is the most complex task. Learn more on testing [here](Contributing.md#testing). +**DISCLAIMER:** We understand that everyone wants to try and use the new features as soon as they're released, but we can't do all the testing ourselves, so we only test the functionality on a basic level. We ask everyone who uses the new pre-release build first to **test the new changes in every possible way first before disabling the pre-release build warning** and proceeding to include the build in your mod release. This would allow us to concentrate on implementing the actual features, which is the most complex task. Learn more on testing [here](Contributing.md#testing). -You can hide the warning by specifying the build number after `-b=` as a command line argument (for example, `-b=1` would hide the warning for development build #1 of Phobos). +You can hide the warning by specifying the exact version of the build you use after `-HideVersionWarning=` as a command line argument (for example, `-HideVersionWarning=0.5.0.0-beta1` would hide the warning for the `v0.5-beta1` pre-release of Phobos). The version is shown in the warning itself and in the title of the respective release; a build only accepts its own version, so the switch has to be updated whenever you update Phobos. Nightly builds don't support hiding the warning at all. ## Saved games filtering -Phobos fully supports saving and loading thanks to prototype code from publicly released Ares 0.A source and it implements it's own filtering which shouldn't conflict with Ares save filtering. Save games between different versions are incompatible due to changes to Phobos extension classes which are present in almost every build release. The filtering mechanism, hovewer, doesn't apply to nightly versions - those use latest development build number on which this nightly is based on. While different nightly version saves may be listed, they are most likely incompatible in case there were changes to extension class fields. +Phobos fully supports saving and loading thanks to prototype code from publicly released Ares 0.A source and it implements it's own filtering which shouldn't conflict with Ares save filtering. Save games between different versions are incompatible due to changes to Phobos extension classes which are present in almost every build release. Nightlies and pre-releases of a version share the savegame ID of the stable release they lead up to, so their saves are filtered as a single version. They may still be incompatible with each other if there were changes to extension class fields. ## Compatibility diff --git a/docs/Miscellanous.md b/docs/Miscellanous.md index adac6b47ba..8759043b87 100644 --- a/docs/Miscellanous.md +++ b/docs/Miscellanous.md @@ -278,7 +278,7 @@ When the exception handler is enabled, Phobos replaces the game's own crash hand Crash folders older than 5 days are cleaned up automatically. The `-FullCrashDump` command line arg makes the automatically written minidump a full memory dump (useful for unattended setups). Crash reports can be enriched with extra information: -- If a `gamemd.pdb` file is present in the game directory, it is used to resolve game addresses to symbol names in the call stacks. `Phobos.pdb` (shipped with devbuilds and nightlies) is picked up automatically for Phobos's own addresses. +- If a `gamemd.pdb` file is present in the game directory, it is used to resolve game addresses to symbol names in the call stacks. `Phobos.pdb` (shipped with every build) is picked up automatically for Phobos's own addresses. - If a `gamemd.edb` exception database file is present in the game directory, its description for the faulting address (if any) is included in the report under "Additional information". The format is shared with Vinifera: one entry per line, `;` starts a comment. ```text diff --git a/docs/Project-guidelines-and-policies.md b/docs/Project-guidelines-and-policies.md index 687cf288b4..c8e05f0362 100644 --- a/docs/Project-guidelines-and-policies.md +++ b/docs/Project-guidelines-and-policies.md @@ -230,15 +230,64 @@ DEFINE_HOOK(0x48381D, CellClass_SpreadTiberium_CellSpread, 0x6) The styleguide is not exhaustive and may be adjusted in the future. ``` -## Git branching model - -Couple of notes regarding the Git practices. We use [git-flow](https://nvie.com/posts/a-successful-git-branching-model/)-like workflow: - - `master` is for stable releases, can have hotfixes pushed to it or branched off like a feature branch with the requirement of version increment and `master` being merged into `develop` after that; - - `develop` is the main development branch; - - `feature/`-prefixed branches (sometimes the prefix may be different if appropriate, like for big fixes or changes) are so called "feature branches" - those are branched off `develop` for every new feature to be introduced into it and then merged back. We use squash merge to merge them back in case of smaller branches and sometimes merge commit in case the branch is so big it would be viable to keep it as is. - - `hotfix/`-prefixed branches may be used in a same manner as `feature/`, but with `master` branch, with a requirement of `master` being merged into `develop` after `hotfix/` branch was squash merged into `master`. - - `release/`-prefixed branches are branched off `develop` when a new stable release is slated to allow working on features for a next release and stability improvements for this release. Those are merged with a merge commit into `master` and `develop` with a stable version number increase, after which the stable version is released. -- When you're working with your local & remote branches use **fast-forward** pulls to get the changes from remote branch to local, **don't merge remote branch into local and vice versa**, this creates junk commits and makes things unsquashable. +## Git branching model / Version lifecycle and release strategy + +Starting from version 0.5, Phobos adopts a new release strategy to enable faster and more frequent releases. + +![Versioning scheme from 0.5 onward](_static/images/versioning-past-0.5.excalidraw.png) + +*Image editable in [Excalidraw](https://excalidraw.com)* + +```{important} +All changes are to be made **exclusively** to `develop` as the source of truth, and then cherry-picked to other branches! +``` + +```{hint} +A brief summary compared to old style: +- devbuilds are now called pre-releases (alpha, beta, RC etc.) and are almost a proper version with docs, all changes tracked in a special changelog subsection, released on the same cadence; +- each pre-release (new devbuild) materializes a version branch, bugfix followups committed to develop get ported to it; +- when enough bugs are fixed - a stable version is created; +- if some critical change that warrants a version bump needs to be applied (e.g. forgot to serialize a field, or fixed a critical bug from a feature released before upcoming version) - we introduce a new version (with docs, version change etc.) on the same branch; +- the new stable release is not the old stable: after 0.5 a stable version is "a devbuild with enough bug fixes", released on a faster cadence with less time spent per version. +``` + +The lifecycle of a version is as follows: + +1. **Development phase**: New features and changes are committed to the `develop` branch. `develop` always carries the version it is working towards: as soon as a release branch is cut, `VERSION_MINOR` (or `VERSION_MAJOR`) in `src/Phobos.version.h` is bumped and `VERSION_REVISION`/`VERSION_PATCH` are reset to 0, so that nightlies are stamped with the version they lead up to instead of one that has already been released. +2. **Pre-release phase**: When enough features have accumulated on `develop`, a pre-release build (e.g., `v0.5-beta1`) is created. This build marks the start of a new *release branch* (e.g., `release/v0.5`) and signifies that active feature development for version 0.5 is complete. This branch will be used for all subsequent testing and the final stable release. + - During this phase, multiple pre-release builds (which can be called beta, alpha, or release candidate) may be published for wider testing. Between pre-releases on the same version number, there shall be no changes that warrant a stable version changelog addition; in other words — only bug fixes, minor additions, and polish to the existing new version feature set are allowed. + - If there's an urgent need to introduce a feature that would warrant new changelog addition on the same branch - it is allowed to **reset the pre-release prefix and increment the appropriate version number**, while also creating the corresponding doc changelog section. +3. **Stable release**: When the pre-release builds are deemed stable enough, a stable release (e.g., `v0.5`) is published from the release's branch. +4. **Maintenance phase**: After the stable release, the release branch enters maintenance mode, where only bug fixes are applied, resulting in patch releases (e.g., `v0.5.0.1`, `v0.5.0.2`). +5. **End of maintenance**: When a new stable release is published (e.g., `v0.6`), the previous minor version branch (e.g., `v0.5.x.y`) is officially deprecated and enters end-of-life, ceasing to receive any further updates, including bug fixes. Concurrently, the new stable release (e.g., `v0.6`) enters its own maintenance phase, and a new release branch for the next version (e.g., `release/v0.7`) may already have been created from the `develop` branch, initiating its pre-release cycle. + +```{hint} +If needed, a new release branch may be started even before the previous one has had a stable release. Doing so will temporarily increase the burden of upkeeping multiple branches, so do it only when there's a valid reason for such. +``` + +```{important} +The `master` branch is deprecated; all development occurs in `develop`, and each version branches off from it. + +**`develop` is the source of truth! Always apply your changes to `develop` first, then cherry-pick them onto the correct branch!** +``` + +### How to publish a release + +Publishing a release is done from a release branch (see the lifecycle above). The steps are: + +1. **Set the version** in `src/Phobos.version.h`. When a release branch is cut, bump `VERSION_MINOR` (or `VERSION_MAJOR`) and reset `VERSION_REVISION` and `VERSION_PATCH` to 0; patch releases only bump `VERSION_PATCH`. +2. **Decide whether it is a pre-release or a stable release.** The pre-release suffix is the knob: as long as `PRERELEASE_SUFFIX` is defined (e.g. `#define PRERELEASE_SUFFIX "beta1"`), a release build is a pre-release; remove the define entirely for a stable release. The suffix can be anything semantic versioning allows (e.g. `alpha5`, `beta1`, `rc3`). +3. **Create a GitHub release and tag** using the short user-facing version you've set in steps 1 and 2 (e.g. `v0.5-alpha1`). The `release.yml` workflow builds the DLL with `BuildType=RELEASE`; + - The changelog is extracted from `docs/Whats-New.md` automatically. **Do not write the changelog yourself!** It will be appended to the text you wrote after you publish the release. Also **do not use GitHub's "Generate release notes" button!** It can't be configured to provide correct output. + - The build is built and attached automatically. **Do not build Phobos releases manually!** + - **GitHub "pre-release" checkbox doesn't affect the produced build type**, it only affects the release's display status for GitHub. +4. **Verify the artifacts** once the build finishes and the artifacts are attached, then announce the release. + +The release tag and name use the short user-facing version (e.g. `v0.5-alpha1`); the DLL reports the full version with trailing zeros (e.g. `0.5.0.0-alpha1`) internally, so that is what appears in the file properties and what the `-HideVersionWarning` switch expects. + +If you want to build a pre-release locally for testing, run `scripts\build.bat Release RELEASE` with the suffix still defined in `version.h`. A plain `scripts\build_debug.bat` or `scripts\build_release.bat` always produces a local build instead. + +### Useful Git config These commands will do the following for all repositories on your PC: 1) remove the automatic merge upon pull and replace it with a rebase; diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 5ed4613f13..f59203386f 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -2,33 +2,30 @@ This page lists the history of changes across stable Phobos releases and also all the stuff that requires modders to change something in their mods to accommodate. -## Migrating +## Migration (breaking changes) + +```{important} +New Phobos user? Read the "Changes to vanilla behavior" subsections in every version below to know what you might need to adjust when installing Phobos +``` + +This serves as a changelog for when you just need to drop the new version in without reading into every version you're skipping, so you can simply read up on this log of breaking changes and apply whatever you might need to apply. ```{hint} You can use the migration utility (can be found on [Phobos supplementaries repo](https://github.com/Phobos-developers/PhobosSupplementaries)) to apply most of the changes automatically using a corresponding sed script file. ``` -### From vanilla +### 0.5 + +#### Changes to vanilla behavior - Vehicles paradropped by AI players now default to `Hunt` mission instead of `Guard`, matching what infantry do. This can be customized by setting `AIParadropMission` on the VehicleType, defaults to `[General] -> AIParadropMission`. - `IsSimpleDeployer` units now obey deploying facing constraint even without deploying animation if `DeployDir` is explicitly set on the unit. - `Vertical=true` projectiles now default to completely downwards initial trajectory/facing regardless of if their projectile image has `Voxel=true` or not. This behavior can be reverted by setting `VerticalInitialFacing=false` on projectile in `rulesmd.ini`. - `Vertical=true` projectiles no longer move horizontally if fired by aircraft by default. To re-enable this behaviour set `Vertical.AircraftFix=false` on the projectile. - Weapons with `Airstrike=true` on Warhead will now check target eligibility for airstrikes regardless of weapon slot. Use `AirstrikeTargets=all` on `Primary` airstrike weapon Warhead to restore previous behaviour. -- `PowerUpNAnim` is now used instead of the upgrade building's image file for upgrade animation if set. Note that displaying a damaged version will still require setting `PowerUpNDamagedAnim` explicitly in all cases, as the fallback to upgrade building image does not extend to it, nor would it be safe to add. `PowersUpToLevel=-1` upgrades still do not work correctly `PowerUpNAnim` and such buildings should forgo using explicit upgrade animations. -- Elite technos no longer scatter by default, behaviour can be restored by including `SCATTER` in their `EliteAbilities`. -- `[CrateRules] -> FreeMCV` now controls whether or not player is forced to receive unit from `[General] -> BaseUnit` from goodie crate if they own no buildings or any existing `[General] -> BaseUnit` vehicles and own more than `[CrateRules] -> FreeMCV.CreditsThreshold` (defaults to 1500) credits. -- Translucent RLE SHPs will now be drawn using a more precise and performant algorithm that has no green tint and banding. Can be disabled with `rulesmd.ini -> [General] -> FixTransparencyBlitters=no`. -- Iron Curtain status is now preserved by default when converting between TechnoTypes via `DeploysInto` / `UndeploysInto`. This behavior can be turned off per-TechnoType and global basis using `[TechnoType]/[CombatDamage] -> IronCurtain.KeptOnDeploy=no`. -- The obsolete `[General] -> WarpIn` has been enabled for the default anim type when technos are warping in. If you want to restore the vanilla behavior, use the same anim type as `[General] -> WarpOut`. -- Vehicles with `Crusher=true` + `OmniCrusher=true` / `MovementZone=CrusherAll` were hardcoded to tilt when crushing vehicles / walls respectively. This now obeys `TiltsWhenCrushes` but can be customized individually for these two scenarios using `TiltsWhenCrushes.Vehicles` and `TiltsWhenCrushes.Overlays`, which both default to `TiltsWhenCrushes`. - The default direction for aircraft landing on an airfield will use the direction specified by `[AudioVisual] -> PoseDir=` instead of the building's direction, which can be reverted by setting `AircraftDockingDir.DefaultToPoseDir=false`. -## Breaking changes - -This serves as a changelog for when you just need to drop the new version in without reading into every version you're skipping, so you can simply read up on this log of breaking changes and apply whatever you might need to apply. - -### Version TBD (develop branch nightly builds) +#### Changes to Phobos behavior - `ProjectileRange` (Ares feature) now has weapon range modifiers applied to it if greater than 0 and unless `ProjectileRange.ApplyModifiers` is set to false on the WeaponType. - `Splits.TargetCellRange` < 0 now applies special behaviour where the projectile does not consider nearby cells as additional targets if there are not enough techno targets to match `Cluster` count at all. @@ -73,7 +70,7 @@ This serves as a changelog for when you just need to drop the new version in wit - `PassengerDeletion.SoylentAllowedHouses`: `none` -> `enemies` - `PassengerDeletion.DisplaySoylentOffset`: `none` -> `all` -#### Changes compared to inter-version builds / pre-releases +##### Changes compared to inter-version builds / pre-releases ```{dropdown} Click to show - Due to the format issue with `select.shp` in vanilla Yuri's Revenge that prevents the [Select box logic](User-Interface.md#select-box) from rendering correctly, `select.shp` no longer serves as the default value for `[SelectBoxType] -> Shape=`, and you need to manually specify a value for this flag. @@ -84,6 +81,16 @@ This serves as a changelog for when you just need to drop the new version in wit ### 0.4 +#### Changes to vanilla behavior + +- `PowerUpNAnim` is now used instead of the upgrade building's image file for upgrade animation if set. Note that displaying a damaged version will still require setting `PowerUpNDamagedAnim` explicitly in all cases, as the fallback to upgrade building image does not extend to it, nor would it be safe to add. `PowersUpToLevel=-1` upgrades still do not work correctly with `PowerUpNAnim` and such buildings should forgo using explicit upgrade animations. +- Elite technos no longer scatter by default, behaviour can be restored by including `SCATTER` in their `EliteAbilities`. +- `[CrateRules] -> FreeMCV` now controls whether or not player is forced to receive unit from `[General] -> BaseUnit` from goodie crate if they own no buildings or any existing `[General] -> BaseUnit` vehicles and own more than `[CrateRules] -> FreeMCV.CreditsThreshold` (defaults to 1500) credits. +- The obsolete `[General] -> WarpIn` has been enabled for the default anim type when technos are warping in. If you want to restore the vanilla behavior, use the same anim type as `[General] -> WarpOut`. +- Vehicles with `Crusher=true` + `OmniCrusher=true` / `MovementZone=CrusherAll` were hardcoded to tilt when crushing vehicles / walls respectively. This now obeys `TiltsWhenCrushes` but can be customized individually for these two scenarios using `TiltsWhenCrushes.Vehicles` and `TiltsWhenCrushes.Overlays`, which both default to `TiltsWhenCrushes`. + +#### Changes to Phobos behavior + - Phobos-introduced Warhead effects like shield modifiers, critical hits, disguise & mind control removal now require Warhead `Verses` to affect target to apply unless `EffectsRequireVerses` is set to false. Shield armor type is used if target has an active shield that cannot be penetrated by the Warhead. - `Trajectory=Straight` projectiles can now snap on targets within 0.5 cells from their detonation point, this distance can be customized via `Trajectory.Straight.TargetSnapDistance`. - `LaunchSW.RealLaunch=false` now checks if firing house has enough credits to satisfy SW's `Money.Amount` in order to be fired. @@ -97,7 +104,7 @@ This serves as a changelog for when you just need to drop the new version in wit - Buildings delivered by trigger action 125 will now **always** play buildup anim as long as it exists. `[ParamTypes] -> 53` is deprecated. - `Shadow` for debris & meteor animations is changed to `ExtraShadow`. -#### Changes compared to inter-version builds / pre-releases +##### Changes compared to inter-version builds / pre-releases ```{dropdown} Click to show - Ivan bombs no longer automatically center on building when attached. Set `[CombatDamage] -> IvanBombAttachToCenter` to true to restore this behaviour. Due to technical constraints this cannot be customized per WeaponType. @@ -123,12 +130,19 @@ This serves as a changelog for when you just need to drop the new version in wit ### 0.3 +#### Changes to vanilla behavior + +- Translucent RLE SHPs will now be drawn using a more precise and performant algorithm that has no green tint and banding. Can be disabled with `rulesmd.ini -> [General] -> FixTransparencyBlitters=no`. +- Iron Curtain status is now preserved by default when converting between TechnoTypes via `DeploysInto` / `UndeploysInto`. This behavior can be turned off per-TechnoType and global basis using `[TechnoType]/[CombatDamage] -> IronCurtain.KeptOnDeploy=no`. + +#### Changes to Phobos behavior + - Keys `rulesmd.ini -> [WarheadType] -> PenetratesShield` and `rulesmd.ini -> [WarheadType] -> BreaksShield` have been changed to `Shield.Penetrate` and `Shield.Break`, respectively. - `Rad.NoOwner` on weapons is deprecated. This has been replaced by `RadHasOwner` key on radiation types itself. It also defaults to no, so radiation once again has no owner house by default. - `RadApplicationDelay` and `RadApplicationDelay.Building` on custom radiation types are now only used if `[Radiation] -> UseGlobalRadApplicationDelay` is explicitly set to false, otherwise values from `[Radiation]` are used. - Existing script actions were renumbered, please use the migration utility to change the numbers to the correct ones. -#### Changes compared to inter-version builds / pre-releases +##### Changes compared to inter-version builds / pre-releases ```{dropdown} Click to show - `Trajectory.Speed` is now defined on projectile instead of weapon. @@ -399,7 +413,7 @@ HideShakeEffects=false ; boolean ## Changelog -### Version TBD (develop branch nightly builds) +### 0.5 ```{dropdown} Click to show :open: @@ -825,6 +839,13 @@ HideShakeEffects=false ; boolean - Fixed the issue of Ares' EMP not suspending the production of AI factories (by CrimRecya) - Removed the restriction that prohibits InfantryTypes from using the InitialPayload logic (by Noble_Fish) - `ProjectileRange` now has weapon range modifiers applied to it if greater than 0 and unless `ProjectileRange.ApplyModifiers` is set to false on the WeaponType (by Starkku) + +``` + +```{dropdown} Pre-release changes + +#### 0.5-alpha1 + ``` ### 0.4.0.3 diff --git a/docs/_ext/__init__.py b/docs/_ext/__init__.py new file mode 100644 index 0000000000..c62c2fb55f --- /dev/null +++ b/docs/_ext/__init__.py @@ -0,0 +1,3 @@ +"""Local Sphinx extensions for the Phobos documentation.""" + +from __future__ import annotations diff --git a/docs/_ext/fix_included_readme_links.py b/docs/_ext/fix_included_readme_links.py new file mode 100644 index 0000000000..8426e0d5de --- /dev/null +++ b/docs/_ext/fix_included_readme_links.py @@ -0,0 +1,55 @@ +""" +Sphinx extension to fix relative links in included README.md. + +When README.md is included into index.md via {include}, the links inside +README.md are relative to the project root (e.g. [x](docs/xxx.md)). +But after inclusion, they should be relative to the docs/ directory +(e.g. [x](xxx.md)). This extension converts them at build time. +""" + +import re +from sphinx.application import Sphinx +from sphinx.util.logging import getLogger + +logger = getLogger(__name__) + +def fix_readme_links(app, docname, source): + """ + Modify the source content of docname if it contains an include of README.md. + Replace markdown link patterns that start with 'docs/' with the plain filename. + """ + # Only process the document that includes README.md (assume it's 'index') + if docname != 'index': + return + + content = source[0] + + # Check if this document includes README.md via MyST's {include} + # MyST converts {include} to `.. include::` directive with appropriate path. + # We check both common forms: ../README.md (from docs/index.md) and README.md (if in same dir) + if '.. include:: ../README.md' not in content and '.. include:: README.md' not in content: + return + + # Fix links: [text](docs/xxx.md) -> [text](xxx.md) + # Correctly capture optional anchor: #section + def fix_link(m): + # m.group(1): filename with .md, m.group(2): anchor including #, or None + anchor = m.group(2) or '' + return f']({m.group(1)}{anchor})' + + new_content = re.sub( + r'\]\(docs/([^)]+\.md)(#[^)]*)?\)', + fix_link, + content + ) + + if new_content != content: + source[0] = new_content + +def setup(app): + app.connect('source-read', fix_readme_links) + return { + 'version': '1.0.2', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } \ No newline at end of file diff --git a/docs/_ext/sanitize_system_messages.py b/docs/_ext/sanitize_system_messages.py new file mode 100644 index 0000000000..772570f3d8 --- /dev/null +++ b/docs/_ext/sanitize_system_messages.py @@ -0,0 +1,88 @@ +"""Keep docutils system messages out of extracted content. + +Background +---------- + +Sphinx's ``ApplySourceWorkaround`` transform (``sphinx.util.nodes. +apply_source_workaround``) sets ``rawsource = node.astext()`` on any +``TextElement``/``image``/``topic`` whose ``rawsource`` is empty. + +MyST renders headings that live inside a directive (such as a sphinx-design +``{dropdown}``) as ``rubric`` nodes whose ``rawsource`` is left empty. Repeated +headings (e.g. the many ``#### Vanilla fixes:`` blocks in ``Whats-New.md``) +produce duplicate implicit targets, and docutils appends an ``INFO/1 +system_message`` child to the rubric (via ``myst_parser``'s +``generate_heading_target`` -> ``document.note_implicit_target``). The +``astext()`` then includes that message, so the rubric's ``rawsource`` ends up +as:: + + Vanilla fixes:D:\\Repos\\Phobos\\docs\\Whats-New.md:845: (INFO/1) Duplicate + implicit target name: "vanilla fixes:". + +The gettext builder later extracts ``rawsource`` as a translatable message, so +these warnings leak into the ``.pot``/``.po`` files. And because the ``Locale`` +transform matches ``rawsource`` against the translation catalog, the polluted +``rawsource`` also stops the duplicate headings from being translated - only the +first (non-duplicate) occurrence ever gets a translation. + +This extension removes the system-message children from the doctree (Sphinx's +``FilterSystemMessages`` would remove them at write time anyway) and restores +the ``rawsource`` that ``ApplySourceWorkaround`` polluted with the message text. +""" + +from __future__ import annotations + +from docutils import nodes +from sphinx.transforms import SphinxTransform + +__version__ = '1.2.0' + + +class SanitizeSystemMessages(SphinxTransform): + """Remove docutils system messages and repair the polluted rawsource. + + Must run after ``ApplySourceWorkaround`` (priority 10), which folds the + attached system message into ``rawsource``, but before the ``Locale`` + transform (priority 20), which matches ``rawsource`` against the translation + catalog. A ``doctree-read`` hook (priority 880) is too late: translations + would already have failed to apply. + """ + + default_priority = 15 + + def apply(self, **kwargs) -> None: + # 1. Drop system-message children from content nodes. + for node in list(self.document.findall(nodes.system_message)): + parent = node.parent + if parent is not None: + parent.remove(node) + + # 2. Restore rawsource that ApplySourceWorkaround polluted with the + # system-message text. + # + # docutils prepends the node's own source path when it formats the + # system message, so the appended segment always starts with that + # path. Strip everything from the path onwards instead of matching + # the message format - this survives smart-quote transforms and + # changes to how docutils words the message. + # + # Reading the source with getattr() is deliberate: MyST stores it as + # a plain attribute, so the docutils attribute-map lookup would + # return None. + for node in self.document.findall(nodes.TextElement): + raw = node.rawsource + src = getattr(node, 'source', None) + if not raw or not src or src not in raw: + continue + idx = raw.find(src) + if idx > 0: + node.rawsource = raw[:idx].rstrip() + + +def setup(app): + app.add_transform(SanitizeSystemMessages) + return { + 'version': __version__, + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/docs/_static/images/versioning-past-0.5.excalidraw.png b/docs/_static/images/versioning-past-0.5.excalidraw.png new file mode 100644 index 0000000000..1439aaa0b3 Binary files /dev/null and b/docs/_static/images/versioning-past-0.5.excalidraw.png differ diff --git a/docs/conf.py b/docs/conf.py index 253443e356..e20326a0df 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -9,10 +9,9 @@ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) +import os +import sys +sys.path.insert(0, os.path.abspath('.')) # -- Project information ----------------------------------------------------- @@ -26,7 +25,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['sphinx_rtd_theme', 'myst_parser', 'sphinx.ext.mathjax', 'sphinx_design'] +extensions = ['sphinx_rtd_theme', 'myst_parser', 'sphinx.ext.mathjax', 'sphinx_design', '_ext.sanitize_system_messages', '_ext.fix_included_readme_links'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po b/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po index 23f45b1289..980af87360 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po +++ b/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po @@ -15,7 +15,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.16.0\n" +"Generated-By: Babel 2.18.0\n" msgid "Credits" msgstr "鸣谢" diff --git a/docs/locale/zh_CN/LC_MESSAGES/Contributing.po b/docs/locale/zh_CN/LC_MESSAGES/Contributing.po index ff74924b06..2bad098dd4 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/Contributing.po +++ b/docs/locale/zh_CN/LC_MESSAGES/Contributing.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Phobos \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-03-02 01:28+0800\n" +"POT-Creation-Date: 2026-08-04 10:03+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -89,7 +89,9 @@ msgid "" "agents, but is also a useful read for any new contributor looking to " "understand the codebase quickly." msgstr "" -"仓库中包å«ä¸€ä»½ [Copilot 指令文件](https://github.com/Phobos-developers/Phobos/blob/develop/.github/copilot-instructions.md),作为项目的快速入门指å—â€”â€”åŒ…å«æž„建ã€é¡¹ç›®ç»“æž„ã€é’©å­æ¨¡å¼ã€è¡¥ä¸å®ã€YRpp 使用方法等内容。该文件å¯è¢« " +"仓库中包å«ä¸€ä»½ [Copilot 指令文件](https://github.com/Phobos-" +"developers/Phobos/blob/develop/.github/copilot-" +"instructions.md),作为项目的快速入门指å—â€”â€”åŒ…å«æž„建ã€é¡¹ç›®ç»“æž„ã€é’©å­æ¨¡å¼ã€è¡¥ä¸å®ã€YRpp 使用方法等内容。该文件å¯è¢« " "GitHub Copilot 和类似的 AI ä»£ç æ™ºèƒ½ä½“è‡ªåŠ¨è¯†åˆ«ï¼ŒåŒæ—¶ä¹Ÿæ˜¯æ–°è´¡çŒ®è€…快速了解代ç åº“的实用å‚考。" msgid "" @@ -152,10 +154,55 @@ msgid "you mention your contribution in the [credits page](CREDITS.md)." msgstr "你在 [鸣谢](CREDITS.md) 页é¢åˆ—出了你的贡献。" msgid "" -"If your change does not fit in standard criteria or too small that it " -"doesn't need the above - add `[Minor]` to your pull request's title, so " -"the CI won't yell at you for no reason." -msgstr "è‹¥å˜æ›´ä¸ç¬¦åˆæ ‡å‡†æµç¨‹æˆ–è§„æ¨¡è¿‡å°æ— éœ€ä¸Šè¿°æ­¥éª¤ï¼Œè¯·åœ¨æ‹‰å–请求标题添加 `[Minor]`,以é¿å… CI 无故报错。" +"Not every change needs all of the above. The table below shows what each " +"kind of change is expected to cover (a checkmark means that kind of entry" +" is required):" +msgstr "" +"å¹¶éžæ¯é¡¹æ›´æ”¹éƒ½éœ€è¦ä¸Šè¿°æ‰€æœ‰å†…容。下表给出了æ¯ç§æ›´æ”¹ç±»åž‹åº”当覆盖的内容(勾å·ä»£è¡¨è¯¥æ¡ç›®ä¸ºå¿…需):" + +msgid "Change type" +msgstr "更改类型" + +msgid "Changelog" +msgstr "版本更新说明" + +msgid "Docs" +msgstr "文档" + +msgid "Credits" +msgstr "鸣谢" + +msgid "New feature, vanilla bugfix, enhancement of a released feature" +msgstr "新功能ã€åŽŸç‰ˆ Bug ä¿®å¤ã€å¢žå¼ºå·²å‘布功能" + +msgid "✓" +msgstr "✓" + +msgid "Improvement to a new (unreleased) feature" +msgstr "改进新(未å‘布)功能" + +msgid "✗" +msgstr "✗" + +msgid "Bugfix to a new (unreleased) feature" +msgstr "新(未å‘布)功能的 Bug ä¿®å¤" + +msgid "Bugfix to an old (released) feature" +msgstr "旧(已å‘布)功能的 Bug ä¿®å¤" + +msgid "Completely minor change (e.g. a typo fix)" +msgstr "完全微å°çš„æ›´æ”¹ï¼ˆä¾‹å¦‚拼写错误)" + +msgid "If editing this table - also edit the PR template." +msgstr "编辑此表格时一并编辑 PR 模版。" + +msgid "" +"The checks for changelog, docs and credits are skipped individually when " +"a maintainer applies the matching label - `Skip Changelog`, `Skip Docs` " +"or `Skip Credits`. If one of the requirements does not apply to your " +"change, say so in the pull request and ask for the corresponding label." +msgstr "" +"当维护者使用对应标签 `Skip Changelog`ã€`Skip Docs` 或 `Skip Credits` æ—¶ç‰ˆæœ¬æ›´æ–°è¯´æ˜Žã€æ–‡æ¡£å’Œé¸£è°¢å„自的检查将被跳过。如果æŸé¡¹è¦æ±‚ä¸é€‚用于你的更改,请在拉å–请求中说明并请求对应的标签。" msgid "" "Every pull request push trigger a nightly build for the latest pushed " diff --git a/docs/locale/zh_CN/LC_MESSAGES/Fixed-or-Improved-Logics.po b/docs/locale/zh_CN/LC_MESSAGES/Fixed-or-Improved-Logics.po index f16987f8f9..f4cdb173c7 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/Fixed-or-Improved-Logics.po +++ b/docs/locale/zh_CN/LC_MESSAGES/Fixed-or-Improved-Logics.po @@ -15,7 +15,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.16.0\n" +"Generated-By: Babel 2.18.0\n" msgid "Fixed / Improved Logics" msgstr "ä¿®å¤æˆ–改进的逻辑" diff --git a/docs/locale/zh_CN/LC_MESSAGES/General-Info.po b/docs/locale/zh_CN/LC_MESSAGES/General-Info.po index 58cb6ef004..95d60ca018 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/General-Info.po +++ b/docs/locale/zh_CN/LC_MESSAGES/General-Info.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Phobos \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-25 14:06+0800\n" +"POT-Creation-Date: 2026-08-04 10:03+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -33,17 +33,17 @@ msgid "" "*stable builds* - those are numbered like your regular versions " "(something close to semantic versioning, e.g. version 1.2.3 for example) " "and ideally should contain no bugs, therefore are safe to use in mods;" -msgstr "**稳定版**:采用常规版本å·ï¼ˆä¾‹å¦‚ v1.2.3),并且ç†è®ºä¸Šä¸åŒ…å«ä»»ä½•æ­¤å‰å·²çŸ¥çš„ Bug,å¯ä»¥å®‰å…¨åœ°ç”¨äºŽ Mod。" +msgstr "**稳定版本**:采用常规版本å·ï¼ˆä¾‹å¦‚ v1.2.3),并且ç†è®ºä¸Šä¸åŒ…å«ä»»ä½•æ­¤å‰å·²çŸ¥çš„ Bug,å¯ä»¥å®‰å…¨åœ°ç”¨äºŽ Mod。" msgid "" -"*development builds* - those are the builds which contain functionality " -"that needs to be tested. They are numbered plainly starting from 0 and " -"incrementing the number on each release. Mod authors still can include " -"those versions with their mods if they want latest features, though we " -"can't guarantee lack of bugs;" +"*pre-release builds* - previously known as *development builds*, these " +"builds mark the start of a new release branch and are used for testing " +"new features before they are finalized. They are numbered with a version " +"and a pre-release suffix (e.g., 0.5-beta1, 0.5-rc2). Mod authors can " +"include these versions with their mods to access the latest features, but" +" we cannot guarantee the absence of bugs;" msgstr "" -"**å¼€å‘版**:包å«å¾…测试功能的版本,采用 `build-` 加上从 `0` å¼€å§‹ä¸”æ¯æ¬¡å‘布åŽé€’å¢žçš„ç®€å•æ•°å­—ç¼–å·ä½œä¸ºç‰ˆæœ¬å·ã€‚Mod 作者ä»å¯åœ¨ " -"Mod 中使用这类版本以获得最新功能,但我们无法ä¿è¯å®ƒä»¬æ²¡æœ‰ Bug。" +"**预å‘布版本**:å³ä¹‹å‰çš„ *å¼€å‘版*ï¼Œæ­¤ç±»æž„å»ºæ ‡å¿—ç€æ–°å‘布分支的开始,用于在新功能最终确定å‰è¿›è¡Œæµ‹è¯•。它们的版本å·ç”±ä¸»ç‰ˆæœ¬å·åŠ ä¸Šé¢„å‘布åŽç¼€ç»„æˆï¼ˆä¾‹å¦‚ `0.5-beta1`ã€`0.5-rc2`)。Mod 作者å¯ä»¥åœ¨ Mod 中包å«è¿™äº›ç‰ˆæœ¬ä»¥èŽ·å–æœ€æ–°åŠŸèƒ½ï¼Œä½†æˆ‘ä»¬æ— æ³•ä¿è¯å®ƒä»¬æ²¡æœ‰ Bug。" msgid "" "*nightly builds* - bleeding edge versions which can include prototypes, " @@ -55,33 +55,47 @@ msgstr "" "**自动构建版本**ï¼šæœ€å‰æ²¿ç‰ˆæœ¬ï¼Œå¯èƒ½åŒ…å«åŽŸåž‹æœºã€ç†è®ºéªŒè¯ã€åºŸå¼ƒåŠŸèƒ½ç­‰ã€‚æ¢è€Œè¨€ä¹‹æˆ‘们无法ä¿è¯è¿™äº›ç‰ˆæœ¬çš„稳定性,它们仅应当用于å助 Phobos " "å¼€å‘和测试而ç»ä¸åº”该用于 Mod çš„å‘布版本。" +msgid "" +"Besides the published builds above, any build you make locally (from " +"Visual Studio, VS Code or the build scripts) is marked as a *local " +"build*: like nightly, it is stamped with the git commit and ref it was " +"built from (plus a `-dirty` marker when the working tree has uncommitted " +"changes) and shows a hideable \"please test\" warning." +msgstr "" +"除了上述å‘布的构建版本,你在本地(通过 Visual Studioã€VS Code 或构建脚本)生æˆçš„任何构建都会标记为 *本地构建*:与自动构建版本类似,它会标记有构建所基于的 git æäº¤å’Œå¼•用(当工作树有未æäº¤æ›´æ”¹æ—¶è¿˜ä¼šæ·»åŠ  `-dirty` 标记),并显示一个å¯éšè—的「please testã€è­¦å‘Šã€‚" + msgid "" "You can find the downloads for these versions on the document's [main " "page](index.md#downloads)." msgstr "ä½ å¯ä»¥åœ¨æ–‡æ¡£ [主页é¢](index.md#downloads) 找到这些版本的下载。" -msgid "Disabling development build warning" -msgstr "关闭开å‘版本警告" +msgid "Disabling pre-release build warning" +msgstr "关闭预å‘布版本警告" msgid "" "**DISCLAIMER:** We understand that everyone wants to try and use the new " "features as soon as they're released, but we can't do all the testing " "ourselves, so we only test the functionality on a basic level. We ask " -"everyone who uses the new development build first to **test the new " -"changes in every possible way first before disabling the development " +"everyone who uses the new pre-release build first to **test the new " +"changes in every possible way first before disabling the pre-release " "build warning** and proceeding to include the build in your mod release. " "This would allow us to concentrate on implementing the actual features, " "which is the most complex task. Learn more on testing " "[here](Contributing.md#testing)." msgstr "" -"**å…责声明**:我们ç†è§£æ¯ä¸ªäººéƒ½å¸Œæœ›å°½å¿«ä½“验新功能的愿望,但我们仅å¯è¿›è¡ŒåŸºç¡€çš„功能验è¯è€Œæ— æ³•完æˆå…¨é¢çš„æµ‹è¯•ã€‚æˆ‘ä»¬è¦æ±‚所有用户在关闭开å‘版本警告å‰åŠ¡å¿…é€šè¿‡å„ç§æ–¹å¼å…¨é¢æµ‹è¯•å˜æ›´å†…容,然åŽå†å°†å¼€å‘版本使用于" +"**å…责声明**:我们ç†è§£æ¯ä¸ªäººéƒ½å¸Œæœ›å°½å¿«ä½“验新功能的愿望,但我们仅å¯è¿›è¡ŒåŸºç¡€çš„功能验è¯è€Œæ— æ³•完æˆå…¨é¢çš„æµ‹è¯•ã€‚æˆ‘ä»¬è¦æ±‚所有用户在关闭预å‘布版本警告å‰åŠ¡å¿…é€šè¿‡å„ç§æ–¹å¼å…¨é¢æµ‹è¯•å˜æ›´å†…容,然åŽå†å°†é¢„å‘布版本使用于" " Mod çš„å‘å¸ƒç‰ˆæœ¬ä¸­ã€‚è¿™å°†ä½¿æˆ‘ä»¬èƒ½å¤Ÿä¸“æ³¨äºŽå®žçŽ°æœ€å¤æ‚的核心功能。测试指å—è§ [此处](Contributing.md#testing)。" msgid "" -"You can hide the warning by specifying the build number after `-b=` as a " -"command line argument (for example, `-b=1` would hide the warning for " -"development build #1 of Phobos)." -msgstr "ä½ å¯ä»¥é€šè¿‡åœ¨å‘½ä»¤è¡Œå‚æ•° `-b=` åŽé¢æŒ‡å®šå¼€å‘ç‰ˆæœ¬çš„ç‰ˆæœ¬å·æ¥éšè—å¼€å‘版本警告(例如 `-b=1` å¯ä»¥éšè— Build#1 å¼€å‘版本的警告)。" +"You can hide the warning by specifying the exact version of the build you" +" use after `-HideVersionWarning=` as a command line argument (for " +"example, `-HideVersionWarning=0.5.0.0-beta1` would hide the warning for " +"the `v0.5-beta1` pre-release of Phobos). The version is shown in the " +"warning itself and in the title of the respective release; a build only " +"accepts its own version, so the switch has to be updated whenever you " +"update Phobos. Nightly builds don't support hiding the warning at all." +msgstr "" +"ä½ å¯ä»¥é€šè¿‡åœ¨å‘½ä»¤è¡Œå‚æ•° `-HideVersionWarning=` åŽé¢æŒ‡å®šæ‰€ä½¿ç”¨çš„æž„å»ºçš„ç¡®åˆ‡ç‰ˆæœ¬å·æ¥éšè—该警告(例如 `-HideVersionWarning=0.5.0.0-beta1` å°†éšè— Phobos `v0.5-beta1` 预å‘布版的警告)。该版本å·ä¼šæ˜¾ç¤ºåœ¨è­¦å‘Šä¿¡æ¯ä»¥åŠå¯¹åº”å‘布的标题中;æ¯ä¸ªæž„å»ºåªæŽ¥å—其自身的版本å·ï¼Œå› æ­¤æ¯å½“æ›´æ–° Phobos 时都需è¦åŒæ­¥æ›´æ–°è¯¥å¼€å…³å‚æ•°ã€‚è‡ªåŠ¨æž„å»ºç‰ˆå®Œå…¨ä¸æ”¯æŒéšè—警告。" msgid "Saved games filtering" msgstr "存档过滤" @@ -91,15 +105,13 @@ msgid "" "publicly released Ares 0.A source and it implements it's own filtering " "which shouldn't conflict with Ares save filtering. Save games between " "different versions are incompatible due to changes to Phobos extension " -"classes which are present in almost every build release. The filtering " -"mechanism, hovewer, doesn't apply to nightly versions - those use latest " -"development build number on which this nightly is based on. While " -"different nightly version saves may be listed, they are most likely " -"incompatible in case there were changes to extension class fields." +"classes which are present in almost every build release. Nightlies and " +"pre-releases of a version share the savegame ID of the stable release " +"they lead up to, so their saves are filtered as a single version. They " +"may still be incompatible with each other if there were changes to " +"extension class fields." msgstr "" -"得益于 Ares0.A 公开的æºç èŒƒä¾‹ï¼ŒPhobos 完全支æŒå­˜è¯»æ¡£åŠŸèƒ½ï¼Œå¹¶ä¸”å®žçŽ°äº†ç‹¬ç«‹çš„è¿‡æ»¤æœºåˆ¶ï¼Œè¿™ä¸Ž Ares 的存档过滤机制没有冲çªã€‚由于 " -"Phobos " -"扩展类几乎在æ¯ä¸ªç‰ˆæœ¬éƒ½æœ‰æ‰€å˜åŠ¨ï¼Œæ‰€ä»¥ä¸åŒç‰ˆæœ¬é—´çš„存档互ä¸å…¼å®¹ã€‚但过滤机制ä¸é€‚用于自动构建版本——这些版本使用其所基于的最新开å‘版本的编å·ã€‚虽然ä¸åŒè‡ªåŠ¨æž„å»ºç‰ˆæœ¬çš„å­˜æ¡£å¯èƒ½æ˜¾ç¤ºåœ¨å­˜è¯»æ¡£åˆ—表中,但如果扩展类字段å‘生了å˜åŠ¨ï¼Œé‚£ä¹ˆè¿™äº›å­˜æ¡£å¾ˆå¯èƒ½å®žé™…上并ä¸å…¼å®¹ã€‚" +"得益于 Ares0.A 公开的æºç èŒƒä¾‹ï¼ŒPhobos 完全支æŒå­˜è¯»æ¡£åŠŸèƒ½ï¼Œå¹¶ä¸”å®žçŽ°äº†ç‹¬ç«‹çš„è¿‡æ»¤æœºåˆ¶ï¼Œè¿™ä¸Ž Ares 的存档过滤机制没有冲çªã€‚由于 Phobos 扩展类几乎在æ¯ä¸ªç‰ˆæœ¬éƒ½æœ‰æ‰€å˜åŠ¨ï¼Œæ‰€ä»¥ä¸åŒç‰ˆæœ¬é—´çš„存档互ä¸å…¼å®¹ã€‚æŸä¸ªç‰ˆæœ¬çš„自动构建版本和预å‘布版本共享其所对应稳定版本的存档 ID,因此它们的存档会被视为åŒä¸€ç‰ˆæœ¬è¿›è¡Œè¿‡æ»¤ã€‚但如果扩展类字段å‘生了更改,它们之间ä»ç„¶å¯èƒ½äº’ä¸å…¼å®¹ã€‚" msgid "Compatibility" msgstr "兼容性" @@ -111,7 +123,9 @@ msgid "" "versions do not provide, and will show an error and exit on startup " "without them." msgstr "" -"Phobos éœ€è¦ [SyringeEx](https://github.com/Phobos-developers/SyringeEx)(v0.1.0.2 åŠä»¥ä¸Šç‰ˆæœ¬ï¼‰ä½œä¸ºå¯åŠ¨å™¨â€”â€”å®ƒä¾èµ–于旧版 Syringe 所ä¸å…·å¤‡çš„功能(通过 SyringeEx 特性标志å‘出信å·ï¼‰ï¼Œå¦‚果没有这些功能,它将在å¯åŠ¨æ—¶æ˜¾ç¤ºé”™è¯¯å¹¶é€€å‡ºã€‚" +"Phobos éœ€è¦ [SyringeEx](https://github.com/Phobos-" +"developers/SyringeEx)(v0.1.0.2 åŠä»¥ä¸Šç‰ˆæœ¬ï¼‰ä½œä¸ºå¯åŠ¨å™¨â€”â€”å®ƒä¾èµ–于旧版 Syringe 所ä¸å…·å¤‡çš„功能(通过 " +"SyringeEx 特性标志å‘出信å·ï¼‰ï¼Œå¦‚果没有这些功能,它将在å¯åŠ¨æ—¶æ˜¾ç¤ºé”™è¯¯å¹¶é€€å‡ºã€‚" msgid "" "While Phobos is standalone, it is designed to be used alongside " diff --git a/docs/locale/zh_CN/LC_MESSAGES/Interoperability.po b/docs/locale/zh_CN/LC_MESSAGES/Interoperability.po index 1daef224c2..5df6c754ba 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/Interoperability.po +++ b/docs/locale/zh_CN/LC_MESSAGES/Interoperability.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Phobos \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-06-13 01:11+0800\n" +"POT-Creation-Date: 2026-06-20 10:13+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,7 +17,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.16.0\n" +"Generated-By: Babel 2.18.0\n" msgid "Interoperability" msgstr "互æ“作性" @@ -128,6 +128,7 @@ msgstr "通过 `pVersion` è¾“å‡ºå‚æ•°è¿”回当å‰çš„ Interop API 版本。" msgid "Parameters:" msgstr "傿•°ï¼š" +#, python-brace-format msgid "`pVersion`: Receives the version structure `{ major, minor, patch }`." msgstr "`pVersion`:接收版本结构体 `{ major, minor, patch }`。" diff --git a/docs/locale/zh_CN/LC_MESSAGES/Miscellanous.po b/docs/locale/zh_CN/LC_MESSAGES/Miscellanous.po index c6e2bfec39..755923568d 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/Miscellanous.po +++ b/docs/locale/zh_CN/LC_MESSAGES/Miscellanous.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Phobos \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-25 14:06+0800\n" +"POT-Creation-Date: 2026-08-04 10:03+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -476,7 +476,9 @@ msgid "" "ported from [Vinifera](https://github.com/Vinifera-Developers/Vinifera). " "When the game crashes, it will:" msgstr "" -"ç§»æ¤è‡ª [Vinifera](https://github.com/Vinifera-Developers/Vinifera):当异常处ç†ç¨‹åºå¯ç”¨æ—¶ï¼ŒPhobos 会使用自身的异常处ç†ç¨‹åºå–代游æˆï¼ˆåŠ Ares)自带的崩溃处ç†ã€‚当游æˆå´©æºƒæ—¶ï¼Œå®ƒä¼šï¼š" +"ç§»æ¤è‡ª [Vinifera](https://github.com/Vinifera-" +"Developers/Vinifera):当异常处ç†ç¨‹åºå¯ç”¨æ—¶ï¼ŒPhobos 会使用自身的异常处ç†ç¨‹åºå–代游æˆï¼ˆåŠ " +"Ares)自带的崩溃处ç†ã€‚当游æˆå´©æºƒæ—¶ï¼Œå®ƒä¼šï¼š" msgid "" "create a per-crash folder `debug\\snapshot-\\` and write into " @@ -486,7 +488,10 @@ msgid "" "layout Ares uses, so the CnCNet client will also fold `debug.log` and " "`syringe.log` into it;" msgstr "" -"创建一个按崩溃时间命å的目录 `debug\\snapshot-<时间戳>\\` 并在里é¢å†™å…¥ä¸€ä»½åŒ…å«å¯„存器ã€è°ƒç”¨æ ˆã€æ ˆè½¬å‚¨å’Œå·²åŠ è½½æ¨¡å—列表的详细崩溃报告(`except.txt`)ã€ä¸€ä¸ªå°åž‹è½¬å‚¨æ–‡ä»¶ï¼ˆ`crashdump.dmp`)以åŠä¸€ä»½ `debug.log` 副本(如果找得到)。该目录布局与 Ares 的相åŒï¼Œå› æ­¤ CnCNet 客户端也会将 `debug.log` å’Œ `syringe.log` 置入其中。" +"创建一个按崩溃时间命å的目录 `debug\\snapshot-<时间戳>\\` " +"并在里é¢å†™å…¥ä¸€ä»½åŒ…å«å¯„存器ã€è°ƒç”¨æ ˆã€æ ˆè½¬å‚¨å’Œå·²åŠ è½½æ¨¡å—列表的详细崩溃报告(`except.txt`)ã€ä¸€ä¸ªå°åž‹è½¬å‚¨æ–‡ä»¶ï¼ˆ`crashdump.dmp`)以åŠä¸€ä»½" +" `debug.log` 副本(如果找得到)。该目录布局与 Ares 的相åŒï¼Œå› æ­¤ CnCNet 客户端也会将 `debug.log` å’Œ " +"`syringe.log` 置入其中。" msgid "" "show a dialog displaying the crash report, with buttons to quit, break " @@ -494,26 +499,28 @@ msgid "" "(`fulldump.dmp`, into the same folder) - large, but the most useful to " "developers." msgstr "" -"显示一个包å«å´©æºƒæŠ¥å‘Šçš„å¯¹è¯æ¡†ï¼Œæä¾›é€€å‡ºã€é™„加调试器中断或é¢å¤–ä¿å­˜å®Œæ•´å†…存转储(åŒç›®å½•下å为 `fulldump.dmp`)的按钮。`fulldump.dmp` 文件较大,但对开å‘人员æ¥è¯´æ˜¯æœ€æœ‰ç”¨çš„。" +"显示一个包å«å´©æºƒæŠ¥å‘Šçš„å¯¹è¯æ¡†ï¼Œæä¾›é€€å‡ºã€é™„加调试器中断或é¢å¤–ä¿å­˜å®Œæ•´å†…存转储(åŒç›®å½•下å为 " +"`fulldump.dmp`)的按钮。`fulldump.dmp` 文件较大,但对开å‘人员æ¥è¯´æ˜¯æœ€æœ‰ç”¨çš„。" msgid "" "Crash folders older than 5 days are cleaned up automatically. The " "`-FullCrashDump` command line arg makes the automatically written " "minidump a full memory dump (useful for unattended setups)." msgstr "" -"超过 5 天的崩溃目录会自动清ç†ã€‚命令函傿•° `-FullCrashDump` å¯è‡ªåŠ¨å°†å®Œæ•´å†…å­˜è½¬å‚¨å†™å…¥å°åž‹è½¬å‚¨ä¸­ï¼ˆé€‚用于无需人工æ“作的自动è¿è¡ŒçŽ¯å¢ƒï¼‰ã€‚" +"超过 5 天的崩溃目录会自动清ç†ã€‚命令函傿•° `-FullCrashDump` " +"å¯è‡ªåŠ¨å°†å®Œæ•´å†…å­˜è½¬å‚¨å†™å…¥å°åž‹è½¬å‚¨ä¸­ï¼ˆé€‚用于无需人工æ“作的自动è¿è¡ŒçŽ¯å¢ƒï¼‰ã€‚" msgid "Crash reports can be enriched with extra information:" -msgstr "" -"崩溃报告å¯ä»¥é™„加é¢å¤–ä¿¡æ¯ï¼š" +msgstr "崩溃报告å¯ä»¥é™„加é¢å¤–ä¿¡æ¯ï¼š" msgid "" "If a `gamemd.pdb` file is present in the game directory, it is used to " "resolve game addresses to symbol names in the call stacks. `Phobos.pdb` " -"(shipped with devbuilds and nightlies) is picked up automatically for " -"Phobos's own addresses." +"(shipped with every build) is picked up automatically for Phobos's own " +"addresses." msgstr "" -"如果游æˆç›®å½•存在 `gamemd.pdb` 文件,它会被用于游æˆåœ°å€è§£æžè°ƒç”¨æ ˆä¸­çš„符å·å称。`Phobos.pdb`ï¼ˆå¼€å‘æž„å»ºå’Œè‡ªåŠ¨æž„å»ºè‡ªå¸¦ï¼‰ä¼šè‡ªåŠ¨ç”¨äºŽè§£æž Phobos 自身的地å€ã€‚" +"如果游æˆç›®å½•存在 `gamemd.pdb` " +"文件,它会被用于游æˆåœ°å€è§£æžè°ƒç”¨æ ˆä¸­çš„符å·å称。`Phobos.pdb`(æ¯ä¸ªæž„å»ºè‡ªå¸¦ï¼‰ä¼šè‡ªåŠ¨ç”¨äºŽè§£æž Phobos 自身的地å€ã€‚" msgid "" "If a `gamemd.edb` exception database file is present in the game " @@ -521,7 +528,8 @@ msgid "" "in the report under \"Additional information\". The format is shared with" " Vinifera: one entry per line, `;` starts a comment." msgstr "" -"如果游æˆç›®å½•存在 `gamemd.edb` 异常数æ®åº“文件,其中对故障地å€çš„æè¿°ï¼ˆè‹¥å­˜åœ¨ï¼‰ä¼šåŒ…å«åœ¨æŠ¥å‘Šçš„“Additional informationâ€ä¸‹ã€‚该格å¼ä¸Ž Vinifera 共享:æ¯è¡Œä¸€ä¸ªæ¡ç›®ï¼Œ`;` 代表注释开始。" +"如果游æˆç›®å½•存在 `gamemd.edb` 异常数æ®åº“文件,其中对故障地å€çš„æè¿°ï¼ˆè‹¥å­˜åœ¨ï¼‰ä¼šåŒ…å«åœ¨æŠ¥å‘Šçš„“Additional " +"informationâ€ä¸‹ã€‚该格å¼ä¸Ž Vinifera 共享:æ¯è¡Œä¸€ä¸ªæ¡ç›®ï¼Œ`;` 代表注释开始。" msgid "" "The exception handler is enabled by default in all builds, including " @@ -529,7 +537,8 @@ msgid "" "this does not interfere with debugging; pass `-ExceptionHandler=false` if" " you want crashes to bypass the handler entirely." msgstr "" -"异常处ç†ç¨‹åºåœ¨åŒ…括 Debug 版本的所有构建版本中默认å¯ç”¨ã€‚附加的调试器ä»ç„¶ä¼˜å…ˆæŽ¥æ”¶å¼‚常,因此这ä¸ä¼šå¹²æ‰°è°ƒè¯•;你å¯ä»¥é€šè¿‡ `-ExceptionHandler=false` 使崩溃完全绕过该处ç†ç¨‹åº" +"异常处ç†ç¨‹åºåœ¨åŒ…括 Debug 版本的所有构建版本中默认å¯ç”¨ã€‚附加的调试器ä»ç„¶ä¼˜å…ˆæŽ¥æ”¶å¼‚常,因此这ä¸ä¼šå¹²æ‰°è°ƒè¯•;你å¯ä»¥é€šè¿‡ " +"`-ExceptionHandler=false` 使崩溃完全绕过该处ç†ç¨‹åº" msgid "" "The CnCNet 5 spawner uses the main loop exception handler for fixes. If " @@ -547,7 +556,8 @@ msgid "" "the process, so windows created by the game and Phobos - dialogs, message" " boxes and the crash dialog - render with modern visual styles." msgstr "" -"gamemd.exe 在å‘å¸ƒæ—¶æ²¡æœ‰åº”ç”¨ç¨‹åºæ¸…å•,因此其窗å£ç»‘定旧的通用控件 v5 并以 Windows 9x æ ·å¼æ¸²æŸ“。现在 Phobos 在进程生命周期内激活其内嵌的通用控件 v6 清å•,以使游æˆå’Œ Phobos åˆ›å»ºçš„å¯¹è¯æ¡†ã€æ¶ˆæ¯æ¡†å’Œå´©æºƒå¯¹è¯æ¡†ä½¿ç”¨çŽ°ä»£è§†è§‰æ ·å¼æ¸²æŸ“。" +"gamemd.exe 在å‘å¸ƒæ—¶æ²¡æœ‰åº”ç”¨ç¨‹åºæ¸…å•,因此其窗å£ç»‘定旧的通用控件 v5 并以 Windows 9x æ ·å¼æ¸²æŸ“。现在 Phobos " +"在进程生命周期内激活其内嵌的通用控件 v6 清å•,以使游æˆå’Œ Phobos åˆ›å»ºçš„å¯¹è¯æ¡†ã€æ¶ˆæ¯æ¡†å’Œå´©æºƒå¯¹è¯æ¡†ä½¿ç”¨çŽ°ä»£è§†è§‰æ ·å¼æ¸²æŸ“。" msgid "Player colors" msgstr "玩家颜色" diff --git a/docs/locale/zh_CN/LC_MESSAGES/New-or-Enhanced-Logics.po b/docs/locale/zh_CN/LC_MESSAGES/New-or-Enhanced-Logics.po index d073303cea..9afb3c9a30 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/New-or-Enhanced-Logics.po +++ b/docs/locale/zh_CN/LC_MESSAGES/New-or-Enhanced-Logics.po @@ -15,7 +15,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.16.0\n" +"Generated-By: Babel 2.18.0\n" msgid "New / Enhanced Logics" msgstr "新增或增强的逻辑" diff --git a/docs/locale/zh_CN/LC_MESSAGES/Project-guidelines-and-policies.po b/docs/locale/zh_CN/LC_MESSAGES/Project-guidelines-and-policies.po index 630bbe4238..ec6e6275ab 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/Project-guidelines-and-policies.po +++ b/docs/locale/zh_CN/LC_MESSAGES/Project-guidelines-and-policies.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Phobos \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-19 04:52+0800\n" +"POT-Creation-Date: 2026-08-04 10:03+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -314,10 +314,10 @@ msgid "" "a separate folder named after vanilla engine class name and contains the " "following:" msgstr "" -"`Ext/` - 原版引擎类的扩展类æºç ã€‚扩展类形æˆäº†ä¸€ä¸ªé•œåƒäº†æ¸¸æˆè‡ªèº«ç±»æ ‘的并行继承层次结构" -"(`Container.h` 中的 `AbstractExt` 为根;例如`BuildingExt : TechnoExt : RadioExt : MissionExt : ObjectExt : AbstractExt`)," -"并且æ¯ä¸ªæ¸¸æˆå¯¹è±¡éƒ½æ°å¥½æºå¸¦ä¸€ä¸ªæœ€æ´¾ç”ŸåŒ¹é…类型的扩展实例,该实例缓存在对象内部统一的 `AbstractClass` `0x18` æ§½ä½ä¸­ã€‚" -"æ¯ä¸ªç±»æ‰©å±•都ä¿å­˜åœ¨ä¸€ä¸ªä»¥åŽŸç‰ˆå¼•æ“Žç±»å称命åçš„å•独文件夹中,并包å«ä»¥ä¸‹å†…容:" +"`Ext/` - 原版引擎类的扩展类æºç ã€‚扩展类形æˆäº†ä¸€ä¸ªé•œåƒäº†æ¸¸æˆè‡ªèº«ç±»æ ‘的并行继承层次结构(`Container.h` 中的 " +"`AbstractExt` 为根;例如`BuildingExt : TechnoExt : RadioExt : MissionExt : " +"ObjectExt : AbstractExt`),并且æ¯ä¸ªæ¸¸æˆå¯¹è±¡éƒ½æ°å¥½æºå¸¦ä¸€ä¸ªæœ€æ´¾ç”ŸåŒ¹é…类型的扩展实例,该实例缓存在对象内部统一的 " +"`AbstractClass` `0x18` æ§½ä½ä¸­ã€‚æ¯ä¸ªç±»æ‰©å±•都ä¿å­˜åœ¨ä¸€ä¸ªä»¥åŽŸç‰ˆå¼•æ“Žç±»å称命åçš„å•独文件夹中,并包å«ä»¥ä¸‹å†…容:" msgid "" "`Body.h` and `Body.cpp` contain class and method definitions/declarations" @@ -330,7 +330,8 @@ msgid "" "`LoadFromINIFile`/`SaveToStream`/`LoadFromStream` overrides, plus static " "helper methods;" msgstr "" -"æ–°çš„æ•°æ®æˆå‘˜ï¼Œä»¥åŠï¼ˆå¯¹äºŽé€‚当的类)`LoadFromINIFile`ï¼`SaveToStream`ï¼`LoadFromStream` çš„é‡å†™ï¼Œå¤–åŠ é™æ€è¾…助方法;" +"æ–°çš„æ•°æ®æˆå‘˜ï¼Œä»¥åŠï¼ˆå¯¹äºŽé€‚当的类)`LoadFromINIFile`ï¼`SaveToStream`ï¼`LoadFromStream` " +"çš„é‡å†™ï¼Œå¤–åŠ é™æ€è¾…助方法;" msgid "" "`ExtContainer`/`ExtMap` - the per-class container (inherits " @@ -346,7 +347,12 @@ msgid "" "itself so code written against the old nested data classes keeps " "compiling;" msgstr "" -"`ExtContainer`ï¼`ExtMap` —— æ¯ä¸ªç±»çš„容器(继承自 `Container.h` 中的 `Container`ï¼‰ï¼Œç”¨äºŽè·Ÿè¸ªä¸€ä¸ªå…·ä½“æ‰©å±•ç±»çš„æ‰€æœ‰æ´»åŠ¨å®žä¾‹ï¼Œä»¥è¿›è¡Œæ‰¹é‡æ“作(分é…ï¼ç§»é™¤ã€é›†ä¸­å¼å­˜æ¡£æµå¼å¤„ç†ã€åŠ è½½åŽé‡é“¾æŽ¥ã€åœºæ™¯æ¸…é™¤ï¼‰ï¼›åªæœ‰å…·ä½“çš„å¶å­ç±»ï¼ˆä¾‹å¦‚ `BuildingExt`ï¼‰æ‰æœ‰å®¹å™¨ï¼Œè€Œå±‚次结构中的æ¯ä¸€çº§éƒ½æä¾›äº†ç±»åž‹åŒ–çš„ `Fetch`ï¼`TryFetch`。容器自身的 `Find`ï¼`TryFind` 查找已弃用,仅为了å‘å‰å…¼å®¹ï¼ˆ`TechnoExt`ï¼`TechnoTypeExt`,其容器被拆分为æ¯ä¸ªå¶å­ç±»ä¸€ä¸ªï¼Œå‡ºäºŽåŒæ ·çš„原因ä¿ç•™äº†ä¸€ä¸ªä»…用于查找的 `ExtMap` å ä½ç¬¦ï¼‰ï¼Œå¹¶ä¸”æ¯ä¸ªé‡åšå‰çš„类都带有一个已弃用的 `ExtData` 别å,这样针对旧嵌套数æ®ç±»ç¼–写的代ç ä»å¯ç¼–译;" +"`ExtContainer`ï¼`ExtMap` —— æ¯ä¸ªç±»çš„容器(继承自 `Container.h` 中的 " +"`Container`ï¼‰ï¼Œç”¨äºŽè·Ÿè¸ªä¸€ä¸ªå…·ä½“æ‰©å±•ç±»çš„æ‰€æœ‰æ´»åŠ¨å®žä¾‹ï¼Œä»¥è¿›è¡Œæ‰¹é‡æ“作(分é…ï¼ç§»é™¤ã€é›†ä¸­å¼å­˜æ¡£æµå¼å¤„ç†ã€åŠ è½½åŽé‡é“¾æŽ¥ã€åœºæ™¯æ¸…é™¤ï¼‰ï¼›åªæœ‰å…·ä½“çš„å¶å­ç±»ï¼ˆä¾‹å¦‚" +" `BuildingExt`ï¼‰æ‰æœ‰å®¹å™¨ï¼Œè€Œå±‚次结构中的æ¯ä¸€çº§éƒ½æä¾›äº†ç±»åž‹åŒ–çš„ `Fetch`ï¼`TryFetch`。容器自身的 " +"`Find`ï¼`TryFind` " +"查找已弃用,仅为了å‘å‰å…¼å®¹ï¼ˆ`TechnoExt`ï¼`TechnoTypeExt`,其容器被拆分为æ¯ä¸ªå¶å­ç±»ä¸€ä¸ªï¼Œå‡ºäºŽåŒæ ·çš„原因ä¿ç•™äº†ä¸€ä¸ªä»…用于查找的" +" `ExtMap` å ä½ç¬¦ï¼‰ï¼Œå¹¶ä¸”æ¯ä¸ªé‡åšå‰çš„类都带有一个已弃用的 `ExtData` 别å,这样针对旧嵌套数æ®ç±»ç¼–写的代ç ä»å¯ç¼–译;" msgid "" "`Fetch`/`TryFetch` statics - the O(1) lookup used at call sites " @@ -354,7 +360,9 @@ msgid "" "extension, `TryFetch` returns null instead (also the right choice while a" " savegame is loading);" msgstr "" -"`Fetch`ï¼`TryFetch` 陿€æ–¹æ³• —— 在调用点使用的 O(1) 查找(`TechnoExt::Fetch(pThis)`);如果对象没有æºå¸¦æ‰©å±•,`Fetch` 会触å‘致命错误,而 `TryFetch` 则返回空(在存档加载期间也是正确的选择);" +"`Fetch`ï¼`TryFetch` 陿€æ–¹æ³• —— 在调用点使用的 O(1) " +"查找(`TechnoExt::Fetch(pThis)`);如果对象没有æºå¸¦æ‰©å±•,`Fetch` 会触å‘致命错误,而 `TryFetch` " +"则返回空(在存档加载期间也是正确的选择);" msgid "" "constructor/destructor and (for appropriate classes) INI reading hooks. " @@ -365,14 +373,18 @@ msgid "" "inline within each cell's own savegame block instead (see " "`Ext/Cell/Body.cpp`)." msgstr "" -"æž„é€ å‡½æ•°ï¼æžæž„函数,以åŠï¼ˆå¯¹äºŽé€‚当的类)INI 读å–é’©å­ã€‚åºåˆ—化集中在 `Phobos.Ext.cpp` 中 —— 没有æ¯ä¸ªç±»çš„存档钩å­ã€‚唯一的例外是 `CellExt`:游æˆå°†å•元格视为值对象,其身份ä¸ç¨³å®šï¼ˆå®ƒä¼šå°±åœ°é‡æ–°åˆå§‹åŒ–它们并进行整体å¤åˆ¶ï¼‰ï¼Œå› æ­¤å•元格扩展被内è”地æŒä¹…化在æ¯ä¸ªå•元格自身的存档å—中(å‚è§ `Ext/Cell/Body.cpp`)。" +"æž„é€ å‡½æ•°ï¼æžæž„函数,以åŠï¼ˆå¯¹äºŽé€‚当的类)INI 读å–é’©å­ã€‚åºåˆ—化集中在 `Phobos.Ext.cpp` 中 —— " +"没有æ¯ä¸ªç±»çš„存档钩å­ã€‚唯一的例外是 " +"`CellExt`:游æˆå°†å•元格视为值对象,其身份ä¸ç¨³å®šï¼ˆå®ƒä¼šå°±åœ°é‡æ–°åˆå§‹åŒ–它们并进行整体å¤åˆ¶ï¼‰ï¼Œå› æ­¤å•元格扩展被内è”地æŒä¹…化在æ¯ä¸ªå•元格自身的存档å—中(å‚è§" +" `Ext/Cell/Body.cpp`)。" msgid "" "Extensions subscribe to pointer invalidation by inheriting " "`Detach::Listener` from `Utilities/Detach.h` and overriding `OnDetach`" " (see `HouseExt` for an example)." msgstr "" -"扩展通过从 `Utilities/Detach.h` 继承 `Detach::Listener` å¹¶é‡å†™ `OnDetach` æ¥è®¢é˜…æŒ‡é’ˆå¤±æ•ˆé€šçŸ¥ï¼ˆç¤ºä¾‹è§ `HouseExt`)。" +"扩展通过从 `Utilities/Detach.h` 继承 `Detach::Listener` å¹¶é‡å†™ `OnDetach` " +"æ¥è®¢é˜…æŒ‡é’ˆå¤±æ•ˆé€šçŸ¥ï¼ˆç¤ºä¾‹è§ `HouseExt`)。" msgid "" "`Hooks.cpp` and `Hooks.*.cpp` contain non-common hooks to correctly patch" @@ -578,67 +590,205 @@ msgstr "若能使用等效的 `constexpr` 或 `__forceinline` å‡½æ•°æ›¿ä»£å°±ä¸ msgid "The styleguide is not exhaustive and may be adjusted in the future." msgstr "æ ·å¼æŒ‡å—å¹¶ä¸è¯¦å°½ï¼Œæœªæ¥å¯èƒ½ä¼šè¿›è¡Œè°ƒæ•´ã€‚" -msgid "Git branching model" -msgstr "Git 分支模型" +msgid "Git branching model / Version lifecycle and release strategy" +msgstr "Git 分支模型ï¼ç‰ˆæœ¬ç”Ÿå‘½å‘¨æœŸä¸Žå‘布策略" msgid "" -"Couple of notes regarding the Git practices. We use [git-" -"flow](https://nvie.com/posts/a-successful-git-branching-model/)-like " -"workflow:" -msgstr "" -"我们使用 [git-flow](https://nvie.com/posts/a-successful-git-branching-model/)" -" 之类的工作æµ:" +"Starting from version 0.5, Phobos adopts a new release strategy to enable" +" faster and more frequent releases." +msgstr "从 0.5 版本开始,Phobos 采用新的å‘å¸ƒç­–ç•¥ä»¥å®žçŽ°æ›´å¿«é€Ÿã€æ›´é¢‘ç¹çš„版本å‘布。" msgid "" -"`master` is for stable releases, can have hotfixes pushed to it or " -"branched off like a feature branch with the requirement of version " -"increment and `master` being merged into `develop` after that;" -msgstr "" -"`master` 用于稳定版本å‘布,å…许直接推é€çƒ­ä¿®å¤è¡¥ä¸æˆ–åƒåŠŸèƒ½åˆ†æ”¯ä¸€æ ·åˆ†ç¦»åˆ†æ”¯ï¼Œä½†éœ€éµå¾ªç‰ˆæœ¬å·é€’å¢žè¦æ±‚,并在之åŽå°† `master` " -"分支åˆå¹¶å›ž `develop` 分支;" +"![Versioning scheme from 0.5 onward](_static/images/versioning-" +"past-0.5.excalidraw.png)" +msgstr "![0.5 之åŽçš„ç‰ˆæœ¬ç®¡ç†æ–¹æ¡ˆ](_static/images/versioning-past-0.5.excalidraw.png)" -msgid "`develop` is the main development branch;" -msgstr "`develop` 是主è¦å¼€å‘分支;" +msgid "Versioning scheme from 0.5 onward" +msgstr "0.5 之åŽçš„ç‰ˆæœ¬ç®¡ç†æ–¹æ¡ˆ" + +msgid "*Image editable in [Excalidraw](https://excalidraw.com)*" +msgstr "*图片å¯åœ¨ [Excalidraw](https://excalidraw.com) 中编辑*" msgid "" -"`feature/`-prefixed branches (sometimes the prefix may be different if " -"appropriate, like for big fixes or changes) are so called \"feature " -"branches\" - those are branched off `develop` for every new feature to be" -" introduced into it and then merged back. We use squash merge to merge " -"them back in case of smaller branches and sometimes merge commit in case " -"the branch is so big it would be viable to keep it as is." -msgstr "" -"带有 `feature/` å‰ç¼€çš„分支(有时根æ®å®žé™…情况å¯èƒ½ä½¿ç”¨ä¸åŒçš„å‰ç¼€ï¼Œä¾‹å¦‚å¤§çš„ä¿®å¤æˆ–æ”¹åŠ¨ï¼‰å³æ‰€è°“的「功能分支ã€â€”—这些分支从 " -"`develop` 分离出æ¥ç”¨äºŽå¼•入新的功能,完æˆåŽåˆå¹¶å›ž " -"`develop`。对于å°åž‹åˆ†æ”¯ï¼Œæˆ‘们使用压缩åˆå¹¶ï¼›è‹¥åˆ†æ”¯è§„模较大,则å¯èƒ½ä½¿ç”¨åˆå¹¶æäº¤æ¥ç»´æŒæäº¤è®°å½•的完整性;" +"All changes are to be made **exclusively** to `develop` as the source of " +"truth, and then cherry-picked to other branches!" +msgstr "所有更改 **å¿…é¡»** 首先æäº¤åˆ°ä½œä¸ºå”¯ä¸€çœŸå®žæºçš„ `develop` 分支,然åŽå†æ‹£é€‰åˆ°å…¶ä»–分支ï¼" + +msgid "A brief summary compared to old style:" +msgstr "与旧方å¼çš„简è¦å¯¹æ¯”:" msgid "" -"`hotfix/`-prefixed branches may be used in a same manner as `feature/`, " -"but with `master` branch, with a requirement of `master` being merged " -"into `develop` after `hotfix/` branch was squash merged into `master`." -msgstr "" -"带有 `hotfix/` å‰ç¼€çš„分支使用方å¼ç±»ä¼¼äºŽ `feature/`,但基于 `master` åˆ†æ”¯åˆ›å»ºï¼Œè¦æ±‚å°† `hotfix/` " -"分支压缩åˆå¹¶åˆ° `master` åŽå¿…须将 `master` åˆå¹¶å›ž `develop`ï¼›" +"devbuilds are now called pre-releases (alpha, beta, RC etc.) and are " +"almost a proper version with docs, all changes tracked in a special " +"changelog subsection, released on the same cadence;" +msgstr "å¼€å‘版(devbuilds)现在称为预å‘布版本(alphaã€betaã€RC ç­‰ï¼‰ï¼Œå‡ ä¹Žæ˜¯ä¸€ä¸ªå®Œæ•´çš„ç‰ˆæœ¬ï¼ŒåŒ…å«æ–‡æ¡£ï¼Œæ‰€æœ‰å˜æ›´è®°å½•在专门的更新日志å°èŠ‚ä¸­ï¼Œä»¥ç›¸åŒçš„节å¥å‘布;" msgid "" -"`release/`-prefixed branches are branched off `develop` when a new stable" -" release is slated to allow working on features for a next release and " -"stability improvements for this release. Those are merged with a merge " -"commit into `master` and `develop` with a stable version number increase," -" after which the stable version is released." -msgstr "" -"带有 `release/` å‰ç¼€çš„分支在计划å‘布新的稳定版本时从 `develop` " -"分离,å…è®¸åŒæ—¶å¼€å‘下个版本的功能和改进当å‰ç‰ˆæœ¬çš„稳定性。这些分支通过åˆå¹¶æäº¤åˆå¹¶åˆ° `master` å’Œ " -"`develop`,并递增稳定版本的版本å·ï¼ŒéšåŽå‘布稳定版本。" +"each pre-release (new devbuild) materializes a version branch, bugfix " +"followups committed to develop get ported to it;" +msgstr "æ¯ä¸ªé¢„å‘布版本(新开å‘版)都会生æˆä¸€ä¸ªç‰ˆæœ¬åˆ†æ”¯ï¼Œæäº¤åˆ° `develop` 分支的åŽç»­ä¿®å¤ä¼šè¢«ç§»æ¤åˆ°è¯¥åˆ†æ”¯ï¼›" + +msgid "when enough bugs are fixed - a stable version is created;" +msgstr "当足够多的 Bug 被修å¤åŽï¼Œå°±ä¼šåˆ›å»ºç¨³å®šç‰ˆæœ¬ï¼›" msgid "" -"When you're working with your local & remote branches use **fast-" -"forward** pulls to get the changes from remote branch to local, **don't " -"merge remote branch into local and vice versa**, this creates junk " -"commits and makes things unsquashable." -msgstr "" -"å½“ä½ åœ¨å¤„ç†æœ¬åœ°ä¸Žè¿œç¨‹åˆ†æ”¯æ—¶åº”当使用 **拉å–(快进)** " -"å°†è¿œç¨‹åˆ†æ”¯çš„å˜æ›´åŒæ­¥åˆ°æœ¬åœ°ï¼Œ**ä¸è¦å°†è¿œç¨‹åˆ†æ”¯åˆå¹¶åˆ°æœ¬åœ°åˆ†æ”¯**,å之亦然,å¦åˆ™ä¼šäº§ç”Ÿåžƒåœ¾æäº¤å¹¶ä½¿ä»£ç æ— æ³•压缩整ç†ã€‚" +"if some critical change that warrants a version bump needs to be applied " +"(e.g. forgot to serialize a field, or fixed a critical bug from a feature" +" released before upcoming version) - we introduce a new version (with " +"docs, version change etc.) on the same branch;" +msgstr "如果需è¦åº”用æŸäº›éœ€è¦ç‰ˆæœ¬å·é€’增的关键更改(例如忘记åºåˆ—化æŸä¸ªå­—段,或修å¤äº†å³å°†å‘å¸ƒçš„ç‰ˆæœ¬ä¹‹å‰æŸä¸ªåŠŸèƒ½ä¸­çš„å…³é”® Bug),我们会在åŒä¸€åˆ†æ”¯ä¸Šå‘å¸ƒä¸€ä¸ªæ–°ç‰ˆæœ¬ï¼ˆåŒ…å«æ–‡æ¡£ã€ç‰ˆæœ¬å·å˜æ›´ç­‰ï¼‰ï¼›" + +msgid "" +"the new stable release is not the old stable: after 0.5 a stable version " +"is \"a devbuild with enough bug fixes\", released on a faster cadence " +"with less time spent per version." +msgstr "新的稳定版本ä¸å†æ˜¯æ—§å¼ç¨³å®šç‰ˆæœ¬ï¼š0.5 之åŽï¼Œç¨³å®šç‰ˆæœ¬å°±æ˜¯â€œä¿®å¤äº†è¶³å¤Ÿå¤š Bug 的开å‘版â€ï¼Œä»¥æ›´å¿«çš„节å¥å‘布,æ¯ä¸ªç‰ˆæœ¬èŠ±è´¹çš„æ—¶é—´æ›´å°‘ã€‚" + +msgid "The lifecycle of a version is as follows:" +msgstr "一个版本的生命周期如下:" + +msgid "" +"**Development phase**: New features and changes are committed to the " +"`develop` branch. `develop` always carries the version it is working " +"towards: as soon as a release branch is cut, `VERSION_MINOR` (or " +"`VERSION_MAJOR`) in `src/Phobos.version.h` is bumped and " +"`VERSION_REVISION`/`VERSION_PATCH` are reset to 0, so that nightlies are " +"stamped with the version they lead up to instead of one that has already " +"been released." +msgstr "**å¼€å‘阶段**ï¼šæ–°åŠŸèƒ½å’Œå˜æ›´æäº¤åˆ° `develop` 分支。`develop` 始终带有其正在开å‘的目标版本å·ï¼šä¸€æ—¦åˆ›å»ºå‘布分支,`src/Phobos.version.h` 中的 `VERSION_MINOR`(或 `VERSION_MAJOR`)就会递增,而 `VERSION_REVISION`ï¼`VERSION_PATCH` 则é‡ç½®ä¸º 0,这样自动构建版本所标记的版本å·å°±æ˜¯å®ƒä»¬æ‰€å¯¹åº”çš„ç›®æ ‡ç‰ˆæœ¬ï¼Œè€Œä¸æ˜¯å·²ç»å‘布的版本。" + +msgid "" +"**Pre-release phase**: When enough features have accumulated on " +"`develop`, a pre-release build (e.g., `v0.5-beta1`) is created. This " +"build marks the start of a new *release branch* (e.g., `release/v0.5`) " +"and signifies that active feature development for version 0.5 is " +"complete. This branch will be used for all subsequent testing and the " +"final stable release." +msgstr "**预å‘布阶段**:当 `develop` 上积累了足够多的功能åŽï¼Œä¼šåˆ›å»ºä¸€ä¸ªé¢„å‘布构建(例如 `v0.5-beta1`ï¼‰ã€‚è¯¥æž„å»ºæ ‡å¿—ç€æ–° *å‘布分支*(例如 `release/v0.5`)的起始,并表明 0.5 版本的功能开å‘已告完æˆã€‚该分支将用于åŽç»­æ‰€æœ‰æµ‹è¯•ä»¥åŠæœ€ç»ˆçš„稳定版本å‘布。" + +msgid "" +"During this phase, multiple pre-release builds (which can be called beta," +" alpha, or release candidate) may be published for wider testing. Between" +" pre-releases on the same version number, there shall be no changes that " +"warrant a stable version changelog addition; in other words — only bug " +"fixes, minor additions, and polish to the existing new version feature " +"set are allowed." +msgstr "在此阶段,å¯èƒ½ä¼šå‘布多个预å‘布构建(å¯ç§°ä¸º betaã€alpha 或å‘布候选版本)以供广泛测试。在åŒä¸€ç‰ˆæœ¬å·çš„预å‘布之间,ä¸åº”存在需è¦åœ¨ç¨³å®šç‰ˆæœ¬æ›´æ–°æ—¥å¿—ä¸­è®°å½•çš„å˜æ›´ï¼›æ¢è¨€ä¹‹â€”—åªå…许进行 Bug ä¿®å¤ã€å°å¹…增补和对现有新功能集的打磨。" + +msgid "" +"If there's an urgent need to introduce a feature that would warrant new " +"changelog addition on the same branch - it is allowed to **reset the pre-" +"release prefix and increment the appropriate version number**, while also" +" creating the corresponding doc changelog section." +msgstr "如果有紧急需求需è¦å¼•入一个需è¦åœ¨åŒä¸€åˆ†æ”¯ä¸Šæ–°å¢žæ›´æ–°æ—¥å¿—记录的功能——å…许 **é‡ç½®é¢„å‘布å‰ç¼€å¹¶é€’增相应的版本å·**ï¼ŒåŒæ—¶è¿˜éœ€è¦åˆ›å»ºå¯¹åº”的文档更新日志章节。" + +msgid "" +"**Stable release**: When the pre-release builds are deemed stable enough," +" a stable release (e.g., `v0.5`) is published from the release's branch." +msgstr "**稳定å‘布**:当预å‘布构建被认为足够稳定时,会从该å‘布分支å‘布稳定版本(例如 `v0.5`)。" + +msgid "" +"**Maintenance phase**: After the stable release, the release branch " +"enters maintenance mode, where only bug fixes are applied, resulting in " +"patch releases (e.g., `v0.5.0.1`, `v0.5.0.2`)." +msgstr "**维护阶段**:稳定版本å‘布åŽï¼Œè¯¥å‘布分支进入维护模å¼ï¼Œåªè¿›è¡Œ Bug ä¿®å¤ï¼Œå¹¶äº§ç”Ÿè¡¥ä¸ç‰ˆæœ¬ï¼ˆä¾‹å¦‚ `v0.5.0.1`ã€`v0.5.0.2`)。" + +msgid "" +"**End of maintenance**: When a new stable release is published (e.g., " +"`v0.6`), the previous minor version branch (e.g., `v0.5.x.y`) is " +"officially deprecated and enters end-of-life, ceasing to receive any " +"further updates, including bug fixes. Concurrently, the new stable " +"release (e.g., `v0.6`) enters its own maintenance phase, and a new " +"release branch for the next version (e.g., `release/v0.7`) may already " +"have been created from the `develop` branch, initiating its pre-release " +"cycle." +msgstr "**维护结æŸ**:当å‘布新的稳定版本(例如 `v0.6`)时,之å‰çš„æ¬¡ç‰ˆæœ¬åˆ†æ”¯ï¼ˆä¾‹å¦‚ `v0.5.x.y`)将被正å¼å¼ƒç”¨å¹¶è¿›å…¥ç”Ÿå‘½å‘¨æœŸç»ˆæ­¢çжæ€ï¼Œä¸å†æŽ¥æ”¶ä»»ä½•进一步更新(包括 Bug ä¿®å¤ï¼‰ã€‚ä¸Žæ­¤åŒæ—¶ï¼Œæ–°çš„稳定版本(例如 `v0.6`)进入其自身的维护阶段,而下一个版本的新å‘布分支(例如 `release/v0.7`)å¯èƒ½å·²ç»ä»Ž `develop` 分支创建,并开始其预å‘布周期。" + +msgid "" +"If needed, a new release branch may be started even before the previous " +"one has had a stable release. Doing so will temporarily increase the " +"burden of upkeeping multiple branches, so do it only when there's a valid" +" reason for such." +msgstr "如果需è¦ï¼Œå³ä½¿ä¸Šä¸€ä¸ªå‘布分支尚未å‘布稳定版本,也å¯ä»¥å¯åŠ¨æ–°çš„å‘布分支。但这样åšä¼šæš‚时增加维护多个分支的负担,因此仅在有充分ç†ç”±æ—¶æ‰åº”如此æ“作。" + +msgid "" +"The `master` branch is deprecated; all development occurs in `develop`, " +"and each version branches off from it." +msgstr "`master` 分支已弃用;所有开å‘å‡åœ¨ `develop` 中进行,æ¯ä¸ªç‰ˆæœ¬éƒ½ä»Žè¯¥åˆ†æ”¯åˆ†ç¦»ã€‚" + +msgid "" +"**`develop` is the source of truth! Always apply your changes to " +"`develop` first, then cherry-pick them onto the correct branch!**" +msgstr "**`develop` 是唯一真实æºï¼è¯·å§‹ç»ˆå…ˆå°†æ›´æ”¹åº”用到 `develop`,然åŽå†æ‹£é€‰åˆ°æ­£ç¡®çš„分支ï¼**" + +msgid "How to publish a release" +msgstr "如何å‘布版本" + +msgid "" +"Publishing a release is done from a release branch (see the lifecycle " +"above). The steps are:" +msgstr "版本å‘布需从å‘布分支进行(å‚è§ä¸Šè¿°ç”Ÿå‘½å‘¨æœŸï¼‰ã€‚步骤如下:" + +msgid "" +"**Set the version** in `src/Phobos.version.h`. When a release branch is " +"cut, bump `VERSION_MINOR` (or `VERSION_MAJOR`) and reset " +"`VERSION_REVISION` and `VERSION_PATCH` to 0; patch releases only bump " +"`VERSION_PATCH`." +msgstr "**设置版本å·**:在 `src/Phobos.version.h` 中设置版本å·ã€‚创建å‘布分支时,递增 `VERSION_MINOR`(或 `VERSION_MAJOR`),并将 `VERSION_REVISION` å’Œ `VERSION_PATCH` é‡ç½®ä¸º 0;补ä¸ç‰ˆæœ¬ä»…递增 `VERSION_PATCH`。" + +msgid "" +"**Decide whether it is a pre-release or a stable release.** The pre-" +"release suffix is the knob: as long as `PRERELEASE_SUFFIX` is defined " +"(e.g. `#define PRERELEASE_SUFFIX \"beta1\"`), a release build is a pre-" +"release; remove the define entirely for a stable release. The suffix can " +"be anything semantic versioning allows (e.g. `alpha5`, `beta1`, `rc3`)." +msgstr "**决定是预å‘布还是稳定版本**:预å‘布åŽç¼€å³æŽ§åˆ¶å¼€å…³ï¼šåªè¦å®šä¹‰äº† `PRERELEASE_SUFFIX`(例如 `#define PRERELEASE_SUFFIX \"beta1\"`),该å‘布构建å³ä¸ºé¢„å‘布版本;若è¦å‘布稳定版本,则完全移除该定义。åŽç¼€å¯ä»¥æ˜¯è¯­ä¹‰åŒ–版本å…许的任何内容(例如 `alpha5`ã€`beta1`ã€`rc3`)。" + +msgid "" +"**Create a GitHub release and tag** using the short user-facing version " +"you've set in steps 1 and 2 (e.g. `v0.5-alpha1`). The `release.yml` " +"workflow builds the DLL with `BuildType=RELEASE`;" +msgstr "**创建 GitHub å‘布和标签**:使用你在步骤 1 å’Œ 2 中设置的é¢å‘用户的简短版本å·ï¼ˆä¾‹å¦‚ `v0.5-alpha1`)。`release.yml` 工作æµä¼šä»¥ `BuildType=RELEASE` 构建 DLLï¼›" + +msgid "" +"The changelog is extracted from `docs/Whats-New.md` automatically. **Do " +"not write the changelog yourself!** It will be appended to the text you " +"wrote after you publish the release. Also **do not use GitHub's " +"\"Generate release notes\" button!** It can't be configured to provide " +"correct output." +msgstr "更新日志会自动从 `docs/Whats-New.md` æå–。**请勿手动编写更新日志ï¼** 它会在你å‘布版本åŽé™„加到你编写的文本之åŽã€‚å¦å¤– **ä¸è¦ä½¿ç”¨ GitHub 的「生æˆå‘å¸ƒè¯´æ˜Žã€æŒ‰é’®ï¼** 它无法é…置以æä¾›æ­£ç¡®çš„输出。" + +msgid "" +"The build is built and attached automatically. **Do not build Phobos " +"releases manually!**" +msgstr "构建会自动编译并附加。**请勿手动构建 Phobos å‘布版本ï¼**" + +msgid "" +"**GitHub \"pre-release\" checkbox doesn't affect the produced build " +"type**, it only affects the release's display status for GitHub." +msgstr "**GitHub 的“预å‘布â€å¤é€‰æ¡†ä¸ä¼šå½±å“生æˆçš„æž„建类型**,它仅影å“该å‘布在 GitHub 上的显示状æ€ã€‚" + +msgid "" +"**Verify the artifacts** once the build finishes and the artifacts are " +"attached, then announce the release." +msgstr "**éªŒè¯æž„建产物**:构建完æˆä¸”产物附加åŽï¼Œå†å®£å¸ƒå‘布。" + +msgid "" +"The release tag and name use the short user-facing version (e.g. " +"`v0.5-alpha1`); the DLL reports the full version with trailing zeros " +"(e.g. `0.5.0.0-alpha1`) internally, so that is what appears in the file " +"properties and what the `-HideVersionWarning` switch expects." +msgstr "å‘布标签和å称使用é¢å‘用户的简短版本å·ï¼ˆä¾‹å¦‚ `v0.5-alpha1`);而 DLL 内部报告的是包å«å°¾éšé›¶çš„完整版本å·ï¼ˆä¾‹å¦‚ `0.5.0.0-alpha1`),因此文件属性中显示的是此完整版本å·ï¼Œä¹Ÿæ˜¯ `-HideVersionWarning` 傿•°æ‰€æœŸæœ›çš„值。" + +msgid "" +"If you want to build a pre-release locally for testing, run " +"`scripts\\build.bat Release RELEASE` with the suffix still defined in " +"`version.h`. A plain `scripts\\build_debug.bat` or " +"`scripts\\build_release.bat` always produces a local build instead." +msgstr "如果你想在本地构建预å‘布版本进行测试,请在 `version.h` 中ä»å®šä¹‰åŽç¼€çš„æƒ…况下è¿è¡Œ `scripts\\build.bat Release RELEASE`。而直接è¿è¡Œ `scripts\\build_debug.bat` 或 `scripts\\build_release.bat` åˆ™å§‹ç»ˆç”Ÿæˆæœ¬åœ°æž„建。" + +msgid "Useful Git config" +msgstr "有用的 Git é…ç½®" msgid "These commands will do the following for all repositories on your PC:" msgstr "这些命令对你电脑上的所有代ç ä»“库执行以下æ“作:" diff --git a/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po b/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po index 9c8d5f810c..1a05fd11b6 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po +++ b/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Phobos \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-08-09 20:48+0800\n" +"POT-Creation-Date: 2026-08-09 21:24+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -26,8 +26,21 @@ msgid "" "mods to accommodate." msgstr "此页é¢åˆ—出了 Phobos ç¨³å®šç‰ˆæœ¬çš„åŽ†å²æ›´æ”¹ä»¥åŠ modder 们为适应当å‰ç‰ˆæœ¬å¯¹å…¶ mod 所需è¦åšçš„å¿…è¦æ”¹åŠ¨ã€‚" -msgid "Migrating" -msgstr "è¿ç§»" +msgid "Migration (breaking changes)" +msgstr "è¿ç§»ï¼ˆç ´å性更改)" + +msgid "" +"New Phobos user? Read the \"Changes to vanilla behavior\" subsections in " +"every version below to know what you might need to adjust when installing" +" Phobos" +msgstr "Phobos 新用户?请阅读以下æ¯ä¸ªç‰ˆæœ¬ä¸­çš„“原版行为更改â€å°èŠ‚ï¼Œä»¥äº†è§£å®‰è£… Phobos æ—¶å¯èƒ½éœ€è¦è°ƒæ•´çš„内容。" + +msgid "" +"This serves as a changelog for when you just need to drop the new version" +" in without reading into every version you're skipping, so you can simply" +" read up on this log of breaking changes and apply whatever you might " +"need to apply." +msgstr "这是一份用于让你åªéœ€æ›¿æ¢æ–°ç‰ˆæœ¬è€Œæ— éœ€äº†è§£ä½ æ‰€è·³è¿‡çš„æ¯ä¸ªç‰ˆæœ¬æ—¶ä½¿ç”¨çš„æ›´æ–°æ—¥å¿—ï¼Œä»¥ä¾¿ä½ å¯ä»¥ç®€å•æŸ¥é˜…è¿™ä»½ç ´åæ€§å˜æ›´æ—¥å¿—并应用你å¯èƒ½éœ€è¦çš„任何更改。" msgid "" "You can use the migration utility (can be found on [Phobos " @@ -38,8 +51,11 @@ msgstr "" "ä½ å¯ä»¥ä½¿ç”¨è¿ç§»å·¥å…·ï¼ˆå¯ä»¥åœ¨ [Phobos 补充资æºåº“](https://github.com/Phobos-" "developers/PhobosSupplementaries) 中找到)通过相应的 sed 脚本文件自动应用大多数更改。" -msgid "From vanilla" -msgstr "由原版" +msgid "0.5" +msgstr "0.5" + +msgid "Changes to vanilla behavior" +msgstr "原版行为更改" msgid "" "Vehicles paradropped by AI players now default to `Hunt` mission instead " @@ -81,74 +97,6 @@ msgstr "" "使用 `Airstrike=true` 弹头的武器现在无论在哪个武器槽ä½éƒ½å°†æ£€æŸ¥ç›®æ ‡çš„类别是å¦å¯è¢«ç©ºè¢­ã€‚需è¦åœ¨ä½œä¸ºä¸»æ­¦å™¨çš„空袭武器弹头上使用 " "`AirstrikeTargets=all` æ¥æ¢å¤æ—§æœ‰è¡Œä¸ºã€‚" -msgid "" -"`PowerUpNAnim` is now used instead of the upgrade building's image file " -"for upgrade animation if set. Note that displaying a damaged version will" -" still require setting `PowerUpNDamagedAnim` explicitly in all cases, as " -"the fallback to upgrade building image does not extend to it, nor would " -"it be safe to add. `PowersUpToLevel=-1` upgrades still do not work " -"correctly `PowerUpNAnim` and such buildings should forgo using explicit " -"upgrade animations." -msgstr "" -"现在如果通过 `PowerUpNAnim` è®¾ç½®äº†åŠ è½½ç‰©åŠ¨ç”»é‚£ä¹ˆå®ƒä»¬å°†ä¼šä½¿ç”¨æ›¿ä»£åŠ è½½ç‰©å»ºç­‘è‡ªèº«çš„å›¾åƒæ¥æ˜¾ç¤ºã€‚注æ„ä½ ä»éœ€æ˜¾å¼è®¾ç½® " -"`PowerUpNDamagedAnim` " -"æ¥å¯ç”¨ä¼¤æ®‹ç‰ˆæœ¬çš„加载物动画,因为并没有添加一个它们ä¸å­˜åœ¨æ—¶å›žé€€åˆ°æœªä¼¤æ®‹ç‰ˆæœ¬åŠ è½½ç‰©å›¾åƒçš„é€»è¾‘ï¼Œå¹¶ä¸”é‚£ä¹Ÿä¸æ˜¯ä¸€ä¸ªå®‰å…¨çš„åšæ³•。`PowersUpToLevel=-1`" -" 的加载物在使用 `PowerUpNAnim` æ—¶ä»ç„¶æ— æ³•正常工作,因此这类建筑应当é¿å…使用显å¼çš„加载物动画。" - -msgid "" -"Elite technos no longer scatter by default, behaviour can be restored by " -"including `SCATTER` in their `EliteAbilities`." -msgstr "精英å•ä½ä¸å†é»˜è®¤èŽ·å¾—åˆ†æ•£èƒ½åŠ›ï¼Œå¯ä»¥é€šè¿‡åœ¨ä»–们的 `EliteAbilities` 中添加 `SCATTER` æ¥å¤åŽŸæ—§æœ‰è¡Œä¸ºã€‚" - -msgid "" -"`[CrateRules] -> FreeMCV` now controls whether or not player is forced to" -" receive unit from `[General] -> BaseUnit` from goodie crate if they own " -"no buildings or any existing `[General] -> BaseUnit` vehicles and own " -"more than `[CrateRules] -> FreeMCV.CreditsThreshold` (defaults to 1500) " -"credits." -msgstr "" -"现在 `[CrateRules] -> FreeMCV` å¯ä»¥æŽ§åˆ¶çŽ©å®¶æ˜¯å¦ä¼šåœ¨ä»–们没有任何建筑物或任何 `BaseUnit` 中的载具且资金超过 " -"`[CrateRules] -> FreeMCV.CreditsThreshold`(默认为 1500)时强制获得一个 `[General] ->" -" BaseUnit` 中的å•ä½ã€‚" - -msgid "" -"Translucent RLE SHPs will now be drawn using a more precise and " -"performant algorithm that has no green tint and banding. Can be disabled " -"with `rulesmd.ini -> [General] -> FixTransparencyBlitters=no`." -msgstr "" -"现在åŠé€æ˜Žçš„ RLE SHP 将使用更精确且性能更高的算法进行绘制,ä¸ä¼šå‡ºçŽ°ç»¿è‰²è‰²è°ƒå’Œæ¡çº¹ã€‚å¯ä»¥é€šè¿‡ `rulesmd.ini -> " -"[General] -> FixTransparencyBlitters=no` æ¥ç¦ç”¨ã€‚" - -msgid "" -"Iron Curtain status is now preserved by default when converting between " -"TechnoTypes via `DeploysInto` / `UndeploysInto`. This behavior can be " -"turned off per-TechnoType and global basis using " -"`[TechnoType]/[CombatDamage] -> IronCurtain.KeptOnDeploy=no`." -msgstr "" -"现在é“幕效果会默认在科技类型通过 `DeploysInto`ï¼`UndeploysInto` è½¬æ¢æ—¶ä¿ç•™ã€‚这一行为å¯ä»¥é€šè¿‡æ¯ä¸ªç§‘技类型和全局设置的" -" `[TechnoType]/[CombatDamage] -> IronCurtain.KeptOnDeploy=no` æ¥å…³é—­ã€‚" - -msgid "" -"The obsolete `[General] -> WarpIn` has been enabled for the default anim " -"type when technos are warping in. If you want to restore the vanilla " -"behavior, use the same anim type as `[General] -> WarpOut`." -msgstr "" -"原本废弃的 `[General] -> WarpIn` å·²å¯ç”¨äºŽç§‘æŠ€ç±»åž‹ä¼ é€æ¥æ—¶çš„é»˜è®¤åŠ¨ç”»ç±»åž‹ã€‚å¦‚æžœæƒ³è¦æ¢å¤åŽŸç‰ˆè¡Œä¸ºï¼Œè¯·ä¸ºå…¶è®¾ç½®ä¸€ä¸ªä¸Ž " -"`[General] -> WarpOut` 相åŒçš„动画类型。" - -msgid "" -"Vehicles with `Crusher=true` + `OmniCrusher=true` / " -"`MovementZone=CrusherAll` were hardcoded to tilt when crushing vehicles /" -" walls respectively. This now obeys `TiltsWhenCrushes` but can be " -"customized individually for these two scenarios using " -"`TiltsWhenCrushes.Vehicles` and `TiltsWhenCrushes.Overlays`, which both " -"default to `TiltsWhenCrushes`." -msgstr "" -"拥有 `Crusher=true` å’Œ `OmniCrusher=true`ï¼`MovementZone=CrusherAll` " -"的载具类型硬编ç åœ¨å…¶ç¢¾åŽ‹è½½å…·ï¼å›´å¢™æ—¶ä¼šæŽ€èµ·è€Œå€¾æ–œã€‚现在此行为éµå¾ª `TiltsWhenCrushes` 设置,但å¯ä»¥ä½¿ç”¨ " -"`TiltsWhenCrushes.Vehicles` å’Œ `TiltsWhenCrushes.Overlays` " -"åˆ†åˆ«å®šä¹‰è¿™ä¸¤ç§æƒ…况,它们都默认为 `TiltsWhenCrushes`。" - msgid "" "The default direction for aircraft landing on an airfield will use the " "direction specified by `[AudioVisual] -> PoseDir=` instead of the " @@ -158,26 +106,16 @@ msgstr "" "战机é™è½åˆ°æœºåœºçš„默认方å‘将使用 `[AudioVisual] -> PoseDir=` 指定的方å‘而ä¸å†æ˜¯å»ºç­‘的方å‘,这å¯ä»¥é€šè¿‡ " "`AircraftDockingDir.DefaultToPoseDir=false` æ¥å¤åŽŸã€‚" -msgid "Breaking changes" -msgstr "ç ´åæ€§æ›´æ”¹" - -msgid "" -"This serves as a changelog for when you just need to drop the new version" -" in without reading into every version you're skipping, so you can simply" -" read up on this log of breaking changes and apply whatever you might " -"need to apply." -msgstr "这是一份用于让你åªéœ€æ›¿æ¢æ–°ç‰ˆæœ¬è€Œæ— éœ€äº†è§£ä½ æ‰€è·³è¿‡çš„æ¯ä¸ªç‰ˆæœ¬æ—¶ä½¿ç”¨çš„æ›´æ–°æ—¥å¿—ï¼Œä»¥ä¾¿ä½ å¯ä»¥ç®€å•æŸ¥é˜…è¿™ä»½ç ´åæ€§å˜æ›´æ—¥å¿—并应用你å¯èƒ½éœ€è¦çš„任何更改。" - -msgid "Version TBD (develop branch nightly builds)" -msgstr "待定版本(开å‘分支自动构建版本)" +msgid "Changes to Phobos behavior" +msgstr "Phobos 行为更改" msgid "" "`ProjectileRange` (Ares feature) now has weapon range modifiers applied " "to it if greater than 0 and unless `ProjectileRange.ApplyModifiers` is " "set to false on the WeaponType." msgstr "" -"`ProjectileRange`(Ares 功能)大于 0 时现在会应用武器射程修正,除éžåœ¨æ­¦å™¨ä¸Šè®¾ç½® " -"`ProjectileRange.ApplyModifiers` 为 false。" +"`ProjectileRange`(Ares 功能)现在在大于 0 时会应用武器射程修正,除éžåœ¨ WeaponType 上将 " +"`ProjectileRange.ApplyModifiers` 设置为 false。" msgid "" "`Splits.TargetCellRange` < 0 now applies special behaviour where the " @@ -455,6 +393,57 @@ msgstr "" msgid "0.4" msgstr "0.4" +msgid "" +"`PowerUpNAnim` is now used instead of the upgrade building's image file " +"for upgrade animation if set. Note that displaying a damaged version will" +" still require setting `PowerUpNDamagedAnim` explicitly in all cases, as " +"the fallback to upgrade building image does not extend to it, nor would " +"it be safe to add. `PowersUpToLevel=-1` upgrades still do not work " +"correctly with `PowerUpNAnim` and such buildings should forgo using " +"explicit upgrade animations." +msgstr "" +"现在如果通过 `PowerUpNAnim` è®¾ç½®äº†åŠ è½½ç‰©åŠ¨ç”»é‚£ä¹ˆå®ƒä»¬å°†ä¼šä½¿ç”¨æ›¿ä»£åŠ è½½ç‰©å»ºç­‘è‡ªèº«çš„å›¾åƒæ¥æ˜¾ç¤ºã€‚注æ„ä½ ä»éœ€æ˜¾å¼è®¾ç½® " +"`PowerUpNDamagedAnim` " +"æ¥å¯ç”¨ä¼¤æ®‹ç‰ˆæœ¬çš„加载物动画,因为并没有添加一个它们ä¸å­˜åœ¨æ—¶å›žé€€åˆ°æœªä¼¤æ®‹ç‰ˆæœ¬åŠ è½½ç‰©å›¾åƒçš„é€»è¾‘ï¼Œå¹¶ä¸”é‚£ä¹Ÿä¸æ˜¯ä¸€ä¸ªå®‰å…¨çš„åšæ³•。`PowersUpToLevel=-1`" +" 的加载物在使用 `PowerUpNAnim` æ—¶ä»ç„¶æ— æ³•正常工作,因此这类建筑应当é¿å…使用显å¼çš„加载物动画。" + +msgid "" +"Elite technos no longer scatter by default, behaviour can be restored by " +"including `SCATTER` in their `EliteAbilities`." +msgstr "精英å•ä½ä¸å†é»˜è®¤èŽ·å¾—åˆ†æ•£èƒ½åŠ›ï¼Œå¯ä»¥é€šè¿‡åœ¨ä»–们的 `EliteAbilities` 中添加 `SCATTER` æ¥å¤åŽŸæ—§æœ‰è¡Œä¸ºã€‚" + +msgid "" +"`[CrateRules] -> FreeMCV` now controls whether or not player is forced to" +" receive unit from `[General] -> BaseUnit` from goodie crate if they own " +"no buildings or any existing `[General] -> BaseUnit` vehicles and own " +"more than `[CrateRules] -> FreeMCV.CreditsThreshold` (defaults to 1500) " +"credits." +msgstr "" +"现在 `[CrateRules] -> FreeMCV` å¯ä»¥æŽ§åˆ¶çŽ©å®¶æ˜¯å¦ä¼šåœ¨ä»–们没有任何建筑物或任何 `BaseUnit` 中的载具且资金超过 " +"`[CrateRules] -> FreeMCV.CreditsThreshold`(默认为 1500)时强制获得一个 `[General] ->" +" BaseUnit` 中的å•ä½ã€‚" + +msgid "" +"The obsolete `[General] -> WarpIn` has been enabled for the default anim " +"type when technos are warping in. If you want to restore the vanilla " +"behavior, use the same anim type as `[General] -> WarpOut`." +msgstr "" +"原本废弃的 `[General] -> WarpIn` å·²å¯ç”¨äºŽç§‘æŠ€ç±»åž‹ä¼ é€æ¥æ—¶çš„é»˜è®¤åŠ¨ç”»ç±»åž‹ã€‚å¦‚æžœæƒ³è¦æ¢å¤åŽŸç‰ˆè¡Œä¸ºï¼Œè¯·ä¸ºå…¶è®¾ç½®ä¸€ä¸ªä¸Ž " +"`[General] -> WarpOut` 相åŒçš„动画类型。" + +msgid "" +"Vehicles with `Crusher=true` + `OmniCrusher=true` / " +"`MovementZone=CrusherAll` were hardcoded to tilt when crushing vehicles /" +" walls respectively. This now obeys `TiltsWhenCrushes` but can be " +"customized individually for these two scenarios using " +"`TiltsWhenCrushes.Vehicles` and `TiltsWhenCrushes.Overlays`, which both " +"default to `TiltsWhenCrushes`." +msgstr "" +"拥有 `Crusher=true` å’Œ `OmniCrusher=true`ï¼`MovementZone=CrusherAll` " +"的载具类型硬编ç åœ¨å…¶ç¢¾åŽ‹è½½å…·ï¼å›´å¢™æ—¶ä¼šæŽ€èµ·è€Œå€¾æ–œã€‚现在此行为éµå¾ª `TiltsWhenCrushes` 设置,但å¯ä»¥ä½¿ç”¨ " +"`TiltsWhenCrushes.Vehicles` å’Œ `TiltsWhenCrushes.Overlays` " +"åˆ†åˆ«å®šä¹‰è¿™ä¸¤ç§æƒ…况,它们都默认为 `TiltsWhenCrushes`。" + msgid "" "Phobos-introduced Warhead effects like shield modifiers, critical hits, " "disguise & mind control removal now require Warhead `Verses` to affect " @@ -707,6 +696,23 @@ msgstr "" msgid "0.3" msgstr "0.3" +msgid "" +"Translucent RLE SHPs will now be drawn using a more precise and " +"performant algorithm that has no green tint and banding. Can be disabled " +"with `rulesmd.ini -> [General] -> FixTransparencyBlitters=no`." +msgstr "" +"现在åŠé€æ˜Žçš„ RLE SHP 将使用更精确且性能更高的算法进行绘制,ä¸ä¼šå‡ºçŽ°ç»¿è‰²è‰²è°ƒå’Œæ¡çº¹ã€‚å¯ä»¥é€šè¿‡ `rulesmd.ini -> " +"[General] -> FixTransparencyBlitters=no` æ¥ç¦ç”¨ã€‚" + +msgid "" +"Iron Curtain status is now preserved by default when converting between " +"TechnoTypes via `DeploysInto` / `UndeploysInto`. This behavior can be " +"turned off per-TechnoType and global basis using " +"`[TechnoType]/[CombatDamage] -> IronCurtain.KeptOnDeploy=no`." +msgstr "" +"现在é“幕效果会默认在科技类型通过 `DeploysInto`ï¼`UndeploysInto` è½¬æ¢æ—¶ä¿ç•™ã€‚这一行为å¯ä»¥é€šè¿‡æ¯ä¸ªç§‘技类型和全局设置的" +" `[TechnoType]/[CombatDamage] -> IronCurtain.KeptOnDeploy=no` æ¥å…³é—­ã€‚" + msgid "" "Keys `rulesmd.ini -> [WarheadType] -> PenetratesShield` and `rulesmd.ini " "-> [WarheadType] -> BreaksShield` have been changed to `Shield.Penetrate`" @@ -2442,14 +2448,16 @@ msgid "" " ApproachTarget](Fixed-or-Improved-Logics.md#stop-immediately-if-the-" "target-enters-the-range-during-approachtarget) (by TaranDahl)" msgstr "" -"[å…许å•ä½åœ¨æŽ¥è¿‘目标期间若目标进入射程则立å³åœæ­¢](Fixed-or-Improved-Logics.md#stop-immediately-if-the-target-enters-the-range-during-approachtarget)(by TaranDahl)" +"[å…许å•ä½åœ¨æŽ¥è¿‘目标期间若目标进入射程则立å³åœæ­¢](Fixed-or-Improved-Logics.md#stop-immediately-" +"if-the-target-enters-the-range-during-approachtarget)(by TaranDahl)" msgid "" "[Allow the unit to keep pursuing the target during ApproachTarget](Fixed-" "or-Improved-Logics.md#keep-pursuing-the-target-during-approachtarget) (by" " TaranDahl)" msgstr "" -"[å…许å•ä½åœ¨æŽ¥è¿‘目标期间æŒç»­è¿½è¸ªç›®æ ‡](Fixed-or-Improved-Logics.md#keep-pursuing-the-target-during-approachtarget) (by TaranDahl)" +"[å…许å•ä½åœ¨æŽ¥è¿‘目标期间æŒç»­è¿½è¸ªç›®æ ‡](Fixed-or-Improved-Logics.md#keep-pursuing-the-target-" +"during-approachtarget) (by TaranDahl)" msgid "" "[Customize whether warhead can prevent crew escape from techno](New-or-" @@ -3321,6 +3329,12 @@ msgstr "" "`ProjectileRange` 大于 0 时现在会应用武器射程修正,除éžåœ¨æ­¦å™¨ä¸Šè®¾ç½® " "`ProjectileRange.ApplyModifiers` 为 false(by Starkku)" +msgid "Pre-release changes" +msgstr "预å‘布版本改动" + +msgid "0.5-alpha1" +msgstr "0.5-alpha1" + msgid "0.4.0.3" msgstr "0.4.0.3" @@ -6459,3 +6473,12 @@ msgstr "çŽ°åœ¨ä¾§è¾¹æ æ‹“展工具æ¡å¯ä»¥è¶…出侧边æ è¾¹ç•Œï¼ˆby Belonit msgid "Lifted stupidly small limit for tooltip character amount (by Belonit)" msgstr "解除了拓展工具æ¡å­—符数é‡å°å¾—愚蠢的上é™ï¼ˆby Belonit)" +#~ msgid "Migrating" +#~ msgstr "è¿ç§»" + +#~ msgid "From vanilla" +#~ msgstr "由原版" + +#~ msgid "Version TBD (develop branch nightly builds)" +#~ msgstr "待定版本(开å‘分支自动构建版本)" + diff --git a/docs/locale/zh_CN/LC_MESSAGES/index.po b/docs/locale/zh_CN/LC_MESSAGES/index.po index 069a258ced..434daa6554 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/index.po +++ b/docs/locale/zh_CN/LC_MESSAGES/index.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-25 14:06+0800\n" +"POT-Creation-Date: 2026-08-04 10:03+0800\n" "PO-Revision-Date: 2025-02-07 13:02+0800\n" "Last-Translator: \n" "Language: zh\n" @@ -181,21 +181,21 @@ msgstr "" "(Bug 最少的版本,但功能更新上éžå¸¸ç¼“慢)" msgid "" -"[Latest development branch builds](https://github.com/Phobos-" -"developers/Phobos/releases) (a bit less bug-free releases, devbuilds get " -"new features when they are finished)" +"[Latest pre-release builds](https://github.com/Phobos-" +"developers/Phobos/releases) (a bit less bug-free releases, pre-releases " +"get new features when they are finished)" msgstr "" -"[最新的开å‘分支版本](https://github.com/Phobos-developers/Phobos/releases) (Bug " -"ç›¸å¯¹è¾ƒå°‘çš„ç‰ˆæœ¬ï¼Œå¼€å‘æž„建会在新功能**完æˆåŽ**ç«‹å³æ›´æ–°ï¼‰" +"[最新的预å‘布版本](https://github.com/Phobos-developers/Phobos/releases) (Bug " +"相对较少的版本,预å‘布版本会在新功能 **完æˆåŽ** ç«‹å³æ›´æ–°ï¼‰" msgid "" "[Latest development branch nightly](https://nightly.link/Phobos-" "developers/Phobos/blob/develop/.github/workflows/nightly.yml) (added " -"unreleased features that will be in next devbuild)" +"unreleased features that will be in the next pre-release)" msgstr "" "[最新的自动构建版本](https://nightly.link/Phobos-" "developers/Phobos/blob/develop/.github/workflows/nightly.yml) " -"(添加了尚未å‘布的功能,这些功能将在下一个开å‘版本中推出)" +"(添加了尚未å‘布的功能,这些功能将在下一个预å‘布版本中推出)" msgid "" "Individual new feature nightly builds for testing can be found in [pull " @@ -204,6 +204,14 @@ msgstr "" "用于测试å•个新功能的自动构建版本å¯åœ¨ [拉å–请求](https://github.com/Phobos-" "developers/Phobos/pulls) 中找到" +msgid "" +"To learn how these build types relate to each other and how versioning " +"works, see the [release model and version lifecycle](docs/Project-" +"guidelines-and-policies.md#git-branching-model-version-lifecycle-and-" +"release-strategy)." +msgstr "" +"è¦äº†è§£è¿™äº›æž„建类型之间的关系以åŠç‰ˆæœ¬ç®¡ç†å¦‚何工作,请å‚阅 [å‘布模型与版本生命周期](Project-guidelines-and-policies.md#git-branching-model-version-lifecycle-and-release-strategy)。" + msgid "Note on nightly builds" msgstr "关于自动构建版本的说明" @@ -240,9 +248,13 @@ msgid "" "feature set, just drop all the files from the archive except " "documentation folder and `Syringe.exe` into your game folder." msgstr "" -"Phobos éœ€è¦ [SyringeEx](https://github.com/Phobos-developers/SyringeEx)(v0.1.0.2 åŠä»¥ä¸Šç‰ˆæœ¬ï¼‰ä»¥è¿è¡Œï¼Œè¿™æ˜¯ä¸€æ¬¾æ‰©å±•的开æºç‰ˆæœ¬ Syringeï¼›" -"游æˆä¼šåœ¨æ—§ç‰ˆ Syringe 下å¯åŠ¨æ—¶æ˜¾ç¤ºé”™è¯¯å¹¶é€€å‡ºã€‚Phobos å‘布包和自动构建版本已附带æ†ç»‘了 SyringeEx çš„ `Syringe.exe`;它也å¯ä»¥åœ¨ [SyringeEx å‘布页é¢](https://github.com/Phobos-" -"developers/SyringeEx/releases) å•ç‹¬ä¸‹è½½ã€‚å¼ºçƒˆå»ºè®®åŒæ—¶ **安装 [Ares](https://launchpad.net/ares/+download)** 以获得完整的 Phobos 功能体验,åªéœ€å°†åŽ‹ç¼©åŒ…ä¸­é™¤ Documentation 目录和 `Syringe.exe` ä¹‹å¤–çš„æ‰€æœ‰æ–‡ä»¶æ”¾å…¥æ¸¸æˆæ ¹ç›®å½•å³å¯ã€‚" +"Phobos éœ€è¦ [SyringeEx](https://github.com/Phobos-" +"developers/SyringeEx)(v0.1.0.2 åŠä»¥ä¸Šç‰ˆæœ¬ï¼‰ä»¥è¿è¡Œï¼Œè¿™æ˜¯ä¸€æ¬¾æ‰©å±•的开æºç‰ˆæœ¬ Syringe;游æˆä¼šåœ¨æ—§ç‰ˆ " +"Syringe 下å¯åŠ¨æ—¶æ˜¾ç¤ºé”™è¯¯å¹¶é€€å‡ºã€‚Phobos å‘布包和自动构建版本已附带æ†ç»‘了 SyringeEx çš„ " +"`Syringe.exe`;它也å¯ä»¥åœ¨ [SyringeEx å‘布页é¢](https://github.com/Phobos-" +"developers/SyringeEx/releases) å•ç‹¬ä¸‹è½½ã€‚å¼ºçƒˆå»ºè®®åŒæ—¶ **安装 " +"[Ares](https://launchpad.net/ares/+download)** 以获得完整的 Phobos " +"功能体验,åªéœ€å°†åŽ‹ç¼©åŒ…ä¸­é™¤ Documentation 目录和 `Syringe.exe` ä¹‹å¤–çš„æ‰€æœ‰æ–‡ä»¶æ”¾å…¥æ¸¸æˆæ ¹ç›®å½•å³å¯ã€‚" msgid "" "Obtain a Phobos \"package\" (official builds can be found on [releases " @@ -252,7 +264,8 @@ msgid "" msgstr "" "èŽ·å– Phobos 「软件包ã€ï¼ˆå¯åœ¨ [å‘布页é¢](https://github.com/Phobos-" "developers/Phobos/releases) " -"找到官方构建版;阅读下文了解如何获å–自动构建版本)。最终得到:`Phobos.dll`ã€`Phobos.pdb` ä»¥åŠæ†ç»‘çš„ SyringeEx 版 `Syringe.exe`。" +"找到官方构建版;阅读下文了解如何获å–自动构建版本)。最终得到:`Phobos.dll`ã€`Phobos.pdb` ä»¥åŠæ†ç»‘çš„ SyringeEx " +"版 `Syringe.exe`。" msgid "" "Place those files in the game folder (where your `gamemd.exe` is " @@ -271,6 +284,13 @@ msgstr "" "`Syringe.exe \"gamemd.exe\" [gamemd.exe çš„å‘½ä»¤è¡Œå‚æ•°]`(如果ä¸éœ€è¦å‚数,请çœç•¥ï¼‰ã€‚Ares 软件包中的 " "`RunAres.bat` 也有相åŒçš„åŠŸèƒ½ï¼Œå› æ­¤ä½ ä¹ŸåŒæ ·å¯ä»¥ä½¿ç”¨å®ƒæ¥å¯åŠ¨ã€‚" +msgid "" +"Be sure to read [migration and breaking changes](docs/Whats-New.md" +"#migration-breaking-changes) to know if you need to adjust something in " +"your mod after Phobos installation (or update)." +msgstr "" +"请务必阅读 [è¿ç§»ä¸Žç ´å性更改](Whats-New.md#migration-breaking-changes),以了解在安装(或更新)Phobos åŽæ˜¯å¦éœ€è¦å¯¹ Mod 进行调整。" + msgid "" "If you already use Ares in your mod, you just need to drop Phobos files " "mentioned above in your game folder, Syringe will load Phobos " @@ -390,12 +410,12 @@ msgid "" msgstr "" "本项目由 [@Belonit](https://github.com/Belonit)(Gluk-v48)和 " "[@Metadorius](https://github.com/Metadorius)(Kerbiter)于 2020 年创立,2021 " -"年首次å‘布稳定版。此åŽå®ƒå·²å‘展æˆä¸ºä¸€ä¸ªç”±ä¼—多贡献者和维护者组æˆçš„大型社区项目。" +"年首次å‘布稳定版本。此åŽå®ƒå·²å‘展æˆä¸ºä¸€ä¸ªç”±ä¼—多贡献者和维护者组æˆçš„大型社区项目。" msgid "" "Phobos has opened the external interfaces of some key components. If you " "are also developing your own engine extension and wish to use Phobos at " -"the same time, please check out [Interoperability](Interoperability.md)." +"the same time, please check out [Interoperability](docs/Interoperability.md)." msgstr "" "Phobos为一些关键组件打开了外部接å£ã€‚如果你也在开å‘è‡ªå·±çš„å¼•æ“Žæ‰©å±•å¹¶ä¸”å¸Œæœ›åŒæ—¶ä½¿ç”¨Phobos,请查阅 " "[互æ“作性](Interoperability.md)。" diff --git a/scripts/build.bat b/scripts/build.bat index ad24a6f110..cc6a27fad0 100644 --- a/scripts/build.bat +++ b/scripts/build.bat @@ -1,8 +1,10 @@ @if not defined _echo echo off -rem Builds a provided build config. +rem Builds a provided build config, optionally with a provided build type +rem (NIGHTLY or RELEASE - none means a plain local build; a pre-release is +rem a RELEASE build with PRERELEASE_SUFFIX set in src/Phobos.version.h). rem Ensure we're in correct directory. cd /D "%~dp0" -call run_msbuild /maxCpuCount /consoleloggerparameters:NoSummary /property:Configuration=%1 +call run_msbuild /maxCpuCount /consoleloggerparameters:NoSummary /property:Configuration=%1 /property:BuildType=%2 diff --git a/scripts/build_debug.bat b/scripts/build_debug.bat index 5502ae892a..18bc79e806 100644 --- a/scripts/build_debug.bat +++ b/scripts/build_debug.bat @@ -1,6 +1,6 @@ @if not defined _echo echo off -rem Builds Phobos DevBuild. +rem Builds Phobos Debug. rem Ensure we're in correct directory. cd /D "%~dp0" diff --git a/scripts/build_devbuild.bat b/scripts/build_devbuild.bat deleted file mode 100644 index 0cc72323e2..0000000000 --- a/scripts/build_devbuild.bat +++ /dev/null @@ -1,8 +0,0 @@ -@if not defined _echo echo off - -rem Builds Phobos DevBuild. - -rem Ensure we're in correct directory. -cd /D "%~dp0" - -call build DevBuild diff --git a/scripts/build_docs_locale.bat b/scripts/build_docs_locale.bat index d8ca69b16e..693c5c74d0 100644 --- a/scripts/build_docs_locale.bat +++ b/scripts/build_docs_locale.bat @@ -6,5 +6,5 @@ rem Ensure we're in correct directory. cd /D "%~dp0" cd ..\docs -sphinx-build -b gettext ./ ./locale -sphinx-intl update -p ./locale -l zh_CN +sphinx-build -b gettext . _build/gettext +sphinx-intl update -p _build/gettext -l zh_CN diff --git a/scripts/clean.bat b/scripts/clean.bat index 16d98dfa24..07ebbbfefc 100644 --- a/scripts/clean.bat +++ b/scripts/clean.bat @@ -7,5 +7,4 @@ cd /D "%~dp0" cd .. if exist Debug\ rmdir /S /Q Debug\ -if exist DevBuild\ rmdir /S /Q DevBuild\ if exist Release\ rmdir /S /Q Release\ diff --git a/scripts/extract_changelog.ps1 b/scripts/extract_changelog.ps1 new file mode 100644 index 0000000000..800562095e --- /dev/null +++ b/scripts/extract_changelog.ps1 @@ -0,0 +1,290 @@ +<# +.SYNOPSIS + Extracts the release notes for a tag out of the What's New document. + +.DESCRIPTION + Whats-New.md is laid out as "type of change -> version": each top level section + (`## Breaking changes`, `## Changelog`) holds one subsection per version. A release + is about a single version, so this script parses the document into a heading tree, + picks every subsection matching the released version wherever it sits in the tree, + and re-emits them as "version -> type of change" - the version is the release + itself, so the type of change becomes the top level heading. + + Markup that only means something to Sphinx is normalized on the way out, so the + result can be used as a release body as is: `{dropdown}` directives are unwrapped, + admonitions become GitHub alerts, directive options are dropped and relative + documentation links are resolved against -LinkBase. +#> +param( + [Parameter(Mandatory = $true)] + [string]$Tag, + + [Parameter(Mandatory = $true)] + [string]$WhatsNewPath, + + [Parameter(Mandatory = $true)] + [string]$OutputPath, + + # Base URL to resolve relative documentation links against, e.g. + # https://github.com/Phobos-developers/Phobos/blob/v0.5/docs + # When empty the links are emitted unchanged, which only works within the docs themselves. + [string]$LinkBase = '' +) + +$ErrorActionPreference = 'Stop' + +# MyST admonitions that map onto GitHub alerts. Anything else is unwrapped silently. +$AlertKinds = @{ + 'note' = 'NOTE' + 'seealso' = 'NOTE' + 'admonition' = 'NOTE' + 'tip' = 'TIP' + 'hint' = 'TIP' + 'important' = 'IMPORTANT' + 'attention' = 'IMPORTANT' + 'warning' = 'WARNING' + 'caution' = 'CAUTION' + 'danger' = 'CAUTION' + 'error' = 'CAUTION' +} + +$linkPrefix = $LinkBase.TrimEnd('/') + +function New-Section([int]$Level, [string]$Title, $Parent) { + [pscustomobject]@{ + Level = $Level + Title = $Title + Parent = $Parent + Lines = [System.Collections.Generic.List[string]]::new() + Children = [System.Collections.Generic.List[object]]::new() + Skip = $false + } +} + +# Returns the fence descriptor for a line that opens or closes a fenced block, else $null. +# Backtick, tilde and MyST colon fences are recognized, of any length at or above three, which +# allows nesting directives by increasing the run length (e.g. `:::{note}` inside `:::{hint}`). +function Get-Fence([string]$Line) { + if ($Line -match '^ {0,3}(?`{3,}|~{3,}|:{3,})[ \t]*(?.*?)[ \t]*$') { + return [pscustomobject]@{ + Char = $Matches.fence.Substring(0, 1) + Len = $Matches.fence.Length + Info = $Matches.info + } + } + return $null +} + +# A fence closes another one when it uses the same character, is at least as long +# and carries no info string. +function Test-FenceCloses($Fence, $Opener) { + return ($Fence.Char -eq $Opener.Char) -and ($Fence.Len -ge $Opener.Len) -and ($Fence.Info -eq '') +} + +# Relative links into the docs are meaningless outside of them, so anchor them to -LinkBase. +function Convert-Link([string]$Text) { + if (-not $linkPrefix) { return $Text } + + $evaluator = [System.Text.RegularExpressions.MatchEvaluator] { + param($m) + '](' + $linkPrefix + '/' + $m.Groups['path'].Value + $m.Groups['frag'].Value + ')' + } + return [regex]::Replace($Text, '\]\((?!\w+:|[#/])(?[^)\s#]+\.md)(?#[^)\s]*)?\)', $evaluator) +} + +# ---- Parse the document into a tree of sections carrying their own contents ---- + +function Read-SectionTree([string[]]$Lines) { + $root = New-Section 0 '' $null + $current = $root + + # Fenced code blocks are opaque - their contents are never markdown. + # MyST directive fences (```{dropdown} etc.) are transparent - they wrap markdown, + # headings included, so they only affect how the contents are emitted. + $code = $null + $directives = [System.Collections.Generic.List[object]]::new() + $inOptions = $false + + foreach ($line in $Lines) { + + if ($code) { + $current.Lines.Add($line) + $fence = Get-Fence $line + if ($fence -and (Test-FenceCloses $fence $code)) { $code = $null } + continue + } + + $fence = Get-Fence $line + if ($fence) { + # Innermost first: a bare fence closes the directive it is nested in. + if ($directives.Count -gt 0 -and (Test-FenceCloses $fence $directives[$directives.Count - 1])) { + $directives.RemoveAt($directives.Count - 1) + $inOptions = $false + continue + } + + if ($fence.Info.StartsWith('{')) { + $kind = ($fence.Info -replace '^\{([^}]*)\}.*$', '$1').Trim().ToLowerInvariant() + $alert = $null + if ($AlertKinds.ContainsKey($kind)) { + $alert = $AlertKinds[$kind] + $current.Lines.Add('') + $current.Lines.Add("> [!$alert]") + } + $directives.Add([pscustomobject]@{ Char = $fence.Char; Len = $fence.Len; Kind = $kind; Alert = $alert }) + $inOptions = $true + continue + } + + $code = $fence + $current.Lines.Add($line) + continue + } + + # `:open:` and friends configure the directive, they are not contents. + if ($inOptions) { + if ($line -match '^\s*:[A-Za-z][A-Za-z0-9_-]*:') { continue } + $inOptions = $false + } + + if ($line -match '^(?#{1,6})\s+(?.*?)\s*#*\s*$') { + $level = $Matches.hashes.Length + while ($current.Level -ge $level) { $current = $current.Parent } + + $node = New-Section $level (Convert-Link $Matches.title) $current + $current.Children.Add($node) + $current = $node + continue + } + + $text = Convert-Link $line + + # Contents of an admonition have to be quoted for the alert to hold them. + $alert = $null + for ($i = $directives.Count - 1; $i -ge 0; $i--) { + if ($directives[$i].Alert) { $alert = $directives[$i].Alert; break } + } + if ($alert) { $text = if ($text.Trim() -eq '') { '>' } else { "> $text" } } + + $current.Lines.Add($text) + } + + return $root +} + +function Get-AllSections($Node) { + foreach ($child in $Node.Children) { + $child + Get-AllSections $child + } +} + +# The version a section documents, or $null when it documents no particular version. +# The whole title has to be the version, so that a section like "3 new trajectories" is contents. +function Get-SectionVersion([string]$Title) { + if ($Title -match '^\s*[vV]?(?<version>\d+(\.\d+)+(-[0-9A-Za-z.]+)?)(\s+\(.*\))?\s*$') { return $Matches.version } + return $null +} + +function Test-HasContents($Node) { + return ($Node.Children.Count -gt 0) -or (@($Node.Lines | Where-Object { $_.Trim() }).Count -gt 0) +} + +# ---- Render a matched section as "type of change -> contents" ---- + +function Add-SectionContents($Node, [int]$Shift, $Sink) { + foreach ($line in $Node.Lines) { $Sink.Add($line) } + + foreach ($child in $Node.Children) { + if ($child.Skip) { continue } + + $level = [Math]::Min(6, [Math]::Max(1, $child.Level + $Shift)) + $Sink.Add('') + $Sink.Add(('#' * $level) + ' ' + $child.Title) + Add-SectionContents $child $Shift $Sink + } +} + +# Pre-release notes live in version-numbered subsections of the section they lead up to (e.g. +# `#### 0.5-alpha2` under `### 0.5`). A release of the base version never carries them, so those +# subsections are always left out of the base sections. A pre-release that documents its own +# changes is matched and rendered on its own instead (see the main flow), so it never reaches +# this point as a base section. +function Set-BuildSectionVisibility($Section) { + foreach ($child in $Section.Children) { + if (Get-SectionVersion $child.Title) { $child.Skip = $true } + } +} + +# The path from the top level section down to the matched one names the type of change. +# Version-numbered sections are not a kind of change: the base version a pre-release leads up to +# (e.g. the `### 0.5` holding a `#### 0.5-alpha2`) is left out of the path. +function Get-SectionKind($Node) { + $chain = @() + $parent = $Node.Parent + while ($parent -and $parent.Level -ge 2) { + if (-not (Get-SectionVersion $parent.Title)) { + $chain = , $parent.Title + $chain + } + $parent = $parent.Parent + } + return ($chain -join ' / ') +} + +# ---- Main ---- + +if (-not (Test-Path -LiteralPath $WhatsNewPath)) { + throw "File not found: $WhatsNewPath" +} + +$content = (Get-Content -LiteralPath $WhatsNewPath -Raw -Encoding utf8) -replace "`r`n", "`n" +$root = Read-SectionTree ($content -split "`n") +$sections = @(Get-AllSections $root) + +$version = $Tag -replace '^[vV]', '' +$baseVersion = $version -replace '-.*$', '' + +$isPreRelease = $baseVersion -ne $version + +# A pre-release is documented as a version-numbered subsection of the version it leads up to. +# When that subsection carries its own notes the pre-release is released as just those notes; an +# empty (or missing) heading falls back to the base version it leads up to. +$matched = @() +if ($isPreRelease) { + $matched = @($sections | Where-Object { (Get-SectionVersion $_.Title) -eq $version -and (Test-HasContents $_) }) +} + +if (-not $matched) { + $matched = @($sections | Where-Object { (Get-SectionVersion $_.Title) -eq $baseVersion }) +} + +if (-not $matched) { + $known = @($sections | ForEach-Object { Get-SectionVersion $_.Title } | Where-Object { $_ } | Select-Object -Unique) -join ', ' + throw "No sections for version '$version' in $WhatsNewPath. Documented versions: $known" +} + +$out = [System.Collections.Generic.List[string]]::new() +foreach ($section in $matched) { + $kind = Get-SectionKind $section + if ($kind) { + $out.Add('') + $out.Add("## $kind") + } + Set-BuildSectionVisibility $section + + # The matched section's own children start right below the type of change heading. + Add-SectionContents $section (2 - $section.Level) $out +} + +$text = ($out -join "`n") -replace '(?m)[ \t]+$', '' +$text = ($text -replace "\n{3,}", "`n`n").Trim() + +if (-not $text) { + throw "Extracted release notes for version '$version' are empty" +} + +$outPath = if ([System.IO.Path]::IsPathRooted($OutputPath)) { $OutputPath } else { Join-Path (Get-Location).Path $OutputPath } +[System.IO.File]::WriteAllText($outPath, $text + "`n", (New-Object System.Text.UTF8Encoding($false))) + +$kinds = @($matched | ForEach-Object { Get-SectionKind $_ }) -join ', ' +Write-Host "Extracted release notes for version '$version' ($kinds) to '$OutputPath'" diff --git a/src/Misc/ExceptionHandler.Report.cpp b/src/Misc/ExceptionHandler.Report.cpp index 1ce2d0397f..112de4ca78 100644 --- a/src/Misc/ExceptionHandler.Report.cpp +++ b/src/Misc/ExceptionHandler.Report.cpp @@ -468,7 +468,10 @@ namespace ExceptionHandler::Append("Phobos version: " PRODUCT_VERSION "\r\n"); #ifdef STR_GIT_COMMIT - ExceptionHandler::Append("Git: " STR_GIT_COMMIT " @ " STR_GIT_BRANCH "\r\n"); + ExceptionHandler::Append("Git commit: " STR_GIT_COMMIT "\r\n"); +#endif +#ifdef STR_GIT_REF + ExceptionHandler::Append("Git ref: " STR_GIT_REF "\r\n"); #endif ExceptionHandler::Append("Phobos base address: 0x%08X\r\n", AresHelper::PhobosBaseAddress); diff --git a/src/Phobos.cpp b/src/Phobos.cpp index 0586921434..2ba8f626e1 100644 --- a/src/Phobos.cpp +++ b/src/Phobos.cpp @@ -11,7 +11,7 @@ #include "Utilities/GeneralUtils.h" #include "Utilities/Parser.h" -#ifndef IS_RELEASE_VER +#ifdef TESTING_BUILD bool HideWarning = false; #endif @@ -31,12 +31,12 @@ bool Phobos::Optimizations::DisableRadDamageOnBuildings = true; bool Phobos::Optimizations::DisableSyncLogging = false; bool Phobos::Optimizations::DisableLaserTracking = true; -#ifdef STR_GIT_COMMIT -const wchar_t* Phobos::VersionDescription = L"Phobos nightly build (" STR_GIT_COMMIT L" @ " STR_GIT_BRANCH L"). DO NOT SHIP IN MODS!"; -#elif !defined(IS_RELEASE_VER) -const wchar_t* Phobos::VersionDescription = L"Phobos development build #" _STR(BUILD_NUMBER) L". Please test the build before shipping."; -#else -//const wchar_t* Phobos::VersionDescription = L"Phobos release build v" FILE_VERSION_STR L"."; +// The leading L"" widens the narrow metadata literals it is concatenated with, so that the +// name and the version are taken from Phobos.version.h rather than spelled out again. +#ifdef NIGHTLY +const wchar_t* Phobos::VersionDescription = L"" PRODUCT_NAME " " PRODUCT_VERSION L". DO NOT SHIP IN MODS!"; +#elif defined(TESTING_BUILD) +const wchar_t* Phobos::VersionDescription = L"" PRODUCT_NAME " " PRODUCT_VERSION L". Please test the build before shipping."; #endif @@ -59,8 +59,13 @@ void Phobos::CmdLineParse(char** ppArgs, int nNumArgs) { Phobos::AppIconPath = ppArgs[++i]; } -#ifndef IS_RELEASE_VER - if (_stricmp(pArg, "-b=" _STR(BUILD_NUMBER)) == 0) +#ifdef TESTING_BUILD + // Suppresses the "please test this build" warning drawn over the game screen. + // The exact version of this very build has to be spelled out (it is printed in + // the warning itself and in the release title), so that the switch can't be set + // once and then silently carried over into a mod release with a newer build. + if (_stricmp(pArg, "-HideVersionWarning=" FILE_VERSION_STR) == 0 + || _stricmp(pArg, "-HideVersionWarning=v" FILE_VERSION_STR) == 0) // as shown in the warning { HideWarning = true; } @@ -131,6 +136,12 @@ void Phobos::CmdLineParse(char** ppArgs, int nNumArgs) ExceptionHandler::Init(); Debug::Log("Initialized version: " PRODUCT_VERSION "\n"); +#ifdef STR_GIT_COMMIT + Debug::Log("Git commit: " STR_GIT_COMMIT "\n"); +#endif +#ifdef STR_GIT_REF + Debug::Log("Git ref: " STR_GIT_REF "\n"); +#endif Debug::Log("ExceptionHandler is %s\n", dontSetExceptionHandler ? "not present" : "present"); } @@ -303,10 +314,10 @@ DEFINE_HOOK(0x4F4583, GScreenClass_DrawText, 0x6) const int marginX = Phobos::Config::MessageDisplayInCenter ? 28 : 10; int coordY = 0; -#ifndef IS_RELEASE_VER -#ifndef STR_GIT_COMMIT +#ifdef TESTING_BUILD +#ifndef NIGHTLY if (!HideWarning) -#endif // !STR_GIT_COMMIT +#endif // !NIGHTLY { auto wanted = Drawing::GetTextDimensions(Phobos::VersionDescription, { 0, 0 }, 0, 2, 0); @@ -324,7 +335,7 @@ DEFINE_HOOK(0x4F4583, GScreenClass_DrawText, 0x6) // add margin for next text coordY = rect.Height; } -#endif // !IS_RELEASE_VER +#endif // !RELEASE if (!Phobos::Config::ShowGameTime || HouseClass::CurrentPlayer->IsObserver()) // already has a timer return 0; diff --git a/src/Phobos.version.h b/src/Phobos.version.h index abd7d3237b..32a63432e5 100644 --- a/src/Phobos.version.h +++ b/src/Phobos.version.h @@ -1,53 +1,113 @@ #ifndef VERSION_H #define VERSION_H -#define _WSTR(x) _WSTR_(x) -#define _WSTR_(x) L ## #x #define _STR(x) _STR_(x) #define _STR_(x) #x -#pragma region Release build version numbering +#pragma region Version numbering // Indicates project maturity and completeness #define VERSION_MAJOR 0 // Indicates major changes and significant additions, like new logics -#define VERSION_MINOR 3 +#define VERSION_MINOR 5 // Indicates minor changes, like vanilla bugfixes, unhardcodings or hacks #define VERSION_REVISION 0 // Indicates Phobos-related bugfixes only -#define VERSION_PATCH 1 +#define VERSION_PATCH 0 + +// The current pre-release being prepared, spelled out in full rather than as a number, so that +// it can be anything semantic versioning allows - "alpha5", "beta1", "rc3", etc. Its presence is +// what makes a release build a pre-release; comment it out for a stable release. +#define PRERELEASE_SUFFIX "alpha1" #pragma endregion -// Build number. Incremented on each released build. -#define BUILD_NUMBER 48 - -// Nightly defines GIT_COMMIT and GIT_BRANCH in GH Actions - -#ifdef IS_RELEASE_VER // Release build metadata - #define SAVEGAME_ID ((VERSION_MAJOR << 24) | (VERSION_MINOR << 16) | (VERSION_REVISION << 8) | VERSION_PATCH) - #define FILE_DESCRIPTION "Phobos, Ares-compatible YR engine extension" - #define FILE_VERSION_STR _STR(VERSION_MAJOR) "." _STR(VERSION_MINOR) "." _STR(VERSION_REVISION) "." _STR(VERSION_PATCH) - #define FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_PATCH - #define PRODUCT_VERSION "Release Build " FILE_VERSION_STR -#elif defined(GIT_COMMIT) // Nightly devbuild metadata - #define STR_GIT_COMMIT _STR(GIT_COMMIT) - #define STR_GIT_BRANCH _STR(GIT_BRANCH) - - #define SAVEGAME_ID ((BUILD_NUMBER << 24) | (BUILD_NUMBER << 12) | (BUILD_NUMBER)) - #define FILE_DESCRIPTION "Unstable nightly devbuild of Phobos engine extension" - #define FILE_VERSION_STR "Commit " STR_GIT_COMMIT - #define FILE_VERSION 0 - #define PRODUCT_VERSION "Nightly Build " STR_GIT_COMMIT " @ " STR_GIT_BRANCH -#else // Regular devbuild metadata - #define SAVEGAME_ID ((BUILD_NUMBER << 24) | (BUILD_NUMBER << 12) | (BUILD_NUMBER)) - #define FILE_DESCRIPTION "Development build of Phobos engine extension" - #define FILE_VERSION_STR "Build #" _STR(BUILD_NUMBER) - #define FILE_VERSION 0,0,0,BUILD_NUMBER - #define PRODUCT_VERSION "Development Build #" _STR(BUILD_NUMBER) +#define VERSION_LONG_STR _STR(VERSION_MAJOR) "." _STR(VERSION_MINOR) "." _STR(VERSION_REVISION) "." _STR(VERSION_PATCH) + +// Savegame compatibility is tied to the version with the patch number left out: patch releases +// only carry Phobos bugfixes and stay compatible with each other. Nightlies and pre-releases of +// a version share the ID with the stable release they lead up to. +#define SAVEGAME_ID ((VERSION_MAJOR << 24) | (VERSION_MINOR << 16) | (VERSION_REVISION << 8)) + +// Git info (commit / ref / dirty), generated by Phobos.props' ComputeGitInfo target into $(IntDir)Generated. +#include "Phobos.Git.h" + +#pragma region Build metadata + +// NIGHTLY / RELEASE come from the BuildType compiler option - used by GH Actions as well - and +// none of them being set means a local build. A pre-release is a RELEASE build that still has +// the PRERELEASE_SUFFIX defined above. STR_GIT_COMMIT / STR_GIT_REF / STR_GIT_DIRTY are +// defined by the generated Phobos.Git.h whenever Git info is available (derived from the +// repository at build time as the full ref, e.g. refs/heads/develop). Pre-releases and +// releases embed +// that info as auxiliary metadata (crash reports, logs, file resources) while keeping a clean +// version string; nightly and local builds carry the Git info in the version itself and differ +// only in the build type name. Everything below is derived from those inputs so that the product +// name, the version and the build type are each spelled out once and stay in sync everywhere they +// surface. + +#define PRODUCT_NAME "Phobos" +#define PRODUCT_FILE_NAME PRODUCT_NAME ".dll" +#define PRODUCT_SUMMARY "Ares-compatible YR engine extension" + +// The "v" prefix is a human-facing convention for version numbers and is only ever applied in +// front of a numeric version - never in front of a ref or commit. It is applied exactly once +// here in PRODUCT_VERSION and no other macro in this header prepends it. +#define VERSION_PREFIX "v" + +// STR_GIT_COMMIT / STR_GIT_REF are defined by the generated Phobos.Git.h when Git info is +// available; STR_GIT_DIRTY falls back to empty when the working tree is clean. +#ifndef STR_GIT_DIRTY + #define STR_GIT_DIRTY "" #endif +// The numeric file version is the full four-part version for every build type. +#define FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_PATCH + +#if defined(RELEASE) + // A RELEASE build whose PRERELEASE_SUFFIX is still defined is a pre-release; + // without it, a stable release. + #ifdef PRERELEASE_SUFFIX + #define BUILD_TYPE_NAME "pre-release build" + #define FILE_VERSION_STR VERSION_LONG_STR "-" PRERELEASE_SUFFIX + #define PRODUCT_VERSION VERSION_PREFIX FILE_VERSION_STR + #else + #define BUILD_TYPE_NAME "release build" + #define FILE_VERSION_STR VERSION_LONG_STR + #define PRODUCT_VERSION VERSION_PREFIX FILE_VERSION_STR + #endif +#else + // Nightly (CI) and local builds are one mostly unified build differing in warning and in + // build type name; the version string carries the Git commit and ref when available. + #ifdef NIGHTLY + #define BUILD_TYPE_NAME "nightly build" + #else + #define BUILD_TYPE_NAME "local build" + #endif + #ifdef STR_GIT_COMMIT + #define FILE_VERSION_STR VERSION_LONG_STR "+" STR_GIT_COMMIT STR_GIT_DIRTY + #else + #define FILE_VERSION_STR VERSION_LONG_STR + #endif + #ifdef STR_GIT_REF + #define PRODUCT_VERSION VERSION_PREFIX FILE_VERSION_STR " @ " STR_GIT_REF + #else + #define PRODUCT_VERSION VERSION_PREFIX FILE_VERSION_STR + #endif +#endif + +// A testing build carries the on-screen "please test the build before shipping" warning and the +// SpecialBuild file flags: everything that is not a stable release - local dev, nightly and +// pre-release builds. A pre-release is a RELEASE build that still has PRERELEASE_SUFFIX defined. +#if !defined(RELEASE) || defined(PRERELEASE_SUFFIX) + #define TESTING_BUILD +#endif + +#define FILE_DESCRIPTION PRODUCT_NAME ", " PRODUCT_SUMMARY " (" BUILD_TYPE_NAME ")" + +#pragma endregion + #endif // VERSION_H diff --git a/src/version.rc b/src/version.rc index 394625a99e..166256e7b9 100644 --- a/src/version.rc +++ b/src/version.rc @@ -1,4 +1,4 @@ -#include <windows.h> +#include <windows.h> #include "Phobos.version.h" @@ -9,7 +9,7 @@ ID_VERSION VERSIONINFO FILEVERSION FILE_VERSION PRODUCTVERSION FILE_VERSION FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifndef IS_RELEASE_VER +#ifdef TESTING_BUILD FILEFLAGS VS_FF_PRERELEASE | VS_FF_SPECIALBUILD #endif @@ -20,16 +20,16 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "ProductName", "Phobos\0" + VALUE "ProductName", PRODUCT_NAME "\0" VALUE "CompanyName", "The Phobos Contributors\0" - VALUE "LegalCopyright", "© The Phobos Contributors 2020-2026\0" + VALUE "LegalCopyright", "© The Phobos Contributors 2020-2026\0" VALUE "FileDescription", FILE_DESCRIPTION "\0" VALUE "FileVersion", FILE_VERSION_STR "\0" VALUE "ProductVersion", PRODUCT_VERSION "\0" - VALUE "InternalName", "Phobos.dll\0" - VALUE "OriginalFilename", "Phobos.dll\0" + VALUE "InternalName", PRODUCT_FILE_NAME "\0" + VALUE "OriginalFilename", PRODUCT_FILE_NAME "\0" -#ifndef IS_RELEASE_VER +#ifdef TESTING_BUILD VALUE "SpecialBuild", "Testing version. Use at your own risk.\0" #endif END @@ -41,8 +41,8 @@ BEGIN #ifdef STR_GIT_COMMIT VALUE "GitCommit", STR_GIT_COMMIT #endif -#ifdef STR_GIT_BRANCH - VALUE "GitBranch", STR_GIT_BRANCH +#ifdef STR_GIT_REF + VALUE "GitRef", STR_GIT_REF #endif END END