From 89cd39f63d251faccdb9b7e73d042039b7f306ca Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Fri, 8 Sep 2023 16:03:11 +0800 Subject: [PATCH 01/22] Initialize 1.20 --- .github/workflows/packer.yml | 256 ++++++------------ .github/workflows/pr-packer.yml | 184 ++++--------- config/packer/1.20-fabric.json | 37 +++ config/packer/1.20.json | 37 +++ projects/1.20-fabric/README.md | 59 ++++ .../minecraft/minecraft/packer-policy.json | 4 + projects/1.20/README.md | 59 ++++ .../minecraft/minecraft/font/default.json | 20 ++ .../font/include/cjk-punctuations.json | 29 ++ .../minecraft/minecraft/font/uniform.json | 16 ++ .../1.20/assets/minecraft/minecraft/readme.md | 24 ++ .../minecraft/textures/font/2em-dash.png | Bin 0 -> 2829 bytes .../textures/font/cjk_punctuations.png | Bin 0 -> 3275 bytes .../minecraft/textures/font/ellipsis.png | Bin 0 -> 2843 bytes src/Uploader/Program.cs | 10 +- 15 files changed, 434 insertions(+), 301 deletions(-) create mode 100644 config/packer/1.20-fabric.json create mode 100644 config/packer/1.20.json create mode 100644 projects/1.20-fabric/README.md create mode 100644 projects/1.20-fabric/assets/minecraft/minecraft/packer-policy.json create mode 100644 projects/1.20/README.md create mode 100644 projects/1.20/assets/minecraft/minecraft/font/default.json create mode 100644 projects/1.20/assets/minecraft/minecraft/font/include/cjk-punctuations.json create mode 100644 projects/1.20/assets/minecraft/minecraft/font/uniform.json create mode 100644 projects/1.20/assets/minecraft/minecraft/readme.md create mode 100644 projects/1.20/assets/minecraft/minecraft/textures/font/2em-dash.png create mode 100644 projects/1.20/assets/minecraft/minecraft/textures/font/cjk_punctuations.png create mode 100644 projects/1.20/assets/minecraft/minecraft/textures/font/ellipsis.png diff --git a/.github/workflows/packer.yml b/.github/workflows/packer.yml index 870327a997ce..0856534b1e2a 100644 --- a/.github/workflows/packer.yml +++ b/.github/workflows/packer.yml @@ -5,197 +5,119 @@ on: push: branches: [main] paths: - - 'config/packer.json' - - 'config/fontmap.txt' + - 'src/**' + - 'config/packer/**' - 'projects/**' + + jobs: build: + if: github.repository == 'CFPAOrg/Minecraft-Mod-Language-Package' + name: Build / Cache Packer and Uploader runs-on: windows-latest steps: - uses: actions/checkout@v2 with: - fetch-depth: 20 ref: main - - name: Check changed path on 1.12 - uses: MarceloPrado/has-changed-path@v1.0 - id: changed-1122 - with: - paths: projects/1.12.2 - - - name: Check changed path on 1.16 - uses: MarceloPrado/has-changed-path@v1.0 - id: changed-116 - with: - paths: projects/1.16 - - - name: Check changed path on 1.16 fabric - uses: MarceloPrado/has-changed-path@v1.0 - id: changed-116-fabric - with: - paths: projects/1.16-fabric - - - name: Check changed path on 1.18 - uses: MarceloPrado/has-changed-path@v1.0 - id: changed-118 - with: - paths: projects/1.18 - - - name: Check changed path on 1.18 fabric - uses: MarceloPrado/has-changed-path@v1.0 - id: changed-118-fabric + # 缓存程序。一方面,在不同job之间需要这么做;另一方面,大约可以改善运行时间? + # actions/cache的逻辑会在job末尾缓存打包程序;如果不命中,就自行构造程序。 + - name: Cache Packer + id: cache-packer + uses: actions/cache@v3 with: - paths: projects/1.18-fabric + key: ${{ runner.os }}-${{ hashFiles('source/Pakcer/**') }} + path: Packer.exe - - name: Check changed path on 1.19 - uses: MarceloPrado/has-changed-path@v1.0 - id: changed-119 + - name: Cache Uploader + id: cache-uploader + uses: actions/cache@v3 with: - paths: projects/1.19 - - # - name: Check changed path on 1.19 fabric - # uses: MarceloPrado/has-changed-path@v1.0 - # id: changed-119-fabric - # with: - # paths: projects/1.19-fabric - - - name: Build Packer + key: ${{ runner.os }}-${{ hashFiles('source/Uploader/**') }} + path: Uploader.exe + + # 构造程序 + - name: Build Packer if not cached + if: steps.cache-packer.outputs.cache_hit != 'true' run: dotnet publish .\src\Packer\Packer.csproj -o ./ -r win-x64 -p:PublishSingleFile=true - - name: Run Packer for 1.12.2 - run: ./Packer --version="1.12.2" - if: steps.changed-1122.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Run Packer for 1.16 - run: ./Packer --version="1.16" - if: steps.changed-116.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Run Packer for 1.16-fabric - run: ./Packer --version="1.16-fabric" - if: steps.changed-116-fabric.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Run Packer for 1.18 - run: ./Packer --version="1.18" - if: steps.changed-118.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Run Packer for 1.18-fabric - run: ./Packer --version="1.18-fabric" - if: steps.changed-118-fabric.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Run Packer for 1.19 - run: ./Packer --version="1.19" - if: steps.changed-119.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - # - name: Run Packer for 1.19-fabric - # run: ./Packer --version="1.19-fabric" - # if: steps.changed-119-fabric.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Create timestamp - id: create_timestamp - run: echo "::set-output name=timestamp::$(date '+%Y%m%d%H%M%s')" - shell: bash + - name: Build Uploader if not cached + if: steps.cache-uploader.outputs.cache_hit != 'true' + run: dotnet publish .\src\Uploader\Uploader.csproj -o ./ -r win-x64 -p:PublishSingeFile=true - # Create the release: https://github.com/actions/create-release - - name: Create release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: Snapshot-${{ steps.create_timestamp.outputs.timestamp }} - release_name: 汉化资源包-Snapshot-${{ steps.create_timestamp.outputs.timestamp }} - draft: false - prerelease: false - # Upload release asset: https://github.com/actions/upload-release-asset - - name: Update release asset for 1.12 - id: upload-release-asset1 - if: steps.changed-1122.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + pack: + if: github.repository == 'CFPAOrg/Minecraft-Mod-Language-Package' + name: Pack Resources and Upload Artifacts + needs: build # 显然,需要存在缓存/已经构造,才能打包。 + strategy: + matrix: + # 支持版本列表。将对这里的每个版本判断,按需打包。 + # 如需添加新版本,在这里添加即可。 + version: ["1.12.2", "1.16", "1.16-fabric", "1.18", "1.18-fabric", "1.19", "1.20", "1.20-fabric"] + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: Minecraft-Mod-Language-Package-1.12.2.zip - asset_name: Minecraft-Mod-Language-Package-1.12.2.zip - asset_content_type: application/zip - - - name: Update release asset for 1.16 - id: upload-release-asset2 - if: steps.changed-116.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 20 + ref: main + + # 由于Github的限制,这里需要重新拉取打包程序。 + - name: Restore Packer + id: cache-restore + uses: actions/cache/restore@v3 with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: Minecraft-Mod-Language-Package-1.16.zip - asset_name: Minecraft-Mod-Language-Package-1.16.zip - asset_content_type: application/zip + key: ${{ runner.os }}-${{ hashFiles('source/Pakcer/**') }} + path: Packer.exe + fail-on-cache-miss: true # 前一步理应构造过的。如果不命中,肯定有问题,不如直接挂掉。 - - - name: Update release asset for 1.16-fabric - id: upload-release-asset3 - if: steps.changed-116-fabric.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Check changed path on ${{ matrix.version }} + uses: MarceloPrado/has-changed-path@v1.0 + id: check-changes with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: Minecraft-Mod-Language-Package-1.16-fabric.zip - asset_name: Minecraft-Mod-Language-Package-1.16-fabric.zip - asset_content_type: application/zip - - - name: Update release asset for 1.18 - id: upload-release-asset4 - if: steps.changed-118.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # 判断位置:该版本文件、该版本配置、代码 + paths: | + projects/${{ matrix.version }} + config/packer/${{ matrix.version }}.json + src/** + + - name: Run Packer for ${{ matrix.version }} + run: ./Packer --version="${{ matrix.version }}" + # 运行逻辑:内容有更改 或 手动运行 + if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' + + # 上传内容:每个版本一个压缩包,包含了资源包和md5校验文件 + - name: Upload Artifact for ${{ matrix.version }} + uses: actions/upload-artifact@v3.0.0 with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: Minecraft-Mod-Language-Package-1.18.zip - asset_name: Minecraft-Mod-Language-Package-1.18.zip - asset_content_type: application/zip - - - name: Update release asset for 1.18-fabric - id: upload-release-asset5 - if: steps.changed-118-fabric.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + name: Minecraft-Mod-Language-Package-${{ matrix.version }} + path: | + Minecraft-Mod-Language-Package-${{ matrix.version }}.zip + ${{matrix.version}}.md5 + if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' + + + upload: + if: github.repository == 'CFPAOrg/Minecraft-Mod-Language-Package' + name: Upload Resource Packs to Remote Server + needs: pack # 显然,需要打包完成后才可以上传给分发服务器 + runs-on: windows-latest + steps: + # 由于Github的限制,这里需要重新拉取打包程序。 + - name: Restore Packer + id: cache-restore + uses: actions/cache/restore@v3 with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: Minecraft-Mod-Language-Package-1.18-fabric.zip - asset_name: Minecraft-Mod-Language-Package-1.18-fabric.zip - asset_content_type: application/zip - - - name: Update release asset for 1.19 - id: upload-release-asset6 - if: steps.changed-119.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + key: ${{ runner.os }}-${{ hashFiles('source/Uploader/**') }} + path: Uploader.exe + fail-on-cache-miss: true # 前一步理应构造过的。如果不命中,肯定有问题,不如直接挂掉。 + + # 还原artifact(资源包) + - name: Restore Artifacts + uses: actions/download-artifact@v3 with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: Minecraft-Mod-Language-Package-1.19.zip - asset_name: Minecraft-Mod-Language-Package-1.19.zip - asset_content_type: application/zip - - # - name: Update release asset for 1.18-fabric - # id: upload-release-asset7 - # if: steps.changed-119-fabric.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - # uses: actions/upload-release-asset@v1 - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # with: - # upload_url: ${{ steps.create_release.outputs.upload_url }} - # asset_path: Minecraft-Mod-Language-Package-1.19-fabric.zip - # asset_name: Minecraft-Mod-Language-Package-1.19-fabric.zip - # asset_content_type: application/zip - - - name: Build Uploader - run: dotnet publish .\src\Uploader\Uploader.csproj -o ./ -r win-x64 -p:PublishSingeFile=true + path: artifacts/ - name: Run Uploader run: .\Uploader --host="${{ secrets.SSH_IP }}" --name="${{ secrets.SSH_USER }}" --password="${{ secrets.SSH_PWD }}" \ No newline at end of file diff --git a/.github/workflows/pr-packer.yml b/.github/workflows/pr-packer.yml index d9b39803ca3f..0eb035bba69e 100644 --- a/.github/workflows/pr-packer.yml +++ b/.github/workflows/pr-packer.yml @@ -1,163 +1,89 @@ -# This is a basic workflow to help you get started with Actions - name: PR Packer -# Controls when the workflow will run on: workflow_dispatch: pull_request: branches: [ main ] paths: - - 'config/packer.json' - - 'config/fontmap.txt' + - 'src/**' + - 'config/packer/**' - 'projects/**' jobs: build: + if: github.repository == 'CFPAOrg/Minecraft-Mod-Language-Package' + name: Build / Cache Packer runs-on: windows-latest steps: - uses: actions/checkout@v2 with: - fetch-depth: 20 + ref: main - - name: Check changed path on 1.12 - uses: MarceloPrado/has-changed-path@v1.0 - id: changed-1122 + # 缓存程序。一方面,在不同job之间需要这么做;另一方面,大约可以改善运行时间? + # actions/cache的逻辑会在job末尾缓存打包程序;如果不命中,就自行构造程序。 + - name: Cache Packer + id: cache-packer + uses: actions/cache@v3 with: - paths: projects/1.12.2 + key: ${{ runner.os }}-${{ hashFiles('source/Pakcer/**') }} + path: Packer.exe - - name: Check changed path on 1.16 - uses: MarceloPrado/has-changed-path@v1.0 - id: changed-116 - with: - paths: projects/1.16 + # 构造程序 + - name: Build Packer if not cached + if: steps.cache-packer.outputs.cache_hit != 'true' + run: dotnet publish .\src\Packer\Packer.csproj -o ./ -r win-x64 -p:PublishSingleFile=true - - name: Check changed path on 1.16 fabric - uses: MarceloPrado/has-changed-path@v1.0 - id: changed-116-fabric - with: - paths: projects/1.16-fabric - - - name: Check changed path on 1.18 - uses: MarceloPrado/has-changed-path@v1.0 - id: changed-118 - with: - paths: projects/1.18 - - name: Check changed path on 1.18 fabric - uses: MarceloPrado/has-changed-path@v1.0 - id: changed-118-fabric + pack: + if: github.repository == 'CFPAOrg/Minecraft-Mod-Language-Package' + name: Pack Resources and Upload Artifacts + needs: build # 显然,需要存在缓存/已经构造,才能打包。 + strategy: + matrix: + # 支持版本列表。将对这里的每个版本判断,按需打包。 + # 如需添加新版本,在这里添加即可。 + version: ["1.12.2", "1.16", "1.16-fabric", "1.18", "1.18-fabric", "1.19", "1.20", "1.20-fabric"] + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 20 + ref: main + + # 由于Github的限制,这里需要重新拉取打包程序。 + - name: Restore Packer + id: cache-restore + uses: actions/cache/restore@v3 with: - paths: projects/1.18-fabric + key: ${{ runner.os }}-${{ hashFiles('source/Pakcer/**') }} + path: Packer.exe + fail-on-cache-miss: true # 前一步理应构造过的。如果不命中,肯定有问题,不如直接挂掉。 - - name: Check changed path on 1.19 + - name: Check changed path on ${{ matrix.version }} uses: MarceloPrado/has-changed-path@v1.0 - id: changed-119 + id: check-changes with: - paths: projects/1.19 - - # - name: Check changed path on 1.19 fabric - # uses: MarceloPrado/has-changed-path@v1.0 - # id: changed-119-fabric - # with: - # paths: projects/1.19-fabric - - - name: Build Packer - run: dotnet publish .\src\Packer\Packer.csproj -o ./ -r win-x64 -p:PublishSingleFile=true - - - name: Run Packer for 1.12.2 - run: ./Packer --version="1.12.2" - if: steps.changed-1122.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' + # 判断位置:该版本文件、该版本配置、代码 + paths: | + projects/${{ matrix.version }} + config/packer/${{ matrix.version }}.json + src/** - - name: Run Packer for 1.16 - run: ./Packer --version="1.16" - if: steps.changed-116.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Run Packer for 1.16-fabric - run: ./Packer --version="1.16-fabric" - if: steps.changed-116-fabric.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Run Packer for 1.18 - run: ./Packer --version="1.18" - if: steps.changed-118.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Run Packer for 1.18-fabric - run: ./Packer --version="1.18-fabric" - if: steps.changed-118-fabric.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Run Packer for 1.19 - run: ./Packer --version="1.19" - if: steps.changed-119.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - # - name: Run Packer for 1.19-fabric - # run: ./Packer --version="1.19-fabric" - # if: steps.changed-119-fabric.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Create timestamp - id: create_timestamp - run: echo "::set-output name=timestamp::$(date '+%Y%m%d%H%M%s')" - shell: bash + - name: Run Packer for ${{ matrix.version }} + run: ./Packer --version="${{ matrix.version }}" + # 运行逻辑:内容有更改 或 手动运行 + if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' # 额 要两分半才能传完 然而 GitHub actions 直接传的话 会压成 zip 内套 zip 就这样了吧 --cy - name: Unzip Files - run: | - unzip -q Minecraft-Mod-Language-Package-1.19.zip -d Minecraft-Mod-Language-Package-1.19 || echo 0 - unzip -q Minecraft-Mod-Language-Package-1.16.zip -d Minecraft-Mod-Language-Package-1.16 || echo 0 - unzip -q Minecraft-Mod-Language-Package-1.18.zip -d Minecraft-Mod-Language-Package-1.18 || echo 0 - unzip -q Minecraft-Mod-Language-Package-1.16-fabric.zip -d Minecraft-Mod-Language-Package-1.16-fabric || echo 0 - unzip -q Minecraft-Mod-Language-Package-1.18-fabric.zip -d Minecraft-Mod-Language-Package-1.18-fabric || echo 0 - unzip -q Minecraft-Mod-Language-Package-1.12.2.zip -d Minecraft-Mod-Language-Package-1.12.2 || echo 0 - # unzip -q Minecraft-Mod-Language-Package-1.19-fabric.zip -d Minecraft-Mod-Language-Package-1.19-fabric || echo 0 + run: unzip -q Minecraft-Mod-Language-Package-${{ matrix.version }}.zip -d Minecraft-Mod-Language-Package-${{ matrix.version }} || echo 0 shell: bash - - name: Upload Artifact 1.12.2 - uses: actions/upload-artifact@v3.0.0 - with: - name: Minecraft-Mod-Language-Package-1.12.2 - path: Minecraft-Mod-Language-Package-1.12.2/* - if: steps.changed-1122.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Upload Artifact 1.16 - uses: actions/upload-artifact@v3.0.0 - with: - name: Minecraft-Mod-Language-Package-1.16 - path: Minecraft-Mod-Language-Package-1.16/* - if: steps.changed-116.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Upload Artifact 1.16 fabric - uses: actions/upload-artifact@v3.0.0 - with: - name: Minecraft-Mod-Language-Package-1.16-fabric - path: Minecraft-Mod-Language-Package-1.16-fabric/* - if: steps.changed-116-fabric.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Upload Artifact 1.18 - uses: actions/upload-artifact@v3.0.0 - with: - name: Minecraft-Mod-Language-Package-1.18 - path: Minecraft-Mod-Language-Package-1.18/* - if: steps.changed-118.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Upload Artifact 1.18 fabric - uses: actions/upload-artifact@v3.0.0 - with: - name: Minecraft-Mod-Language-Package-1.18-fabric - path: Minecraft-Mod-Language-Package-1.18-fabric/* - if: steps.changed-118-fabric.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - - name: Upload Artifact 1.19 + - name: Upload Artifact for ${{ matrix.version }} uses: actions/upload-artifact@v3.0.0 with: - name: Minecraft-Mod-Language-Package-1.19 - path: Minecraft-Mod-Language-Package-1.19/* - if: steps.changed-119.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - - # - name: Upload Artifact 1.19 fabric - # uses: actions/upload-artifact@v3.0.0 - # with: - # name: Minecraft-Mod-Language-Package-1.19-fabric - # path: Minecraft-Mod-Language-Package-1.19-fabric/* - # if: steps.changed-119-fabric.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - + name: Minecraft-Mod-Language-Package-${{ matrix.version }} + path: Minecraft-Mod-Language-Package-${{ matrix.version }}/* + if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' \ No newline at end of file diff --git a/config/packer/1.20-fabric.json b/config/packer/1.20-fabric.json new file mode 100644 index 000000000000..a9b6e91752cb --- /dev/null +++ b/config/packer/1.20-fabric.json @@ -0,0 +1,37 @@ +{ + "targetVersion": "1.20-fabric", + "targetLanguage": [ + "zh_cn" + ], + "additionalContent": [ + "LICENSE", + "pack.mcmeta", + "pack.png", + "README.md" + ], + "modNameBlackList": [], + "domainBlackList": [], + "noProcessNamespace": [ + "font", + "textures" + ], + "replacementMap": { + "[[钅卢]]": "\ud872\udf3b", + "[[钅杜]]": "\ud872\udf4a", + "[[钅喜]]": "\ud872\udf73", + "[[钅波]]": "\ud872\udf5b", + "[[钅黑]]": "\ud872\udf76", + "[[钅麦]]": "\u9fcf", + "[[钅达]]": "\ud86d\udffc", + "[[钅仑]]": "\ud872\udf2d", + "[[钅哥]]": "\u9fd4", + "[[钅尔]]": "\u9fed", + "[[钅夫]]": "\ud86d\udce7", + "[[钅立]]": "\ud86d\udff7", + "[[石田]]": "\u9fec", + "[[奥气]]": "\u9feb", + "[[气奥]]": "\u9feb", + "……": "\u22ef\u22ef", + "——": "\u2e3f" + } +} \ No newline at end of file diff --git a/config/packer/1.20.json b/config/packer/1.20.json new file mode 100644 index 000000000000..a889b47239d2 --- /dev/null +++ b/config/packer/1.20.json @@ -0,0 +1,37 @@ +{ + "targetVersion": "1.20", + "targetLanguage": [ + "zh_cn" + ], + "additionalContent": [ + "LICENSE", + "pack.mcmeta", + "pack.png", + "README.md" + ], + "modNameBlackList": [], + "domainBlackList": [], + "noProcessNamespace": [ + "font", + "textures" + ], + "replacementMap": { + "[[钅卢]]": "\ud872\udf3b", + "[[钅杜]]": "\ud872\udf4a", + "[[钅喜]]": "\ud872\udf73", + "[[钅波]]": "\ud872\udf5b", + "[[钅黑]]": "\ud872\udf76", + "[[钅麦]]": "\u9fcf", + "[[钅达]]": "\ud86d\udffc", + "[[钅仑]]": "\ud872\udf2d", + "[[钅哥]]": "\u9fd4", + "[[钅尔]]": "\u9fed", + "[[钅夫]]": "\ud86d\udce7", + "[[钅立]]": "\ud86d\udff7", + "[[石田]]": "\u9fec", + "[[奥气]]": "\u9feb", + "[[气奥]]": "\u9feb", + "……": "\u22ef\u22ef", + "——": "\u2e3f" + } +} \ No newline at end of file diff --git a/projects/1.20-fabric/README.md b/projects/1.20-fabric/README.md new file mode 100644 index 000000000000..c91f0d7d0662 --- /dev/null +++ b/projects/1.20-fabric/README.md @@ -0,0 +1,59 @@ +![pack.png](https://i.loli.net/2018/02/18/5a8974407b453.png) +--- + +| CurseForge 下载量 | 支持版本 | 翻译进度 | Github Actions | 最新快照版本 | +| :--: | :--: | :--: | :--: | :--: | +| [![CurseForge](http://cf.way2muchnoise.eu/full_simplified-chinese-localization-resource-package_downloads.svg)](https://minecraft.curseforge.com/projects/simplified-chinese-localization-resource-package) | [![CurseForge](http://cf.way2muchnoise.eu/versions/simplified-chinese-localization-resource-package.svg)](https://minecraft.curseforge.com/projects/simplified-chinese-localization-resource-package) | ![weblate](https://weblate-t.exz.me/widgets/langpack/-/svg-badge.svg) | ![Packer](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/workflows/Packer/badge.svg?branch=1.12.2) | [![GitHub release](https://img.shields.io/github/release/CFPAOrg/Minecraft-Mod-Language-Package.svg)](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/releases/latest) | + +## 仓库说明 + +这是 Minecraft 模组汉化项目的仓库,本项目目前采用 Weblate 平台进行模组项目翻译;
+用以解决模组作者不接收汉化、汉化提交更新速度慢等诸多问题;
+想要参与翻译?请访问我们的官方网站,并仔细阅读相关事宜以加入我们:
+### + +直接向本仓库提交 PR 亦可; + +你在翻译时, 应先了解需注意的有关事项,具体参见:[《Minecraft Mod简体中文翻译规范与指南》](https://github.com/Meow-J/Mod-Translation-Styleguide/blob/master/README.md)。 + +## 授权 + +本作品采用 [知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/)([简体中文](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh))进行许可,协议全文可 [在此](./LICENSE) 找到。
+ +## 使用方式 + +点击 [此处](https://minecraft.curseforge.com/projects/simplified-chinese-localization-resource-package) 可打开 CurseForge 页面下载 release 版本资源包。
+点击 [此处](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/releases/latest) 可以下载快照版本资源包。
+只需要像**普通材质包**一样,在游戏中加载上该资源包,即可拥有汉化。建议装上该资源包后重启游戏,以避免出现其他问题。 + +## 相关信息 + +**目前的翻译计划是什么样的呢?我可以递交想翻译的列表么?**
+目前已根据在 CurseForge 网站上的受欢迎程度,选取了 1.16.5 版本下载了 1000 多个模组。如果你有什么想要额外添加翻译的模组,可以通过我们的 [问题追踪器](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/issues) 递交意见,或者直接通过邮箱递交意见或建议。
+其他版本目前还暂时没有涉足计划(不过 1.7.10 应该是不会做了)。 + +关于具体的宣传,可以参见 [MCBBS 推广宣传帖](http://www.mcbbs.net/thread-774087-1-1.html); + +关于整个事情的经过,可以查看酒石酸菌的 [博客帖子](https://baka943.coding.me/2018/01/03/2018-01-03-AnIntroForWeblate/); + +**你们是怎么做到流水线式的翻译的?**
+emmmm,原理其实很简单。
+ +- 通过爬虫爬取 CurseForge 的热门模组; +- 脚本推送回 GitHub 仓库; +- Weblate 检测到仓库变动,自动抓取 GitHub 变动; +- 翻译人员在 Weblate 上翻译,Weblate 自动推回到 GitHub; +- Github Actions 检测到仓库变动,自动构建并打包; +- Github Actions 自动发布到 GitHub 的 release 上,以供下载; + +## 鸣谢 + +感谢 `phi` 搭建出了 Weblate 服务器,还实现了机翻功能;
+感谢 `Summpot`,`Nullpinter` 制作了新版本的 C# 爬虫;
+感谢 `PeakXing` 制作的 logo;
+感谢 `雪尼`、`FledgeXu`、`asdflj` 等在内的诸多人的意见和建议;
+感谢本项目的最初贡献者 `Aemande123`,`DYColdWind`,`Snownee`,`yuanjie000`,`forestbat`,`3TUSK`,`SihenZhang`,`MoXiaoFreak`,`gloomy_banana`,`yuanjie000`,`exia00125`,`luckyu19` 提供的汉化。(排名不分先后)
+感谢玩家 `R_liu` 提供的拔刀剑本地化;
+资源包中镶嵌了 `3TUSK` 提供的 [全角标点修复文件](./project/assets/minecraft/readme.md);
+最后感谢那些参与翻译,并致力于本地化推广的各位玩家,你们辛苦了。
+在本仓库的 [Contributors](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/graphs/contributors) 页面可以查看所有翻译贡献者。 diff --git a/projects/1.20-fabric/assets/minecraft/minecraft/packer-policy.json b/projects/1.20-fabric/assets/minecraft/minecraft/packer-policy.json new file mode 100644 index 000000000000..75b22dfd6411 --- /dev/null +++ b/projects/1.20-fabric/assets/minecraft/minecraft/packer-policy.json @@ -0,0 +1,4 @@ +{ + "type": "plainclone", + "source": "./projects/1.16/assets/minecraft/minecraft" +} \ No newline at end of file diff --git a/projects/1.20/README.md b/projects/1.20/README.md new file mode 100644 index 000000000000..c91f0d7d0662 --- /dev/null +++ b/projects/1.20/README.md @@ -0,0 +1,59 @@ +![pack.png](https://i.loli.net/2018/02/18/5a8974407b453.png) +--- + +| CurseForge 下载量 | 支持版本 | 翻译进度 | Github Actions | 最新快照版本 | +| :--: | :--: | :--: | :--: | :--: | +| [![CurseForge](http://cf.way2muchnoise.eu/full_simplified-chinese-localization-resource-package_downloads.svg)](https://minecraft.curseforge.com/projects/simplified-chinese-localization-resource-package) | [![CurseForge](http://cf.way2muchnoise.eu/versions/simplified-chinese-localization-resource-package.svg)](https://minecraft.curseforge.com/projects/simplified-chinese-localization-resource-package) | ![weblate](https://weblate-t.exz.me/widgets/langpack/-/svg-badge.svg) | ![Packer](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/workflows/Packer/badge.svg?branch=1.12.2) | [![GitHub release](https://img.shields.io/github/release/CFPAOrg/Minecraft-Mod-Language-Package.svg)](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/releases/latest) | + +## 仓库说明 + +这是 Minecraft 模组汉化项目的仓库,本项目目前采用 Weblate 平台进行模组项目翻译;
+用以解决模组作者不接收汉化、汉化提交更新速度慢等诸多问题;
+想要参与翻译?请访问我们的官方网站,并仔细阅读相关事宜以加入我们:
+### + +直接向本仓库提交 PR 亦可; + +你在翻译时, 应先了解需注意的有关事项,具体参见:[《Minecraft Mod简体中文翻译规范与指南》](https://github.com/Meow-J/Mod-Translation-Styleguide/blob/master/README.md)。 + +## 授权 + +本作品采用 [知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/)([简体中文](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh))进行许可,协议全文可 [在此](./LICENSE) 找到。
+ +## 使用方式 + +点击 [此处](https://minecraft.curseforge.com/projects/simplified-chinese-localization-resource-package) 可打开 CurseForge 页面下载 release 版本资源包。
+点击 [此处](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/releases/latest) 可以下载快照版本资源包。
+只需要像**普通材质包**一样,在游戏中加载上该资源包,即可拥有汉化。建议装上该资源包后重启游戏,以避免出现其他问题。 + +## 相关信息 + +**目前的翻译计划是什么样的呢?我可以递交想翻译的列表么?**
+目前已根据在 CurseForge 网站上的受欢迎程度,选取了 1.16.5 版本下载了 1000 多个模组。如果你有什么想要额外添加翻译的模组,可以通过我们的 [问题追踪器](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/issues) 递交意见,或者直接通过邮箱递交意见或建议。
+其他版本目前还暂时没有涉足计划(不过 1.7.10 应该是不会做了)。 + +关于具体的宣传,可以参见 [MCBBS 推广宣传帖](http://www.mcbbs.net/thread-774087-1-1.html); + +关于整个事情的经过,可以查看酒石酸菌的 [博客帖子](https://baka943.coding.me/2018/01/03/2018-01-03-AnIntroForWeblate/); + +**你们是怎么做到流水线式的翻译的?**
+emmmm,原理其实很简单。
+ +- 通过爬虫爬取 CurseForge 的热门模组; +- 脚本推送回 GitHub 仓库; +- Weblate 检测到仓库变动,自动抓取 GitHub 变动; +- 翻译人员在 Weblate 上翻译,Weblate 自动推回到 GitHub; +- Github Actions 检测到仓库变动,自动构建并打包; +- Github Actions 自动发布到 GitHub 的 release 上,以供下载; + +## 鸣谢 + +感谢 `phi` 搭建出了 Weblate 服务器,还实现了机翻功能;
+感谢 `Summpot`,`Nullpinter` 制作了新版本的 C# 爬虫;
+感谢 `PeakXing` 制作的 logo;
+感谢 `雪尼`、`FledgeXu`、`asdflj` 等在内的诸多人的意见和建议;
+感谢本项目的最初贡献者 `Aemande123`,`DYColdWind`,`Snownee`,`yuanjie000`,`forestbat`,`3TUSK`,`SihenZhang`,`MoXiaoFreak`,`gloomy_banana`,`yuanjie000`,`exia00125`,`luckyu19` 提供的汉化。(排名不分先后)
+感谢玩家 `R_liu` 提供的拔刀剑本地化;
+资源包中镶嵌了 `3TUSK` 提供的 [全角标点修复文件](./project/assets/minecraft/readme.md);
+最后感谢那些参与翻译,并致力于本地化推广的各位玩家,你们辛苦了。
+在本仓库的 [Contributors](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/graphs/contributors) 页面可以查看所有翻译贡献者。 diff --git a/projects/1.20/assets/minecraft/minecraft/font/default.json b/projects/1.20/assets/minecraft/minecraft/font/default.json new file mode 100644 index 000000000000..475571c9e600 --- /dev/null +++ b/projects/1.20/assets/minecraft/minecraft/font/default.json @@ -0,0 +1,20 @@ +{ + "providers": [ + { + "type": "reference", + "id": "minecraft:include/cjk-punctuations" + }, + { + "type": "reference", + "id": "minecraft:include/space" + }, + { + "type": "reference", + "id": "minecraft:include/default" + }, + { + "type": "reference", + "id": "minecraft:include/unifont" + } + ] +} diff --git a/projects/1.20/assets/minecraft/minecraft/font/include/cjk-punctuations.json b/projects/1.20/assets/minecraft/minecraft/font/include/cjk-punctuations.json new file mode 100644 index 000000000000..82fc2914d039 --- /dev/null +++ b/projects/1.20/assets/minecraft/minecraft/font/include/cjk-punctuations.json @@ -0,0 +1,29 @@ +{ + "providers":[ + { + "type":"bitmap", + "file": "minecraft:font/cjk_punctuations.png", + "ascent": 7, + "chars": [ + "\u3001\u3002\u300a\u300b\u3010\u3011\u2018\u2019\u201c\u0000\u3008\u3009\u0000\u0000\u0000\u0000", + "\u201d\uff01\uff08\uff09\uff0c\uff1a\uff1b\uff1f\u2014\u00b7\u0000\u0000\u0000\u0000\u0000\u0000" + ] + }, + { + "type":"bitmap", + "file": "minecraft:font/ellipsis.png", + "ascent": 7, + "chars": [ + "\u22ef" + ] + }, + { + "type": "bitmap", + "file": "minecraft:font/2em-dash.png", + "ascent": 7, + "chars": [ + "\u2e3a" + ] + } + ] +} \ No newline at end of file diff --git a/projects/1.20/assets/minecraft/minecraft/font/uniform.json b/projects/1.20/assets/minecraft/minecraft/font/uniform.json new file mode 100644 index 000000000000..32d3ee8fdb14 --- /dev/null +++ b/projects/1.20/assets/minecraft/minecraft/font/uniform.json @@ -0,0 +1,16 @@ +{ + "providers": [ + { + "type": "reference", + "id": "minecraft:include/cjk-punctuations" + }, + { + "type": "reference", + "id": "minecraft:include/space" + }, + { + "type": "reference", + "id": "minecraft:include/unifont" + } + ] +} diff --git a/projects/1.20/assets/minecraft/minecraft/readme.md b/projects/1.20/assets/minecraft/minecraft/readme.md new file mode 100644 index 000000000000..019ec9e42ef4 --- /dev/null +++ b/projects/1.20/assets/minecraft/minecraft/readme.md @@ -0,0 +1,24 @@ +# 全角字符修正与特殊字符补充 +- 本包添加了几个特殊字符字体,用于补充部分新确定的元素名称 +- 本包修正了中文全角字符的宽度和位置问题。 + +## 本包建议翻译文本采用左侧书写,在打包阶段使用脚本转换成右侧字符 + +| 翻译文本 | 转换字符 | 备注 | +| :------: | :------------: | :----------------------------------: | +| [[钅卢]] | `\ue900` | | +| [[钅杜]] | `\ue901` | | +| [[钅喜]] | `\ue902` | | +| [[钅波]] | `\ue903` | | +| [[钅黑]] | `\ue904` | | +| [[钅麦]] | `\u9fcf` | | +| [[钅达]] | `\ue906` | | +| [[钅仑]] | `\ue907` | | +| [[钅哥]] | `\u9fd4` | | +| [[钅尔]] | `\u9fed` | | +| [[钅夫]] | `\ue90a` | | +| 镆 | `\u9546` | 此元素名已存在对应字符,无需修改替换 | +| [[钅立]] | `\ue90c` | | +| [[石田]] | `\u9fec` | | +| [[奥气]] | `\u9feb` | | +| …… | `\ue908\ue909` | 全角省略号的修改 | \ No newline at end of file diff --git a/projects/1.20/assets/minecraft/minecraft/textures/font/2em-dash.png b/projects/1.20/assets/minecraft/minecraft/textures/font/2em-dash.png new file mode 100644 index 0000000000000000000000000000000000000000..b683b4dd420e946726d3e92b40b28fe0129dd391 GIT binary patch literal 2829 zcmV+o3-a`dP)KLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z06IxTK~#9!?9o9D03Zy-&_99+@b9xY;JO`J1utm?GG6B1DMz f^Z)<=|NjF3Hx>s?j!7la00000NkvXXu0mjfIH+DI literal 0 HcmV?d00001 diff --git a/projects/1.20/assets/minecraft/minecraft/textures/font/cjk_punctuations.png b/projects/1.20/assets/minecraft/minecraft/textures/font/cjk_punctuations.png new file mode 100644 index 0000000000000000000000000000000000000000..7ad25d1665c0b495cb66debcce5793e9f135cae7 GIT binary patch literal 3275 zcmV;+3^enJP)KLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z0r*KoK~#9!?3_`q!XOYu)%g2n|LdF$^!+wOD-6sq&~p+Kqg4zrmwU18^Ei&b2LRlX z*J8g{8=sGCw|rQR0spxG8w)@dr1CZIiT_Q6BHGo-#Vf)0YCz`qCwFJHgy0kt9pxD zfS7nvIs&Vm_l^xX0DuVs;gRVneuD!Tk(azqM5%EB5v#urItKhQJ;iSn0O>4XE$kjZ zv5Xjqic42vGb31fVCYogKvP1ECauDiNUgjXb#=7yt*b`s&Ln z43IzoG@$so805NtxE}#j^DYXv=j<&dk4-OrX%tMr0emcUS!9Ca0k6-xCz6WqNxMM{nvLhCvG4B&_B^7xcDhf z1OOndAVSa{K=uJ|&GbYOfC&Py`hU*5oI!{9LAU_uCL%CXKsbdLmK6X=5(9ed|1K*h zA_80O0Ynx~@4f3JLH`i}V2S`lWLtGE;FSdkpoxC~009600|2_Yomcs9WKIA8002ov JPDHLkV1gIaCsqIe literal 0 HcmV?d00001 diff --git a/projects/1.20/assets/minecraft/minecraft/textures/font/ellipsis.png b/projects/1.20/assets/minecraft/minecraft/textures/font/ellipsis.png new file mode 100644 index 0000000000000000000000000000000000000000..70a21a0b5e077b47e5379817048b33ade3d7c8ea GIT binary patch literal 2843 zcmV+$3*_{PP)KLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z07ywhK~#9!?AEaj03ZkeL9loKJzW4B2Qaa~;y$6HxKNQ*HKVZ+%>e)a0001d30P-t tdfsinKzc|3000000J;Gi009600{|g53;#YOj(z|D002ovPDHLkV1g8uUnc+n literal 0 HcmV?d00001 diff --git a/src/Uploader/Program.cs b/src/Uploader/Program.cs index 8a03ccbea28f..745b0c7f8914 100644 --- a/src/Uploader/Program.cs +++ b/src/Uploader/Program.cs @@ -33,9 +33,9 @@ static int Main(string host, string name, string password) // 获取可用的资源包,准备上传 - var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory()); - var packList = currentDirectory - .EnumerateFiles("Minecraft-Mod-Language-Package-*.zip"); + var artifactDirectory = new DirectoryInfo(Path.Join(Directory.GetCurrentDirectory(), "artifacts")); + var packList = artifactDirectory + .EnumerateFiles("Minecraft-Mod-Language-Package-*.zip", SearchOption.AllDirectories); Log.Information("检测到的资源包数目:{0}", packList.Count()); @@ -70,8 +70,8 @@ static int Main(string host, string name, string password) }); // 临时操作 在使用旧md5校验的程序弃用以后需要删除 - var md5List = currentDirectory - .EnumerateFiles("*.md5"); + var md5List = artifactDirectory + .EnumerateFiles("*.md5", SearchOption.AllDirectories); md5List.ToList() .ForEach(_ => { From b063bd9a03b2ad590f6baa01281d3051842575bb Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sun, 16 Jul 2023 18:11:46 +0800 Subject: [PATCH 02/22] Fix paths --- .../entangled/entangled/lang/en_us.json | 46 +++++------ .../entangled/entangled/lang/zh_cn.json | 46 +++++------ .../morecrossbows/lang/zh_cn.json | 78 +++++++++---------- 3 files changed, 85 insertions(+), 85 deletions(-) diff --git a/projects/1.20/assets/entangled/entangled/lang/en_us.json b/projects/1.20/assets/entangled/entangled/lang/en_us.json index edcfb8aa7e37..f654fbd87da4 100644 --- a/projects/1.20/assets/entangled/entangled/lang/en_us.json +++ b/projects/1.20/assets/entangled/entangled/lang/en_us.json @@ -1,24 +1,24 @@ -{ - "entangled.block.block": "Entangled Block", - "entangled.item.item": "Entangled Binder", - "entangled.entangled_block.info.ranged_same_dimension": "Can be bound to blocks in the same dimension up to %d blocks away", - "entangled.entangled_block.info.infinite_same_dimension": "Can be bound to blocks in the same dimension", - "entangled.entangled_block.info.ranged_other_dimension": "Can be bound to blocks up to %d blocks away or to blocks in other dimensions", - "entangled.entangled_block.info.infinite_other_dimension": "Can be bound to other blocks", - "entangled.entangled_block.info.bound": "Bound to %1$s in the %5$s at (%2$d, %3$d, %4$d)", - "entangled.entangled_block.unbind": "Block unbound!", - "entangled.entangled_block.no_selection": "No block selected!", - "entangled.entangled_block.self": "Can't bind a block to itself!", - "entangled.entangled_block.bind": "Block bound!", - "entangled.entangled_block.wrong_dimension": "The targeted block must be in the same dimension!", - "entangled.entangled_block.too_far": "The targeted block is too far away!", - "entangled.entangled_binder.info": "Can bind entangled blocks to other blocks", - "entangled.entangled_binder.info.target.unknown": "Linked to a block in the %4$s at (%1$d, %2$d, %3$d)", - "entangled.entangled_binder.info.target.known": "Linked to %1$s in the %5$s at (%2$d, %3$d, %4$d)", - "entangled.entangled_binder.select": "Block selected!", - "entangled.entangled_binder.clear": "Connection cleared!", - "entangled.waila.bound_same_dimension": "Bound to %1$s at (%2$d, %3$d, %4$d)", - "entangled.waila.bound_other_dimension": "Bound to %1$s in the %5$s at (%2$d, %3$d, %4$d)", - "entangled.waila.unbound": "Unbound", - "config.jade.plugin_entangled.entangled_block_component": "Entangled Block" +{ + "entangled.block.block": "Entangled Block", + "entangled.item.item": "Entangled Binder", + "entangled.entangled_block.info.ranged_same_dimension": "Can be bound to blocks in the same dimension up to %d blocks away", + "entangled.entangled_block.info.infinite_same_dimension": "Can be bound to blocks in the same dimension", + "entangled.entangled_block.info.ranged_other_dimension": "Can be bound to blocks up to %d blocks away or to blocks in other dimensions", + "entangled.entangled_block.info.infinite_other_dimension": "Can be bound to other blocks", + "entangled.entangled_block.info.bound": "Bound to %1$s in the %5$s at (%2$d, %3$d, %4$d)", + "entangled.entangled_block.unbind": "Block unbound!", + "entangled.entangled_block.no_selection": "No block selected!", + "entangled.entangled_block.self": "Can't bind a block to itself!", + "entangled.entangled_block.bind": "Block bound!", + "entangled.entangled_block.wrong_dimension": "The targeted block must be in the same dimension!", + "entangled.entangled_block.too_far": "The targeted block is too far away!", + "entangled.entangled_binder.info": "Can bind entangled blocks to other blocks", + "entangled.entangled_binder.info.target.unknown": "Linked to a block in the %4$s at (%1$d, %2$d, %3$d)", + "entangled.entangled_binder.info.target.known": "Linked to %1$s in the %5$s at (%2$d, %3$d, %4$d)", + "entangled.entangled_binder.select": "Block selected!", + "entangled.entangled_binder.clear": "Connection cleared!", + "entangled.waila.bound_same_dimension": "Bound to %1$s at (%2$d, %3$d, %4$d)", + "entangled.waila.bound_other_dimension": "Bound to %1$s in the %5$s at (%2$d, %3$d, %4$d)", + "entangled.waila.unbound": "Unbound", + "config.jade.plugin_entangled.entangled_block_component": "Entangled Block" } \ No newline at end of file diff --git a/projects/1.20/assets/entangled/entangled/lang/zh_cn.json b/projects/1.20/assets/entangled/entangled/lang/zh_cn.json index 6baf30baf905..823de88a6f78 100644 --- a/projects/1.20/assets/entangled/entangled/lang/zh_cn.json +++ b/projects/1.20/assets/entangled/entangled/lang/zh_cn.json @@ -1,24 +1,24 @@ -{ - "entangled.block.block": "纠缠方块", - "entangled.item.item": "纠缠绑定器", - "entangled.entangled_block.info.ranged_same_dimension": "可以绑定到同一维度内最远%d格的方块", - "entangled.entangled_block.info.infinite_same_dimension": "可以绑定到同一维度内的方块", - "entangled.entangled_block.info.ranged_other_dimension": "可以绑定到同一维度内最远%d格的方块或其他维度的方块", - "entangled.entangled_block.info.infinite_other_dimension": "可以绑定到其他方块", - "entangled.entangled_block.info.bound": "已绑定至位于%5$s维度(%2$d,%3$d,%4$d)的%1$s", - "entangled.entangled_block.unbind": "方块已解绑!", - "entangled.entangled_block.no_selection": "未选择方块!", - "entangled.entangled_block.self": "不能绑定方块本身!", - "entangled.entangled_block.bind": "方块已绑定!", - "entangled.entangled_block.wrong_dimension": "目标方块必须在同一维度!", - "entangled.entangled_block.too_far": "目标方块距离过远!", - "entangled.entangled_binder.info": "可以将纠缠方块与其他方块绑定", - "entangled.entangled_binder.info.target.unknown": "连接到位于%4$s维度(%1$d,%2$d,%3$d)的方块", - "entangled.entangled_binder.info.target.known": "已连接到位于%5$s维度(%2$d,%3$d,%4$d)的%1$s", - "entangled.entangled_binder.select": "方块已选择!", - "entangled.entangled_binder.clear": "连接已清除!", - "entangled.waila.bound_same_dimension": "已绑定至(%2$d,%3$d,%4$d)的%1$s", - "entangled.waila.bound_other_dimension": "已绑定至位于%5$s维度(%2$d,%3$d,%4$d)的%1$s", - "entangled.waila.unbound": "未绑定", - "config.jade.plugin_entangled.entangled_block_component": "纠缠方块" +{ + "entangled.block.block": "纠缠方块", + "entangled.item.item": "纠缠绑定器", + "entangled.entangled_block.info.ranged_same_dimension": "可以绑定到同一维度内最远%d格的方块", + "entangled.entangled_block.info.infinite_same_dimension": "可以绑定到同一维度内的方块", + "entangled.entangled_block.info.ranged_other_dimension": "可以绑定到同一维度内最远%d格的方块或其他维度的方块", + "entangled.entangled_block.info.infinite_other_dimension": "可以绑定到其他方块", + "entangled.entangled_block.info.bound": "已绑定至位于%5$s维度(%2$d,%3$d,%4$d)的%1$s", + "entangled.entangled_block.unbind": "方块已解绑!", + "entangled.entangled_block.no_selection": "未选择方块!", + "entangled.entangled_block.self": "不能绑定方块本身!", + "entangled.entangled_block.bind": "方块已绑定!", + "entangled.entangled_block.wrong_dimension": "目标方块必须在同一维度!", + "entangled.entangled_block.too_far": "目标方块距离过远!", + "entangled.entangled_binder.info": "可以将纠缠方块与其他方块绑定", + "entangled.entangled_binder.info.target.unknown": "连接到位于%4$s维度(%1$d,%2$d,%3$d)的方块", + "entangled.entangled_binder.info.target.known": "已连接到位于%5$s维度(%2$d,%3$d,%4$d)的%1$s", + "entangled.entangled_binder.select": "方块已选择!", + "entangled.entangled_binder.clear": "连接已清除!", + "entangled.waila.bound_same_dimension": "已绑定至(%2$d,%3$d,%4$d)的%1$s", + "entangled.waila.bound_other_dimension": "已绑定至位于%5$s维度(%2$d,%3$d,%4$d)的%1$s", + "entangled.waila.unbound": "未绑定", + "config.jade.plugin_entangled.entangled_block_component": "纠缠方块" } \ No newline at end of file diff --git a/projects/1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json b/projects/1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json index 93ba3bcdc0c2..6496e10d5ff2 100644 --- a/projects/1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json +++ b/projects/1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json @@ -1,40 +1,40 @@ -{ - "item。morecrossbows.copper_crossbow": "铜弩", - "item。morecrossbows.iron_crossbow": "铁弩", - "item.morecrossbows.golden_crossbow": "金弩", - "item.morecrossbows.emerald_crossbow": "绿宝石弩", - "item.morecrossbows.diamond_crossbow": "钻石弩", - "item.morecrossbows。netherite_crossbow": "下界合金弩", - "item.morecrossbows.gilded_netherite_crossbow": "镀金下界合金弩", - "item.morecrossbows.enderite_crossbow": "末影合金弩", - "item.morecrossbows.gilded_enderite_crossbow": "镀金末影合金弩", - - "upgrade.morecrossbows.crossbow_upgrade": "弩升级", - "item.morecrossbows.smithing_template.crossbow_upgrade.additions_slot_description": "把下一级材料的块放在这里。", - "item.morecrossbows.smithing_template.crossbow_upgrade.applies_to": "弩", - "item.morecrossbows.smithing_template.crossbow_upgrade.base_slot_description": "在这里放一把弩。", - "item.morecrossbows.smithing_template.crossbow_upgrade.ingredients": "铜、铁、金、绿宝石、钻石块", - - "tooltip.morecrossbows.damage_tooltip": "弹射物伤害", - "tooltip.morecrossbows.speed_multiplier": "速度倍率", - "tooltip.morecrossbows.charge_time": "蓄力时间", - - "advancements.adventure.morecrossbows.obtain_copper_crossbow.title": "铜弩", - "advancements.adventure.morecrossbows.obtain_copper_crossbow.description": "铜做的弩!", - "advancements.adventure.morecrossbows.obtain_iron_crossbow.title": "铁弩", - "advancements.adventure.morecrossbows.obtain_iron_crossbow.description": "铁做的弩!", - "advancements.adventure.morecrossbows.obtain_golden_crossbow.title": "金弩", - "advancements.adventure.morecrossbows.obtain_golden_crossbow.description": "金做的弩!", - "advancements.adventure.morecrossbows.obtain_emerald_crossbow.title": "绿宝石弩", - "advancements.adventure.morecrossbows.obtain_emerald_crossbow.description": "绿宝石做的弩!", - "advancements.adventure.morecrossbows.obtain_diamond_crossbow.title": "钻石弩", - "advancements.adventure.morecrossbows.obtain_diamond_crossbow.description": "钻石做的弩!", - "advancements.adventure.morecrossbows.obtain_netherite_crossbow.title": "下界合金弩", - "advancements.adventure.morecrossbows.obtain_netherite_crossbow.description": "下界合金做的弩!", - "advancements.adventure.morecrossbows.obtain_gilded_netherite_crossbow.title": "镀金下界合金做的弩", - "advancements.adventure.morecrossbows.obtain_gilded_netherite_crossbow.description": "镀金下界合金做的弩!", - "advancements.adventure.morecrossbows.obtain_enderite_crossbow.title": "末影合金弩", - "advancements.adventure.morecrossbows.obtain_enderite_crossbow.description": "末影合金做的弩!", - "advancements.adventure.morecrossbows.obtain_gilded_enderite_crossbow.title": "镀金末影合金做的弩", - "advancements.adventure.morecrossbows.obtain_gilded_enderite_crossbow.description": "镀金末影合金做的弩!" +{ + "item。morecrossbows.copper_crossbow": "铜弩", + "item。morecrossbows.iron_crossbow": "铁弩", + "item.morecrossbows.golden_crossbow": "金弩", + "item.morecrossbows.emerald_crossbow": "绿宝石弩", + "item.morecrossbows.diamond_crossbow": "钻石弩", + "item.morecrossbows。netherite_crossbow": "下界合金弩", + "item.morecrossbows.gilded_netherite_crossbow": "镀金下界合金弩", + "item.morecrossbows.enderite_crossbow": "末影合金弩", + "item.morecrossbows.gilded_enderite_crossbow": "镀金末影合金弩", + + "upgrade.morecrossbows.crossbow_upgrade": "弩升级", + "item.morecrossbows.smithing_template.crossbow_upgrade.additions_slot_description": "把下一级材料的块放在这里。", + "item.morecrossbows.smithing_template.crossbow_upgrade.applies_to": "弩", + "item.morecrossbows.smithing_template.crossbow_upgrade.base_slot_description": "在这里放一把弩。", + "item.morecrossbows.smithing_template.crossbow_upgrade.ingredients": "铜、铁、金、绿宝石、钻石块", + + "tooltip.morecrossbows.damage_tooltip": "弹射物伤害", + "tooltip.morecrossbows.speed_multiplier": "速度倍率", + "tooltip.morecrossbows.charge_time": "蓄力时间", + + "advancements.adventure.morecrossbows.obtain_copper_crossbow.title": "铜弩", + "advancements.adventure.morecrossbows.obtain_copper_crossbow.description": "铜做的弩!", + "advancements.adventure.morecrossbows.obtain_iron_crossbow.title": "铁弩", + "advancements.adventure.morecrossbows.obtain_iron_crossbow.description": "铁做的弩!", + "advancements.adventure.morecrossbows.obtain_golden_crossbow.title": "金弩", + "advancements.adventure.morecrossbows.obtain_golden_crossbow.description": "金做的弩!", + "advancements.adventure.morecrossbows.obtain_emerald_crossbow.title": "绿宝石弩", + "advancements.adventure.morecrossbows.obtain_emerald_crossbow.description": "绿宝石做的弩!", + "advancements.adventure.morecrossbows.obtain_diamond_crossbow.title": "钻石弩", + "advancements.adventure.morecrossbows.obtain_diamond_crossbow.description": "钻石做的弩!", + "advancements.adventure.morecrossbows.obtain_netherite_crossbow.title": "下界合金弩", + "advancements.adventure.morecrossbows.obtain_netherite_crossbow.description": "下界合金做的弩!", + "advancements.adventure.morecrossbows.obtain_gilded_netherite_crossbow.title": "镀金下界合金做的弩", + "advancements.adventure.morecrossbows.obtain_gilded_netherite_crossbow.description": "镀金下界合金做的弩!", + "advancements.adventure.morecrossbows.obtain_enderite_crossbow.title": "末影合金弩", + "advancements.adventure.morecrossbows.obtain_enderite_crossbow.description": "末影合金做的弩!", + "advancements.adventure.morecrossbows.obtain_gilded_enderite_crossbow.title": "镀金末影合金做的弩", + "advancements.adventure.morecrossbows.obtain_gilded_enderite_crossbow.description": "镀金末影合金做的弩!" } \ No newline at end of file From a6d2011449421f3cc9b6c8816f1b526fdac72afe Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Thu, 3 Aug 2023 16:16:22 +0800 Subject: [PATCH 03/22] Miscellaneous Updates --- .github/workflows/packer.yml | 98 +++++++++++++----- .github/workflows/pr-packer.yml | 13 ++- .gitignore | 21 ++-- .../font/include/cjk-punctuations.json | 2 +- .../font/{2em-dash.png => 2em_dash.png} | Bin 2829 -> 2829 bytes 5 files changed, 93 insertions(+), 41 deletions(-) rename projects/1.20/assets/minecraft/minecraft/textures/font/{2em-dash.png => 2em_dash.png} (96%) diff --git a/.github/workflows/packer.yml b/.github/workflows/packer.yml index 0856534b1e2a..3befb16abed5 100644 --- a/.github/workflows/packer.yml +++ b/.github/workflows/packer.yml @@ -3,7 +3,7 @@ name: Packer on: workflow_dispatch: push: - branches: [main] + branches: [ main ] paths: - 'src/**' - 'config/packer/**' @@ -12,14 +12,12 @@ on: jobs: - build: + build-packer: if: github.repository == 'CFPAOrg/Minecraft-Mod-Language-Package' - name: Build / Cache Packer and Uploader + name: Build / Cache Packer runs-on: windows-latest steps: - uses: actions/checkout@v2 - with: - ref: main # 缓存程序。一方面,在不同job之间需要这么做;另一方面,大约可以改善运行时间? # actions/cache的逻辑会在job末尾缓存打包程序;如果不命中,就自行构造程序。 @@ -27,41 +25,77 @@ jobs: id: cache-packer uses: actions/cache@v3 with: - key: ${{ runner.os }}-${{ hashFiles('source/Pakcer/**') }} + key: ${{ runner.os }}-${{ hashFiles('src/Pakcer/**') }} path: Packer.exe + lookup-only: true + # 构造程序 + - name: Build Packer if not cached + if: steps.cache-packer.outputs.cache_hit != 'true' + run: dotnet publish .\src\Packer\Packer.csproj -o ./ -r win-x64 -p:PublishSingleFile=true + + build-uploader: + if: github.repository == 'CFPAOrg/Minecraft-Mod-Language-Package' + name: Build / Cache Uploader + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + + # 缓存程序。一方面,在不同job之间需要这么做;另一方面,大约可以改善运行时间? + # actions/cache的逻辑会在job末尾缓存打包程序;如果不命中,就自行构造程序。 - name: Cache Uploader id: cache-uploader uses: actions/cache@v3 with: - key: ${{ runner.os }}-${{ hashFiles('source/Uploader/**') }} + key: ${{ runner.os }}-${{ hashFiles('src/Uploader/**') }} path: Uploader.exe - - # 构造程序 - - name: Build Packer if not cached - if: steps.cache-packer.outputs.cache_hit != 'true' - run: dotnet publish .\src\Packer\Packer.csproj -o ./ -r win-x64 -p:PublishSingleFile=true + lookup-only: true + # 构造程序 - name: Build Uploader if not cached if: steps.cache-uploader.outputs.cache_hit != 'true' run: dotnet publish .\src\Uploader\Uploader.csproj -o ./ -r win-x64 -p:PublishSingeFile=true + initialize-release: + if: github.repository == 'CFPAOrg/Minecraft-Mod-Language-Package' + name: Initialize Release + runs-on: windows-latest + steps: + + - name: Create timestamp + id: create_timestamp + run: echo "::set-output name=timestamp::$(date '+%Y%m%d%H%M%s')" + shell: bash + + # Create the release: https://github.com/actions/create-release + - name: Create release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: Snapshot-${{ steps.create_timestamp.outputs.timestamp }} + release_name: 汉化资源包-Snapshot-${{ steps.create_timestamp.outputs.timestamp }} + draft: false + prerelease: false + outputs: + upload-url: ${{ steps.create_release.outputs.upload_url }} + pack: if: github.repository == 'CFPAOrg/Minecraft-Mod-Language-Package' - name: Pack Resources and Upload Artifacts - needs: build # 显然,需要存在缓存/已经构造,才能打包。 + name: Pack Resources and Upload Artifacts/Releases + needs: [ build-packer, initialize-release ] # 显然,需要存在打包程序,才能打包。 strategy: matrix: - # 支持版本列表。将对这里的每个版本判断,按需打包。 + # 版本列表。将对这里的每个版本判断,按需打包。 # 如需添加新版本,在这里添加即可。 - version: ["1.12.2", "1.16", "1.16-fabric", "1.18", "1.18-fabric", "1.19", "1.20", "1.20-fabric"] + version: [ "1.12.2", "1.16", "1.16-fabric", "1.18", "1.18-fabric", "1.19", "1.20", "1.20-fabric" ] runs-on: windows-latest steps: - uses: actions/checkout@v2 with: - fetch-depth: 20 - ref: main + fetch-depth: 20 # 显然,需要有提交历史才能比较提交。20这个数是任意的。 # 由于Github的限制,这里需要重新拉取打包程序。 - name: Restore Packer @@ -77,7 +111,7 @@ jobs: id: check-changes with: # 判断位置:该版本文件、该版本配置、代码 - paths: | + paths: > projects/${{ matrix.version }} config/packer/${{ matrix.version }}.json src/** @@ -85,27 +119,41 @@ jobs: - name: Run Packer for ${{ matrix.version }} run: ./Packer --version="${{ matrix.version }}" # 运行逻辑:内容有更改 或 手动运行 - if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' + if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - # 上传内容:每个版本一个压缩包,包含了资源包和md5校验文件 + # Artifact 上传内容:每个版本一个压缩包,包含了资源包和md5校验文件 - name: Upload Artifact for ${{ matrix.version }} uses: actions/upload-artifact@v3.0.0 with: name: Minecraft-Mod-Language-Package-${{ matrix.version }} path: | Minecraft-Mod-Language-Package-${{ matrix.version }}.zip - ${{matrix.version}}.md5 + ${{ matrix.version }}.md5 + if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' + + # Upload release asset: https://github.com/actions/upload-release-asset + - name: Update release asset for ${{ matrix.version }} + id: upload-release-asset if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.initialize-release.outputs.upload-url }} + asset_path: Minecraft-Mod-Language-Package-${{ matrix.version }}.zip + asset_name: Minecraft-Mod-Language-Package-${{ matrix.version }}.zip + asset_content_type: application/zip upload: if: github.repository == 'CFPAOrg/Minecraft-Mod-Language-Package' name: Upload Resource Packs to Remote Server - needs: pack # 显然,需要打包完成后才可以上传给分发服务器 + needs: [ pack, build-uploader ] # 显然,需要打包完成,并且存在上传程序,才可以上传给分发服务器 runs-on: windows-latest steps: - # 由于Github的限制,这里需要重新拉取打包程序。 - - name: Restore Packer + + # 由于Github的限制,这里需要重新拉取上传程序。 + - name: Restore Uploader id: cache-restore uses: actions/cache/restore@v3 with: diff --git a/.github/workflows/pr-packer.yml b/.github/workflows/pr-packer.yml index 0eb035bba69e..ae2dbde072d6 100644 --- a/.github/workflows/pr-packer.yml +++ b/.github/workflows/pr-packer.yml @@ -18,8 +18,6 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@v2 - with: - ref: main # 缓存程序。一方面,在不同job之间需要这么做;另一方面,大约可以改善运行时间? # actions/cache的逻辑会在job末尾缓存打包程序;如果不命中,就自行构造程序。 @@ -27,8 +25,9 @@ jobs: id: cache-packer uses: actions/cache@v3 with: - key: ${{ runner.os }}-${{ hashFiles('source/Pakcer/**') }} + key: ${{ runner.os }}-${{ hashFiles('src/Pakcer/**') }} path: Packer.exe + lookup-only: true # 构造程序 - name: Build Packer if not cached @@ -49,15 +48,14 @@ jobs: steps: - uses: actions/checkout@v2 with: - fetch-depth: 20 - ref: main + fetch-depth: 20 # 显然,需要有提交历史才能比较提交。20这个数是任意的。 # 由于Github的限制,这里需要重新拉取打包程序。 - name: Restore Packer id: cache-restore uses: actions/cache/restore@v3 with: - key: ${{ runner.os }}-${{ hashFiles('source/Pakcer/**') }} + key: ${{ runner.os }}-${{ hashFiles('src/Pakcer/**') }} path: Packer.exe fail-on-cache-miss: true # 前一步理应构造过的。如果不命中,肯定有问题,不如直接挂掉。 @@ -66,7 +64,7 @@ jobs: id: check-changes with: # 判断位置:该版本文件、该版本配置、代码 - paths: | + paths: > projects/${{ matrix.version }} config/packer/${{ matrix.version }}.json src/** @@ -80,6 +78,7 @@ jobs: - name: Unzip Files run: unzip -q Minecraft-Mod-Language-Package-${{ matrix.version }}.zip -d Minecraft-Mod-Language-Package-${{ matrix.version }} || echo 0 shell: bash + if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - name: Upload Artifact for ${{ matrix.version }} uses: actions/upload-artifact@v3.0.0 diff --git a/.gitignore b/.gitignore index 93c64e02fb82..3d152dd748ea 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,19 @@ Minecraft-Mod-Language-Package-*.zip Packer.exe Packer.xml +# CFPA-backlogs + +cfr.jar +Formatter.exe +Spider.exe +clrcompression.dll +clrjit.dll +coreclr.dll +mscordaccore.dll +/src/Packer/Properties/launchSettings.json + +# artifact temporary files +artifacts/ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. @@ -370,11 +383,3 @@ MigrationBackup/ # Fody - auto-generated XML schema FodyWeavers.xsd -cfr.jar -Formatter.exe -Spider.exe -clrcompression.dll -clrjit.dll -coreclr.dll -mscordaccore.dll -/src/Packer/Properties/launchSettings.json diff --git a/projects/1.20/assets/minecraft/minecraft/font/include/cjk-punctuations.json b/projects/1.20/assets/minecraft/minecraft/font/include/cjk-punctuations.json index 82fc2914d039..8a18537c968a 100644 --- a/projects/1.20/assets/minecraft/minecraft/font/include/cjk-punctuations.json +++ b/projects/1.20/assets/minecraft/minecraft/font/include/cjk-punctuations.json @@ -19,7 +19,7 @@ }, { "type": "bitmap", - "file": "minecraft:font/2em-dash.png", + "file": "minecraft:font/2em_dash.png", "ascent": 7, "chars": [ "\u2e3a" diff --git a/projects/1.20/assets/minecraft/minecraft/textures/font/2em-dash.png b/projects/1.20/assets/minecraft/minecraft/textures/font/2em_dash.png similarity index 96% rename from projects/1.20/assets/minecraft/minecraft/textures/font/2em-dash.png rename to projects/1.20/assets/minecraft/minecraft/textures/font/2em_dash.png index b683b4dd420e946726d3e92b40b28fe0129dd391..e8291ce5ab02b1c27575af310e60ba5fce84d609 100644 GIT binary patch delta 78 zcmeAb>lNE@oXc$^FM|TlkpujTTK{f0mA;_XYJ1RA@4=FtQyDu2421$2?sm+5vdg)J iLvX$v0|UeV|I7>vkF%Q==2zGPxeT7JelF{r5}E+Qd>sz} delta 78 zcmeAb>lNE@oXgFTmqCH&=mq;G&JXW5TRhk$8^x-h$*6vIEssY_$HWe%7jAD Date: Fri, 8 Sep 2023 16:05:07 +0800 Subject: [PATCH 04/22] Synchronize README format --- projects/1.20-fabric/README.md | 59 ---------------------------------- projects/1.20/README.md | 59 ---------------------------------- 2 files changed, 118 deletions(-) delete mode 100644 projects/1.20-fabric/README.md delete mode 100644 projects/1.20/README.md diff --git a/projects/1.20-fabric/README.md b/projects/1.20-fabric/README.md deleted file mode 100644 index c91f0d7d0662..000000000000 --- a/projects/1.20-fabric/README.md +++ /dev/null @@ -1,59 +0,0 @@ -![pack.png](https://i.loli.net/2018/02/18/5a8974407b453.png) ---- - -| CurseForge 下载量 | 支持版本 | 翻译进度 | Github Actions | 最新快照版本 | -| :--: | :--: | :--: | :--: | :--: | -| [![CurseForge](http://cf.way2muchnoise.eu/full_simplified-chinese-localization-resource-package_downloads.svg)](https://minecraft.curseforge.com/projects/simplified-chinese-localization-resource-package) | [![CurseForge](http://cf.way2muchnoise.eu/versions/simplified-chinese-localization-resource-package.svg)](https://minecraft.curseforge.com/projects/simplified-chinese-localization-resource-package) | ![weblate](https://weblate-t.exz.me/widgets/langpack/-/svg-badge.svg) | ![Packer](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/workflows/Packer/badge.svg?branch=1.12.2) | [![GitHub release](https://img.shields.io/github/release/CFPAOrg/Minecraft-Mod-Language-Package.svg)](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/releases/latest) | - -## 仓库说明 - -这是 Minecraft 模组汉化项目的仓库,本项目目前采用 Weblate 平台进行模组项目翻译;
-用以解决模组作者不接收汉化、汉化提交更新速度慢等诸多问题;
-想要参与翻译?请访问我们的官方网站,并仔细阅读相关事宜以加入我们:
-### - -直接向本仓库提交 PR 亦可; - -你在翻译时, 应先了解需注意的有关事项,具体参见:[《Minecraft Mod简体中文翻译规范与指南》](https://github.com/Meow-J/Mod-Translation-Styleguide/blob/master/README.md)。 - -## 授权 - -本作品采用 [知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/)([简体中文](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh))进行许可,协议全文可 [在此](./LICENSE) 找到。
- -## 使用方式 - -点击 [此处](https://minecraft.curseforge.com/projects/simplified-chinese-localization-resource-package) 可打开 CurseForge 页面下载 release 版本资源包。
-点击 [此处](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/releases/latest) 可以下载快照版本资源包。
-只需要像**普通材质包**一样,在游戏中加载上该资源包,即可拥有汉化。建议装上该资源包后重启游戏,以避免出现其他问题。 - -## 相关信息 - -**目前的翻译计划是什么样的呢?我可以递交想翻译的列表么?**
-目前已根据在 CurseForge 网站上的受欢迎程度,选取了 1.16.5 版本下载了 1000 多个模组。如果你有什么想要额外添加翻译的模组,可以通过我们的 [问题追踪器](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/issues) 递交意见,或者直接通过邮箱递交意见或建议。
-其他版本目前还暂时没有涉足计划(不过 1.7.10 应该是不会做了)。 - -关于具体的宣传,可以参见 [MCBBS 推广宣传帖](http://www.mcbbs.net/thread-774087-1-1.html); - -关于整个事情的经过,可以查看酒石酸菌的 [博客帖子](https://baka943.coding.me/2018/01/03/2018-01-03-AnIntroForWeblate/); - -**你们是怎么做到流水线式的翻译的?**
-emmmm,原理其实很简单。
- -- 通过爬虫爬取 CurseForge 的热门模组; -- 脚本推送回 GitHub 仓库; -- Weblate 检测到仓库变动,自动抓取 GitHub 变动; -- 翻译人员在 Weblate 上翻译,Weblate 自动推回到 GitHub; -- Github Actions 检测到仓库变动,自动构建并打包; -- Github Actions 自动发布到 GitHub 的 release 上,以供下载; - -## 鸣谢 - -感谢 `phi` 搭建出了 Weblate 服务器,还实现了机翻功能;
-感谢 `Summpot`,`Nullpinter` 制作了新版本的 C# 爬虫;
-感谢 `PeakXing` 制作的 logo;
-感谢 `雪尼`、`FledgeXu`、`asdflj` 等在内的诸多人的意见和建议;
-感谢本项目的最初贡献者 `Aemande123`,`DYColdWind`,`Snownee`,`yuanjie000`,`forestbat`,`3TUSK`,`SihenZhang`,`MoXiaoFreak`,`gloomy_banana`,`yuanjie000`,`exia00125`,`luckyu19` 提供的汉化。(排名不分先后)
-感谢玩家 `R_liu` 提供的拔刀剑本地化;
-资源包中镶嵌了 `3TUSK` 提供的 [全角标点修复文件](./project/assets/minecraft/readme.md);
-最后感谢那些参与翻译,并致力于本地化推广的各位玩家,你们辛苦了。
-在本仓库的 [Contributors](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/graphs/contributors) 页面可以查看所有翻译贡献者。 diff --git a/projects/1.20/README.md b/projects/1.20/README.md deleted file mode 100644 index c91f0d7d0662..000000000000 --- a/projects/1.20/README.md +++ /dev/null @@ -1,59 +0,0 @@ -![pack.png](https://i.loli.net/2018/02/18/5a8974407b453.png) ---- - -| CurseForge 下载量 | 支持版本 | 翻译进度 | Github Actions | 最新快照版本 | -| :--: | :--: | :--: | :--: | :--: | -| [![CurseForge](http://cf.way2muchnoise.eu/full_simplified-chinese-localization-resource-package_downloads.svg)](https://minecraft.curseforge.com/projects/simplified-chinese-localization-resource-package) | [![CurseForge](http://cf.way2muchnoise.eu/versions/simplified-chinese-localization-resource-package.svg)](https://minecraft.curseforge.com/projects/simplified-chinese-localization-resource-package) | ![weblate](https://weblate-t.exz.me/widgets/langpack/-/svg-badge.svg) | ![Packer](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/workflows/Packer/badge.svg?branch=1.12.2) | [![GitHub release](https://img.shields.io/github/release/CFPAOrg/Minecraft-Mod-Language-Package.svg)](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/releases/latest) | - -## 仓库说明 - -这是 Minecraft 模组汉化项目的仓库,本项目目前采用 Weblate 平台进行模组项目翻译;
-用以解决模组作者不接收汉化、汉化提交更新速度慢等诸多问题;
-想要参与翻译?请访问我们的官方网站,并仔细阅读相关事宜以加入我们:
-### - -直接向本仓库提交 PR 亦可; - -你在翻译时, 应先了解需注意的有关事项,具体参见:[《Minecraft Mod简体中文翻译规范与指南》](https://github.com/Meow-J/Mod-Translation-Styleguide/blob/master/README.md)。 - -## 授权 - -本作品采用 [知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/)([简体中文](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh))进行许可,协议全文可 [在此](./LICENSE) 找到。
- -## 使用方式 - -点击 [此处](https://minecraft.curseforge.com/projects/simplified-chinese-localization-resource-package) 可打开 CurseForge 页面下载 release 版本资源包。
-点击 [此处](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/releases/latest) 可以下载快照版本资源包。
-只需要像**普通材质包**一样,在游戏中加载上该资源包,即可拥有汉化。建议装上该资源包后重启游戏,以避免出现其他问题。 - -## 相关信息 - -**目前的翻译计划是什么样的呢?我可以递交想翻译的列表么?**
-目前已根据在 CurseForge 网站上的受欢迎程度,选取了 1.16.5 版本下载了 1000 多个模组。如果你有什么想要额外添加翻译的模组,可以通过我们的 [问题追踪器](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/issues) 递交意见,或者直接通过邮箱递交意见或建议。
-其他版本目前还暂时没有涉足计划(不过 1.7.10 应该是不会做了)。 - -关于具体的宣传,可以参见 [MCBBS 推广宣传帖](http://www.mcbbs.net/thread-774087-1-1.html); - -关于整个事情的经过,可以查看酒石酸菌的 [博客帖子](https://baka943.coding.me/2018/01/03/2018-01-03-AnIntroForWeblate/); - -**你们是怎么做到流水线式的翻译的?**
-emmmm,原理其实很简单。
- -- 通过爬虫爬取 CurseForge 的热门模组; -- 脚本推送回 GitHub 仓库; -- Weblate 检测到仓库变动,自动抓取 GitHub 变动; -- 翻译人员在 Weblate 上翻译,Weblate 自动推回到 GitHub; -- Github Actions 检测到仓库变动,自动构建并打包; -- Github Actions 自动发布到 GitHub 的 release 上,以供下载; - -## 鸣谢 - -感谢 `phi` 搭建出了 Weblate 服务器,还实现了机翻功能;
-感谢 `Summpot`,`Nullpinter` 制作了新版本的 C# 爬虫;
-感谢 `PeakXing` 制作的 logo;
-感谢 `雪尼`、`FledgeXu`、`asdflj` 等在内的诸多人的意见和建议;
-感谢本项目的最初贡献者 `Aemande123`,`DYColdWind`,`Snownee`,`yuanjie000`,`forestbat`,`3TUSK`,`SihenZhang`,`MoXiaoFreak`,`gloomy_banana`,`yuanjie000`,`exia00125`,`luckyu19` 提供的汉化。(排名不分先后)
-感谢玩家 `R_liu` 提供的拔刀剑本地化;
-资源包中镶嵌了 `3TUSK` 提供的 [全角标点修复文件](./project/assets/minecraft/readme.md);
-最后感谢那些参与翻译,并致力于本地化推广的各位玩家,你们辛苦了。
-在本仓库的 [Contributors](https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/graphs/contributors) 页面可以查看所有翻译贡献者。 From 96151dbd57eba09bd77fd3afc93fe0375601f445 Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Fri, 8 Sep 2023 23:58:36 +0800 Subject: [PATCH 05/22] Initial commit --- src/Packer/Extensions/ArchiveExtension.cs | 63 ++--------- src/Packer/Extensions/DirectoryExtension.cs | 10 ++ src/Packer/Lib.cs | 109 ++++++-------------- src/Packer/Models/Config.cs | 4 +- src/Packer/Models/IResourceFileProvider.cs | 59 +++++++++++ src/Packer/Models/Providers/LanguageFile.cs | 66 ++++++++++++ src/Packer/Models/Providers/RawFile.cs | 64 ++++++++++++ src/Packer/Models/Providers/TextFile.cs | 78 ++++++++++++++ src/Packer/Packer.csproj | 2 + src/Packer/Program.cs | 73 ++++++++++--- src/Packer/Utils.cs | 23 +++-- 11 files changed, 392 insertions(+), 159 deletions(-) create mode 100644 src/Packer/Models/IResourceFileProvider.cs create mode 100644 src/Packer/Models/Providers/LanguageFile.cs create mode 100644 src/Packer/Models/Providers/RawFile.cs create mode 100644 src/Packer/Models/Providers/TextFile.cs diff --git a/src/Packer/Extensions/ArchiveExtension.cs b/src/Packer/Extensions/ArchiveExtension.cs index a8f373f02bcb..706904210584 100644 --- a/src/Packer/Extensions/ArchiveExtension.cs +++ b/src/Packer/Extensions/ArchiveExtension.cs @@ -1,5 +1,6 @@ using Packer.Models; using Serilog; +using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; @@ -13,24 +14,6 @@ namespace Packer.Extensions /// static public class ArchiveExtension { - /// - /// 按要求写入语言文件,并加Log - /// - /// 压缩文件 - /// 目标路径 - /// 写入内容 - /// - public static async Task CreateLangFile(this ZipArchive archive, string destination, string content) - { - destination = destination.NormalizePath(); - Log.Information("正在添加 {0}", destination); - using var writer = new StreamWriter( - archive.CreateEntry(destination) - .Open()); - await writer.WriteAsync(content); - writer.Flush(); // 确保一下 - } - /// /// 初始化压缩包

/// 包括压缩包的基础文件 @@ -63,48 +46,18 @@ public static void Initialize(this ZipArchive archive, Config config) Log.Information("初始化完成"); } - /// - /// 写入选出的Asset们 + /// 校验将要传入压缩包的的文件是否存在重名
///
- /// 压缩文件 - /// 选出的内容 - /// - public static async Task WriteContent(this ZipArchive archive, IEnumerable content) - { - Log.Information("添加处理后的文件"); - - - var tasks = content.SelectMany(asset => asset.contents.Select(file => archive.CreateLangFile(Path.Combine("assets", - asset.domainName, - file.RelativePath), - file.StringifiedContent))); - - await Task.WhenAll(content.SelectMany( - asset => asset.contents.Select( - file => archive.CreateLangFile(destination: Path.Combine("assets", - asset.domainName, - file.RelativePath), - content: file.StringifiedContent)))); - Log.Information("添加完毕"); - } - - /// - /// 写入非文本处理的文件 - /// - /// 压缩文件 - /// 非文本处理的文件 - public static void WriteBypassed(this ZipArchive archive, Dictionary bypassed) + /// 所查询的压缩包 + /// 所查询的路径 + /// 传入文件存在重名。 + public static void ValidateEntryDistinctness(this ZipArchive archive, string entryName) { - Log.Information("添加未经处理的文件"); - foreach (var pair in bypassed) + if (archive.GetEntry(entryName) != null) { - var normalizedEntryName = pair.Value.NormalizePath(); - Log.Information("正在添加 {0}", normalizedEntryName); - archive.CreateEntryFromFile(sourceFileName: pair.Key, - entryName: normalizedEntryName); + throw new InvalidOperationException($"An entry named {entryName} already exists."); } - Log.Information("添加完毕"); } } } diff --git a/src/Packer/Extensions/DirectoryExtension.cs b/src/Packer/Extensions/DirectoryExtension.cs index ac5a3e3e63ad..130854064443 100644 --- a/src/Packer/Extensions/DirectoryExtension.cs +++ b/src/Packer/Extensions/DirectoryExtension.cs @@ -13,7 +13,17 @@ namespace Packer.Extensions ///
public static class DirectoryExtension { + public static IEnumerable EnumerateProviders + (this DirectoryInfo namespaceDirectory, + Config config) + // 其实这个我还没想好要不要叫Enumerate,毕竟可能不一定能做成Linq的样子 + { + var policyFile = namespaceDirectory.GetFiles("packer-policy.json").FirstOrDefault(); + + var policy = Utils.RetrieveStrategy(policyFile); + throw null; + } /// /// 从[namespace]生成所需的Asset对象,采用本目录下放置的配置文件 diff --git a/src/Packer/Lib.cs b/src/Packer/Lib.cs index 1513f6be9bd7..d4e8c61b587a 100644 --- a/src/Packer/Lib.cs +++ b/src/Packer/Lib.cs @@ -12,89 +12,38 @@ namespace Packer static class Lib { /// - /// 从主库中选出所需文本。 + /// 从主库中选出所需文本 /// /// 所使用的配置 - /// 传出非文本处理的文件 + /// + /// 需要包含的模组列表,按模组唯一标识符
+ /// 若为,表示包含所有模组 + /// /// - public static IEnumerable RetrieveContent(Config config, out Dictionary unprocessed) - { - // 警告:下面的代码中,有部分变量的名称并不规范!远期可能会调整这一部分。 + public static IEnumerable RetrieveContent( + Config config, + IEnumerable? targetModIdentifiers) - // 注:仓库的文件结构如下:(仅考虑主要翻译文件) - // projects//assets////path/to/the/file - // 其中, 与 config.Version 一致 - // 是唯一的,但 都不是唯一的 - // 目标文件层级: - // assets///path/to/the/file - // - // 在目标层级以外的文件不支持处理,需要作为基础文件加入 - - // 预备工作 - Log.Information("开始生成待打包的文件"); - var bypassed = new Dictionary(); // 文件完整路径 -> 压缩包中的完整路径 - var result = new Dictionary(); // domain -> 该domain对应的Asset对象 - var existingDomains = new Dictionary(); // domain -> 模组名 - - // 下面开始检索模组 - // 以后可能会用更好看的linq语法写,但是现在就这样了 - var mods = new DirectoryInfo($"./projects/{config.Version}/assets") - .EnumerateDirectories() // assets/ 的下级文件夹 - .Select(modDirectory => new Mod() - { - modName = modDirectory.Name, - assets = modDirectory - .EnumerateDirectories() // / 的下级文件夹 - .Select(assetDirectory => new Asset() - { - domainName = assetDirectory.Name, - contents = assetDirectory.AggregateAssetFiles(config, ref bypassed) - }) - }); - foreach (var mod in mods) - { - var name = mod.modName; - if (!mod.assets.Any()) continue; // 没有 asset 的情况 - - foreach (var asset in mod.assets) - { - var domain = asset.domainName; - if (config.ModBlackList.Contains(name)) - { - Log.Information("跳过了黑名单中的 mod:{0}(asset-domain:{1})", name, domain); - continue; - } - if (config.DomainBlackList.Contains(domain)) - { - Log.Information("跳过了黑名单中的 asset-domain:{0}(对应 mod:{1})", domain, name); - continue; - } - Log.Information("正在处理 {0}(asset-domain:{1})", name, domain); - - // 强制中止打包,防止异常文件流出 - if(!Regex.IsMatch(domain, @"^[a-z0-9_\-.]+$", RegexOptions.Singleline)) - throw new ArgumentOutOfRangeException(paramName: nameof(domain), - actualValue: domain, - message: "非法的命名空间名称。强制中止"); - - if (!existingDomains.ContainsKey(domain)) - { - Log.Information("未检测到重合。直接加入"); - result.Add(domain, asset); - Log.Information("向 asset-domain 映射表中加入:{0} -> {1}", domain, name); - existingDomains.Add(domain, name); - } - else - { - Log.Warning("检测到 asset-domain 与 {0} 重合", existingDomains[domain]); - result.Remove(domain, out var existing); - result.Add(domain, existing.Combine(asset)); - } - } - } - Log.Information("文件列表生成完毕"); - unprocessed = bypassed; // 正式传出非文本文件 - return result.Select(_ => _.Value); - } + // 成功实现了没分号的C#语句...这就是查询表达式吗( + => from modDirectory in new DirectoryInfo($"./projects/{config.Version}/assets") + .EnumerateDirectories() + let modIdentifier = modDirectory.Name + // 模组筛选,按模组标识符 + where targetModIdentifiers is null // 未提供列表,全部打包 + || targetModIdentifiers.Contains(modIdentifier) // 有列表,仅打包列表中的项 + from namespaceDirectory in modDirectory.EnumerateDirectories() + let namespaceName = namespaceDirectory.Name + // 检查命名空间格式,拒绝错误格式 + // 但是写成表达式以后,没法现场丢异常了... + where !Regex.IsMatch(namespaceName, + @"^[a-z0-9_\-.]+$", + RegexOptions.Singleline) + from provider in namespaceDirectory.EnumerateProviders(config) + // 合并文件;我猜没写错 + group provider by namespaceName into namespaceGroup + select namespaceGroup + .Aggregate(seed: null as IResourceFileProvider, // 好家伙 类型推断系统推断不出TAggregate + (accumlate, next) // 为什么这个参数叫func不叫accumlator或者aggregator... + => next.Append(accumlate, overrideExisting: false)); } } diff --git a/src/Packer/Models/Config.cs b/src/Packer/Models/Config.cs index 2b5fc311abf9..ddbd298ab526 100644 --- a/src/Packer/Models/Config.cs +++ b/src/Packer/Models/Config.cs @@ -7,7 +7,7 @@ namespace Packer /// 配置文件 /// 主要config/packer.json加载 ///
- public class Config + public struct Config { /// /// 打包的目标版本 @@ -55,5 +55,7 @@ public class Config /// [JsonPropertyName("replacementMap")] public Dictionary CharatcerReplacement { get; set; } + + public Dictionary DestinationReplacement { get; set; } } } diff --git a/src/Packer/Models/IResourceFileProvider.cs b/src/Packer/Models/IResourceFileProvider.cs new file mode 100644 index 000000000000..3b5987ff8f7a --- /dev/null +++ b/src/Packer/Models/IResourceFileProvider.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.IO.Compression; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Packer.Models +{ + /// + /// 表示可以被添加到资源包中的内容
+ /// 可以有很多实现:文本文件、非文本文件、组合表...... + ///
+ /// + /// 这是IMMUTABLE! + /// + public interface IResourceFileProvider + { + /// + /// 在本提供器的基础上,尝试添加新提供器中的内容 + /// + /// 需要添加的新 + /// 冲突解决方案。若为,保留本文件的内容;否则,保留新文件的内容 + /// 合并得到的新 + public IResourceFileProvider Append(IResourceFileProvider? incoming, bool overrideExisting = false) + // 默认实现 + => overrideExisting + ? (incoming ?? this) // 如果来源是null,无论冲突配置如何,都不应返回null + : this; + + /// + /// 在该提供器的内容中执行替换 + /// + /// 替换的匹配模式,使用 + /// 替换文本 + /// 替换得到的新 + public IResourceFileProvider ReplaceContent(string searchPattern, string replacement) + // 默认实现 + => this; + + /// + /// 在该提供器的目标地址中执行替换 + /// + /// 替换的匹配模式,使用 + /// 替换文本 + /// 替换得到的新 + public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) + // 默认实现 + => this; + + /// + /// 将该提供器的内容写入到资源包的正确位置 + /// + /// + /// + /// 资源包中已有同名文件 + public Task WriteToArchive(ZipArchive archive); + } +} diff --git a/src/Packer/Models/Providers/LanguageFile.cs b/src/Packer/Models/Providers/LanguageFile.cs new file mode 100644 index 000000000000..5ca5916797d0 --- /dev/null +++ b/src/Packer/Models/Providers/LanguageFile.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.IO.Compression; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Packer.Models.Providers +{ + + + + public enum LanguageFileFormat + { + Lang = 0, + Json = 1 + } + + + internal class TermMappingProvider : IResourceFileProvider + { + public Dictionary Map { get; } + + public TermMappingProvider(Dictionary map) + { + Map = map; + } + + public IResourceFileProvider Append(IResourceFileProvider? incoming, bool overrideExisting = false) + { + if (incoming is not TermMappingProvider) + throw new ArgumentException($"Argument not an instance of {typeof(TermMappingProvider)}.", + nameof(incoming)); + var inProvider = incoming as TermMappingProvider; + + if (inProvider is null) throw new ArgumentNullException(nameof(incoming)); + + var (baseMap, inMap) = overrideExisting + ? (Map, inProvider.Map) + : (inProvider.Map, Map); // 交换顺序 + + foreach (var pair in inMap) + { + baseMap.TryAdd(pair.Key, pair.Value); + } + + return new TermMappingProvider(baseMap); + } + + public IResourceFileProvider ReplaceContent(string searchPattern, string replacement) + { + throw new NotImplementedException(); + } + + public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) + { + throw new NotImplementedException(); + } + + public Task WriteToArchive(ZipArchive archive) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Packer/Models/Providers/RawFile.cs b/src/Packer/Models/Providers/RawFile.cs new file mode 100644 index 000000000000..94efbeb03e41 --- /dev/null +++ b/src/Packer/Models/Providers/RawFile.cs @@ -0,0 +1,64 @@ +using Packer.Extensions; +using Serilog; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Packer.Models.Providers +{ + /// + /// 一般文件的提供器。不提供合并、替换支持 + /// + /// + /// 对于非文本文件,使用该类 + /// + public class RawFile : IResourceFileProvider + { + /// + /// 文件的源地址 + /// + public FileInfo SourceFile { get; } + + /// + /// 目标地址 + /// + public string Destination { get; } + + /// + /// 从给定的文件引用构造提供器 + /// + /// 源文件的引用 + /// 目标地址 + public RawFile(FileInfo sourceFile, string destination) + { + SourceFile = sourceFile; + Destination = destination; + } + + + /// + public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) + => new RawFile(SourceFile, + Regex.Replace(Destination, searchPattern, replacement)); + + /// + public async Task WriteToArchive(ZipArchive archive) + { + var destination = Destination.NormalizePath(); + Log.Information("正在添加 {0}", destination); + + archive.ValidateEntryDistinctness(destination); + + // 为什么这ZipArchive.CreateEntryFromFile没有Async变种...只有手动实现了 + using var source = SourceFile.OpenRead(); + using var entry = archive.CreateEntry(destination) + .Open(); + await source.CopyToAsync(entry); + } + } +} diff --git a/src/Packer/Models/Providers/TextFile.cs b/src/Packer/Models/Providers/TextFile.cs new file mode 100644 index 000000000000..18072b4c9670 --- /dev/null +++ b/src/Packer/Models/Providers/TextFile.cs @@ -0,0 +1,78 @@ +using Packer.Extensions; +using Serilog; +using System.IO; +using System.IO.Compression; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Packer.Models.Providers +{ + /// + /// 文本文件的提供器,支持内容替换,但不支持文件合并 + /// + /// + /// 对于普通的文本文件,使用该类 + /// + public class TextFile : IResourceFileProvider + { + /// + /// 提供器所携带的文本内容 + /// + public string Content { get; } + /// + /// 目标地址 + /// + public string Destination { get; } + + /// + /// 从给定的构造提供器。 + /// + /// 读取源 + /// 目标地址 + public TextFile(Stream stream, string destination) + { + Destination = destination; + using var reader = new StreamReader(stream, Encoding.UTF8); + Content = reader.ReadToEnd(); + } + + /// + /// 从给定的文本内容构造提供器。 + /// + /// 来源文本 + /// 目标地址 + public TextFile(string content, string destination) + { + Content = content; + Destination = destination; + } + + + public IResourceFileProvider ReplaceContent(string searchPattern, string replacement) + => new TextFile(Regex.Replace(Content, + searchPattern, + replacement), + Content); + /// + public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) + => new TextFile(Content, + Regex.Replace(Destination, + searchPattern, + replacement)); + /// + public async Task WriteToArchive(ZipArchive archive) + { + var destination = Destination.NormalizePath(); + Log.Information("正在添加 {0}", destination); + + archive.ValidateEntryDistinctness(destination); + + using var writer = new StreamWriter( + archive.CreateEntry(destination) + .Open(), + Encoding.UTF8); + await writer.WriteAsync(Content); + } + } +} diff --git a/src/Packer/Packer.csproj b/src/Packer/Packer.csproj index db77fb7f587b..3e7ae5065b02 100644 --- a/src/Packer/Packer.csproj +++ b/src/Packer/Packer.csproj @@ -3,6 +3,8 @@ Exe net7.0 + enable + none diff --git a/src/Packer/Program.cs b/src/Packer/Program.cs index 0b598b35ea89..aa1b8ebf718d 100644 --- a/src/Packer/Program.cs +++ b/src/Packer/Program.cs @@ -1,8 +1,11 @@ using Packer.Extensions; +using Packer.Models; using Serilog; using System; using System.IO; using System.IO.Compression; +using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Packer @@ -10,7 +13,7 @@ namespace Packer class Program { // 由于某些魔法,这里可以直接加参数 - public static async Task Main(string version = null) + public static async Task Main(string version, string[]? targets) { Log.Logger = new LoggerConfiguration() .Enrich.FromLogContext() @@ -19,31 +22,69 @@ public static async Task Main(string version = null) .CreateLogger(); if (version is null) - { throw new ArgumentNullException(nameof(version)); - } + var targetModIdentifiers = targets?.ToList(); var config = await Utils.RetrieveConfig(configTemplate: "./config/packer/{0}.json", version: version); - // Packer输出的文件名,可以随时更改 - string packName = $"./Minecraft-Mod-Language-Package-{config.Version}.zip"; - Log.Information("开始对版本 {0} 的打包", config.Version); - await using var stream = File.Create(packName); - var archive = new ZipArchive(stream, ZipArchiveMode.Update, leaveOpen: true); - archive.Initialize(config); + var rawQuery = Lib.RetrieveContent(config, targetModIdentifiers); + var query = // 这就是查询表达式吗( + from modDirectory in new DirectoryInfo($"./projects/{config.Version}/assets") + .EnumerateDirectories() + let modIdentifier = modDirectory.Name + // 模组筛选,按模组标识符 + where targetModIdentifiers is null // 未提供列表,全部打包 + || targetModIdentifiers.Contains(modIdentifier) // 有列表,仅打包列表中的项 + where !config.ModBlackList.Contains(modIdentifier) // 没有被明确排除 + from namespaceDirectory in modDirectory.EnumerateDirectories() + let namespaceName = namespaceDirectory.Name + where !config.DomainBlackList.Contains(modIdentifier) // 没有被明确排除 + // 检查命名空间格式,拒绝错误格式 + // 但是写成表达式以后,没法现场丢异常了... + where !Regex.IsMatch(namespaceName, + @"^[a-z0-9_\-.]+$", + RegexOptions.Singleline) + from provider in namespaceDirectory.EnumerateProviders(config) + group provider by namespaceName into namespaceGroup// 合并文件;我猜没写错 + select namespaceGroup + .Aggregate(seed: null as IResourceFileProvider, // 好家伙 类型推断系统推断不出TAggregate + (accumlate, next) // 为什么这个参数叫func不叫accumlator或者aggregator... + => next.Append(accumlate, overrideExisting: false)) into provider + // 替换内容中的特殊字符 + select config.CharatcerReplacement + .Aggregate(seed: provider, + (accumlate, replacement) + => accumlate.ReplaceContent( + replacement.Key, + replacement.Value)) into provider + // 替换目标路径中的对象 + select config.DestinationReplacement + .Aggregate(seed: provider, + (accumlate, replacement) + => accumlate.ReplaceContent( + replacement.Key, + replacement.Value)); - await archive.WriteContent(Lib.RetrieveContent(config, out var bypassed)); - archive.WriteBypassed(bypassed); // 将跳过的文件一并加入 + // TODO 把初始化内容也做成IEnumerable,尤其是pack.mcmeta + // var initializers = from fileName in config.FilesToInitialize select new ... - Log.Information("对版本 {0} 的打包结束", config.Version); - archive.Dispose(); // 关闭压缩文档,不关闭流 + string packName = $"./Minecraft-Mod-Language-Package-{config.Version}.zip"; + await using var stream = File.Create(packName); + using (var archive = new ZipArchive(stream, ZipArchiveMode.Update, leaveOpen: true)) + { + archive.Initialize(config); + await Task.WhenAll(from provider in query select provider.WriteToArchive(archive)); + } - // 临时操作 - File.WriteAllText($"./{config.Version}.md5", stream.ComputeMD5()); - stream.Dispose(); + Log.Information("对版本 {0} 的打包结束。共包含了 {1} 个文件", + config.Version, + query.Count()); + var md5 = stream.ComputeMD5(); + Log.Information("打包文件的 MD5 值:{0}", md5); + File.WriteAllText($"./{config.Version}.md5", md5); } } } diff --git a/src/Packer/Utils.cs b/src/Packer/Utils.cs index 34c3b732b4e4..0fb99b660bc0 100644 --- a/src/Packer/Utils.cs +++ b/src/Packer/Utils.cs @@ -26,13 +26,22 @@ public static async Task RetrieveConfig(string configTemplate, string ve return JsonSerializer.Deserialize(reader); } - public static PackerStrategy RetrieveStrategy(FileInfo file) - => file is null - ? new PackerStrategy { Type = PackerStrategyType.NoAction } // 默认类型 - : JsonSerializer.Deserialize(file.OpenText().ReadToEnd(), new JsonSerializerOptions - { - Converters = { new JsonStringEnumConverter() } - }); + public static PackerStrategy RetrieveStrategy(FileInfo? file) + { + if (file is null) + { + return new PackerStrategy { Type = PackerStrategyType.NoAction }; + } + else + { + var result = JsonSerializer.Deserialize( + file.OpenText().ReadToEnd(), + new JsonSerializerOptions + { + Converters = { new JsonStringEnumConverter() } + }); + } + } /// /// 将两个带有TranslatedFile的列表合并,对冲突项按照target优先进行合并。 From ab639dd4d7d8215fda44964600171c4da1c9c558 Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sun, 17 Sep 2023 11:41:00 +0800 Subject: [PATCH 06/22] 2 --- src/Packer/Extensions/ContentExtension.cs | 94 ++-- src/Packer/Extensions/DirectoryExtension.cs | 422 +++++++++------- src/Packer/Extensions/SerializingExtension.cs | 199 ++++---- src/Packer/Lib.cs | 94 ++-- src/Packer/Models/Config.cs | 4 +- src/Packer/Models/IResourceFileProvider.cs | 15 +- src/Packer/Models/Mod.cs | 90 ++-- .../Models/Providers/CompositionProvider.cs | 34 ++ src/Packer/Models/Providers/LanguageFile.cs | 116 +++-- src/Packer/Models/Providers/McMetaProvider.cs | 22 + src/Packer/Models/Providers/RawFile.cs | 9 +- .../Models/Providers/TermMappingProvider.cs | 167 +++++++ src/Packer/Models/Providers/TextFile.cs | 15 +- src/Packer/Models/TranslatedFile.cs | 458 +++++++++--------- src/Packer/Program.cs | 36 +- src/Packer/Utils.cs | 117 ++--- 16 files changed, 1126 insertions(+), 766 deletions(-) create mode 100644 src/Packer/Models/Providers/CompositionProvider.cs create mode 100644 src/Packer/Models/Providers/McMetaProvider.cs create mode 100644 src/Packer/Models/Providers/TermMappingProvider.cs diff --git a/src/Packer/Extensions/ContentExtension.cs b/src/Packer/Extensions/ContentExtension.cs index 97b53a91ff79..fa41c4d34dce 100644 --- a/src/Packer/Extensions/ContentExtension.cs +++ b/src/Packer/Extensions/ContentExtension.cs @@ -12,8 +12,21 @@ namespace Packer.Extensions /// /// 对字符串的一些拓展方法 /// - public static class ContentExtension + public static partial class ContentExtension { + [GeneratedRegex(@"^[a-z0-9_.-]+$", RegexOptions.Singleline)] + private static partial Regex ValidNamespaceRegex(); + + public static bool ValidateNamespace(this string namespaceName) + { + // 强行丢异常...行吧 + if (!ValidNamespaceRegex().IsMatch(namespaceName)) + throw new ArgumentOutOfRangeException(nameof(namespaceName), namespaceName, "Invalid namespace name."); + return true; + } + + + /// /// 将文件的目标路径正规化,以免各种加载出错 /// @@ -21,7 +34,6 @@ public static class ContentExtension /// public static string NormalizePath(this string path) => path.Replace('\\', '/') // 修正正反斜杠导致的压缩文件读取问题 - //.ToLower() // 确保大小写 * 由于语言类型需要大小写而禁用该条 ; /// @@ -37,37 +49,37 @@ public static string StripModName(this string path) return Path.Join(_.ToArray()); } - /// - /// 文本预处理

- /// 目前仅有特殊符号更换,但还是预留了空间 - ///
- /// 待处理的文本 - /// 文本种类,用于判断是否转义 - /// 所使用的配置 - /// - public static string Preprocess(this string content, FileCategory category, Config config) - { - // 特殊符号替换 - foreach (var mapping in config.CharatcerReplacement) - { - var escaped = JavaScriptEncoder.Default.Encode(mapping.Value); - if (content.Contains(mapping.Key)) - { - Log.Information("正在进行特殊符号替换:{0} -> {1}", mapping.Key, escaped); - } + ///// + ///// 文本预处理

+ ///// 目前仅有特殊符号更换,但还是预留了空间 + /////
+ ///// 待处理的文本 + ///// 文本种类,用于判断是否转义 + ///// 所使用的配置 + ///// + //public static string Preprocess(this string content, FileCategory category, Config config) + //{ + // // 特殊符号替换 + // foreach (var mapping in config.CharatcerReplacement) + // { + // var escaped = JavaScriptEncoder.Default.Encode(mapping.Value); + // if (content.Contains(mapping.Key)) + // { + // Log.Information("正在进行特殊符号替换:{0} -> {1}", mapping.Key, escaped); + // } - if ((category & FileCategory.JsonAlike) == FileCategory.JsonAlike) - { // 替换为 unicode 转义码 - content = content.Replace(mapping.Key, escaped); - } - else - { // 替换为 unicode 字符 - content = content.Replace(mapping.Key, mapping.Value); - } + // if ((category & FileCategory.JsonAlike) == FileCategory.JsonAlike) + // { // 替换为 unicode 转义码 + // content = content.Replace(mapping.Key, escaped); + // } + // else + // { // 替换为 unicode 字符 + // content = content.Replace(mapping.Key, mapping.Value); + // } - } - return content; - } + // } + // return content; + //} /// /// 判断文件是否需要跳过预处理

@@ -76,14 +88,8 @@ public static string Preprocess(this string content, FileCategory category, Conf /// 文件所在的位置 /// 所使用的配置 /// - public static bool NeedBypass(this string location, Config config) - { - foreach (var @namespace in config.BypassedNamespace) - { - if (location.StartsWith(@namespace + "/")) return true; - } - return false; - } + public static bool IsForceIncluded(this string location, Config config) + => config.ForceInclusionDomain.Any(_ => location.StartsWith(_ + '/')); /// /// 判断文件是否属于应跳过的语言 @@ -91,14 +97,8 @@ public static bool NeedBypass(this string location, Config config) /// 文件所在的位置 /// 所使用的配置 /// - public static bool IsTargetLang(this string location, Config config) - { - foreach (var lang in config.TargetLanguages) - { - if (location.Contains(lang, StringComparison.OrdinalIgnoreCase)) return true; - } - return false; - } + public static bool IsInTargetLanguage(this string location, Config config) + => config.TargetLanguages.Any(_ => location.Contains(_, StringComparison.OrdinalIgnoreCase)); // 临时方法 /// diff --git a/src/Packer/Extensions/DirectoryExtension.cs b/src/Packer/Extensions/DirectoryExtension.cs index 130854064443..b506663c0dc5 100644 --- a/src/Packer/Extensions/DirectoryExtension.cs +++ b/src/Packer/Extensions/DirectoryExtension.cs @@ -1,195 +1,293 @@ using Packer.Models; +using Packer.Models.Providers; using Serilog; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.Json; +using System.Text.RegularExpressions; namespace Packer.Extensions { + using EvaluatorReturnType = IEnumerable<(IResourceFileProvider provider, bool overrides)>; + using ParameterType = Dictionary; + + /// /// 用于处理\[namespace]层级的不同加载策略的拓展方法,以及一些辅助方法 /// - public static class DirectoryExtension + public static partial class DirectoryExtension { + [GeneratedRegex(@"^assets/[a-z0-9_.-]+/lang/[a-zA-Z0-9_-]+\.(?:json|lang)$", RegexOptions.Singleline)] + private static partial Regex LanguageFileRegex(); + + + /// + /// 加载策略所使用的标准方法代理 + /// + /// 加载的基准位置 + /// 采用的全局配置 + /// 局部打包配置的附加参数 + /// 一个,第一参数为提供器的目标 + public delegate EvaluatorReturnType + ProviderEvaluator(DirectoryInfo namespaceDirectory, + Config config, + Dictionary parameters); + + public static Dictionary functionTable = new() + { + { PackerStrategyType.NoAction, FromCurrentDirectory }, + { PackerStrategyType.CloneMissing, FromSpecifiedDirectory } // , + // ... + }; + public static IEnumerable EnumerateProviders - (this DirectoryInfo namespaceDirectory, - Config config) - // 其实这个我还没想好要不要叫Enumerate,毕竟可能不一定能做成Linq的样子 + (this DirectoryInfo namespaceDirectory, Config config) + => from enumeratedPair in namespaceDirectory.EnumerateRawProviders(config) + group enumeratedPair by enumeratedPair.provider.Destination into providerGroup + select providerGroup.Aggregate( + seed: null as IResourceFileProvider, + (accumlate, next) + => next.provider.ApplyTo(accumlate, next.overrides)) /* into provider + select provider.ReplaceDestination(@"(?<=^assets/)[^/]*(?=/)", + namespaceDirectory.Name) */ ;// WARNING:路径替换要做到具体方法里面! + + static EvaluatorReturnType EnumerateRawProviders(this DirectoryInfo namespaceDirectory, Config config) { var policyFile = namespaceDirectory.GetFiles("packer-policy.json").FirstOrDefault(); + var policyList = Utils.RetrieveStrategy(policyFile); - var policy = Utils.RetrieveStrategy(policyFile); - - throw null; + return from policy in policyList + from enumeratedPair in functionTable[policy.Type](namespaceDirectory, config, policy.Parameters) + select enumeratedPair; } - /// - /// 从[namespace]生成所需的Asset对象,采用本目录下放置的配置文件 - /// - /// 目标路径 - /// 采用的配置 - /// 未经处理的文件 - /// - public static IEnumerable AggregateAssetFiles(this DirectoryInfo assetPath, - Config config, - ref Dictionary bypassed) + ///// + ///// 从[namespace]生成所需的Asset对象,采用本目录下放置的配置文件 + ///// + ///// 目标路径 + ///// 采用的配置 + ///// 未经处理的文件 + ///// + //public static IEnumerable AggregateAssetFiles(this DirectoryInfo assetPath, + // Config config, + // ref Dictionary bypassed) + //{ + // // 读取局域配置文件;若为空,配置为“无操作”(直接处理文件) + // var policy = Utils.RetrieveStrategy(assetPath.GetFiles("packer-policy.json").FirstOrDefault()); + + // if (policy.Type != PackerStrategyType.NoAction) + // Log.Information("对asset-domain {2} 采用非标准检索策略:{0} w/ {1}", + // policy.Type, + // policy.Parameters, + // assetPath.Name); + + // // Delegate是个好东西 要不然这参数不知道要多长 + // // 不过,什么时候能支持集合字面量......这样子就甚至不用写类型了 + // // 目前支持的打包策略 + // Dictionary functionTable = new() + // { + // { PackerStrategyType.NoAction, FromImmediateDirectory }, + // { PackerStrategyType.PlainClone, FromIndirectDirectory }, + // { PackerStrategyType.CloneMissing, FromMixedDirectory }, + // { PackerStrategyType.BackPort, FromBackPort }, + // { PackerStrategyType.Patch, FromPatches } + // }; + // return functionTable[policy.Type](assetPath, config, ref bypassed, policy.Parameters); + //} + + + + static IResourceFileProvider CreateProviderFromFile(FileInfo file, string destination, Config config) { - // 读取局域配置文件;若为空,配置为“无操作”(直接处理文件) - var policy = Utils.RetrieveStrategy(assetPath.GetFiles("packer-policy.json").FirstOrDefault()); - - if (policy.Type != PackerStrategyType.NoAction) - Log.Information("对asset-domain {2} 采用非标准检索策略:{0} w/ {1}", - policy.Type, - policy.Parameters, - assetPath.Name); - - // Delegate是个好东西 要不然这参数不知道要多长 - // 不过,什么时候能支持集合字面量......这样子就甚至不用写类型了 - // 目前支持的打包策略 - Dictionary functionTable = new() + var extension = file.Extension; + if (file.Directory!.Name == "lang") { - { PackerStrategyType.NoAction, FromImmediateDirectory }, - { PackerStrategyType.PlainClone, FromIndirectDirectory }, - { PackerStrategyType.CloneMissing, FromMixedDirectory }, - { PackerStrategyType.BackPort, FromBackPort }, - { PackerStrategyType.Patch, FromPatches } + switch (extension) + { + case ".json": return JsonLanguageFile.Create(file, destination); + case ".lang": return LangLanguageFile.Create(file, destination); + }; + } + return extension switch + { + // 已知的文本文件类型 + ".txt" or ".json" or ".md" => TextFile.Create(file, destination), + _ => new RawFile(file, destination) }; - return functionTable[policy.Type](assetPath, config, ref bypassed, policy.Parameters); } - /// - /// 加载策略所使用的标准方法代理 - /// - /// 目标路径 - /// 采用的全局配置 - /// 不经处理的文件 - /// 局部打包配置的附加参数 - /// - public delegate IEnumerable Del(DirectoryInfo assetDirectory, + + + + + + static EvaluatorReturnType FromCurrentDirectory(DirectoryInfo namespaceDirectory, Config config, - ref Dictionary unprocessed, - Dictionary parameters); - - static IEnumerable FromMixedDirectory(DirectoryInfo assetDirectory, - Config config, - ref Dictionary unprocessed, - Dictionary parameters) - => Utils.MergeFiles(FromImmediateDirectory(assetDirectory, config, ref unprocessed, parameters), - FromIndirectDirectory(assetDirectory, config, ref unprocessed, parameters)); - - static IEnumerable FromBackPort(DirectoryInfo assetDirectory, - Config config, - ref Dictionary unprocessed, - Dictionary parameters) - => Utils.PortFiles(FromImmediateDirectory(assetDirectory, config, ref unprocessed, parameters), - FromIndirectDirectory(assetDirectory, config, ref unprocessed, parameters)); - - static IEnumerable FromIndirectDirectory(DirectoryInfo assetDirectory, - Config config, - ref Dictionary unprocessed, - Dictionary parameters) - => AggregateAssetFiles(new DirectoryInfo(parameters["source"].GetString()), config, ref unprocessed); - - static IEnumerable FromPatches(DirectoryInfo assetDirectory, - Config config, - ref Dictionary unprocessed, - Dictionary parameters) + ParameterType parameters) + => from candidate in namespaceDirectory.EnumerateFiles("*", SearchOption.AllDirectories) + let relativePath = Path.GetRelativePath(namespaceDirectory.FullName, + candidate.FullName) + .NormalizePath() + let destination = Path.Combine(namespaceDirectory.Name, + relativePath) + .NormalizePath() + let domain = relativePath.Split('/')[0] + where relativePath != "packer-policy.json" // TODO:其他文件 // 策略文件本身不包含 + where destination.IsInTargetLanguage(config) // 含有正确的语言标记 + || relativePath.IsForceIncluded(config) // 强制包含 + let provider = CreateProviderFromFile(candidate, destination, config) + select (provider, DoesOverride(parameters)); + + static EvaluatorReturnType FromSpecifiedDirectory(DirectoryInfo namespaceDirectory, + Config config, + ParameterType parameters) { - var reference = FromIndirectDirectory(assetDirectory, config, ref unprocessed, parameters) - .ToDictionary(_ => _.RelativePath); - var patchList = JsonSerializer.Deserialize>(parameters["patches"]); - foreach (var patch in patchList) - { - Log.Information("对文件 {0} 应用 {1} 处的 patch。", patch.Key, patch.Value); - reference.Remove(patch.Key, out var target); - var patchText = string.Join('\n', File.ReadAllLines(patch.Value)); // 不要问我为什么D-M-P默认换行是LF - reference.Add(patch.Key, target.ApplyPatch(patchText)); - } - return reference.Values; + var redirect = parameters["source"].GetString(); + var namespaceName = namespaceDirectory.Name; + namespaceName.ValidateNamespace(); + var redirectDirectory = new DirectoryInfo(redirect!); + return from candidate in redirectDirectory.EnumerateRawProviders(config) + let provider = candidate.provider + .ReplaceDestination(@"^(?<=^assets/)[^/]*(?=/)", + namespaceName) + select (provider, DoesOverride(parameters)); } - // 目前所有策略的终点方法 - static IEnumerable FromImmediateDirectory(DirectoryInfo assetDirectory, - Config config, - ref Dictionary unprocessed, - Dictionary parameters) + + + + static bool DoesOverride(ParameterType parameters) { - var bypassed = unprocessed; - var result = assetDirectory.EnumerateFiles("*", SearchOption.AllDirectories) // / 的下级文件 - .Select(file => - { // 这里开始真正的检索。被跳过的文本用 null 代替 - var prefixLength = assetDirectory.FullName.Length; - var relativePath = file.FullName[(prefixLength + 1)..] - .Replace('\\', '/'); // 在asset-domain下的位置,规范为用正斜杠分割 - - // 处理被跳过的文本。处理顺序:policy -> [bypass](font, textures) -> !zh_cn - // 顺序乱了会导致字体文件被丢弃,因为没有带zh_cn - - // 跳过检索策略文件 - if (relativePath == "packer-policy.json") - { - return null; - } - - // 选出不经过处理路径的文件 - if (relativePath.NeedBypass(config)) - { - var target = Path.Combine("assets", - assetDirectory.Name, - relativePath); - Log.Information("跳过了标记为直接加入的命名空间:{0} -> {1}", - relativePath.Split('/')[0], - target); - - if (bypassed.ContainsValue(target)){ - Log.Warning("在未处理文件中检测到重复项。丢弃将要加入的新项"); - return null; - } - bypassed.Add(file.FullName, target); - return null; - } - - // 跳过非中文文件 - if (!relativePath.IsTargetLang(config)) - { - return null; - } - - // 跳过非中文文件 - if (!relativePath.IsTargetLang(config)) - { - return null; - } - - // 处理正常的语言文件 - // TODO:Json5支持 - var parsingCategory = file.Extension switch - { - ".json" => FileCategory.JsonAlike, - _ => FileCategory.LangAlike - }; - if (relativePath.StartsWith("lang/")) - { - return new LangFile(file.OpenRead(), - parsingCategory | FileCategory.LanguageFile, - config) - { - RelativePath = relativePath - }; - } - else - { - return new TranslatedFile(file.OpenRead(), - parsingCategory | FileCategory.OtherFiles, - config) - { - RelativePath = relativePath - }; - } - }).Where(_ => _ is not null); // 排除掉跳过的文件 - return result; + var hasKey = parameters.TryGetValue("overrides", out var element); + return hasKey ? element.GetBoolean() : false; } + + + + + + + //static IEnumerable FromMixedDirectory(DirectoryInfo assetDirectory, + // Config config, + // ref Dictionary unprocessed, + // Dictionary parameters) + // => Utils.MergeFiles(FromImmediateDirectory(assetDirectory, config, ref unprocessed, parameters), + // FromIndirectDirectory(assetDirectory, config, ref unprocessed, parameters)); + + //static IEnumerable FromBackPort(DirectoryInfo assetDirectory, + // Config config, + // ref Dictionary unprocessed, + // Dictionary parameters) + // => Utils.PortFiles(FromImmediateDirectory(assetDirectory, config, ref unprocessed, parameters), + // FromIndirectDirectory(assetDirectory, config, ref unprocessed, parameters)); + + //static IEnumerable FromIndirectDirectory(DirectoryInfo assetDirectory, + // Config config, + // ref Dictionary unprocessed, + // Dictionary parameters) + // => AggregateAssetFiles(new DirectoryInfo(parameters["source"].GetString()), config, ref unprocessed); + + //static IEnumerable FromPatches(DirectoryInfo assetDirectory, + // Config config, + // ref Dictionary unprocessed, + // Dictionary parameters) + //{ + // var reference = FromIndirectDirectory(assetDirectory, config, ref unprocessed, parameters) + // .ToDictionary(_ => _.RelativePath); + // var patchList = JsonSerializer.Deserialize>(parameters["patches"]); + // foreach (var patch in patchList) + // { + // Log.Information("对文件 {0} 应用 {1} 处的 patch。", patch.Key, patch.Value); + // reference.Remove(patch.Key, out var target); + // var patchText = string.Join('\n', File.ReadAllLines(patch.Value)); // 不要问我为什么D-M-P默认换行是LF + // reference.Add(patch.Key, target.ApplyPatch(patchText)); + // } + // return reference.Values; + //} + + //// 目前所有策略的终点方法 + //static IEnumerable FromImmediateDirectory(DirectoryInfo assetDirectory, + // Config config, + // ref Dictionary unprocessed, + // Dictionary parameters) + //{ + // var bypassed = unprocessed; + // var result = assetDirectory.EnumerateFiles("*", SearchOption.AllDirectories) // / 的下级文件 + // .Select(file => + // { // 这里开始真正的检索。被跳过的文本用 null 代替 + // var prefixLength = assetDirectory.FullName.Length; + // var relativePath = file.FullName[(prefixLength + 1)..] + // .Replace('\\', '/'); // 在asset-domain下的位置,规范为用正斜杠分割 + + // // 处理被跳过的文本。处理顺序:policy -> [bypass](font, textures) -> !zh_cn + // // 顺序乱了会导致字体文件被丢弃,因为没有带zh_cn + + // // 跳过检索策略文件 + // if (relativePath == "packer-policy.json") + // { + // return null; + // } + + // // 选出不经过处理路径的文件 + // if (relativePath.IsForceIncluded(config)) + // { + // var target = Path.Combine("assets", + // assetDirectory.Name, + // relativePath); + // Log.Information("跳过了标记为直接加入的命名空间:{0} -> {1}", + // relativePath.Split('/')[0], + // target); + + // if (bypassed.ContainsValue(target)) + // { + // Log.Warning("在未处理文件中检测到重复项。丢弃将要加入的新项"); + // return null; + // } + // bypassed.Add(file.FullName, target); + // return null; + // } + + // // 跳过非中文文件 + // if (!relativePath.IsInTargetLanguage(config)) + // { + // return null; + // } + + // // 跳过非中文文件 + // if (!relativePath.IsInTargetLanguage(config)) + // { + // return null; + // } + + // // 处理正常的语言文件 + // // TODO:Json5支持 + // var parsingCategory = file.Extension switch + // { + // ".json" => FileCategory.JsonAlike, + // _ => FileCategory.LangAlike + // }; + // if (relativePath.StartsWith("lang/")) + // { + // return new LangFile(file.OpenRead(), + // parsingCategory | FileCategory.LanguageFile, + // config) + // { + // RelativePath = relativePath + // }; + // } + // else + // { + // return new TranslatedFile(file.OpenRead(), + // parsingCategory | FileCategory.OtherFiles, + // config) + // { + // RelativePath = relativePath + // }; + // } + // }).Where(_ => _ is not null); // 排除掉跳过的文件 + // return result; + //} } } diff --git a/src/Packer/Extensions/SerializingExtension.cs b/src/Packer/Extensions/SerializingExtension.cs index 812d675c5a61..520cb9905de5 100644 --- a/src/Packer/Extensions/SerializingExtension.cs +++ b/src/Packer/Extensions/SerializingExtension.cs @@ -1,104 +1,105 @@ -using Packer.Models; -using Serilog; -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.Json; +//using Packer.Models; +//using Packer.Models.Providers; +//using Serilog; +//using System; +//using System.Collections.Generic; +//using System.Text; +//using System.Text.Json; -namespace Packer.Extensions -{ - static class SerializingExtension - { - public static string SerializeAsset(this Dictionary assetMap, FileCategory category) - => category switch - { - // Json 文件,直接写出 - FileCategory.JsonTranslationFormat => JsonSerializer.Serialize(assetMap, - new JsonSerializerOptions - { - WriteIndented = true - }), - // Lang文件 - FileCategory.LangTranslationFormat => SerializeFromLang(assetMap), - _ => null // 其实不应该执行到这个地方 - }; +//namespace Packer.Extensions +//{ +// static class SerializingExtension +// { +// public static string SerializeAsset(this Dictionary assetMap, FileCategory category) +// => category switch +// { +// // Json 文件,直接写出 +// FileCategory.JsonTranslationFormat => JsonSerializer.Serialize(assetMap, +// new JsonSerializerOptions +// { +// WriteIndented = true +// }), +// // Lang文件 +// FileCategory.LangTranslationFormat => SerializeFromLang(assetMap), +// _ => null // 其实不应该执行到这个地方 +// }; - static string SerializeFromLang(Dictionary assetMap) - { - // lang格式化还好说 - var sb = new StringBuilder(); - foreach (var pair in assetMap) - { - sb.AppendJoin('=', pair.Key, pair.Value); - sb.Append(Environment.NewLine); - } - return sb.ToString(); - } +// static string SerializeFromLang(Dictionary assetMap) +// { +// // lang格式化还好说 +// var sb = new StringBuilder(); +// foreach (var pair in assetMap) +// { +// sb.AppendJoin('=', pair.Key, pair.Value); +// sb.Append(Environment.NewLine); +// } +// return sb.ToString(); +// } - public static Dictionary DeserializeAsset(this string content, FileCategory category) - => category switch - { - FileCategory.JsonTranslationFormat - => JsonSerializer.Deserialize>(content, - new JsonSerializerOptions - { - ReadCommentHandling = JsonCommentHandling.Skip // 打包过程应当兼容注释,但不需要写入注释 - }), // 直接有的算法 - FileCategory.LangTranslationFormat => DeserializeFromLang(content), - _ => null // 其实不应该执行到这个地方 - }; +// public static Dictionary DeserializeAsset(this string content, FileCategory category) +// => category switch +// { +// FileCategory.JsonTranslationFormat +// => JsonSerializer.Deserialize>(content, +// new JsonSerializerOptions +// { +// ReadCommentHandling = JsonCommentHandling.Skip // 打包过程应当兼容注释,但不需要写入注释 +// }), // 直接有的算法 +// FileCategory.LangTranslationFormat => DeserializeFromLang(content), +// _ => null // 其实不应该执行到这个地方 +// }; - static Dictionary DeserializeFromLang(string content) - { - // 甚至不是自动机...所以不敢多用,否则会炸 +// static Dictionary DeserializeFromLang(string content) +// { +// // 甚至不是自动机...所以不敢多用,否则会炸 - // 下面的 Verbose 仅供调试,不会在 log 里出现 - // .lang的格式真的乱... - Log.Verbose("开始反序列化 .lang 文件"); - // #PARSE_ESCAPE就算了吧 - var result = new Dictionary(); - var isInComment = false; // 处理多行注释 - new List(content.Split(Environment.NewLine, - StringSplitOptions.RemoveEmptyEntries)) - .ForEach(line => - { - var isSingleLineComment = false; - new List { "//", "#" } - .ForEach(_ => { isSingleLineComment |= line.StartsWith(_); }); - if (isSingleLineComment) - { - Log.Verbose("跳过了单行注释:{0}", line); - } - else if (isInComment) // 多行注释内 - { - Log.Verbose("{0}", line); - if (line.Trim() - .EndsWith("*/")) - { - isInComment = false; // 跳出注释 - } - } - else if (line.StartsWith("/*")) // 开始多行注释 - { - Log.Verbose("跳过了多行注释:{0}", line); - } - else // 真正的条目 - { - Log.Verbose("添加对应映射:{0}", line); - var spiltPosition = line.IndexOf('='); - try - { - result.Add(line[..spiltPosition], line[(spiltPosition + 1)..]); - } - catch (Exception e) - { - Log.Warning(e.ToString()); - } - } - } - ); - Log.Verbose("反序列化完成"); - return result; - } - } -} +// // 下面的 Verbose 仅供调试,不会在 log 里出现 +// // .lang的格式真的乱... +// Log.Verbose("开始反序列化 .lang 文件"); +// // #PARSE_ESCAPE就算了吧 +// var result = new Dictionary(); +// var isInComment = false; // 处理多行注释 +// new List(content.Split(Environment.NewLine, +// StringSplitOptions.RemoveEmptyEntries)) +// .ForEach(line => +// { +// var isSingleLineComment = false; +// new List { "//", "#" } +// .ForEach(_ => { isSingleLineComment |= line.StartsWith(_); }); +// if (isSingleLineComment) +// { +// Log.Verbose("跳过了单行注释:{0}", line); +// } +// else if (isInComment) // 多行注释内 +// { +// Log.Verbose("{0}", line); +// if (line.Trim() +// .EndsWith("*/")) +// { +// isInComment = false; // 跳出注释 +// } +// } +// else if (line.StartsWith("/*")) // 开始多行注释 +// { +// Log.Verbose("跳过了多行注释:{0}", line); +// } +// else // 真正的条目 +// { +// Log.Verbose("添加对应映射:{0}", line); +// var spiltPosition = line.IndexOf('='); +// try +// { +// result.Add(line[..spiltPosition], line[(spiltPosition + 1)..]); +// } +// catch (Exception e) +// { +// Log.Warning(e.ToString()); +// } +// } +// } +// ); +// Log.Verbose("反序列化完成"); +// return result; +// } +// } +//} diff --git a/src/Packer/Lib.cs b/src/Packer/Lib.cs index d4e8c61b587a..dae6789d8ffd 100644 --- a/src/Packer/Lib.cs +++ b/src/Packer/Lib.cs @@ -1,49 +1,49 @@ -using Packer.Extensions; -using Packer.Models; -using Serilog; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; +//using Packer.Extensions; +//using Packer.Models; +//using Serilog; +//using System; +//using System.Collections.Generic; +//using System.IO; +//using System.Linq; +//using System.Text.RegularExpressions; -namespace Packer -{ - static class Lib - { - /// - /// 从主库中选出所需文本 - /// - /// 所使用的配置 - /// - /// 需要包含的模组列表,按模组唯一标识符
- /// 若为,表示包含所有模组 - /// - /// - public static IEnumerable RetrieveContent( - Config config, - IEnumerable? targetModIdentifiers) +//namespace Packer +//{ +// static class Lib +// { +// /// +// /// 从主库中选出所需文本 +// /// +// /// 所使用的配置 +// /// +// /// 需要包含的模组列表,按模组唯一标识符
+// /// 若为,表示包含所有模组 +// /// +// /// +// public static IEnumerable RetrieveContent( +// Config config, +// IEnumerable? targetModIdentifiers) - // 成功实现了没分号的C#语句...这就是查询表达式吗( - => from modDirectory in new DirectoryInfo($"./projects/{config.Version}/assets") - .EnumerateDirectories() - let modIdentifier = modDirectory.Name - // 模组筛选,按模组标识符 - where targetModIdentifiers is null // 未提供列表,全部打包 - || targetModIdentifiers.Contains(modIdentifier) // 有列表,仅打包列表中的项 - from namespaceDirectory in modDirectory.EnumerateDirectories() - let namespaceName = namespaceDirectory.Name - // 检查命名空间格式,拒绝错误格式 - // 但是写成表达式以后,没法现场丢异常了... - where !Regex.IsMatch(namespaceName, - @"^[a-z0-9_\-.]+$", - RegexOptions.Singleline) - from provider in namespaceDirectory.EnumerateProviders(config) - // 合并文件;我猜没写错 - group provider by namespaceName into namespaceGroup - select namespaceGroup - .Aggregate(seed: null as IResourceFileProvider, // 好家伙 类型推断系统推断不出TAggregate - (accumlate, next) // 为什么这个参数叫func不叫accumlator或者aggregator... - => next.Append(accumlate, overrideExisting: false)); - } -} +// // 成功实现了没分号的C#语句...这就是查询表达式吗( +// => from modDirectory in new DirectoryInfo($"./projects/{config.Version}/assets") +// .EnumerateDirectories() +// let modIdentifier = modDirectory.Name +// // 模组筛选,按模组标识符 +// where targetModIdentifiers is null // 未提供列表,全部打包 +// || targetModIdentifiers.Contains(modIdentifier) // 有列表,仅打包列表中的项 +// from namespaceDirectory in modDirectory.EnumerateDirectories() +// let namespaceName = namespaceDirectory.Name +// // 检查命名空间格式,拒绝错误格式 +// // 但是写成表达式以后,没法现场丢异常了... +// where !Regex.IsMatch(namespaceName, +// @"^[a-z0-9_\-.]+$", +// RegexOptions.Singleline) +// from provider in namespaceDirectory.EnumerateProviders(config) +// // 合并文件;我猜没写错 +// group provider by namespaceName into namespaceGroup +// select namespaceGroup +// .Aggregate(seed: null as IResourceFileProvider, // 好家伙 类型推断系统推断不出TAggregate +// (accumlate, next) // 为什么这个参数叫func不叫accumlator或者aggregator... +// => next.ApplyTo(accumlate, overrideExisting: false)); +// } +//} diff --git a/src/Packer/Models/Config.cs b/src/Packer/Models/Config.cs index ddbd298ab526..f6d73453db8a 100644 --- a/src/Packer/Models/Config.cs +++ b/src/Packer/Models/Config.cs @@ -48,7 +48,7 @@ public struct Config /// 按照namespace识别 ///
[JsonPropertyName("noProcessNamespace")] - public List BypassedNamespace { get; set; } + public List ForceInclusionDomain { get; set; } /// /// 字符替换表,版本限定 @@ -56,6 +56,8 @@ public struct Config [JsonPropertyName("replacementMap")] public Dictionary CharatcerReplacement { get; set; } + + [JsonPropertyName("destinitionReplacement")] public Dictionary DestinationReplacement { get; set; } } } diff --git a/src/Packer/Models/IResourceFileProvider.cs b/src/Packer/Models/IResourceFileProvider.cs index 3b5987ff8f7a..d46025bf05e9 100644 --- a/src/Packer/Models/IResourceFileProvider.cs +++ b/src/Packer/Models/IResourceFileProvider.cs @@ -22,9 +22,9 @@ public interface IResourceFileProvider /// 需要添加的新 /// 冲突解决方案。若为,保留本文件的内容;否则,保留新文件的内容 /// 合并得到的新 - public IResourceFileProvider Append(IResourceFileProvider? incoming, bool overrideExisting = false) + public IResourceFileProvider ApplyTo(IResourceFileProvider? incoming, bool overrideExisting = false) // 默认实现 - => overrideExisting + => !overrideExisting ? (incoming ?? this) // 如果来源是null,无论冲突配置如何,都不应返回null : this; @@ -44,16 +44,19 @@ public IResourceFileProvider ReplaceContent(string searchPattern, string replace /// 替换的匹配模式,使用 /// 替换文本 /// 替换得到的新 - public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) - // 默认实现 - => this; + public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement); /// /// 将该提供器的内容写入到资源包的正确位置 /// /// - /// /// 资源包中已有同名文件 public Task WriteToArchive(ZipArchive archive); + + /// + /// 获取该提供器的目标位置 + /// + /// 目标在资源包中的相对位置,从根目录算起 + public string Destination { get; } } } diff --git a/src/Packer/Models/Mod.cs b/src/Packer/Models/Mod.cs index 78f618397855..8f2876da621a 100644 --- a/src/Packer/Models/Mod.cs +++ b/src/Packer/Models/Mod.cs @@ -1,48 +1,48 @@ -using System.Collections.Generic; +//using System.Collections.Generic; -namespace Packer.Models -{ - /// - /// 模组译文的抽象表示 - /// - public class Mod - { - /// - /// 模组名 - /// - public string modName; - /// - /// 采用的asset,按asset-domain分 - /// - public IEnumerable assets; - } +//namespace Packer.Models +//{ +// /// +// /// 模组译文的抽象表示 +// /// +// public class Mod +// { +// /// +// /// 模组名 +// /// +// public string modName; +// /// +// /// 采用的asset,按asset-domain分 +// /// +// public IEnumerable assets; +// } - /// - /// asset的抽象表示 - /// - public class Asset - { - /// - /// asset-domain名 - /// - public string domainName; - /// - /// 该asset-domain下的文件 - /// - public IEnumerable contents; - /// - /// domain合并,并解决重复文件问题 - /// - /// 要合并的对象 - /// - public Asset Combine(Asset other) - { +// /// +// /// asset的抽象表示 +// /// +// public class Asset +// { +// /// +// /// asset-domain名 +// /// +// public string domainName; +// /// +// /// 该asset-domain下的文件 +// /// +// public IEnumerable contents; +// /// +// /// domain合并,并解决重复文件问题 +// /// +// /// 要合并的对象 +// /// +// public Asset Combine(Asset other) +// { - return new Asset() - { - domainName = this.domainName, - contents = Utils.MergeFiles(this.contents, other.contents) - }; - } - } -} +// return new Asset() +// { +// domainName = this.domainName, +// contents = Utils.MergeFiles(this.contents, other.contents) +// }; +// } +// } +//} diff --git a/src/Packer/Models/Providers/CompositionProvider.cs b/src/Packer/Models/Providers/CompositionProvider.cs new file mode 100644 index 000000000000..bea32ad5ae87 --- /dev/null +++ b/src/Packer/Models/Providers/CompositionProvider.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.IO; +using System.Text.Json.Nodes; + +namespace Packer.Models.Providers +{ + using LangMappingProvider = TermMappingProvider; + using JsonMappingProvider = TermMappingProvider; + + + // 考量:Helper? + public class CompositionProvider : TermMappingProvider + { + public CompositionProvider(ITermDictionary map, string destination) : base(map, destination) { } + + public CompositionProvider Create(FileInfo file) + { + + } + } + + + internal struct CompositonData + { + public string Target { get; set; } + public List Entries { get; set; } + } + + internal struct CompositionEntry + { + public Dictionary Templates { get; set; } + public Dictionary Parameters { get; set; } + } +} diff --git a/src/Packer/Models/Providers/LanguageFile.cs b/src/Packer/Models/Providers/LanguageFile.cs index 5ca5916797d0..3c236d655f67 100644 --- a/src/Packer/Models/Providers/LanguageFile.cs +++ b/src/Packer/Models/Providers/LanguageFile.cs @@ -1,66 +1,92 @@ -using System; +using Serilog; +using System; using System.Collections.Generic; -using System.IO.Compression; +using System.IO; using System.Linq; using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; +using System.Text.Json.Nodes; namespace Packer.Models.Providers { + using LangMappingProvider = TermMappingProvider; + using JsonMappingProvider = TermMappingProvider; - - public enum LanguageFileFormat - { - Lang = 0, - Json = 1 - } - - - internal class TermMappingProvider : IResourceFileProvider + public class LangLanguageFile : LangMappingProvider { - public Dictionary Map { get; } - - public TermMappingProvider(Dictionary map) + public LangLanguageFile(ITermDictionary map, string destination) : base(map, destination) { } + public static LangLanguageFile Create(FileInfo file, string destination) { - Map = map; + using var stream = file.OpenRead(); + using var reader = new StreamReader(stream, Encoding.UTF8); + var content = reader.ReadToEnd(); + return new(new LangDictionaryWrapper(DeserializeFromLang(content)), destination); } - public IResourceFileProvider Append(IResourceFileProvider? incoming, bool overrideExisting = false) + // RAW CONTENT + static Dictionary DeserializeFromLang(string content) { - if (incoming is not TermMappingProvider) - throw new ArgumentException($"Argument not an instance of {typeof(TermMappingProvider)}.", - nameof(incoming)); - var inProvider = incoming as TermMappingProvider; - - if (inProvider is null) throw new ArgumentNullException(nameof(incoming)); - - var (baseMap, inMap) = overrideExisting - ? (Map, inProvider.Map) - : (inProvider.Map, Map); // 交换顺序 - - foreach (var pair in inMap) - { - baseMap.TryAdd(pair.Key, pair.Value); - } + // 甚至不是自动机...所以不敢多用,否则会炸 - return new TermMappingProvider(baseMap); - } - - public IResourceFileProvider ReplaceContent(string searchPattern, string replacement) - { - throw new NotImplementedException(); + // 下面的 Verbose 仅供调试,不会在 log 里出现 + // .lang的格式真的乱... + Log.Verbose("开始反序列化 .lang 文件"); + // #PARSE_ESCAPE就算了吧 + var result = new Dictionary(); + var isInComment = false; // 处理多行注释 + new List(content.Split(Environment.NewLine, + StringSplitOptions.RemoveEmptyEntries)) + .ForEach(line => + { + var isSingleLineComment = false; + new List { "//", "#" } + .ForEach(_ => { isSingleLineComment |= line.StartsWith(_); }); + if (isSingleLineComment) + { + Log.Verbose("跳过了单行注释:{0}", line); + } + else if (isInComment) // 多行注释内 + { + Log.Verbose("{0}", line); + if (line.Trim() + .EndsWith("*/")) + { + isInComment = false; // 跳出注释 + } + } + else if (line.StartsWith("/*")) // 开始多行注释 + { + Log.Verbose("跳过了多行注释:{0}", line); + } + else // 真正的条目 + { + Log.Verbose("添加对应映射:{0}", line); + var spiltPosition = line.IndexOf('='); + try + { + result.Add(line[..spiltPosition], line[(spiltPosition + 1)..]); + } + catch (Exception e) + { + Log.Warning(e.ToString()); + } + } + } + ); + Log.Verbose("反序列化完成"); + return result; } + } - public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) - { - throw new NotImplementedException(); - } - public Task WriteToArchive(ZipArchive archive) + public class JsonLanguageFile : JsonMappingProvider + { + public JsonLanguageFile(ITermDictionary map, string destination) : base(map, destination) { } + public static JsonLanguageFile Create(FileInfo file, string destination) { - throw new NotImplementedException(); + using var stream = file.OpenRead(); + return new(new JsonDictionaryWrapper(JsonNode.Parse(stream).AsObject()), destination); } } + } diff --git a/src/Packer/Models/Providers/McMetaProvider.cs b/src/Packer/Models/Providers/McMetaProvider.cs new file mode 100644 index 000000000000..2a7776921e18 --- /dev/null +++ b/src/Packer/Models/Providers/McMetaProvider.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.IO.Compression; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Packer.Models.Providers +{ + internal class McMetaProvider : IResourceFileProvider + { + public string Destination => "pack.mcmeta"; + + public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) + => this; + + public Task WriteToArchive(ZipArchive archive) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Packer/Models/Providers/RawFile.cs b/src/Packer/Models/Providers/RawFile.cs index 94efbeb03e41..e43c155e4ce0 100644 --- a/src/Packer/Models/Providers/RawFile.cs +++ b/src/Packer/Models/Providers/RawFile.cs @@ -1,11 +1,7 @@ using Packer.Extensions; using Serilog; -using System; -using System.Collections.Generic; using System.IO; using System.IO.Compression; -using System.Linq; -using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -44,7 +40,10 @@ public RawFile(FileInfo sourceFile, string destination) /// public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) => new RawFile(SourceFile, - Regex.Replace(Destination, searchPattern, replacement)); + Regex.Replace(Destination, + searchPattern, + replacement, + RegexOptions.Singleline)); /// public async Task WriteToArchive(ZipArchive archive) diff --git a/src/Packer/Models/Providers/TermMappingProvider.cs b/src/Packer/Models/Providers/TermMappingProvider.cs new file mode 100644 index 000000000000..52c05a2aff72 --- /dev/null +++ b/src/Packer/Models/Providers/TermMappingProvider.cs @@ -0,0 +1,167 @@ +using Packer.Extensions; +using Serilog; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Text.Encodings.Web; +using System.Text; +using System.Text.Json; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Text.Json.Nodes; +using System.Linq; + +namespace Packer.Models.Providers +{ + + + + public interface ITermDictionary : IDictionary + { + // TODO:Parse + public string ProvideStringContent(); + public ITermDictionary ReplaceContent(string searchPattern, string replacement); + public static ITermDictionary Create(IDictionary nominalMapping) + => throw new NotImplementedException(); + } + + + public class TermMappingProvider : IResourceFileProvider + { + public ITermDictionary Map { get; } + public string Destination { get; } + + public TermMappingProvider(ITermDictionary map, string destination) + { + Map = map; + Destination = destination; + } + + public IResourceFileProvider ApplyTo(IResourceFileProvider? incoming, bool overrideExisting = false) + { + if (incoming is not TermMappingProvider) + throw new ArgumentException($"Argument not an instance of {typeof(TermMappingProvider)}.", + nameof(incoming)); + var inProvider = incoming as TermMappingProvider; + + if (inProvider is null) throw new ArgumentNullException(nameof(incoming)); + + var (baseMap, inMap) = !overrideExisting + ? (Map, inProvider.Map) + : (inProvider.Map, Map); // 交换顺序 + + foreach (var pair in inMap) + { + baseMap.TryAdd(pair.Key, pair.Value); + } + + return new TermMappingProvider(baseMap, Destination); + } + + public IResourceFileProvider ReplaceContent(string searchPattern, string replacement) + => new TermMappingProvider( + Map.ReplaceContent(searchPattern, replacement), + Destination); + + public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) + => new TermMappingProvider( + Map, + Regex.Replace(Destination, + searchPattern, + replacement, + RegexOptions.Singleline)); + + public async Task WriteToArchive(ZipArchive archive) + { + var destination = Destination.NormalizePath(); + Log.Information("正在添加 {0}", destination); + + archive.ValidateEntryDistinctness(destination); + + using var writer = new StreamWriter( + archive.CreateEntry(destination) + .Open(), + Encoding.UTF8); + await writer.WriteAsync(Map.ProvideStringContent()); + } + } + + + + + internal class LangDictionaryWrapper : Dictionary, ITermDictionary + { + public LangDictionaryWrapper(IDictionary dictionary) : base(dictionary) { } + + public string ProvideStringContent() + { + var builder = new StringBuilder(); + foreach (var (key, value) in this) + { + builder.AppendJoin('=', key, value); + builder.Append(Environment.NewLine); + } + return builder.ToString(); + } + + public ITermDictionary ReplaceContent(string searchPattern, string replacement) + { + var result = new Dictionary(); + foreach (var (key, value) in this) + { + var replaced = Regex.Replace(value, + searchPattern, + replacement, + RegexOptions.Singleline); + result.Add(key, replaced); + } + return new LangDictionaryWrapper(result); + } + + public static ITermDictionary Create(IDictionary nominalMapping) + => new LangDictionaryWrapper(nominalMapping); + } + + internal class JsonDictionaryWrapper : Dictionary, ITermDictionary + { + public JsonDictionaryWrapper(IDictionary dictionary) : base(dictionary) { } + + public string ProvideStringContent() + => JsonSerializer.Serialize(this, new JsonSerializerOptions() + { + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }); + + public ITermDictionary ReplaceContent(string searchPattern, string replacement) + { + var result = new Dictionary(); + foreach(var (key, value) in this) + { + if (value.GetType() == typeof(JsonValue) + && value.AsValue().TryGetValue(out var stringValue)) + { + var replaced = Regex.Replace(stringValue, + searchPattern, + replacement, + RegexOptions.Singleline); + result.Add(key, JsonValue.Create(replaced)!); // 我猜不会null罢 + continue; + } + result.Add(key, value); + } + return new JsonDictionaryWrapper(result); + } + + public static ITermDictionary Create(IDictionary nominalMapping) + { + var query = from pair in nominalMapping + let key = pair.Key + let value = pair.Value + let node = JsonValue.Create(value)! + select (key, node); + var transformed = query.ToDictionary(_ => _.key, _ => _.node as JsonNode); + return new JsonDictionaryWrapper(transformed); + } + } +} diff --git a/src/Packer/Models/Providers/TextFile.cs b/src/Packer/Models/Providers/TextFile.cs index 18072b4c9670..2e9d1420a0b9 100644 --- a/src/Packer/Models/Providers/TextFile.cs +++ b/src/Packer/Models/Providers/TextFile.cs @@ -28,13 +28,14 @@ public class TextFile : IResourceFileProvider /// /// 从给定的构造提供器。 /// - /// 读取源 + /// 读取源 /// 目标地址 - public TextFile(Stream stream, string destination) + public static TextFile Create(FileInfo file, string destination) { - Destination = destination; + using var stream = file.OpenRead(); using var reader = new StreamReader(stream, Encoding.UTF8); - Content = reader.ReadToEnd(); + var content = reader.ReadToEnd(); + return new TextFile(content, destination); } /// @@ -52,14 +53,16 @@ public TextFile(string content, string destination) public IResourceFileProvider ReplaceContent(string searchPattern, string replacement) => new TextFile(Regex.Replace(Content, searchPattern, - replacement), + replacement, + RegexOptions.Singleline), Content); /// public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) => new TextFile(Content, Regex.Replace(Destination, searchPattern, - replacement)); + replacement, + RegexOptions.Singleline)); /// public async Task WriteToArchive(ZipArchive archive) { diff --git a/src/Packer/Models/TranslatedFile.cs b/src/Packer/Models/TranslatedFile.cs index 2c3afc390a33..39cbbb7d7b4b 100644 --- a/src/Packer/Models/TranslatedFile.cs +++ b/src/Packer/Models/TranslatedFile.cs @@ -1,229 +1,229 @@ -using DiffMatchPatch; -using Packer.Extensions; -using Serilog; -using System; -using System.Collections.Generic; -using System.IO; - -namespace Packer.Models -{ - /// - /// 标志文件类型的枚举。目前而言有[是否按.json]和[是否按\lang\]两类 - /// - [Flags] - public enum FileCategory - { - /// - /// 仅用于初始化为默认态 - /// - None = 0, - /// - /// 类 .json,标识需要转义与 json 式序列化 - /// - JsonAlike = 1, - /// - /// 类 .lang,标识无需转义与 lang 式序列化 - /// - LangAlike = 2, - /// - /// 位于 /lang/ 中的文件,进行合并等 - /// - LanguageFile = 4, - /// - /// 位于其余位置的文件,不进行合并 - /// - OtherFiles = 8, - /// - /// */lang/*.json - /// - JsonTranslationFormat = JsonAlike | LanguageFile, - /// - /// */lang/*.lang - /// - LangTranslationFormat = LangAlike | LanguageFile, - /// - /// */[not-lang]/*.json - /// - JsonOthers = JsonAlike | OtherFiles, - /// - /// */[not-lang]/*.lang - /// - LangOthers = LangAlike | OtherFiles - } - - /// - /// 语言文本的抽象。这是基本类
- /// 基本上是immutable的 - ///
- public class TranslatedFile - { - /// - /// asset-domain下的位置 - /// - public string RelativePath { get; init; } - - /// - /// 该文件的文本,用字符串表示

- /// 因此,不能存储非文本文件! - ///
- public string StringifiedContent { get; } - - /// - /// 文件类型 - /// - public FileCategory Category { get; } - - /// - /// 从文件流构造内容 - /// - public TranslatedFile(Stream stream, FileCategory category, Config config) - { // 注:文件流在此处被关闭 - using var reader = new StreamReader(stream); - StringifiedContent = reader.ReadToEnd().Preprocess(category, config); - this.Category = category; - } - - /// - /// 从文本构造内容 - /// - public TranslatedFile(FileCategory category, string content) - { - this.Category = category; - StringifiedContent = content; - } - - /// - /// 伪合并文件 - /// - virtual public TranslatedFile Combine(TranslatedFile file) - { - Log.Information("文件不支持合并。取消合并"); - return this; - } - - /// - /// 伪适配文件 - /// - virtual public TranslatedFile Port(TranslatedFile file) - { - Log.Information("文件不支持适配。直接覆盖"); - return file; - } - - /// - /// 对该文件的内容进行Google Diff-Match-Patch算法 - /// - public TranslatedFile ApplyPatch(string patch) - { - // 对应的Patch可以自行生成,或者也可以做一个小工具,虽然不在这里 - // 应用Patch时,需要先根据Patch文本生成Patch列表,再应用Patch - // - // patch_apply 返回object[] [0]=string [1]=bool[] - var dmp = new diff_match_patch(); - var patchList = dmp.patch_fromText(patch); - return new TranslatedFile(Category, - (string)dmp.patch_apply(patchList, StringifiedContent)[0]); - } - } - - /// - /// 可以按照/lang/文件夹下解析的文件。这是衍生类
- /// 基本上是immutable的 - ///
- public class LangFile : TranslatedFile - { - private bool deserialized = false; // 非必要不解析,免得残废的lang解析炸掉 - private Dictionary _deserializedContent; - - /// - /// 按照基础语言文件的格式解析而成的词条列表。
- /// 在访问时才会解析。 - ///
- public Dictionary DeserializedContent - { - get - { - if (!deserialized) - { - deserialized = true; - _deserializedContent = StringifiedContent.DeserializeAsset(Category); - } - return _deserializedContent; - } - } - - /// - /// 从文件流构造内容 - /// - public LangFile(Stream stream, FileCategory category, Config config) - : base(stream, category, config) - { - _deserializedContent = null; - } - /// - /// 从映射表构造内容 - /// - public LangFile(FileCategory category, Dictionary content) - : base(category, content.SerializeAsset(category)) - { - _deserializedContent = content; - deserialized = true; - } - /// - /// 真合并文件 - /// - public override LangFile Combine(TranslatedFile file) - { - Log.Information("合并文件:{0}", this.RelativePath); - - var castedFile = (LangFile)file; - if (castedFile is null) - { - Log.Information("检测到不支持合并的文件。取消合并"); - return this; - } - - var resultMap = new Dictionary(DeserializedContent); - foreach (var pair in castedFile.DeserializedContent) - { - if (!resultMap.TryAdd(pair.Key, pair.Value)) - { - Log.Warning("检测到相同 key 的条目:{0} -> {1} | {2},选取 {1}", - pair.Key, resultMap[pair.Key], pair.Value); - } - } - - return new LangFile(this.Category, resultMap) - { - RelativePath = this.RelativePath - }; - } - - /// - /// 真适配文件 - /// - public override TranslatedFile Port(TranslatedFile file) - { - var castedFile = (LangFile)file; - if (castedFile is null) - { - Log.Information("检测到不支持合并的文件。取消合并"); - return file; - } - - var resultMap = DeserializedContent; - foreach(var key in resultMap.Keys) - { - if(castedFile.DeserializedContent.TryGetValue(key, out var value)) - { - Log.Information("正在替换适配项:<{0}> {1} => {2}", key, resultMap[key], value); - resultMap[key] = value; - } - } - return new LangFile(this.Category, resultMap) - { - RelativePath = this.RelativePath - }; - } - } -} +//using DiffMatchPatch; +//using Packer.Extensions; +//using Serilog; +//using System; +//using System.Collections.Generic; +//using System.IO; + +//namespace Packer.Models +//{ +// /// +// /// 标志文件类型的枚举。目前而言有[是否按.json]和[是否按\lang\]两类 +// /// +// [Flags] +// public enum FileCategory +// { +// /// +// /// 仅用于初始化为默认态 +// /// +// None = 0, +// /// +// /// 类 .json,标识需要转义与 json 式序列化 +// /// +// JsonAlike = 1, +// /// +// /// 类 .lang,标识无需转义与 lang 式序列化 +// /// +// LangAlike = 2, +// /// +// /// 位于 /lang/ 中的文件,进行合并等 +// /// +// LanguageFile = 4, +// /// +// /// 位于其余位置的文件,不进行合并 +// /// +// OtherFiles = 8, +// /// +// /// */lang/*.json +// /// +// JsonTranslationFormat = JsonAlike | LanguageFile, +// /// +// /// */lang/*.lang +// /// +// LangTranslationFormat = LangAlike | LanguageFile, +// /// +// /// */[not-lang]/*.json +// /// +// JsonOthers = JsonAlike | OtherFiles, +// /// +// /// */[not-lang]/*.lang +// /// +// LangOthers = LangAlike | OtherFiles +// } + +// /// +// /// 语言文本的抽象。这是基本类
+// /// 基本上是immutable的 +// ///
+// public class TranslatedFile +// { +// /// +// /// asset-domain下的位置 +// /// +// public string RelativePath { get; init; } + +// /// +// /// 该文件的文本,用字符串表示

+// /// 因此,不能存储非文本文件! +// ///
+// public string StringifiedContent { get; } + +// /// +// /// 文件类型 +// /// +// public FileCategory Category { get; } + +// /// +// /// 从文件流构造内容 +// /// +// public TranslatedFile(Stream stream, FileCategory category, Config config) +// { // 注:文件流在此处被关闭 +// using var reader = new StreamReader(stream); +// StringifiedContent = reader.ReadToEnd().Preprocess(category, config); +// this.Category = category; +// } + +// /// +// /// 从文本构造内容 +// /// +// public TranslatedFile(FileCategory category, string content) +// { +// this.Category = category; +// StringifiedContent = content; +// } + +// /// +// /// 伪合并文件 +// /// +// virtual public TranslatedFile Combine(TranslatedFile file) +// { +// Log.Information("文件不支持合并。取消合并"); +// return this; +// } + +// /// +// /// 伪适配文件 +// /// +// virtual public TranslatedFile Port(TranslatedFile file) +// { +// Log.Information("文件不支持适配。直接覆盖"); +// return file; +// } + +// /// +// /// 对该文件的内容进行Google Diff-Match-Patch算法 +// /// +// public TranslatedFile ApplyPatch(string patch) +// { +// // 对应的Patch可以自行生成,或者也可以做一个小工具,虽然不在这里 +// // 应用Patch时,需要先根据Patch文本生成Patch列表,再应用Patch +// // +// // patch_apply 返回object[] [0]=string [1]=bool[] +// var dmp = new diff_match_patch(); +// var patchList = dmp.patch_fromText(patch); +// return new TranslatedFile(Category, +// (string)dmp.patch_apply(patchList, StringifiedContent)[0]); +// } +// } + +// /// +// /// 可以按照/lang/文件夹下解析的文件。这是衍生类
+// /// 基本上是immutable的 +// ///
+// public class LangFile : TranslatedFile +// { +// private bool deserialized = false; // 非必要不解析,免得残废的lang解析炸掉 +// private Dictionary _deserializedContent; + +// /// +// /// 按照基础语言文件的格式解析而成的词条列表。
+// /// 在访问时才会解析。 +// ///
+// public Dictionary DeserializedContent +// { +// get +// { +// if (!deserialized) +// { +// deserialized = true; +// _deserializedContent = StringifiedContent.DeserializeAsset(Category); +// } +// return _deserializedContent; +// } +// } + +// /// +// /// 从文件流构造内容 +// /// +// public LangFile(Stream stream, FileCategory category, Config config) +// : base(stream, category, config) +// { +// _deserializedContent = null; +// } +// /// +// /// 从映射表构造内容 +// /// +// public LangFile(FileCategory category, Dictionary content) +// : base(category, content.SerializeAsset(category)) +// { +// _deserializedContent = content; +// deserialized = true; +// } +// /// +// /// 真合并文件 +// /// +// public override LangFile Combine(TranslatedFile file) +// { +// Log.Information("合并文件:{0}", this.RelativePath); + +// var castedFile = (LangFile)file; +// if (castedFile is null) +// { +// Log.Information("检测到不支持合并的文件。取消合并"); +// return this; +// } + +// var resultMap = new Dictionary(DeserializedContent); +// foreach (var pair in castedFile.DeserializedContent) +// { +// if (!resultMap.TryAdd(pair.Key, pair.Value)) +// { +// Log.Warning("检测到相同 key 的条目:{0} -> {1} | {2},选取 {1}", +// pair.Key, resultMap[pair.Key], pair.Value); +// } +// } + +// return new LangFile(this.Category, resultMap) +// { +// RelativePath = this.RelativePath +// }; +// } + +// /// +// /// 真适配文件 +// /// +// public override TranslatedFile Port(TranslatedFile file) +// { +// var castedFile = (LangFile)file; +// if (castedFile is null) +// { +// Log.Information("检测到不支持合并的文件。取消合并"); +// return file; +// } + +// var resultMap = DeserializedContent; +// foreach(var key in resultMap.Keys) +// { +// if(castedFile.DeserializedContent.TryGetValue(key, out var value)) +// { +// Log.Information("正在替换适配项:<{0}> {1} => {2}", key, resultMap[key], value); +// resultMap[key] = value; +// } +// } +// return new LangFile(this.Category, resultMap) +// { +// RelativePath = this.RelativePath +// }; +// } +// } +//} diff --git a/src/Packer/Program.cs b/src/Packer/Program.cs index aa1b8ebf718d..1714ed7b0ec6 100644 --- a/src/Packer/Program.cs +++ b/src/Packer/Program.cs @@ -30,38 +30,32 @@ public static async Task Main(string version, string[]? targets) Log.Information("开始对版本 {0} 的打包", config.Version); - var rawQuery = Lib.RetrieveContent(config, targetModIdentifiers); var query = // 这就是查询表达式吗( from modDirectory in new DirectoryInfo($"./projects/{config.Version}/assets") .EnumerateDirectories() let modIdentifier = modDirectory.Name - // 模组筛选,按模组标识符 - where targetModIdentifiers is null // 未提供列表,全部打包 - || targetModIdentifiers.Contains(modIdentifier) // 有列表,仅打包列表中的项 - where !config.ModBlackList.Contains(modIdentifier) // 没有被明确排除 + where targetModIdentifiers is null // 未提供列表,全部打包 + || targetModIdentifiers.Contains(modIdentifier) // 有列表,仅打包列表中的项 + where !config.ModBlackList.Contains(modIdentifier) // 没有被明确排除 from namespaceDirectory in modDirectory.EnumerateDirectories() let namespaceName = namespaceDirectory.Name - where !config.DomainBlackList.Contains(modIdentifier) // 没有被明确排除 - // 检查命名空间格式,拒绝错误格式 - // 但是写成表达式以后,没法现场丢异常了... - where !Regex.IsMatch(namespaceName, - @"^[a-z0-9_\-.]+$", - RegexOptions.Singleline) + where !config.DomainBlackList.Contains(namespaceName) // 没有被明确排除 + where namespaceName.ValidateNamespace() // 不是非法名称 from provider in namespaceDirectory.EnumerateProviders(config) - group provider by namespaceName into namespaceGroup// 合并文件;我猜没写错 - select namespaceGroup - .Aggregate(seed: null as IResourceFileProvider, // 好家伙 类型推断系统推断不出TAggregate - (accumlate, next) // 为什么这个参数叫func不叫accumlator或者aggregator... - => next.Append(accumlate, overrideExisting: false)) into provider - // 替换内容中的特殊字符 - select config.CharatcerReplacement + group provider by provider.Destination into destinationGroup + select destinationGroup + .Aggregate(seed: null as IResourceFileProvider, // 合并文件 + (accumlate, next) + => next.ApplyTo( + accumlate, + overrideExisting: false)) into provider + select config.CharatcerReplacement // 内容的字符替换 .Aggregate(seed: provider, (accumlate, replacement) => accumlate.ReplaceContent( replacement.Key, replacement.Value)) into provider - // 替换目标路径中的对象 - select config.DestinationReplacement + select config.DestinationReplacement // 全局路径替换:预留 .Aggregate(seed: provider, (accumlate, replacement) => accumlate.ReplaceContent( @@ -73,6 +67,7 @@ select config.DestinationReplacement string packName = $"./Minecraft-Mod-Language-Package-{config.Version}.zip"; await using var stream = File.Create(packName); + using (var archive = new ZipArchive(stream, ZipArchiveMode.Update, leaveOpen: true)) { archive.Initialize(config); @@ -83,6 +78,7 @@ select config.DestinationReplacement config.Version, query.Count()); var md5 = stream.ComputeMD5(); + Log.Information("打包文件的 MD5 值:{0}", md5); File.WriteAllText($"./{config.Version}.md5", md5); } diff --git a/src/Packer/Utils.cs b/src/Packer/Utils.cs index 0fb99b660bc0..d084c37b630e 100644 --- a/src/Packer/Utils.cs +++ b/src/Packer/Utils.cs @@ -14,6 +14,10 @@ namespace Packer { static class Utils { + + + + public static async Task RetrieveConfig(string configTemplate, string version) { Log.Information("正在获取配置。目标版本:{0}", version); @@ -26,75 +30,80 @@ public static async Task RetrieveConfig(string configTemplate, string ve return JsonSerializer.Deserialize(reader); } - public static PackerStrategy RetrieveStrategy(FileInfo? file) + public static List RetrieveStrategy(FileInfo? file) { if (file is null) { - return new PackerStrategy { Type = PackerStrategyType.NoAction }; + return new List + { + new PackerStrategy { Type = PackerStrategyType.NoAction } + }; } else { - var result = JsonSerializer.Deserialize( + var result = JsonSerializer.Deserialize>( file.OpenText().ReadToEnd(), new JsonSerializerOptions { - Converters = { new JsonStringEnumConverter() } + Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) } }); + if (result is null) + throw new InvalidDataException($"The policy file {file.FullName} cannot have null values."); + return result; } } - /// - /// 将两个带有TranslatedFile的列表合并,对冲突项按照target优先进行合并。 - /// - /// 合并对象,优先选择 - /// 合并对象,非优先 - /// - public static IEnumerable MergeFiles(IEnumerable baseFile, IEnumerable incoming) - { - var mapping = new Dictionary(); // asset-domain下的目标位置 -> 文件 - if (!baseFile.Any()) return incoming; - if (!incoming.Any()) return baseFile; - foreach (var file in baseFile) - { - mapping.Add(file.RelativePath, file); - } - foreach (var file in incoming) - { - if (!mapping.TryAdd(file.RelativePath, file)) - { - mapping.Remove(file.RelativePath, out var existing); - mapping.Add(existing.RelativePath, existing.Combine(file)); - } - } - return mapping.Values; - } + ///// + ///// 将两个带有TranslatedFile的列表合并,对冲突项按照target优先进行合并。 + ///// + ///// 合并对象,优先选择 + ///// 合并对象,非优先 + ///// + //public static IEnumerable MergeFiles(IEnumerable baseFile, IEnumerable incoming) + //{ + // var mapping = new Dictionary(); // asset-domain下的目标位置 -> 文件 + // if (!baseFile.Any()) return incoming; + // if (!incoming.Any()) return baseFile; + // foreach (var file in baseFile) + // { + // mapping.Add(file.RelativePath, file); + // } + // foreach (var file in incoming) + // { + // if (!mapping.TryAdd(file.RelativePath, file)) + // { + // mapping.Remove(file.RelativePath, out var existing); + // mapping.Add(existing.RelativePath, existing.Combine(file)); + // } + // } + // return mapping.Values; + //} - /// - /// 基于原位置的文件key,用incoming的词条进行替换。未被替换的保持原文。 - /// - /// 原位置的基准文件 - /// 更新文件 - /// - public static IEnumerable PortFiles(IEnumerable baseFile, IEnumerable incoming) - { - var mapping = new Dictionary(); // asset-domain下的目标位置 -> 文件 - if (!incoming.Any()) return baseFile; - foreach (var file in baseFile) - { - mapping.Add(file.RelativePath, file); - } - foreach (var file in incoming) - { - if (!mapping.TryAdd(file.RelativePath, file)) - { - mapping.Remove(file.RelativePath, out var existing); - mapping.Add(existing.RelativePath, existing.Port(file)); - } - } - return mapping.Values; - } + ///// + ///// 基于原位置的文件key,用incoming的词条进行替换。未被替换的保持原文。 + ///// + ///// 原位置的基准文件 + ///// 更新文件 + ///// + //public static IEnumerable PortFiles(IEnumerable baseFile, IEnumerable incoming) + //{ + // var mapping = new Dictionary(); // asset-domain下的目标位置 -> 文件 + // if (!incoming.Any()) return baseFile; + // foreach (var file in baseFile) + // { + // mapping.Add(file.RelativePath, file); + // } + // foreach (var file in incoming) + // { + // if (!mapping.TryAdd(file.RelativePath, file)) + // { + // mapping.Remove(file.RelativePath, out var existing); + // mapping.Add(existing.RelativePath, existing.Port(file)); + // } + // } + // return mapping.Values; + //} - // 下面的这些...其实都不是我写的... public static string AppendTimestamp(string path) { From 83713d2e809dfc77e22709ecc39c501da5332a49 Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sat, 30 Sep 2023 18:47:05 +0800 Subject: [PATCH 07/22] Finalize Packer code (ish) --- src/Packer/Extensions/ArchiveExtension.cs | 42 +-- src/Packer/Extensions/ContentExtension.cs | 108 +++--- src/Packer/Extensions/DirectoryExtension.cs | 322 +++++------------- src/Packer/Extensions/SerializingExtension.cs | 105 ------ src/Packer/Lib.cs | 49 --- src/Packer/Models/Config.cs | 101 ++++-- src/Packer/Models/IResourceFileProvider.cs | 5 +- src/Packer/Models/McMeta.cs | 28 -- src/Packer/Models/Mod.cs | 48 --- src/Packer/Models/PackerPolicy.cs | 43 +++ src/Packer/Models/PackerStrategy.cs | 63 ---- .../Models/Providers/CompositionHelper.cs | 98 ++++++ .../Models/Providers/CompositionProvider.cs | 34 -- src/Packer/Models/Providers/LanguageFile.cs | 92 ----- src/Packer/Models/Providers/McMetaProvider.cs | 52 ++- src/Packer/Models/Providers/RawFile.cs | 6 +- .../Models/Providers/TermMappingProvider.cs | 262 ++++++++++---- src/Packer/Models/Providers/TextFile.cs | 21 +- src/Packer/Models/TranslatedFile.cs | 229 ------------- src/Packer/Program.cs | 60 ++-- src/Packer/Utils.cs | 135 +++----- 21 files changed, 680 insertions(+), 1223 deletions(-) delete mode 100644 src/Packer/Extensions/SerializingExtension.cs delete mode 100644 src/Packer/Lib.cs delete mode 100644 src/Packer/Models/McMeta.cs delete mode 100644 src/Packer/Models/Mod.cs create mode 100644 src/Packer/Models/PackerPolicy.cs delete mode 100644 src/Packer/Models/PackerStrategy.cs create mode 100644 src/Packer/Models/Providers/CompositionHelper.cs delete mode 100644 src/Packer/Models/Providers/CompositionProvider.cs delete mode 100644 src/Packer/Models/Providers/LanguageFile.cs delete mode 100644 src/Packer/Models/TranslatedFile.cs diff --git a/src/Packer/Extensions/ArchiveExtension.cs b/src/Packer/Extensions/ArchiveExtension.cs index 706904210584..62121c98727b 100644 --- a/src/Packer/Extensions/ArchiveExtension.cs +++ b/src/Packer/Extensions/ArchiveExtension.cs @@ -1,51 +1,13 @@ -using Packer.Models; -using Serilog; -using System; -using System.Collections.Generic; -using System.IO; +using System; using System.IO.Compression; -using System.Linq; -using System.Threading.Tasks; namespace Packer.Extensions { /// - /// 用于创建压缩包的各种拓展方法 + /// 用于压缩包的拓展方法 /// static public class ArchiveExtension { - /// - /// 初始化压缩包

- /// 包括压缩包的基础文件 - ///
- /// 压缩文件 - /// 所使用的配置 - public static void Initialize(this ZipArchive archive, Config config) - { - Log.Information("开始初始化压缩包"); - string commonPrefix = $"./projects/{config.Version}"; - config.FilesToInitialize.ForEach(path => - { - var destination = path.StripModName() // 除掉一层文件夹(在 assets/ 里的各种 fix) - .NormalizePath(); - Log.Information("初始化压缩包:添加 {0}", destination); - - // pack.mcmeta 特殊处理:添加时间戳 - if(destination == "pack.mcmeta") - { - using var writer = new StreamWriter( - archive.CreateEntry(destination) - .Open()); - - writer.Write(Utils.AppendTimestamp($"{commonPrefix}/{path}")); - return; - } - - archive.CreateEntryFromFile($"{commonPrefix}/{path}", destination); - }); - - Log.Information("初始化完成"); - } /// /// 校验将要传入压缩包的的文件是否存在重名
///
diff --git a/src/Packer/Extensions/ContentExtension.cs b/src/Packer/Extensions/ContentExtension.cs index fa41c4d34dce..bac9be751178 100644 --- a/src/Packer/Extensions/ContentExtension.cs +++ b/src/Packer/Extensions/ContentExtension.cs @@ -1,11 +1,8 @@ -using Packer.Models; -using Serilog; -using System; +using System; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text.RegularExpressions; -using System.Text.Encodings.Web; namespace Packer.Extensions { @@ -14,9 +11,27 @@ namespace Packer.Extensions ///
public static partial class ContentExtension { + /// + /// 将文件的目标路径正规化,以免各种加载出错 + /// + /// 目标路径 + /// 正规化后的文件路径 + public static string NormalizePath(this string path) + => path.Replace('\\', '/'); // 修正正反斜杠导致的压缩文件读取问题 + + [GeneratedRegex(@"^[a-z0-9_.-]+$", RegexOptions.Singleline)] - private static partial Regex ValidNamespaceRegex(); + internal static partial Regex ValidNamespaceRegex(); + /// + /// 检查命名空间名称是否合法 + /// + /// + /// 合法的命名空间名称只包括小写字母、数字、_、.、- + /// + /// 待校验的命名空间名称 + /// 若合法,返回 + /// 校验的命名空间不合法 public static bool ValidateNamespace(this string namespaceName) { // 强行丢异常...行吧 @@ -26,83 +41,50 @@ public static bool ValidateNamespace(this string namespaceName) } - /// - /// 将文件的目标路径正规化,以免各种加载出错 + /// 判断domain是否强制包含 /// - /// 目标路径 - /// - public static string NormalizePath(this string path) - => path.Replace('\\', '/') // 修正正反斜杠导致的压缩文件读取问题 - ; + /// 文件所在的位置 + /// 所使用的配置 + public static bool IsDomainForceIncluded(this string location, Config config) + => config.Floating.InclusionDomains.Any(_ => location.StartsWith(_ + '/')); /// - /// 移除模组名一级,在基础文件处理处用到 + /// 判断domain是否强制排除 /// - /// 目标文件在库中assets\1\2\...>式位置 - /// - public static string StripModName(this string path) - { - var _ = path.Split('/').ToList(); - - if (_.Count >= 2) _.RemoveAt(1); // 认为模组名在第一处 / 的后面 - return Path.Join(_.ToArray()); - } - - ///// - ///// 文本预处理

- ///// 目前仅有特殊符号更换,但还是预留了空间 - /////
- ///// 待处理的文本 - ///// 文本种类,用于判断是否转义 - ///// 所使用的配置 - ///// - //public static string Preprocess(this string content, FileCategory category, Config config) - //{ - // // 特殊符号替换 - // foreach (var mapping in config.CharatcerReplacement) - // { - // var escaped = JavaScriptEncoder.Default.Encode(mapping.Value); - // if (content.Contains(mapping.Key)) - // { - // Log.Information("正在进行特殊符号替换:{0} -> {1}", mapping.Key, escaped); - // } - - // if ((category & FileCategory.JsonAlike) == FileCategory.JsonAlike) - // { // 替换为 unicode 转义码 - // content = content.Replace(mapping.Key, escaped); - // } - // else - // { // 替换为 unicode 字符 - // content = content.Replace(mapping.Key, mapping.Value); - // } + /// 文件所在的位置 + /// 所使用的配置 + public static bool IsDomainForceExcluded(this string location, Config config) + => config.Floating.ExclusionDomains.Any(_ => location.StartsWith(_ + '/')); - // } - // return content; - //} + /// + /// 判断文件是否属于目标语言 + /// + /// 文件所在的位置 + /// 所使用的配置 + public static bool IsInTargetLanguage(this string location, Config config) + => config.Base.TargetLanguages.Any(_ => location.Contains(_, StringComparison.OrdinalIgnoreCase)); /// - /// 判断文件是否需要跳过预处理

- /// 一般而言,图片类文件需要跳过;这一点可以在config\packer.json里控制 + /// 判断文件路径是否强制排除 ///
/// 文件所在的位置 /// 所使用的配置 - /// - public static bool IsForceIncluded(this string location, Config config) - => config.ForceInclusionDomain.Any(_ => location.StartsWith(_ + '/')); + public static bool IsPathForceExcluded(this string location, Config config) + => config.Floating.ExclusionPaths.Contains(location); /// - /// 判断文件是否属于应跳过的语言 + /// 判断文件路径是否强制包含 /// /// 文件所在的位置 /// 所使用的配置 - /// - public static bool IsInTargetLanguage(this string location, Config config) - => config.TargetLanguages.Any(_ => location.Contains(_, StringComparison.OrdinalIgnoreCase)); + public static bool IsPathForceIncluded(this string location, Config config) + => config.Floating.InclusionPaths.Contains(location); + // 临时方法 /// - /// 计算给定流中全体内容的MD5值。 + /// 计算给定流中全体内容的MD5值 /// /// 被计算的流 /// diff --git a/src/Packer/Extensions/DirectoryExtension.cs b/src/Packer/Extensions/DirectoryExtension.cs index b506663c0dc5..0eb484ba9ff0 100644 --- a/src/Packer/Extensions/DirectoryExtension.cs +++ b/src/Packer/Extensions/DirectoryExtension.cs @@ -1,12 +1,10 @@ using Packer.Models; using Packer.Models.Providers; -using Serilog; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.Json; -using System.Text.RegularExpressions; namespace Packer.Extensions { @@ -19,10 +17,6 @@ namespace Packer.Extensions ///
public static partial class DirectoryExtension { - [GeneratedRegex(@"^assets/[a-z0-9_.-]+/lang/[a-zA-Z0-9_-]+\.(?:json|lang)$", RegexOptions.Singleline)] - private static partial Regex LanguageFileRegex(); - - /// /// 加载策略所使用的标准方法代理 /// @@ -33,121 +27,76 @@ public static partial class DirectoryExtension public delegate EvaluatorReturnType ProviderEvaluator(DirectoryInfo namespaceDirectory, Config config, - Dictionary parameters); + ParameterType? parameters); - public static Dictionary functionTable = new() + /// + /// 从到加载方法的查询表 + /// + internal static Dictionary functionTable = new() { - { PackerStrategyType.NoAction, FromCurrentDirectory }, - { PackerStrategyType.CloneMissing, FromSpecifiedDirectory } // , - // ... + { PackerPolicyType.Direct, FromCurrentDirectory }, // 现场生成 + { PackerPolicyType.Indirect, FromSpecifiedDirectory }, // 给定目录 + { PackerPolicyType.Composition, FromComposition } // 组合生成 }; + /// + /// 从给定的命名空间,基于当地的packer-policy.json + /// 与packer-config-fixup.json,遍历 + /// + /// 命名空间所在目录 + /// 所使用的全局配置 + /// public static IEnumerable EnumerateProviders (this DirectoryInfo namespaceDirectory, Config config) => from enumeratedPair in namespaceDirectory.EnumerateRawProviders(config) - group enumeratedPair by enumeratedPair.provider.Destination into providerGroup - select providerGroup.Aggregate( - seed: null as IResourceFileProvider, - (accumlate, next) - => next.provider.ApplyTo(accumlate, next.overrides)) /* into provider - select provider.ReplaceDestination(@"(?<=^assets/)[^/]*(?=/)", - namespaceDirectory.Name) */ ;// WARNING:路径替换要做到具体方法里面! - - static EvaluatorReturnType EnumerateRawProviders(this DirectoryInfo namespaceDirectory, Config config) - { - var policyFile = namespaceDirectory.GetFiles("packer-policy.json").FirstOrDefault(); - var policyList = Utils.RetrieveStrategy(policyFile); - - return from policy in policyList - from enumeratedPair in functionTable[policy.Type](namespaceDirectory, config, policy.Parameters) - select enumeratedPair; - } - - ///// - ///// 从[namespace]生成所需的Asset对象,采用本目录下放置的配置文件 - ///// - ///// 目标路径 - ///// 采用的配置 - ///// 未经处理的文件 - ///// - //public static IEnumerable AggregateAssetFiles(this DirectoryInfo assetPath, - // Config config, - // ref Dictionary bypassed) - //{ - // // 读取局域配置文件;若为空,配置为“无操作”(直接处理文件) - // var policy = Utils.RetrieveStrategy(assetPath.GetFiles("packer-policy.json").FirstOrDefault()); - - // if (policy.Type != PackerStrategyType.NoAction) - // Log.Information("对asset-domain {2} 采用非标准检索策略:{0} w/ {1}", - // policy.Type, - // policy.Parameters, - // assetPath.Name); - - // // Delegate是个好东西 要不然这参数不知道要多长 - // // 不过,什么时候能支持集合字面量......这样子就甚至不用写类型了 - // // 目前支持的打包策略 - // Dictionary functionTable = new() - // { - // { PackerStrategyType.NoAction, FromImmediateDirectory }, - // { PackerStrategyType.PlainClone, FromIndirectDirectory }, - // { PackerStrategyType.CloneMissing, FromMixedDirectory }, - // { PackerStrategyType.BackPort, FromBackPort }, - // { PackerStrategyType.Patch, FromPatches } - // }; - // return functionTable[policy.Type](assetPath, config, ref bypassed, policy.Parameters); - //} + group enumeratedPair by enumeratedPair.provider.Destination into providerGroup + select providerGroup.Aggregate( + seed: null as IResourceFileProvider, + (accumulate, next) + => next.provider.ApplyTo(accumulate, next.overrides)); + /// + /// 遍历未经合并的文件,用于递归调用 + /// + internal static EvaluatorReturnType EnumerateRawProviders(this DirectoryInfo namespaceDirectory, Config config) + => from policy in Utils.RetrieveStrategy(namespaceDirectory) + from enumeratedPair in functionTable[policy.Type].Invoke( + namespaceDirectory, config, policy.Parameters) + select enumeratedPair; - static IResourceFileProvider CreateProviderFromFile(FileInfo file, string destination, Config config) + internal static EvaluatorReturnType FromCurrentDirectory(DirectoryInfo namespaceDirectory, + Config config, + ParameterType? parameters) { - var extension = file.Extension; - if (file.Directory!.Name == "lang") - { - switch (extension) - { - case ".json": return JsonLanguageFile.Create(file, destination); - case ".lang": return LangLanguageFile.Create(file, destination); - }; - } - return extension switch - { - // 已知的文本文件类型 - ".txt" or ".json" or ".md" => TextFile.Create(file, destination), - _ => new RawFile(file, destination) - }; + var floatingConfig = Utils.RetrieveLocalConfig(namespaceDirectory); + var localConfig = config.Modify(floatingConfig); + + return from candidate in namespaceDirectory.EnumerateFiles("*", SearchOption.AllDirectories) + let relativePath = Path.GetRelativePath(namespaceDirectory.FullName, + candidate.FullName) + .NormalizePath() + let destination = Path.Combine(namespaceDirectory.Name, + relativePath) + .NormalizePath() + let domain = relativePath.Split('/')[0] + where !relativePath.IsPathForceExcluded(localConfig) // [1] 排除路径 -- packer-policy等 + where (relativePath.IsPathForceIncluded(localConfig) // [2] 包含路径 [单列] + || relativePath.IsDomainForceIncluded(localConfig) // [3] 包含domain -- font/ textures/ + || (destination.IsInTargetLanguage(localConfig) // [4] 语言标记 -- 含zh_cn的 + && relativePath.IsDomainForceExcluded(localConfig))) // [5] 排除domain [暂无] + let provider = CreateProviderFromFile(candidate, destination, localConfig) + select (provider, DoesOverride(parameters)); } - - - - - - static EvaluatorReturnType FromCurrentDirectory(DirectoryInfo namespaceDirectory, - Config config, - ParameterType parameters) - => from candidate in namespaceDirectory.EnumerateFiles("*", SearchOption.AllDirectories) - let relativePath = Path.GetRelativePath(namespaceDirectory.FullName, - candidate.FullName) - .NormalizePath() - let destination = Path.Combine(namespaceDirectory.Name, - relativePath) - .NormalizePath() - let domain = relativePath.Split('/')[0] - where relativePath != "packer-policy.json" // TODO:其他文件 // 策略文件本身不包含 - where destination.IsInTargetLanguage(config) // 含有正确的语言标记 - || relativePath.IsForceIncluded(config) // 强制包含 - let provider = CreateProviderFromFile(candidate, destination, config) - select (provider, DoesOverride(parameters)); - - static EvaluatorReturnType FromSpecifiedDirectory(DirectoryInfo namespaceDirectory, - Config config, - ParameterType parameters) + internal static EvaluatorReturnType FromSpecifiedDirectory(DirectoryInfo namespaceDirectory, + Config config, + ParameterType? parameters) { - var redirect = parameters["source"].GetString(); + var redirect = parameters!["source"].GetString(); var namespaceName = namespaceDirectory.Name; - namespaceName.ValidateNamespace(); var redirectDirectory = new DirectoryInfo(redirect!); + return from candidate in redirectDirectory.EnumerateRawProviders(config) let provider = candidate.provider .ReplaceDestination(@"^(?<=^assets/)[^/]*(?=/)", @@ -155,139 +104,46 @@ static EvaluatorReturnType FromSpecifiedDirectory(DirectoryInfo namespaceDirecto select (provider, DoesOverride(parameters)); } + internal static EvaluatorReturnType FromComposition(DirectoryInfo namespaceDirectory, + Config config, + ParameterType? parameters) + { + var compositionPath = parameters!["source"].GetString(); + var type = parameters["type"].GetString(); + var compositionFile = new FileInfo(compositionPath!); + IResourceFileProvider provider = type switch // 类型推断不出要用接口 + { + "lang" => LangMappingHelper.CreateFromComposition(compositionFile), + "json" => JsonMappingHelper.CreateFromComposition(compositionFile), + _ => throw new InvalidOperationException($"Unexpected Type parameter at {namespaceDirectory.FullName}.") + }; + yield return (provider, DoesOverride(parameters)); + } + internal static IResourceFileProvider CreateProviderFromFile(FileInfo file, string destination, Config config) + { + var extension = file.Extension; + return file.Directory!.Name == "lang" + ? extension switch + { + ".json" => JsonMappingHelper.CreateFromFile(file, destination), + ".lang" => JsonMappingHelper.CreateFromFile(file, destination), + _ => throw new InvalidOperationException($"Invalid Type of Language File at {file.FullName}.") + } + : extension switch + { + // 已知的文本文件类型 + ".txt" or ".json" or ".md" => TextFile.Create(file, destination), + _ => new RawFile(file, destination) + }; + } - static bool DoesOverride(ParameterType parameters) + internal static bool DoesOverride(ParameterType? parameters) { + if (parameters is null) return false; var hasKey = parameters.TryGetValue("overrides", out var element); return hasKey ? element.GetBoolean() : false; } - - - - - - - //static IEnumerable FromMixedDirectory(DirectoryInfo assetDirectory, - // Config config, - // ref Dictionary unprocessed, - // Dictionary parameters) - // => Utils.MergeFiles(FromImmediateDirectory(assetDirectory, config, ref unprocessed, parameters), - // FromIndirectDirectory(assetDirectory, config, ref unprocessed, parameters)); - - //static IEnumerable FromBackPort(DirectoryInfo assetDirectory, - // Config config, - // ref Dictionary unprocessed, - // Dictionary parameters) - // => Utils.PortFiles(FromImmediateDirectory(assetDirectory, config, ref unprocessed, parameters), - // FromIndirectDirectory(assetDirectory, config, ref unprocessed, parameters)); - - //static IEnumerable FromIndirectDirectory(DirectoryInfo assetDirectory, - // Config config, - // ref Dictionary unprocessed, - // Dictionary parameters) - // => AggregateAssetFiles(new DirectoryInfo(parameters["source"].GetString()), config, ref unprocessed); - - //static IEnumerable FromPatches(DirectoryInfo assetDirectory, - // Config config, - // ref Dictionary unprocessed, - // Dictionary parameters) - //{ - // var reference = FromIndirectDirectory(assetDirectory, config, ref unprocessed, parameters) - // .ToDictionary(_ => _.RelativePath); - // var patchList = JsonSerializer.Deserialize>(parameters["patches"]); - // foreach (var patch in patchList) - // { - // Log.Information("对文件 {0} 应用 {1} 处的 patch。", patch.Key, patch.Value); - // reference.Remove(patch.Key, out var target); - // var patchText = string.Join('\n', File.ReadAllLines(patch.Value)); // 不要问我为什么D-M-P默认换行是LF - // reference.Add(patch.Key, target.ApplyPatch(patchText)); - // } - // return reference.Values; - //} - - //// 目前所有策略的终点方法 - //static IEnumerable FromImmediateDirectory(DirectoryInfo assetDirectory, - // Config config, - // ref Dictionary unprocessed, - // Dictionary parameters) - //{ - // var bypassed = unprocessed; - // var result = assetDirectory.EnumerateFiles("*", SearchOption.AllDirectories) // / 的下级文件 - // .Select(file => - // { // 这里开始真正的检索。被跳过的文本用 null 代替 - // var prefixLength = assetDirectory.FullName.Length; - // var relativePath = file.FullName[(prefixLength + 1)..] - // .Replace('\\', '/'); // 在asset-domain下的位置,规范为用正斜杠分割 - - // // 处理被跳过的文本。处理顺序:policy -> [bypass](font, textures) -> !zh_cn - // // 顺序乱了会导致字体文件被丢弃,因为没有带zh_cn - - // // 跳过检索策略文件 - // if (relativePath == "packer-policy.json") - // { - // return null; - // } - - // // 选出不经过处理路径的文件 - // if (relativePath.IsForceIncluded(config)) - // { - // var target = Path.Combine("assets", - // assetDirectory.Name, - // relativePath); - // Log.Information("跳过了标记为直接加入的命名空间:{0} -> {1}", - // relativePath.Split('/')[0], - // target); - - // if (bypassed.ContainsValue(target)) - // { - // Log.Warning("在未处理文件中检测到重复项。丢弃将要加入的新项"); - // return null; - // } - // bypassed.Add(file.FullName, target); - // return null; - // } - - // // 跳过非中文文件 - // if (!relativePath.IsInTargetLanguage(config)) - // { - // return null; - // } - - // // 跳过非中文文件 - // if (!relativePath.IsInTargetLanguage(config)) - // { - // return null; - // } - - // // 处理正常的语言文件 - // // TODO:Json5支持 - // var parsingCategory = file.Extension switch - // { - // ".json" => FileCategory.JsonAlike, - // _ => FileCategory.LangAlike - // }; - // if (relativePath.StartsWith("lang/")) - // { - // return new LangFile(file.OpenRead(), - // parsingCategory | FileCategory.LanguageFile, - // config) - // { - // RelativePath = relativePath - // }; - // } - // else - // { - // return new TranslatedFile(file.OpenRead(), - // parsingCategory | FileCategory.OtherFiles, - // config) - // { - // RelativePath = relativePath - // }; - // } - // }).Where(_ => _ is not null); // 排除掉跳过的文件 - // return result; - //} } -} +} \ No newline at end of file diff --git a/src/Packer/Extensions/SerializingExtension.cs b/src/Packer/Extensions/SerializingExtension.cs deleted file mode 100644 index 520cb9905de5..000000000000 --- a/src/Packer/Extensions/SerializingExtension.cs +++ /dev/null @@ -1,105 +0,0 @@ -//using Packer.Models; -//using Packer.Models.Providers; -//using Serilog; -//using System; -//using System.Collections.Generic; -//using System.Text; -//using System.Text.Json; - -//namespace Packer.Extensions -//{ -// static class SerializingExtension -// { -// public static string SerializeAsset(this Dictionary assetMap, FileCategory category) -// => category switch -// { -// // Json 文件,直接写出 -// FileCategory.JsonTranslationFormat => JsonSerializer.Serialize(assetMap, -// new JsonSerializerOptions -// { -// WriteIndented = true -// }), -// // Lang文件 -// FileCategory.LangTranslationFormat => SerializeFromLang(assetMap), -// _ => null // 其实不应该执行到这个地方 -// }; - -// static string SerializeFromLang(Dictionary assetMap) -// { -// // lang格式化还好说 -// var sb = new StringBuilder(); -// foreach (var pair in assetMap) -// { -// sb.AppendJoin('=', pair.Key, pair.Value); -// sb.Append(Environment.NewLine); -// } -// return sb.ToString(); -// } - -// public static Dictionary DeserializeAsset(this string content, FileCategory category) -// => category switch -// { -// FileCategory.JsonTranslationFormat -// => JsonSerializer.Deserialize>(content, -// new JsonSerializerOptions -// { -// ReadCommentHandling = JsonCommentHandling.Skip // 打包过程应当兼容注释,但不需要写入注释 -// }), // 直接有的算法 -// FileCategory.LangTranslationFormat => DeserializeFromLang(content), -// _ => null // 其实不应该执行到这个地方 -// }; - -// static Dictionary DeserializeFromLang(string content) -// { -// // 甚至不是自动机...所以不敢多用,否则会炸 - -// // 下面的 Verbose 仅供调试,不会在 log 里出现 -// // .lang的格式真的乱... -// Log.Verbose("开始反序列化 .lang 文件"); -// // #PARSE_ESCAPE就算了吧 -// var result = new Dictionary(); -// var isInComment = false; // 处理多行注释 -// new List(content.Split(Environment.NewLine, -// StringSplitOptions.RemoveEmptyEntries)) -// .ForEach(line => -// { -// var isSingleLineComment = false; -// new List { "//", "#" } -// .ForEach(_ => { isSingleLineComment |= line.StartsWith(_); }); -// if (isSingleLineComment) -// { -// Log.Verbose("跳过了单行注释:{0}", line); -// } -// else if (isInComment) // 多行注释内 -// { -// Log.Verbose("{0}", line); -// if (line.Trim() -// .EndsWith("*/")) -// { -// isInComment = false; // 跳出注释 -// } -// } -// else if (line.StartsWith("/*")) // 开始多行注释 -// { -// Log.Verbose("跳过了多行注释:{0}", line); -// } -// else // 真正的条目 -// { -// Log.Verbose("添加对应映射:{0}", line); -// var spiltPosition = line.IndexOf('='); -// try -// { -// result.Add(line[..spiltPosition], line[(spiltPosition + 1)..]); -// } -// catch (Exception e) -// { -// Log.Warning(e.ToString()); -// } -// } -// } -// ); -// Log.Verbose("反序列化完成"); -// return result; -// } -// } -//} diff --git a/src/Packer/Lib.cs b/src/Packer/Lib.cs deleted file mode 100644 index dae6789d8ffd..000000000000 --- a/src/Packer/Lib.cs +++ /dev/null @@ -1,49 +0,0 @@ -//using Packer.Extensions; -//using Packer.Models; -//using Serilog; -//using System; -//using System.Collections.Generic; -//using System.IO; -//using System.Linq; -//using System.Text.RegularExpressions; - -//namespace Packer -//{ -// static class Lib -// { -// /// -// /// 从主库中选出所需文本 -// /// -// /// 所使用的配置 -// /// -// /// 需要包含的模组列表,按模组唯一标识符
-// /// 若为,表示包含所有模组 -// /// -// /// -// public static IEnumerable RetrieveContent( -// Config config, -// IEnumerable? targetModIdentifiers) - -// // 成功实现了没分号的C#语句...这就是查询表达式吗( -// => from modDirectory in new DirectoryInfo($"./projects/{config.Version}/assets") -// .EnumerateDirectories() -// let modIdentifier = modDirectory.Name -// // 模组筛选,按模组标识符 -// where targetModIdentifiers is null // 未提供列表,全部打包 -// || targetModIdentifiers.Contains(modIdentifier) // 有列表,仅打包列表中的项 -// from namespaceDirectory in modDirectory.EnumerateDirectories() -// let namespaceName = namespaceDirectory.Name -// // 检查命名空间格式,拒绝错误格式 -// // 但是写成表达式以后,没法现场丢异常了... -// where !Regex.IsMatch(namespaceName, -// @"^[a-z0-9_\-.]+$", -// RegexOptions.Singleline) -// from provider in namespaceDirectory.EnumerateProviders(config) -// // 合并文件;我猜没写错 -// group provider by namespaceName into namespaceGroup -// select namespaceGroup -// .Aggregate(seed: null as IResourceFileProvider, // 好家伙 类型推断系统推断不出TAggregate -// (accumlate, next) // 为什么这个参数叫func不叫accumlator或者aggregator... -// => next.ApplyTo(accumlate, overrideExisting: false)); -// } -//} diff --git a/src/Packer/Models/Config.cs b/src/Packer/Models/Config.cs index f6d73453db8a..c19c488b175f 100644 --- a/src/Packer/Models/Config.cs +++ b/src/Packer/Models/Config.cs @@ -1,63 +1,110 @@ using System.Collections.Generic; +using System.Linq; using System.Text.Json.Serialization; namespace Packer { /// - /// 配置文件 - /// 主要config/packer.json加载 + /// 配置项 /// public struct Config + { + /// + /// 基础配置,版本唯一 + /// + public BaseConfig Base { get; set; } + /// + /// 浮动配置,可与命名空间下的文件合并 + /// + public FloatingConfig Floating { get; set; } + + /// + /// 从命名空间下的局域配置加载内容。 + /// + public Config Modify(FloatingConfig? floatingConfig) + { + // 好家伙 这玩意还是个Nullable + if (!floatingConfig.HasValue) return this; + return new() + { + Base = Base, + Floating = Floating.Merge(floatingConfig.Value) + }; + } + } + + /// + /// 基础配置,版本唯一 + /// + public struct BaseConfig { /// /// 打包的目标版本 /// - [JsonPropertyName("targetVersion")] public string Version { get; set; } /// - /// 打包的目标语言

+ /// 打包的目标语言 ///
- [JsonPropertyName("targetLanguage")] public string[] TargetLanguages { get; set; } /// - /// 打包过程的基础文件(如在assets/以外的文件,或不宜通过打包流程的) + /// 不进行打包的mod(按[curseforge-]name) /// - [JsonPropertyName("additionalContent")] - public List FilesToInitialize { get; set; } + public IEnumerable ExclusionMods { get; set; } /// - /// 不进行打包的mod(按[curseforge-]name处理)

- /// 有可能作为基础文件 + /// 不进行打包的namespace ///
- [JsonPropertyName("modNameBlackList")] - public List ModBlackList { get; set; } + public IEnumerable ExclusionNamespaces { get; set; } + } + /// + /// 浮动配置,可与命名空间下的文件合并 + /// + public struct FloatingConfig + { /// - /// 不进行打包的asset-domain

- /// 有可能作为基础文件 + /// 强制包含的domain ///
- [JsonPropertyName("domainBlackList")] - public List DomainBlackList { get; set; } - + public IEnumerable InclusionDomains { get; set; } + /// + /// 强制排除的domain + /// + public IEnumerable ExclusionDomains { get; set; } + /// + /// 强制包含的路径 + /// + public IEnumerable ExclusionPaths { get; set; } /// - /// (这不是基础文件!)

- /// 进入打包流程,但不按照语言文件格式化(也就不回避重复文件)

- /// 图片文件必须经过此流程!

- /// 按照namespace识别 + /// 强制排除的路径 ///
- [JsonPropertyName("noProcessNamespace")] - public List ForceInclusionDomain { get; set; } + public IEnumerable InclusionPaths { get; set; } /// - /// 字符替换表,版本限定 + /// 文本字符替换表 /// - [JsonPropertyName("replacementMap")] public Dictionary CharatcerReplacement { get; set; } + /// + /// 内容替换表 + /// + public Dictionary DestinationReplacement { get; set; } + + /// + /// 从另一对象合并配置 + /// + public FloatingConfig Merge(FloatingConfig other) => new() + { + ExclusionPaths = ExclusionPaths.Concat(other.ExclusionPaths).Distinct(), + ExclusionDomains = ExclusionDomains.Concat(other.ExclusionDomains).Distinct(), + InclusionDomains = InclusionDomains.Concat(other.InclusionDomains).Distinct(), + InclusionPaths = InclusionPaths.Concat(other.InclusionPaths).Distinct(), + CharatcerReplacement = CharatcerReplacement.Concat(other.CharatcerReplacement).DistinctBy(_ => _.Key) + .ToDictionary(_ => _.Key, _ => _.Value), + DestinationReplacement = DestinationReplacement.Concat(other.DestinationReplacement).DistinctBy(_ => _.Key) + .ToDictionary(_ => _.Key, _ => _.Value) + }; - [JsonPropertyName("destinitionReplacement")] - public Dictionary DestinationReplacement { get; set; } } } diff --git a/src/Packer/Models/IResourceFileProvider.cs b/src/Packer/Models/IResourceFileProvider.cs index d46025bf05e9..76255e044182 100644 --- a/src/Packer/Models/IResourceFileProvider.cs +++ b/src/Packer/Models/IResourceFileProvider.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.IO.Compression; -using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -54,9 +52,8 @@ public IResourceFileProvider ReplaceContent(string searchPattern, string replace public Task WriteToArchive(ZipArchive archive); /// - /// 获取该提供器的目标位置 + /// 目标在资源包中的相对位置,从根目录算起 /// - /// 目标在资源包中的相对位置,从根目录算起 public string Destination { get; } } } diff --git a/src/Packer/Models/McMeta.cs b/src/Packer/Models/McMeta.cs deleted file mode 100644 index 28f69882df73..000000000000 --- a/src/Packer/Models/McMeta.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Packer.Models -{ - /// - /// MCMETA格式

- /// 唯一用处是写修改日期 - ///
- public class McMeta - { - /// - /// - /// - [JsonPropertyName("pack")] public McMetaPack Pack { get; set; } - } - - /// - /// - public class McMetaPack - { - /// - /// - [JsonPropertyName("pack_format")] public int Format { get; set; } - /// - /// - [JsonPropertyName("description")] public string Description { get; set; } - } -} \ No newline at end of file diff --git a/src/Packer/Models/Mod.cs b/src/Packer/Models/Mod.cs deleted file mode 100644 index 8f2876da621a..000000000000 --- a/src/Packer/Models/Mod.cs +++ /dev/null @@ -1,48 +0,0 @@ -//using System.Collections.Generic; - -//namespace Packer.Models -//{ -// /// -// /// 模组译文的抽象表示 -// /// -// public class Mod -// { -// /// -// /// 模组名 -// /// -// public string modName; -// /// -// /// 采用的asset,按asset-domain分 -// /// -// public IEnumerable assets; -// } - -// /// -// /// asset的抽象表示 -// /// -// public class Asset -// { -// /// -// /// asset-domain名 -// /// -// public string domainName; -// /// -// /// 该asset-domain下的文件 -// /// -// public IEnumerable contents; -// /// -// /// domain合并,并解决重复文件问题 -// /// -// /// 要合并的对象 -// /// -// public Asset Combine(Asset other) -// { - -// return new Asset() -// { -// domainName = this.domainName, -// contents = Utils.MergeFiles(this.contents, other.contents) -// }; -// } -// } -//} diff --git a/src/Packer/Models/PackerPolicy.cs b/src/Packer/Models/PackerPolicy.cs new file mode 100644 index 000000000000..fb86d121b3ef --- /dev/null +++ b/src/Packer/Models/PackerPolicy.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Packer.Models +{ + /// + /// Packer 的局域打包策略类型 + /// + public enum PackerPolicyType + { + /// + /// 从当前位置加载文件。 + /// + Direct, + /// + /// 从指定位置加载文件。 + /// + Indirect, + /// + /// 从组合文件创建指定语言文件。 + /// + Composition + } + + /// + /// Packer的局域打包策略。包含策略类型,以及不同策略使用的额外参数 + /// + public class PackerPolicy + { + /// + /// 打包策略的类型参数 + /// + public PackerPolicyType Type { get; set; } + + /// + /// 打包策略的额外参数 + /// + [JsonExtensionData] + public Dictionary? Parameters { get; set; } + // JsonExtensionData要求以此种格式传入 + } +} diff --git a/src/Packer/Models/PackerStrategy.cs b/src/Packer/Models/PackerStrategy.cs deleted file mode 100644 index 835f51ddb073..000000000000 --- a/src/Packer/Models/PackerStrategy.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Collections.Generic; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Packer.Models -{ - /// - /// Packer 的局域打包策略类型 - /// - public enum PackerStrategyType - { - /// - /// 不进行额外操作,直接按照本处的文件结构打包

- /// 附加参数:无 - ///
- NoAction, - /// - /// 仅从某处复制文件,忽略当前目录的内容

- /// 附加参数:

- /// "source": string 复制源地址 - ///
- PlainClone, - /// - /// 使用本处的文件结构,随后从源地址补充文件

- /// 全体文件以本处优先

- /// 附加参数:

- /// "source": string 复制源地址 - ///
- CloneMissing, - /// - /// 使用此处的文件结构,仅对此处存在的条目从源地址更新

- /// 附加参数:

- /// "source": string 复制源地址 - ///
- BackPort, - /// - /// 从某处复制文件,然后应用由Google Diff-Match-Patch算法生成的修改项

- /// 附加参数:

- /// "source": string 复制源地址

- /// "patches": Dictionary<string, string> patch列表: patch目标 -> patch文本 - ///
- Patch - } - - /// - /// Packer的局域打包策略。包含策略类型,以及不同策略使用的额外参数 - /// - public class PackerStrategy - { - /// - /// 打包策略的类型参数 - /// - [JsonPropertyName("type")] - public PackerStrategyType Type { get; set; } - - /// - /// 打包策略的额外参数 - /// - [JsonExtensionData] - public Dictionary Parameters { get; set; } - // JsonExtensionData要求以此种格式传入 - } -} diff --git a/src/Packer/Models/Providers/CompositionHelper.cs b/src/Packer/Models/Providers/CompositionHelper.cs new file mode 100644 index 000000000000..5fed86a38e78 --- /dev/null +++ b/src/Packer/Models/Providers/CompositionHelper.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; + +namespace Packer.Models.Providers +{ + using LangMappingProvider = TermMappingProvider; + using JsonMappingProvider = TermMappingProvider; + + public static partial class LangMappingHelper + { + /// + /// 从组合文件创建 + /// + /// 组合文件 + public static LangMappingProvider CreateFromComposition(FileInfo file) + { + using var reader = file.OpenText(); + var data = JsonSerializer.Deserialize( + reader.ReadToEnd(), + new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + return new LangMappingProvider( + new LangDictionaryWrapper(CompositionHelper.CreateRawDictionary(data)), + data.Target); + } + } + + public static partial class JsonMappingHelper + { + /// + /// 从组合文件创建 + /// + /// 组合文件 + public static JsonMappingProvider CreateFromComposition(FileInfo file) + { + using var reader = file.OpenText(); + var data = JsonSerializer.Deserialize( + reader.ReadToEnd(), + new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + return new JsonMappingProvider( + JsonDictionaryWrapper.Create(CompositionHelper.CreateRawDictionary(data)), + data.Target); + } + } + + internal static class CompositionHelper + { + internal static Dictionary CreateRawDictionary(CompositionData data) + { + var query = from entry in data.Entries + let templates = entry.Templates + let parameters = entry.Parameters.CrossMap() + from parameter in parameters + from template in templates + let formattedKey = string.Format(template.Key, parameter.Key.ToArray()) + let formattedValue = string.Format(template.Value, parameter.Value.ToArray()) + select (formattedKey, formattedValue); + return query.ToDictionary(_ => _.formattedKey, _ => _.formattedValue); + } + + internal static IEnumerable, IEnumerable>> + CrossMap(this IEnumerable>> origin) + => origin.Aggregate( + seed: Enumerable.Empty, IEnumerable>>(), + (accumulate, next) => from incomingPair in next + join existingGroup in accumulate on true equals true + select KeyValuePair.Create( + existingGroup.Key.Append(incomingPair.Key), + existingGroup.Value.Append(incomingPair.Value))); + } + + + // composition format: + // - root + // * object + // - string target => 本文件产生组合的目标地址。 + // * list + // * object + // * object templates => 组合所用的模板。所有内容采用C#格式化模式填写。 + // - => + // * list params => 参数表。参数按照列举顺序排列。不支持嵌套,必须字面量。 + // * object + // - => + + internal struct CompositionData + { + public string Target { get; set; } + public List Entries { get; set; } + } + + internal struct CompositionEntry + { + public Dictionary Templates { get; set; } + public List> Parameters { get; set; } + } +} diff --git a/src/Packer/Models/Providers/CompositionProvider.cs b/src/Packer/Models/Providers/CompositionProvider.cs deleted file mode 100644 index bea32ad5ae87..000000000000 --- a/src/Packer/Models/Providers/CompositionProvider.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Text.Json.Nodes; - -namespace Packer.Models.Providers -{ - using LangMappingProvider = TermMappingProvider; - using JsonMappingProvider = TermMappingProvider; - - - // 考量:Helper? - public class CompositionProvider : TermMappingProvider - { - public CompositionProvider(ITermDictionary map, string destination) : base(map, destination) { } - - public CompositionProvider Create(FileInfo file) - { - - } - } - - - internal struct CompositonData - { - public string Target { get; set; } - public List Entries { get; set; } - } - - internal struct CompositionEntry - { - public Dictionary Templates { get; set; } - public Dictionary Parameters { get; set; } - } -} diff --git a/src/Packer/Models/Providers/LanguageFile.cs b/src/Packer/Models/Providers/LanguageFile.cs deleted file mode 100644 index 3c236d655f67..000000000000 --- a/src/Packer/Models/Providers/LanguageFile.cs +++ /dev/null @@ -1,92 +0,0 @@ -using Serilog; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.Json.Nodes; - -namespace Packer.Models.Providers -{ - - using LangMappingProvider = TermMappingProvider; - using JsonMappingProvider = TermMappingProvider; - - public class LangLanguageFile : LangMappingProvider - { - public LangLanguageFile(ITermDictionary map, string destination) : base(map, destination) { } - public static LangLanguageFile Create(FileInfo file, string destination) - { - using var stream = file.OpenRead(); - using var reader = new StreamReader(stream, Encoding.UTF8); - var content = reader.ReadToEnd(); - return new(new LangDictionaryWrapper(DeserializeFromLang(content)), destination); - } - - // RAW CONTENT - static Dictionary DeserializeFromLang(string content) - { - // 甚至不是自动机...所以不敢多用,否则会炸 - - // 下面的 Verbose 仅供调试,不会在 log 里出现 - // .lang的格式真的乱... - Log.Verbose("开始反序列化 .lang 文件"); - // #PARSE_ESCAPE就算了吧 - var result = new Dictionary(); - var isInComment = false; // 处理多行注释 - new List(content.Split(Environment.NewLine, - StringSplitOptions.RemoveEmptyEntries)) - .ForEach(line => - { - var isSingleLineComment = false; - new List { "//", "#" } - .ForEach(_ => { isSingleLineComment |= line.StartsWith(_); }); - if (isSingleLineComment) - { - Log.Verbose("跳过了单行注释:{0}", line); - } - else if (isInComment) // 多行注释内 - { - Log.Verbose("{0}", line); - if (line.Trim() - .EndsWith("*/")) - { - isInComment = false; // 跳出注释 - } - } - else if (line.StartsWith("/*")) // 开始多行注释 - { - Log.Verbose("跳过了多行注释:{0}", line); - } - else // 真正的条目 - { - Log.Verbose("添加对应映射:{0}", line); - var spiltPosition = line.IndexOf('='); - try - { - result.Add(line[..spiltPosition], line[(spiltPosition + 1)..]); - } - catch (Exception e) - { - Log.Warning(e.ToString()); - } - } - } - ); - Log.Verbose("反序列化完成"); - return result; - } - } - - - public class JsonLanguageFile : JsonMappingProvider - { - public JsonLanguageFile(ITermDictionary map, string destination) : base(map, destination) { } - public static JsonLanguageFile Create(FileInfo file, string destination) - { - using var stream = file.OpenRead(); - return new(new JsonDictionaryWrapper(JsonNode.Parse(stream).AsObject()), destination); - } - } - -} diff --git a/src/Packer/Models/Providers/McMetaProvider.cs b/src/Packer/Models/Providers/McMetaProvider.cs index 2a7776921e18..c6dcab9b8e50 100644 --- a/src/Packer/Models/Providers/McMetaProvider.cs +++ b/src/Packer/Models/Providers/McMetaProvider.cs @@ -1,22 +1,56 @@ -using System; -using System.Collections.Generic; +using Packer.Extensions; +using Serilog; +using System; +using System.IO; using System.IO.Compression; -using System.Linq; using System.Text; using System.Threading.Tasks; namespace Packer.Models.Providers { - internal class McMetaProvider : IResourceFileProvider + /// + /// 用于表示pack.mcmeta的提供器。写入时将会附加打包时间 + /// + public class McMetaProvider : TextFile { - public string Destination => "pack.mcmeta"; + internal McMetaProvider(string content, string destination) : base(content, destination) { } - public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) - => this; + /// + /// 从给定的构造提供器。 + /// + /// 读取源 + /// 目标地址 + public static new McMetaProvider Create(FileInfo file, string destination) + { + using var stream = file.OpenRead(); + using var reader = new StreamReader(stream, Encoding.UTF8); + var content = reader.ReadToEnd(); + return new McMetaProvider(content, destination); + } - public Task WriteToArchive(ZipArchive archive) + /// + public override string Destination => "pack.mcmeta"; + /// + public override IResourceFileProvider ReplaceContent(string searchPattern, string replacement) + => this; + /// + public override IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) + => this; + /// + public override async Task WriteToArchive(ZipArchive archive) { - throw new NotImplementedException(); + var destination = Destination.NormalizePath(); + Log.Information("正在添加 {0}", destination); + + var content = string.Format(Content, DateTime.UtcNow.AddHours(8) /* UTC +8:00 */); + + archive.ValidateEntryDistinctness(destination); + + using var writer = new StreamWriter( + archive.CreateEntry(destination) + .Open(), + Encoding.UTF8); + await writer.WriteAsync(content); } } } diff --git a/src/Packer/Models/Providers/RawFile.cs b/src/Packer/Models/Providers/RawFile.cs index e43c155e4ce0..101fcf8bfac5 100644 --- a/src/Packer/Models/Providers/RawFile.cs +++ b/src/Packer/Models/Providers/RawFile.cs @@ -20,13 +20,11 @@ public class RawFile : IResourceFileProvider ///
public FileInfo SourceFile { get; } - /// - /// 目标地址 - /// + /// public string Destination { get; } /// - /// 从给定的文件引用构造提供器 + /// 从给定的构造提供器 /// /// 源文件的引用 /// 目标地址 diff --git a/src/Packer/Models/Providers/TermMappingProvider.cs b/src/Packer/Models/Providers/TermMappingProvider.cs index 52c05a2aff72..3dcac7a057ed 100644 --- a/src/Packer/Models/Providers/TermMappingProvider.cs +++ b/src/Packer/Models/Providers/TermMappingProvider.cs @@ -14,30 +14,134 @@ namespace Packer.Models.Providers { + using LangMappingProvider = TermMappingProvider; + using JsonMappingProvider = TermMappingProvider; - - + #region termDictionary + /// + /// 可以作为语言文件使用的键值对包装 + /// + /// 内部使用的值类型 public interface ITermDictionary : IDictionary { - // TODO:Parse + /// + /// 从内部的键值对表示生成正确的语言文件文本 + /// + /// 生成文本 public string ProvideStringContent(); + /// + /// 在内部键值对的值中,对于文本部分,执行给定的替换。 + /// + /// 替换的匹配模式,使用 + /// 替换文本 + /// 替换得到的新 public ITermDictionary ReplaceContent(string searchPattern, string replacement); - public static ITermDictionary Create(IDictionary nominalMapping) - => throw new NotImplementedException(); } + internal class LangDictionaryWrapper : Dictionary, ITermDictionary + { + public LangDictionaryWrapper(IDictionary dictionary) : base(dictionary) { } + + public string ProvideStringContent() + { + var builder = new StringBuilder(); + foreach (var (key, value) in this) + { + builder.AppendJoin('=', key, value); + builder.Append(Environment.NewLine); + } + return builder.ToString(); + } + + public ITermDictionary ReplaceContent(string searchPattern, string replacement) + { + var result = new Dictionary(); + foreach (var (key, value) in this) + { + var replaced = Regex.Replace(value, + searchPattern, + replacement, + RegexOptions.Singleline); + result.Add(key, replaced); + } + return new LangDictionaryWrapper(result); + } + } + + internal class JsonDictionaryWrapper : Dictionary, ITermDictionary + { + public JsonDictionaryWrapper(IDictionary dictionary) : base(dictionary) { } + + public string ProvideStringContent() + => JsonSerializer.Serialize(this, new JsonSerializerOptions() + { + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }); + + public ITermDictionary ReplaceContent(string searchPattern, string replacement) + { + var result = new Dictionary(); + foreach (var (key, value) in this) + { + if (value.GetType() == typeof(JsonValue) + && value.AsValue().TryGetValue(out var stringValue)) + { + var replaced = Regex.Replace(stringValue, + searchPattern, + replacement, + RegexOptions.Singleline); + result.Add(key, JsonValue.Create(replaced)!); // 我猜不会null罢 + continue; + } + result.Add(key, value); + } + return new JsonDictionaryWrapper(result); + } + + public static ITermDictionary Create(IDictionary nominalMapping) + { + var query = from pair in nominalMapping + let key = pair.Key + let value = pair.Value + let node = JsonValue.Create(value)! + select (key, node); + var transformed = query.ToDictionary(_ => _.key, _ => _.node as JsonNode); + return new JsonDictionaryWrapper(transformed); + } + } + + #endregion + #region Provider + /// + /// 语言文件的提供器。支持内容替换、文件合并 + /// + /// + /// 对于在lang/下的文件,使用该类型 + /// + /// 内部使用的值类型 public class TermMappingProvider : IResourceFileProvider { + /// + /// 语言文件所表示的映射表 + /// public ITermDictionary Map { get; } + + /// public string Destination { get; } + /// + /// 从给定的映射表构造提供器 + /// + /// 映射表 + /// 目标地址 public TermMappingProvider(ITermDictionary map, string destination) { Map = map; Destination = destination; } + /// public IResourceFileProvider ApplyTo(IResourceFileProvider? incoming, bool overrideExisting = false) { if (incoming is not TermMappingProvider) @@ -59,11 +163,13 @@ public IResourceFileProvider ApplyTo(IResourceFileProvider? incoming, bool overr return new TermMappingProvider(baseMap, Destination); } + /// public IResourceFileProvider ReplaceContent(string searchPattern, string replacement) => new TermMappingProvider( Map.ReplaceContent(searchPattern, replacement), Destination); + /// public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) => new TermMappingProvider( Map, @@ -72,6 +178,7 @@ public IResourceFileProvider ReplaceDestination(string searchPattern, string rep replacement, RegexOptions.Singleline)); + /// public async Task WriteToArchive(ZipArchive archive) { var destination = Destination.NormalizePath(); @@ -86,82 +193,99 @@ public async Task WriteToArchive(ZipArchive archive) await writer.WriteAsync(Map.ProvideStringContent()); } } + #endregion - - - - internal class LangDictionaryWrapper : Dictionary, ITermDictionary + #region Helper + /// + /// 用于生成的辅助类 + /// + public static partial class LangMappingHelper { - public LangDictionaryWrapper(IDictionary dictionary) : base(dictionary) { } - - public string ProvideStringContent() + /// + /// 从给定的语言文件创建 + /// + /// 读取源 + /// 目标地址 + public static LangMappingProvider CreateFromFile(FileInfo file, string destination) { - var builder = new StringBuilder(); - foreach (var (key, value) in this) - { - builder.AppendJoin('=', key, value); - builder.Append(Environment.NewLine); - } - return builder.ToString(); + using var stream = file.OpenRead(); + using var reader = new StreamReader(stream, Encoding.UTF8); + var content = reader.ReadToEnd(); + return new (new LangDictionaryWrapper(DeserializeFromLang(content)), destination); } - public ITermDictionary ReplaceContent(string searchPattern, string replacement) + // RAW + // TODO:仔细检查一遍 + // TODO:PARSE-ESCAPE + internal static Dictionary DeserializeFromLang(string content) { - var result = new Dictionary(); - foreach (var (key, value) in this) - { - var replaced = Regex.Replace(value, - searchPattern, - replacement, - RegexOptions.Singleline); - result.Add(key, replaced); - } - return new LangDictionaryWrapper(result); - } - - public static ITermDictionary Create(IDictionary nominalMapping) - => new LangDictionaryWrapper(nominalMapping); - } - - internal class JsonDictionaryWrapper : Dictionary, ITermDictionary - { - public JsonDictionaryWrapper(IDictionary dictionary) : base(dictionary) { } - - public string ProvideStringContent() - => JsonSerializer.Serialize(this, new JsonSerializerOptions() - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping - }); + // 甚至不是自动机...所以不敢多用,否则会炸 - public ITermDictionary ReplaceContent(string searchPattern, string replacement) - { - var result = new Dictionary(); - foreach(var (key, value) in this) - { - if (value.GetType() == typeof(JsonValue) - && value.AsValue().TryGetValue(out var stringValue)) + // 下面的 Verbose 仅供调试,不会在 log 里出现 + // .lang的格式真的乱... + Log.Verbose("开始反序列化 .lang 文件"); + // #PARSE_ESCAPE就算了吧 + var result = new Dictionary(); + var isInComment = false; // 处理多行注释 + new List(content.Split(Environment.NewLine, + StringSplitOptions.RemoveEmptyEntries)) + .ForEach(line => { - var replaced = Regex.Replace(stringValue, - searchPattern, - replacement, - RegexOptions.Singleline); - result.Add(key, JsonValue.Create(replaced)!); // 我猜不会null罢 - continue; + var isSingleLineComment = false; + new List { "//", "#" } + .ForEach(_ => { isSingleLineComment |= line.StartsWith(_); }); + if (isSingleLineComment) + { + Log.Verbose("跳过了单行注释:{0}", line); + } + else if (isInComment) // 多行注释内 + { + Log.Verbose("{0}", line); + if (line.Trim() + .EndsWith("*/")) + { + isInComment = false; // 跳出注释 + } + } + else if (line.StartsWith("/*")) // 开始多行注释 + { + Log.Verbose("跳过了多行注释:{0}", line); + } + else // 真正的条目 + { + Log.Verbose("添加对应映射:{0}", line); + var spiltPosition = line.IndexOf('='); + try + { + result.Add(line[..spiltPosition], line[(spiltPosition + 1)..]); + } + catch (Exception e) + { + Log.Warning(e.ToString()); + } + } } - result.Add(key, value); - } - return new JsonDictionaryWrapper(result); + ); + Log.Verbose("反序列化完成"); + return result; } + } - public static ITermDictionary Create(IDictionary nominalMapping) + /// + /// 用于生成的辅助类 + /// + public static partial class JsonMappingHelper + { + /// + /// 从给定的语言文件创建 + /// + /// 读取源 + /// 目标地址 + public static JsonMappingProvider CreateFromFile(FileInfo file, string destination) { - var query = from pair in nominalMapping - let key = pair.Key - let value = pair.Value - let node = JsonValue.Create(value)! - select (key, node); - var transformed = query.ToDictionary(_ => _.key, _ => _.node as JsonNode); - return new JsonDictionaryWrapper(transformed); + using var stream = file.OpenRead(); + return new(new JsonDictionaryWrapper(JsonNode.Parse(stream)!.AsObject()!), destination); } } + #endregion } diff --git a/src/Packer/Models/Providers/TextFile.cs b/src/Packer/Models/Providers/TextFile.cs index 2e9d1420a0b9..408e1add8c63 100644 --- a/src/Packer/Models/Providers/TextFile.cs +++ b/src/Packer/Models/Providers/TextFile.cs @@ -19,14 +19,13 @@ public class TextFile : IResourceFileProvider /// /// 提供器所携带的文本内容 /// - public string Content { get; } - /// - /// 目标地址 - /// - public string Destination { get; } + public virtual string Content { get; } + + /// + public virtual string Destination { get; } /// - /// 从给定的构造提供器。 + /// 从给定的构造提供器 /// /// 读取源 /// 目标地址 @@ -39,7 +38,7 @@ public static TextFile Create(FileInfo file, string destination) } /// - /// 从给定的文本内容构造提供器。 + /// 从给定的文本内容构造提供器 /// /// 来源文本 /// 目标地址 @@ -49,22 +48,22 @@ public TextFile(string content, string destination) Destination = destination; } - - public IResourceFileProvider ReplaceContent(string searchPattern, string replacement) + /// + public virtual IResourceFileProvider ReplaceContent(string searchPattern, string replacement) => new TextFile(Regex.Replace(Content, searchPattern, replacement, RegexOptions.Singleline), Content); /// - public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) + public virtual IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) => new TextFile(Content, Regex.Replace(Destination, searchPattern, replacement, RegexOptions.Singleline)); /// - public async Task WriteToArchive(ZipArchive archive) + public virtual async Task WriteToArchive(ZipArchive archive) { var destination = Destination.NormalizePath(); Log.Information("正在添加 {0}", destination); diff --git a/src/Packer/Models/TranslatedFile.cs b/src/Packer/Models/TranslatedFile.cs deleted file mode 100644 index 39cbbb7d7b4b..000000000000 --- a/src/Packer/Models/TranslatedFile.cs +++ /dev/null @@ -1,229 +0,0 @@ -//using DiffMatchPatch; -//using Packer.Extensions; -//using Serilog; -//using System; -//using System.Collections.Generic; -//using System.IO; - -//namespace Packer.Models -//{ -// /// -// /// 标志文件类型的枚举。目前而言有[是否按.json]和[是否按\lang\]两类 -// /// -// [Flags] -// public enum FileCategory -// { -// /// -// /// 仅用于初始化为默认态 -// /// -// None = 0, -// /// -// /// 类 .json,标识需要转义与 json 式序列化 -// /// -// JsonAlike = 1, -// /// -// /// 类 .lang,标识无需转义与 lang 式序列化 -// /// -// LangAlike = 2, -// /// -// /// 位于 /lang/ 中的文件,进行合并等 -// /// -// LanguageFile = 4, -// /// -// /// 位于其余位置的文件,不进行合并 -// /// -// OtherFiles = 8, -// /// -// /// */lang/*.json -// /// -// JsonTranslationFormat = JsonAlike | LanguageFile, -// /// -// /// */lang/*.lang -// /// -// LangTranslationFormat = LangAlike | LanguageFile, -// /// -// /// */[not-lang]/*.json -// /// -// JsonOthers = JsonAlike | OtherFiles, -// /// -// /// */[not-lang]/*.lang -// /// -// LangOthers = LangAlike | OtherFiles -// } - -// /// -// /// 语言文本的抽象。这是基本类
-// /// 基本上是immutable的 -// ///
-// public class TranslatedFile -// { -// /// -// /// asset-domain下的位置 -// /// -// public string RelativePath { get; init; } - -// /// -// /// 该文件的文本,用字符串表示

-// /// 因此,不能存储非文本文件! -// ///
-// public string StringifiedContent { get; } - -// /// -// /// 文件类型 -// /// -// public FileCategory Category { get; } - -// /// -// /// 从文件流构造内容 -// /// -// public TranslatedFile(Stream stream, FileCategory category, Config config) -// { // 注:文件流在此处被关闭 -// using var reader = new StreamReader(stream); -// StringifiedContent = reader.ReadToEnd().Preprocess(category, config); -// this.Category = category; -// } - -// /// -// /// 从文本构造内容 -// /// -// public TranslatedFile(FileCategory category, string content) -// { -// this.Category = category; -// StringifiedContent = content; -// } - -// /// -// /// 伪合并文件 -// /// -// virtual public TranslatedFile Combine(TranslatedFile file) -// { -// Log.Information("文件不支持合并。取消合并"); -// return this; -// } - -// /// -// /// 伪适配文件 -// /// -// virtual public TranslatedFile Port(TranslatedFile file) -// { -// Log.Information("文件不支持适配。直接覆盖"); -// return file; -// } - -// /// -// /// 对该文件的内容进行Google Diff-Match-Patch算法 -// /// -// public TranslatedFile ApplyPatch(string patch) -// { -// // 对应的Patch可以自行生成,或者也可以做一个小工具,虽然不在这里 -// // 应用Patch时,需要先根据Patch文本生成Patch列表,再应用Patch -// // -// // patch_apply 返回object[] [0]=string [1]=bool[] -// var dmp = new diff_match_patch(); -// var patchList = dmp.patch_fromText(patch); -// return new TranslatedFile(Category, -// (string)dmp.patch_apply(patchList, StringifiedContent)[0]); -// } -// } - -// /// -// /// 可以按照/lang/文件夹下解析的文件。这是衍生类
-// /// 基本上是immutable的 -// ///
-// public class LangFile : TranslatedFile -// { -// private bool deserialized = false; // 非必要不解析,免得残废的lang解析炸掉 -// private Dictionary _deserializedContent; - -// /// -// /// 按照基础语言文件的格式解析而成的词条列表。
-// /// 在访问时才会解析。 -// ///
-// public Dictionary DeserializedContent -// { -// get -// { -// if (!deserialized) -// { -// deserialized = true; -// _deserializedContent = StringifiedContent.DeserializeAsset(Category); -// } -// return _deserializedContent; -// } -// } - -// /// -// /// 从文件流构造内容 -// /// -// public LangFile(Stream stream, FileCategory category, Config config) -// : base(stream, category, config) -// { -// _deserializedContent = null; -// } -// /// -// /// 从映射表构造内容 -// /// -// public LangFile(FileCategory category, Dictionary content) -// : base(category, content.SerializeAsset(category)) -// { -// _deserializedContent = content; -// deserialized = true; -// } -// /// -// /// 真合并文件 -// /// -// public override LangFile Combine(TranslatedFile file) -// { -// Log.Information("合并文件:{0}", this.RelativePath); - -// var castedFile = (LangFile)file; -// if (castedFile is null) -// { -// Log.Information("检测到不支持合并的文件。取消合并"); -// return this; -// } - -// var resultMap = new Dictionary(DeserializedContent); -// foreach (var pair in castedFile.DeserializedContent) -// { -// if (!resultMap.TryAdd(pair.Key, pair.Value)) -// { -// Log.Warning("检测到相同 key 的条目:{0} -> {1} | {2},选取 {1}", -// pair.Key, resultMap[pair.Key], pair.Value); -// } -// } - -// return new LangFile(this.Category, resultMap) -// { -// RelativePath = this.RelativePath -// }; -// } - -// /// -// /// 真适配文件 -// /// -// public override TranslatedFile Port(TranslatedFile file) -// { -// var castedFile = (LangFile)file; -// if (castedFile is null) -// { -// Log.Information("检测到不支持合并的文件。取消合并"); -// return file; -// } - -// var resultMap = DeserializedContent; -// foreach(var key in resultMap.Keys) -// { -// if(castedFile.DeserializedContent.TryGetValue(key, out var value)) -// { -// Log.Information("正在替换适配项:<{0}> {1} => {2}", key, resultMap[key], value); -// resultMap[key] = value; -// } -// } -// return new LangFile(this.Category, resultMap) -// { -// RelativePath = this.RelativePath -// }; -// } -// } -//} diff --git a/src/Packer/Program.cs b/src/Packer/Program.cs index 1714ed7b0ec6..777b8305d36f 100644 --- a/src/Packer/Program.cs +++ b/src/Packer/Program.cs @@ -1,18 +1,18 @@ using Packer.Extensions; using Packer.Models; +using Packer.Models.Providers; using Serilog; using System; using System.IO; using System.IO.Compression; using System.Linq; -using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Packer { class Program { - // 由于某些魔法,这里可以直接加参数 + // System.CommandLine.DragonFruit支持 public static async Task Main(string version, string[]? targets) { Log.Logger = new LoggerConfiguration() @@ -21,66 +21,68 @@ public static async Task Main(string version, string[]? targets) .MinimumLevel.Information() // 以便 debug 时修改这一等级 .CreateLogger(); - if (version is null) - throw new ArgumentNullException(nameof(version)); var targetModIdentifiers = targets?.ToList(); var config = await Utils.RetrieveConfig(configTemplate: "./config/packer/{0}.json", version: version); - Log.Information("开始对版本 {0} 的打包", config.Version); + Log.Information("开始对版本 {0} 的打包", config.Base.Version); var query = // 这就是查询表达式吗( - from modDirectory in new DirectoryInfo($"./projects/{config.Version}/assets") - .EnumerateDirectories() + from modDirectory in new DirectoryInfo($"./projects/{config.Base.Version}/assets") + .EnumerateDirectories() let modIdentifier = modDirectory.Name - where targetModIdentifiers is null // 未提供列表,全部打包 - || targetModIdentifiers.Contains(modIdentifier) // 有列表,仅打包列表中的项 - where !config.ModBlackList.Contains(modIdentifier) // 没有被明确排除 + where targetModIdentifiers is null // 未提供列表,全部打包 + || targetModIdentifiers.Contains(modIdentifier) // 有列表,仅打包列表中的项 + where !config.Base.ExclusionMods.Contains(modIdentifier) // 没有被明确排除 from namespaceDirectory in modDirectory.EnumerateDirectories() let namespaceName = namespaceDirectory.Name - where !config.DomainBlackList.Contains(namespaceName) // 没有被明确排除 - where namespaceName.ValidateNamespace() // 不是非法名称 + where !config.Base.ExclusionNamespaces.Contains(namespaceName) // 没有被明确排除 + where namespaceName.ValidateNamespace() // 不是非法名称 from provider in namespaceDirectory.EnumerateProviders(config) group provider by provider.Destination into destinationGroup select destinationGroup - .Aggregate(seed: null as IResourceFileProvider, // 合并文件 - (accumlate, next) + .Aggregate(seed: null as IResourceFileProvider, // 合并文件 + (accumulate, next) => next.ApplyTo( - accumlate, + accumulate, overrideExisting: false)) into provider - select config.CharatcerReplacement // 内容的字符替换 + select config.Floating.CharatcerReplacement // 内容的字符替换 .Aggregate(seed: provider, - (accumlate, replacement) - => accumlate.ReplaceContent( + (accumulate, replacement) + => accumulate.ReplaceContent( replacement.Key, replacement.Value)) into provider - select config.DestinationReplacement // 全局路径替换:预留 + select config.Floating.DestinationReplacement // 全局路径替换:预留 .Aggregate(seed: provider, - (accumlate, replacement) - => accumlate.ReplaceContent( + (accumulate, replacement) + => accumulate.ReplaceContent( replacement.Key, replacement.Value)); - // TODO 把初始化内容也做成IEnumerable,尤其是pack.mcmeta - // var initializers = from fileName in config.FilesToInitialize select new ... - string packName = $"./Minecraft-Mod-Language-Package-{config.Version}.zip"; + var initialsQuery = from file in new DirectoryInfo($"./projects/{config.Base.Version}") + .EnumerateFiles() + select (file.Name == "pack.mcmeta") + ? McMetaProvider.Create(file, file.Name) // 类型推断不出要用接口 + : new RawFile(file, file.Name) as IResourceFileProvider; + + string packName = $"./Minecraft-Mod-Language-Package-{config.Base.Version}.zip"; await using var stream = File.Create(packName); using (var archive = new ZipArchive(stream, ZipArchiveMode.Update, leaveOpen: true)) { - archive.Initialize(config); - await Task.WhenAll(from provider in query select provider.WriteToArchive(archive)); + await Task.WhenAll(from provider in query.Concat(initialsQuery) + select provider.WriteToArchive(archive)); } - Log.Information("对版本 {0} 的打包结束。共包含了 {1} 个文件", - config.Version, + Log.Information("对版本 {0} 的打包结束。共写入了 {1} 个文件", + config.Base.Version, query.Count()); var md5 = stream.ComputeMD5(); Log.Information("打包文件的 MD5 值:{0}", md5); - File.WriteAllText($"./{config.Version}.md5", md5); + File.WriteAllText($"./{config.Base.Version}.md5", md5); } } } diff --git a/src/Packer/Utils.cs b/src/Packer/Utils.cs index d084c37b630e..4b980619a184 100644 --- a/src/Packer/Utils.cs +++ b/src/Packer/Utils.cs @@ -12,12 +12,33 @@ namespace Packer { - static class Utils + /// + /// 杂项工具类 + /// + public static class Utils { + /// + /// 从给定的命名空间获取局域配置 + /// + /// 命名空间目录 + /// 若文件存在,返回;否则,返回 + public static FloatingConfig? RetrieveLocalConfig(DirectoryInfo directory) + { + var configFile = directory.GetFiles("local-config.json").FirstOrDefault(); + if (configFile is null) return null; + using var reader = configFile.OpenText(); + return JsonSerializer.Deserialize( + reader.ReadToEnd(), + new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + } - + /// + /// 从仓库根目录获取全局配置 + /// + /// 配置路径模板 + /// 打包版本,用于定位全局配置 public static async Task RetrieveConfig(string configTemplate, string version) { Log.Information("正在获取配置。目标版本:{0}", version); @@ -26,96 +47,38 @@ public static async Task RetrieveConfig(string configTemplate, string ve Log.Information("配置位置:{0}", configPath); - var reader = await File.ReadAllBytesAsync(configPath); - return JsonSerializer.Deserialize(reader); + var content = await File.ReadAllBytesAsync(configPath); + return JsonSerializer.Deserialize( + content, + new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); } - public static List RetrieveStrategy(FileInfo? file) + /// + /// 从给定的命名空间获取策略内容 + /// + /// 命名空间目录 + /// 若文件存在,返回对应的内容;否则,返回Direct + /// 策略文件非法 + public static List RetrieveStrategy(DirectoryInfo directory) { + var file = directory.GetFiles("packer-policy.json").FirstOrDefault(); + if (file is null) - { - return new List - { - new PackerStrategy { Type = PackerStrategyType.NoAction } + return new List + { + new PackerPolicy { Type = PackerPolicyType.Direct } }; - } - else - { - var result = JsonSerializer.Deserialize>( - file.OpenText().ReadToEnd(), - new JsonSerializerOptions - { - Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) } - }); - if (result is null) - throw new InvalidDataException($"The policy file {file.FullName} cannot have null values."); - return result; - } - } - ///// - ///// 将两个带有TranslatedFile的列表合并,对冲突项按照target优先进行合并。 - ///// - ///// 合并对象,优先选择 - ///// 合并对象,非优先 - ///// - //public static IEnumerable MergeFiles(IEnumerable baseFile, IEnumerable incoming) - //{ - // var mapping = new Dictionary(); // asset-domain下的目标位置 -> 文件 - // if (!baseFile.Any()) return incoming; - // if (!incoming.Any()) return baseFile; - // foreach (var file in baseFile) - // { - // mapping.Add(file.RelativePath, file); - // } - // foreach (var file in incoming) - // { - // if (!mapping.TryAdd(file.RelativePath, file)) - // { - // mapping.Remove(file.RelativePath, out var existing); - // mapping.Add(existing.RelativePath, existing.Combine(file)); - // } - // } - // return mapping.Values; - //} - - ///// - ///// 基于原位置的文件key,用incoming的词条进行替换。未被替换的保持原文。 - ///// - ///// 原位置的基准文件 - ///// 更新文件 - ///// - //public static IEnumerable PortFiles(IEnumerable baseFile, IEnumerable incoming) - //{ - // var mapping = new Dictionary(); // asset-domain下的目标位置 -> 文件 - // if (!incoming.Any()) return baseFile; - // foreach (var file in baseFile) - // { - // mapping.Add(file.RelativePath, file); - // } - // foreach (var file in incoming) - // { - // if (!mapping.TryAdd(file.RelativePath, file)) - // { - // mapping.Remove(file.RelativePath, out var existing); - // mapping.Add(existing.RelativePath, existing.Port(file)); - // } - // } - // return mapping.Values; - //} - - - public static string AppendTimestamp(string path) - { - var mcmeta = path; - var meta = JsonSerializer.Deserialize(File.ReadAllText(mcmeta)); - var time = DateTime.UtcNow.AddHours(8); // UTC+8:00 - meta.Pack.Description += $"\n打包时间:{time:yyyy-MM-ddTHH:mm:ssZ}"; - return JsonSerializer.Serialize(meta, new JsonSerializerOptions() - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - WriteIndented = true - }); + using var reader = file.OpenText(); + var result = JsonSerializer.Deserialize>( + reader.ReadToEnd(), + new JsonSerializerOptions + { + Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) } + }); + if (result is null) + throw new InvalidDataException($"The policy file {file.FullName} cannot have null values."); + return result; } } } From b8b013278c6f06ad4cd922aba5715c208b9cc241 Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sun, 1 Oct 2023 12:39:42 +0800 Subject: [PATCH 08/22] Migration phase I --- Packer-Doc.md | 123 ++++++++++++++++++ Packer-Index-Doc.md | 32 ----- config/packer/1.20-fabric.json | 73 ++++++----- config/packer/1.20.json | 73 ++++++----- config/packer/packer-example.json | 30 +++++ .../mixed-clone/extra/extra.txt | 1 - .../mixed-clone/lang/zh_cn.json | 4 - .../mixed-clone/packer-policy.json | 4 - .../assets/0-example-nop/nop/lang/zh_cn.json | 4 - .../0-example-nop/nop/packer-policy.json | 3 - .../patch/lang/zh_cn.json.patch | 14 -- .../0-example-patch/patch/packer-policy.json | 7 - .../0-example-port/port/lang/zh_cn.json | 4 - .../0-example-port/port/packer-policy.json | 4 - .../clone/packer-policy.json | 4 - .../minecraft/minecraft/packer-policy.json | 10 +- projects/1.20-fabric/pack.mcmeta | 10 +- projects/1.20/pack.mcmeta | 10 +- projects/packer-example/README.txt | 1 + .../composite/lang/zh_cn.json | 4 + .../example-composite/composite/other.txt | 1 + .../composite/packer-policy.json | 13 ++ .../compositions/zh_cn.json-composition.json | 37 ++++++ .../composition/local-config.json | 10 ++ .../composition/packer-policy.json | 7 + .../example-direct/direct/lang/en_us.json | 20 +++ .../example-direct/direct/lang/zh_cn.json | 20 +++ .../assets/example-direct/direct/other.txt | 1 + .../indirect/packer-policy.json | 6 + projects/packer-example/pack.mcmeta | 6 + src/Packer/Extensions/ContentExtension.cs | 3 +- src/Packer/Extensions/DirectoryExtension.cs | 38 +++--- src/Packer/Models/Config.cs | 19 +-- .../Models/Providers/CompositionHelper.cs | 3 +- src/Packer/Models/Providers/McMetaProvider.cs | 2 +- .../Models/Providers/TermMappingProvider.cs | 11 +- src/Packer/Models/Providers/TextFile.cs | 4 +- src/Packer/Program.cs | 12 +- src/Packer/Utils.cs | 3 +- 39 files changed, 424 insertions(+), 207 deletions(-) create mode 100644 Packer-Doc.md delete mode 100644 Packer-Index-Doc.md create mode 100644 config/packer/packer-example.json delete mode 100644 projects/1.19/assets/0-example-mixed-clone/mixed-clone/extra/extra.txt delete mode 100644 projects/1.19/assets/0-example-mixed-clone/mixed-clone/lang/zh_cn.json delete mode 100644 projects/1.19/assets/0-example-mixed-clone/mixed-clone/packer-policy.json delete mode 100644 projects/1.19/assets/0-example-nop/nop/lang/zh_cn.json delete mode 100644 projects/1.19/assets/0-example-nop/nop/packer-policy.json delete mode 100644 projects/1.19/assets/0-example-patch/patch/lang/zh_cn.json.patch delete mode 100644 projects/1.19/assets/0-example-patch/patch/packer-policy.json delete mode 100644 projects/1.19/assets/0-example-port/port/lang/zh_cn.json delete mode 100644 projects/1.19/assets/0-example-port/port/packer-policy.json delete mode 100644 projects/1.19/assets/0-example-simple-clone/clone/packer-policy.json create mode 100644 projects/packer-example/README.txt create mode 100644 projects/packer-example/assets/example-composite/composite/lang/zh_cn.json create mode 100644 projects/packer-example/assets/example-composite/composite/other.txt create mode 100644 projects/packer-example/assets/example-composite/composite/packer-policy.json create mode 100644 projects/packer-example/assets/example-composition/composition/compositions/zh_cn.json-composition.json create mode 100644 projects/packer-example/assets/example-composition/composition/local-config.json create mode 100644 projects/packer-example/assets/example-composition/composition/packer-policy.json create mode 100644 projects/packer-example/assets/example-direct/direct/lang/en_us.json create mode 100644 projects/packer-example/assets/example-direct/direct/lang/zh_cn.json create mode 100644 projects/packer-example/assets/example-direct/direct/other.txt create mode 100644 projects/packer-example/assets/example-indirect/indirect/packer-policy.json create mode 100644 projects/packer-example/pack.mcmeta diff --git a/Packer-Doc.md b/Packer-Doc.md new file mode 100644 index 000000000000..0f1e18b78d0e --- /dev/null +++ b/Packer-Doc.md @@ -0,0 +1,123 @@ +# 打包机制文档 + +## 注意事项 +- 文件地址中,目录分隔符**一律使用正斜杠**! +- 下述说明中,**完整地址**永远指从**仓库根目录**算起的地址,例如根目录下的`CONTRIBUTING.md`即为`CONTRIBUTING.md`,1.12版本资源包的`pack.png`即为`projects/1.12.2/pack.png`。 +- 下述说明中,**相对地址**永远指从**特定命名空间的文件夹**算起的地址,例如仓库中的`projects/1.18/assets/minecraft/minecraft/font/default.json`即为`font/default.json`。 +- 下述说明中,**目标地址**永远指分发的资源包中,该文件应当被放置的位置,例如上一条中提及的文件就是`assets/minecraft/font/default.json`。 +- 本次打包器更新以后,对于**非文本文件**无需特殊处理;打包器会将所有*未知的*拓展名按照非文本文件处理,无需特殊配置。 + - 目前而言,打包器会将`lang/`下的`.lang`和`.json`作为语言文件,其余的`.txt`, `.md`, `.json`作为普通文本文件,其余文件都作为非文本文件。
如果出现其他格式,可以后续添加——尽管这一部分没有添加显式的配置项。 + + + +## 配置文件 + +配置文件分为两类: +- 放置在`./config/packer`下的**全局**配置文件,用作整个打包流程的基础配置; +- 放置在各命名空间下的**局域**配置文件,用于对特定命名空间(以及模组)提供特殊的配置项。 + +### 文件格式 + +**全局**配置文件`./config/packer/.json`的格式如下: + +- 根标签 object + - `base` object
打包流程中的*不变配置*,不能被文件结构中的**局域配置文件**改写。包含的内容都是**不低于**命名空间层级的,因为局域配置文件就是放在命名空间一级中的。 + - `version` string
该配置文件指向的版本,以`projects/`中的文件夹名称为准。原则上*应当*与文件名中的[version]一致。 + - `targetLanguages` list
打包的目标语言,即最终在资源包中存在的语言。 + - string
目标语言,即该版本使用的语言标识符。
以在`lang`下的语言文件的文件名,以及其他文件的路径中,标明语言的部分为准。目前而言,使用的是`zh_cn`,尽管有消息称将要改用`zho_Hans-CN`。 + - `exclusionMods` list
被打包器排除的模组文件夹。
如果因为某些原因需要移除某个模组的翻译(如移交官方/其他团体等),但意图保留原有翻译,可能需要这一项。 + - string
排除的模组。 + - `exclusionNamespaces` list
被打包器排除的 **[namespace]** | **(命名空间)**。
暂时闲置,以待后续需求。 + - string
排除的命名空间。 + - `floating` object
打包流程中的*可变配置*,可能被文件结构中的**局域配置文件**改写。包含的内容都是**低于**命名空间层级的,因为局域配置文件就是放在命名空间一级中的。 + - `inclusionDomains` list
强制包含的 **[domain]**。
一般而言,用于通常不会包含**语言标识符**的`domain`。
一般而言会包含`font`与`textures`,因为这两处往往包含非文本文件(尽管也可能有文本文件),且字体修复已经需要用到这两个domain;其他内容多半会出现在*局域配置*中。 + - string
强制包含的domain名称。 + - `exclusionDomains` list
强制排除的 **[domain]**。
暂时闲置,或可用于排除一些策略相关的零散文件。 + - string
强制排除的domain名称。 + - `exclusionPaths` list
强制排除的 **[相对地址]**。 + - string
强制排除的文件的**相对地址**。
一般而言,在主配置中只会放置通用的忽略对象,例如`packer-policy.json`和`local-config.json`;其余条目最好放在*局域配置*中。 + - `inclusionPaths` list
强制包含的 **[相对地址]**。
暂时闲置,可以用于添加零散的无语言标记文件。 + - string
强制包含的文件的**相对地址**。 + - `characterReplacement` object
打包时采用的字符替换表。用于将部分字符替换至特殊位点,也可单纯用于简化输入。目前而言,包含了字体修复的有关内容。 + - `<查询语句>` string
用以替换**正则表达式**`<查询语句>`匹配对象的内容,可以是一个或多个字符,甚至可以在这里用**正则替换语句**。
主要用于*字体修复包*所需的**符号替换**,此时,查询语句通常是字面量,替换内容一般而言总是以四位*Unicode转义码*填写;对于**基础多语种平面(BMP)**以外的字符,最好用**UTF-16代理对**书写。 + - `destinationReplacement` object
打包时采用的目标地址替换。
可以用于移动文件,但暂时闲置。 + - `<查询语句>` string
用以替换**正则表达式**`<查询语句>`匹配对象的内容,可以是一个或多个字符,甚至可以在这里用**正则替换语句**。 + +**局域**配置文件`./projects//assets///local-config.json`的格式与全局配置文件中,`floating`标签下的内容(*浮动配置*)一致。 + +### 文件容斥顺序 + +介于在配置文件中出现了多种包含/排除文件的配置项,有必要说明以下这些项生效的顺序: +1. `exclusionMods`和`exclusionNamespaces`在进入命名空间前即会排除相应的文件夹——甚至不会加载其中的`local-config.json`。
当然,如果是通过*检索策略*访问的,则这一项不会生效。 +2. 在剩下的命名空间中,检索文件。下面的配置项可能会被*局域配置*修改,除了`targetLanguages`以外。 +3. 在所有检索到的文件中,排除掉`exclusionPaths`指定的文件,即便是通过*检索策略*访问的。 +4. 在剩下的文件中,直接包含`inclusionPaths`和`inclusionDomains`指定的文件。 +5. 在剩下的文件中,排除掉`exclusionDomains`指定的文件。 +6. 在剩下的文件中,仅包含由`targetLanguages`指定的,在路径中任意位置包含有*简体中文语言标记*的文件,其他文件不予保存。 + +### 局域配置文件的重写规则 + +- 如果在某个命名空间内检测到存在`local-config.json`,打包器将会在全局配置的基础上,在其*可变配置*中**添加**该文件中的内容,并用这一修改后的配置执行**该命名空间下的**检索工作。 +- 最好不要与全局配置中的内容重复。尽管理论上这样子可以运行,但是重复项保留哪一个或许不容易断定。 +- 需要注意的是,如果通过*检索策略***引用其他命名空间**,打包器**只**会加载目标命名空间的局域配置,而**不会**加载原空间的局域配置;不过,在原位进行的检索工作不受影响。 + +## 检索策略 + +对于每个**命名空间文件夹**(注意这个概念和**命名空间**有着细微差别),打包器除了可以原位检索文件以外,还可以**使用不同的检索方式**。目前,可用的检索方式有两种: +1. **引用**给定的命名空间。 +2. 从给定的**组合**文件,直接生成语言文件(或部分)。 + +计划中,将对*非语言文件的文本文件*添加一个**修改包**策略,但是这个策略暂时还没实现,部分原因是在上一版打包器中,这个策略还没被用过。 + +单独看起来,这或许没什么用(Packer的上一版中,功能还要多些);但有一点很重要: +这些加载策略(包括**原位**加载)是可以**串联**、**递归**的!于是,通过这三种策略,应该可以满足许多需求。 + +- **串联**:在一个策略文件中,可以放置**多条策略**。策略将会从前往后执行,**前者**优先——和*Minecraft资源包*顺序差不多。不过,如果有需要,在策略文件中也预留了一个字段,用来**覆盖**前序文件。 +- **递归**:如果**引用**了其他命名空间文件夹,那里的策略文件**也会生效**。这意味着可以实现*连续引用*——尽管前提是不出现**循环引用**。 + +部分案例被放在了`./projects/packer-example/`这一虚拟的“版本”下。很明显,我们**并不会**分发这一版本,但如果有条件,可以在本地构造打包器,并用这一版本做试验。 + +### 策略相关文件的格式 + +#### packer-policy.json + +对于每个**命名空间文件夹**,策略文件为`./projects//assets///packer-policy.json`。 +若找不到该策略,默认策略文件内容为`[{"type": "direct"}]`。 + +- 根标签 list
打包器需要执行的策略,**从前往后执行**。如果有冲突内容,默认以**前者**优先——当然这是可以配置的。 + - object
单项策略。部分参数可变。 + - `overrides` bool
是否可以用本步的文件覆盖前序文件。如果无此项,默认为`false`。
关于这里的“覆盖”,对于**非语言文件**(不在`lang\`下),指的是**全文**覆盖;对于**语言文件**,则是**按条目**覆盖。 + - `type` string
策略的类型。可为以下选项之一: + - `direct` 默认选项。不进行特殊处理,直接按照此处的文件结构打包。 + - `indirect` 引用给定的命名空间。对于这些文件,其*目标地址*中的*命名空间*将会自动替换为本策略所在的命名空间。 + - `source` string
引用命名空间所在文件夹的**完整地址**。 + - `composition`
从给定的*组合文件*,直接生成语言文件(或部分)。
这些组合文件可能不会被自动排除;可以考虑使用*局域配置*处理。 + - `source` string
引用组合文件的**完整位置**。 + - `destType` string
需要生成的语言文件的类型。可以为`json`或`lang`。 + +#### [组合文件].json + +- 根标签 object + - `target` string
生成的语言文件的**目标地址**。 + * `entries` list
需要生成的组合项。这些项将会分别执行组合以后,连接起来。
**如果存在键冲突,打包器会在此崩溃!**有计划在后期更改这一行为。 + * object
单项策略。 + * `templates` object
组合所用的模板。所有内容采用**C#格式化模式**填写。
粗略地说,其中的格式符有形式`{0}, {1}, {2},...`;完整的定义可见 *.net文档*。 + - `<键模板>` string
`<键模板>`对应的值模板。 + * `parameters` list
组合所用的参数表。参数按照模板中的**索引**顺序排列。不支持嵌套,必须字面量。 + * object
每个索引位置上可用的参数。 + - `<键参数>` string
`<键参数>`对应的值参数。 + +### 组合文件 + +组合文件用来生成“组合型”的**语言文件/语言文件片段**,也就是那些有大量重复文本、有明显的格式的语言文件片段。 +组合文件的工作原理如下: +1. 获取`entries`中的全部条目,每个条目代表一种组合模式。 +2. 每个条目中,由`templates`中的所有条目充当模板,`parameters`中的所有条目充当参数,生成若干组合后的条目。 + - 在`parameter`中,有时会出现多于一组参数;这种情况下,每组参数都会自由组合。 + - 同样的,`templates`也会和每一套参数自由组合。 +3. 将所有组合后的条目汇总,生成语言文件。 + - 在这一过程中,如果出现了**键冲突**,目前而言,**打包器会在此崩溃!**不过,如果后续观察表明确实存在此种需要,也会考虑修改这一行为。 + +组合文件可以和其他打包策略混合使用,以修改组合中效果不好的部分,或者添加非组合的内容。 + +组合文件理论上可以放在任何位置,使用任何名称;因此,打包器的*基础配置*没有办法排除掉这些文件。不过,为了方便,最好将其汇总在一个位置,采用明确的名称,以便在*局域配置*中排除。 \ No newline at end of file diff --git a/Packer-Index-Doc.md b/Packer-Index-Doc.md deleted file mode 100644 index a0b3fb281a60..000000000000 --- a/Packer-Index-Doc.md +++ /dev/null @@ -1,32 +0,0 @@ -# 打包机制-自定义文件检索策略 - -本仓库的打包器支持对不同模组使用不同的**检索策略**。 -## 注意事项 -- 检索策略仅对**未配置为跳过处理**的文件有正常行为。在`clonemissing`和`backport`下,目前而言,**跳过处理的文件**均优先取**既有文件**;在`patch`下,目前**并不**支持对**跳过处理的文件**添加修改包。 - - 既有的全局配置中,在`font/`和`textures/`下的文件全部**跳过处理**,即便是文本文件。 - - 关于全局配置中的跳过选项,详见[此处](./CONTRIBUTING.md#packer)。 -- 目前而言,`patch`策略还不支持递归调用。`noaction`显然没有递归之忧。对于其他选项,打包器支持**递归调用**:对其他目录的引用可以包含其中的`packer-policy.json`;打包器可以在该目录建立新的**自定义检索策略**。 - - 如果遇到**循环引用**,打包器可能不会自动中止,而是持续运行,直到*栈溢出*;应当尽量避免这一情况的发生。 - -## 策略配置 - -对于每个**asset-domain**,策略文件为`./projects//assets///packer-policy.json`。 -若找不到该策略,默认策略文件为`{"type": "noaction"}`。 - -### 策略文件的格式 - -packer-policy.json - -- 根标签 - - `type` string -> 策略的类型。可为以下选项之一: - - `noaction` 默认选项。不进行特殊处理,直接按照此处的文件结构打包。如果没有对文件同步或版本对照的特殊要求,使用该类型。如:[示例文件](./projects/1.19/assets/0-example-nop/nop/packer-policy.json) - - `plainclone` 直接引用另一位置的文件结构。如果需要文本完全同步,使用该类型。如:[示例文件](./projects/1.19/assets/0-example-simple-clone/clone/packer-policy.json) - - `source` string -> 复制的源地址。需要从本仓库的根目录开始计算,使用`./`前缀。 - - `clonemissing` 使用此处的文件结构,但在检索完文件后,根据另一位置的文件结构**补充**文本。对于出现冲突的条目,若为`lang/`下的内容,将会按照`key`合并,冲突项采用此处的文本;若为其他位置的文件,直接采用此处的文件。如:[示例文件](./projects/1.19/assets/0-example-mixed-clone/mixed-clone/packer-policy.json) - - `source` string -> 补充文件的源地址。需要从本仓库的根目录开始计算,使用`./`前缀。 - - `backport` 使用此处的文件结构,但在此基础上,从另一位置的文件结构**更新**已有的文本。对于`lang/`下的内容,仅会对已有的`key`更新内容,原本不存在的`key`不会新增;对于其他位置的文件,仅会对已有的文件进行替换,原本不存在的文件不会新增。例如,如果需要从高版本将文件同步至低版本,使用该类型。如:[示例文件](./projects/1.19/assets/0-example-port/port/packer-policy.json) - - `source` string -> 更新文件的源地址。需要从本仓库的根目录开始计算,使用`./`前缀。 - - `patch` 引用另一位置的文件结构,但在其中的部分文件上额外应用自定义的修改。修改使用[Google Diff-Match-Patch算法](https://github.com/google/diff-match-patch)生成;尽管原则上可以放在任意位置、采用任意后缀名,建议将修改文件放在被修改文件相应的位置,采用`.patch`后缀,以保持统一性。如:[示例文件](./projects/1.19/assets/0-example-patch/patch/packer-policy.json) - - `source` string -> 复制的源地址。需要从本仓库的根目录开始计算,使用`./`前缀。 - - `patches` object -> 修改文件,以及对应的修改目标。 - - `修改目标的相对路径` string -> 修改文件的源地址。需要从本仓库的根目录开始计算,使用`./`前缀;`修改目标的相对路径`需要为在复制源地址的`/`下方的相对位置,必须使用`/`作为分隔符,如`lang/zh_cn.json`。 diff --git a/config/packer/1.20-fabric.json b/config/packer/1.20-fabric.json index a9b6e91752cb..072d278bdaa2 100644 --- a/config/packer/1.20-fabric.json +++ b/config/packer/1.20-fabric.json @@ -1,37 +1,42 @@ { - "targetVersion": "1.20-fabric", - "targetLanguage": [ - "zh_cn" - ], - "additionalContent": [ - "LICENSE", - "pack.mcmeta", - "pack.png", - "README.md" - ], - "modNameBlackList": [], - "domainBlackList": [], - "noProcessNamespace": [ - "font", - "textures" - ], - "replacementMap": { - "[[钅卢]]": "\ud872\udf3b", - "[[钅杜]]": "\ud872\udf4a", - "[[钅喜]]": "\ud872\udf73", - "[[钅波]]": "\ud872\udf5b", - "[[钅黑]]": "\ud872\udf76", - "[[钅麦]]": "\u9fcf", - "[[钅达]]": "\ud86d\udffc", - "[[钅仑]]": "\ud872\udf2d", - "[[钅哥]]": "\u9fd4", - "[[钅尔]]": "\u9fed", - "[[钅夫]]": "\ud86d\udce7", - "[[钅立]]": "\ud86d\udff7", - "[[石田]]": "\u9fec", - "[[奥气]]": "\u9feb", - "[[气奥]]": "\u9feb", - "……": "\u22ef\u22ef", - "——": "\u2e3f" + "base": { + "version": "1.20-fabric", + "targetLanguages": [ + "zh_cn" + ], + "exclusionMods": [], + "exclusionNamespaces": [] + }, + "floating": { + "inclusionDomains": [ + "font", + "textures" + ], + "exclusionDomains": [], + "exclusionPaths": [ + "packer-policy.json", + "local-config.json" + ], + "inclusionPaths": [], + "characterReplacement": { + "[[钅卢]]": "\ud872\udf3b", + "[[钅杜]]": "\ud872\udf4a", + "[[钅喜]]": "\ud872\udf73", + "[[钅波]]": "\ud872\udf5b", + "[[钅黑]]": "\ud872\udf76", + "[[钅麦]]": "\u9fcf", + "[[钅达]]": "\ud86d\udffc", + "[[钅仑]]": "\ud872\udf2d", + "[[钅哥]]": "\u9fd4", + "[[钅尔]]": "\u9fed", + "[[钅夫]]": "\ud86d\udce7", + "[[钅立]]": "\ud86d\udff7", + "[[石田]]": "\u9fec", + "[[奥气]]": "\u9feb", + "[[气奥]]": "\u9feb", + "……": "\u22ef\u22ef", + "——": "\u2e3f" + }, + "destinationReplacement": {} } } \ No newline at end of file diff --git a/config/packer/1.20.json b/config/packer/1.20.json index a889b47239d2..8cf5760bd3f0 100644 --- a/config/packer/1.20.json +++ b/config/packer/1.20.json @@ -1,37 +1,42 @@ { - "targetVersion": "1.20", - "targetLanguage": [ - "zh_cn" - ], - "additionalContent": [ - "LICENSE", - "pack.mcmeta", - "pack.png", - "README.md" - ], - "modNameBlackList": [], - "domainBlackList": [], - "noProcessNamespace": [ - "font", - "textures" - ], - "replacementMap": { - "[[钅卢]]": "\ud872\udf3b", - "[[钅杜]]": "\ud872\udf4a", - "[[钅喜]]": "\ud872\udf73", - "[[钅波]]": "\ud872\udf5b", - "[[钅黑]]": "\ud872\udf76", - "[[钅麦]]": "\u9fcf", - "[[钅达]]": "\ud86d\udffc", - "[[钅仑]]": "\ud872\udf2d", - "[[钅哥]]": "\u9fd4", - "[[钅尔]]": "\u9fed", - "[[钅夫]]": "\ud86d\udce7", - "[[钅立]]": "\ud86d\udff7", - "[[石田]]": "\u9fec", - "[[奥气]]": "\u9feb", - "[[气奥]]": "\u9feb", - "……": "\u22ef\u22ef", - "——": "\u2e3f" + "base": { + "version": "1.20", + "targetLanguages": [ + "zh_cn" + ], + "exclusionMods": [], + "exclusionNamespaces": [] + }, + "floating": { + "inclusionDomains": [ + "font", + "textures" + ], + "exclusionDomains": [], + "exclusionPaths": [ + "packer-policy.json", + "local-config.json" + ], + "inclusionPaths": [], + "characterReplacement": { + "[[钅卢]]": "\ud872\udf3b", + "[[钅杜]]": "\ud872\udf4a", + "[[钅喜]]": "\ud872\udf73", + "[[钅波]]": "\ud872\udf5b", + "[[钅黑]]": "\ud872\udf76", + "[[钅麦]]": "\u9fcf", + "[[钅达]]": "\ud86d\udffc", + "[[钅仑]]": "\ud872\udf2d", + "[[钅哥]]": "\u9fd4", + "[[钅尔]]": "\u9fed", + "[[钅夫]]": "\ud86d\udce7", + "[[钅立]]": "\ud86d\udff7", + "[[石田]]": "\u9fec", + "[[奥气]]": "\u9feb", + "[[气奥]]": "\u9feb", + "……": "\u22ef\u22ef", + "——": "\u2e3f" + }, + "destinationReplacement": {} } } \ No newline at end of file diff --git a/config/packer/packer-example.json b/config/packer/packer-example.json new file mode 100644 index 000000000000..47b31e97788e --- /dev/null +++ b/config/packer/packer-example.json @@ -0,0 +1,30 @@ +{ + "base": { + "version": "packer-example", + "targetLanguages": [ + "zh_cn" + ], + "exclusionMods": [], + "exclusionNamespaces": [] + }, + "floating": { + "inclusionDomains": [ + "font", + "textures" + ], + "exclusionDomains": [], + "exclusionPaths": [ + "packer-policy.json", + "local-config.json" + ], + "inclusionPaths": [ + "other.txt" + ], + "characterReplacement": { + "[[TEMPLATE]]": "[[REPALCEMENT]]" + }, + "destinationReplacement": { + "[[TEMPLATE]]": "[[REPALCEMENT]]" + } + } +} \ No newline at end of file diff --git a/projects/1.19/assets/0-example-mixed-clone/mixed-clone/extra/extra.txt b/projects/1.19/assets/0-example-mixed-clone/mixed-clone/extra/extra.txt deleted file mode 100644 index ce7a60f9fb91..000000000000 --- a/projects/1.19/assets/0-example-mixed-clone/mixed-clone/extra/extra.txt +++ /dev/null @@ -1 +0,0 @@ -exexe exexe \ No newline at end of file diff --git a/projects/1.19/assets/0-example-mixed-clone/mixed-clone/lang/zh_cn.json b/projects/1.19/assets/0-example-mixed-clone/mixed-clone/lang/zh_cn.json deleted file mode 100644 index e8b9d44b06fb..000000000000 --- a/projects/1.19/assets/0-example-mixed-clone/mixed-clone/lang/zh_cn.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "key1": "new value 1", - "key3": "new value 3" -} \ No newline at end of file diff --git a/projects/1.19/assets/0-example-mixed-clone/mixed-clone/packer-policy.json b/projects/1.19/assets/0-example-mixed-clone/mixed-clone/packer-policy.json deleted file mode 100644 index dcfd344d8dfc..000000000000 --- a/projects/1.19/assets/0-example-mixed-clone/mixed-clone/packer-policy.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "clonemissing", - "source": "./projects/1.19/assets/0-example-nop/nop" -} \ No newline at end of file diff --git a/projects/1.19/assets/0-example-nop/nop/lang/zh_cn.json b/projects/1.19/assets/0-example-nop/nop/lang/zh_cn.json deleted file mode 100644 index 9b24d09faca1..000000000000 --- a/projects/1.19/assets/0-example-nop/nop/lang/zh_cn.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "key1": "value1", - "key2": "value2" -} \ No newline at end of file diff --git a/projects/1.19/assets/0-example-nop/nop/packer-policy.json b/projects/1.19/assets/0-example-nop/nop/packer-policy.json deleted file mode 100644 index e6043069e4d8..000000000000 --- a/projects/1.19/assets/0-example-nop/nop/packer-policy.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "noaction" -} \ No newline at end of file diff --git a/projects/1.19/assets/0-example-patch/patch/lang/zh_cn.json.patch b/projects/1.19/assets/0-example-patch/patch/lang/zh_cn.json.patch deleted file mode 100644 index 831d1cf538b4..000000000000 --- a/projects/1.19/assets/0-example-patch/patch/lang/zh_cn.json.patch +++ /dev/null @@ -1,14 +0,0 @@ -@@ -4,24 +4,28 @@ - %22key1%22: %22 -+new - value1%22,%0A -@@ -33,18 +33,22 @@ - %22key --2 -+3 - %22: %22 -+new - value --2 -+3 - %22%0A%7D \ No newline at end of file diff --git a/projects/1.19/assets/0-example-patch/patch/packer-policy.json b/projects/1.19/assets/0-example-patch/patch/packer-policy.json deleted file mode 100644 index a75e14b615d8..000000000000 --- a/projects/1.19/assets/0-example-patch/patch/packer-policy.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "patch", - "source": "./projects/1.19/assets/0-example-nop/nop", - "patches": { - "lang/zh_cn.json": "./projects/1.19/assets/0-example-patch/patch/lang/zh_cn.json.patch" - } -} \ No newline at end of file diff --git a/projects/1.19/assets/0-example-port/port/lang/zh_cn.json b/projects/1.19/assets/0-example-port/port/lang/zh_cn.json deleted file mode 100644 index 245d5df201df..000000000000 --- a/projects/1.19/assets/0-example-port/port/lang/zh_cn.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "key1": "value1", - "key4": "value4" -} \ No newline at end of file diff --git a/projects/1.19/assets/0-example-port/port/packer-policy.json b/projects/1.19/assets/0-example-port/port/packer-policy.json deleted file mode 100644 index 422748cc0dcf..000000000000 --- a/projects/1.19/assets/0-example-port/port/packer-policy.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "backport", - "source": "./projects/1.19/assets/0-example-mixed-clone/mixed-clone" -} \ No newline at end of file diff --git a/projects/1.19/assets/0-example-simple-clone/clone/packer-policy.json b/projects/1.19/assets/0-example-simple-clone/clone/packer-policy.json deleted file mode 100644 index df2d5f484bc6..000000000000 --- a/projects/1.19/assets/0-example-simple-clone/clone/packer-policy.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "plainclone", - "source": "./projects/1.19/assets/0-example-nop/nop" -} \ No newline at end of file diff --git a/projects/1.20-fabric/assets/minecraft/minecraft/packer-policy.json b/projects/1.20-fabric/assets/minecraft/minecraft/packer-policy.json index 75b22dfd6411..a0802b736d3f 100644 --- a/projects/1.20-fabric/assets/minecraft/minecraft/packer-policy.json +++ b/projects/1.20-fabric/assets/minecraft/minecraft/packer-policy.json @@ -1,4 +1,6 @@ -{ - "type": "plainclone", - "source": "./projects/1.16/assets/minecraft/minecraft" -} \ No newline at end of file +[ + { + "type": "indirect", + "source": "./projects/1.20/assets/minecraft/minecraft" + } +] \ No newline at end of file diff --git a/projects/1.20-fabric/pack.mcmeta b/projects/1.20-fabric/pack.mcmeta index e05fae8f9262..bce9c05f5259 100644 --- a/projects/1.20-fabric/pack.mcmeta +++ b/projects/1.20-fabric/pack.mcmeta @@ -1,6 +1,6 @@ -{ - "pack": { +{{ + "pack": {{ "pack_format": 15, - "description": "汉化万用包,仅供1.20.1Fabric使用" - } -} \ No newline at end of file + "description": "汉化万用包,仅供1.20.1Fabric使用/n打包时间:{0:yyyy-MM-ddTHH:mm:ssZ}" + }} +}} \ No newline at end of file diff --git a/projects/1.20/pack.mcmeta b/projects/1.20/pack.mcmeta index 1f2b80f1586a..b50bb96ae784 100644 --- a/projects/1.20/pack.mcmeta +++ b/projects/1.20/pack.mcmeta @@ -1,6 +1,6 @@ -{ - "pack": { +{{ + "pack": {{ "pack_format": 15, - "description": "汉化万用包,仅供1.20.1Forge使用" - } -} \ No newline at end of file + "description": "汉化万用包,仅供1.20.1Forge使用/n打包时间:{0:yyyy-MM-ddTHH:mm:ssZ}" + }} +}} \ No newline at end of file diff --git a/projects/packer-example/README.txt b/projects/packer-example/README.txt new file mode 100644 index 000000000000..08e00ed29169 --- /dev/null +++ b/projects/packer-example/README.txt @@ -0,0 +1 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \ No newline at end of file diff --git a/projects/packer-example/assets/example-composite/composite/lang/zh_cn.json b/projects/packer-example/assets/example-composite/composite/lang/zh_cn.json new file mode 100644 index 000000000000..1d7f3709db82 --- /dev/null +++ b/projects/packer-example/assets/example-composite/composite/lang/zh_cn.json @@ -0,0 +1,4 @@ +{ + "key3": "new value3", + "key_7_9": "new value_7_9" +} \ No newline at end of file diff --git a/projects/packer-example/assets/example-composite/composite/other.txt b/projects/packer-example/assets/example-composite/composite/other.txt new file mode 100644 index 000000000000..38f438fea794 --- /dev/null +++ b/projects/packer-example/assets/example-composite/composite/other.txt @@ -0,0 +1 @@ +////////////REPLACEMENT//////////// \ No newline at end of file diff --git a/projects/packer-example/assets/example-composite/composite/packer-policy.json b/projects/packer-example/assets/example-composite/composite/packer-policy.json new file mode 100644 index 000000000000..b6c48de2a6df --- /dev/null +++ b/projects/packer-example/assets/example-composite/composite/packer-policy.json @@ -0,0 +1,13 @@ +[ + { + "type": "direct" + }, + { + "type": "indirect", + "source": "projects/packer-example/assets/example-indirect/indirect" + }, + { + "type": "indirect", + "source": "projects/packer-example/assets/example-composition/composition" + } +] \ No newline at end of file diff --git a/projects/packer-example/assets/example-composition/composition/compositions/zh_cn.json-composition.json b/projects/packer-example/assets/example-composition/composition/compositions/zh_cn.json-composition.json new file mode 100644 index 000000000000..fea771c361ea --- /dev/null +++ b/projects/packer-example/assets/example-composition/composition/compositions/zh_cn.json-composition.json @@ -0,0 +1,37 @@ +{ + "target": "assets/composition/lang/zh_cn.json", + "entries": [ + { + "templates": { + "key_{0}_{1}": "value_{0}_{1}", + "altkey_{0}_{1}": "altvalue_{0}_{1}" + }, + "parameters": [ + { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7", + "8": "8", + "9": "9" + }, + { + "00": "00", + "01": "01", + "02": "02", + "03": "03", + "04": "04", + "05": "05", + "06": "06", + "07": "07", + "08": "08", + "09": "09" + } + ] + } + ] +} \ No newline at end of file diff --git a/projects/packer-example/assets/example-composition/composition/local-config.json b/projects/packer-example/assets/example-composition/composition/local-config.json new file mode 100644 index 000000000000..3670d611ac56 --- /dev/null +++ b/projects/packer-example/assets/example-composition/composition/local-config.json @@ -0,0 +1,10 @@ +{ + "inclusionDomains": [], + "exclusionDomains": [ + "compositions" + ], + "exclusionPaths": [], + "inclusionPaths": [], + "characterReplacement": {}, + "destinationReplacement": {} +} \ No newline at end of file diff --git a/projects/packer-example/assets/example-composition/composition/packer-policy.json b/projects/packer-example/assets/example-composition/composition/packer-policy.json new file mode 100644 index 000000000000..3d360165b4c2 --- /dev/null +++ b/projects/packer-example/assets/example-composition/composition/packer-policy.json @@ -0,0 +1,7 @@ +[ + { + "type": "composition", + "destType": "json", + "source": "projects/packer-example/assets/example-composition/composition/compositions/zh_cn.json-composition.json" + } +] \ No newline at end of file diff --git a/projects/packer-example/assets/example-direct/direct/lang/en_us.json b/projects/packer-example/assets/example-direct/direct/lang/en_us.json new file mode 100644 index 000000000000..6ccb0f975d80 --- /dev/null +++ b/projects/packer-example/assets/example-direct/direct/lang/en_us.json @@ -0,0 +1,20 @@ +{ + "key1": "ununvalue1", + "key2": "ununvalue2", + "key3": "ununvalue3", + "key4": "ununvalue4", + "key5": "ununvalue5", + "key6": "ununvalue6", + "key7": "ununvalue7", + "key8": "ununvalue8", + "key9": "ununvalue9", + "key10": "ununvalue10", + "key11": "ununvalue11", + "key12": "ununvalue12", + "key13": "ununvalue13", + "key14": "ununvalue14", + "key15": "ununvalue15", + "key16": "ununvalue16", + "key17": "ununvalue17", + "key18": "ununvalue18" +} \ No newline at end of file diff --git a/projects/packer-example/assets/example-direct/direct/lang/zh_cn.json b/projects/packer-example/assets/example-direct/direct/lang/zh_cn.json new file mode 100644 index 000000000000..7942577b11d5 --- /dev/null +++ b/projects/packer-example/assets/example-direct/direct/lang/zh_cn.json @@ -0,0 +1,20 @@ +{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + "key4": "value4", + "key5": "value5", + "key6": "value6", + "key7": "value7", + "key8": "value8", + "key9": "value9", + "key10": "value10", + "key11": "value11", + "key12": "value12", + "key13": "value13", + "key14": "value14", + "key15": "value15", + "key16": "value16", + "key17": "value17", + "key18": "value18" +} \ No newline at end of file diff --git a/projects/packer-example/assets/example-direct/direct/other.txt b/projects/packer-example/assets/example-direct/direct/other.txt new file mode 100644 index 000000000000..08e00ed29169 --- /dev/null +++ b/projects/packer-example/assets/example-direct/direct/other.txt @@ -0,0 +1 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \ No newline at end of file diff --git a/projects/packer-example/assets/example-indirect/indirect/packer-policy.json b/projects/packer-example/assets/example-indirect/indirect/packer-policy.json new file mode 100644 index 000000000000..164b89d90ca6 --- /dev/null +++ b/projects/packer-example/assets/example-indirect/indirect/packer-policy.json @@ -0,0 +1,6 @@ +[ + { + "type": "indirect", + "source": "projects/packer-example/assets/example-direct/direct" + } +] \ No newline at end of file diff --git a/projects/packer-example/pack.mcmeta b/projects/packer-example/pack.mcmeta new file mode 100644 index 000000000000..c3b7467d5a17 --- /dev/null +++ b/projects/packer-example/pack.mcmeta @@ -0,0 +1,6 @@ +{{ + "pack": {{ + "pack_format": 2147483647, + "description": "演示用包,不用于分发/n打包时间:{0:yyyy-MM-ddTHH:mm:ssZ}" + }} +}} \ No newline at end of file diff --git a/src/Packer/Extensions/ContentExtension.cs b/src/Packer/Extensions/ContentExtension.cs index bac9be751178..811ff75f676a 100644 --- a/src/Packer/Extensions/ContentExtension.cs +++ b/src/Packer/Extensions/ContentExtension.cs @@ -1,4 +1,5 @@ -using System; +using Serilog; +using System; using System.IO; using System.Linq; using System.Security.Cryptography; diff --git a/src/Packer/Extensions/DirectoryExtension.cs b/src/Packer/Extensions/DirectoryExtension.cs index 0eb484ba9ff0..0fcabea233ce 100644 --- a/src/Packer/Extensions/DirectoryExtension.cs +++ b/src/Packer/Extensions/DirectoryExtension.cs @@ -1,5 +1,6 @@ using Packer.Models; using Packer.Models.Providers; +using Serilog; using System; using System.Collections.Generic; using System.IO; @@ -71,20 +72,20 @@ internal static EvaluatorReturnType FromCurrentDirectory(DirectoryInfo namespace { var floatingConfig = Utils.RetrieveLocalConfig(namespaceDirectory); var localConfig = config.Modify(floatingConfig); - + return from candidate in namespaceDirectory.EnumerateFiles("*", SearchOption.AllDirectories) let relativePath = Path.GetRelativePath(namespaceDirectory.FullName, candidate.FullName) .NormalizePath() - let destination = Path.Combine(namespaceDirectory.Name, - relativePath) + let fullPath = Path.GetRelativePath(".", candidate.FullName) + let destination = Path.Combine( + "assets", namespaceDirectory.Name, relativePath) .NormalizePath() - let domain = relativePath.Split('/')[0] where !relativePath.IsPathForceExcluded(localConfig) // [1] 排除路径 -- packer-policy等 where (relativePath.IsPathForceIncluded(localConfig) // [2] 包含路径 [单列] || relativePath.IsDomainForceIncluded(localConfig) // [3] 包含domain -- font/ textures/ || (destination.IsInTargetLanguage(localConfig) // [4] 语言标记 -- 含zh_cn的 - && relativePath.IsDomainForceExcluded(localConfig))) // [5] 排除domain [暂无] + && !relativePath.IsDomainForceExcluded(localConfig))) // [5] 排除domain [暂无] let provider = CreateProviderFromFile(candidate, destination, localConfig) select (provider, DoesOverride(parameters)); } @@ -99,7 +100,7 @@ internal static EvaluatorReturnType FromSpecifiedDirectory(DirectoryInfo namespa return from candidate in redirectDirectory.EnumerateRawProviders(config) let provider = candidate.provider - .ReplaceDestination(@"^(?<=^assets/)[^/]*(?=/)", + .ReplaceDestination(@"(?<=^assets/)[^/]*(?=/)", namespaceName) select (provider, DoesOverride(parameters)); } @@ -109,7 +110,7 @@ internal static EvaluatorReturnType FromComposition(DirectoryInfo namespaceDirec ParameterType? parameters) { var compositionPath = parameters!["source"].GetString(); - var type = parameters["type"].GetString(); + var type = parameters["destType"].GetString(); var compositionFile = new FileInfo(compositionPath!); IResourceFileProvider provider = type switch // 类型推断不出要用接口 { @@ -124,19 +125,20 @@ internal static EvaluatorReturnType FromComposition(DirectoryInfo namespaceDirec internal static IResourceFileProvider CreateProviderFromFile(FileInfo file, string destination, Config config) { var extension = file.Extension; - return file.Directory!.Name == "lang" - ? extension switch - { - ".json" => JsonMappingHelper.CreateFromFile(file, destination), - ".lang" => JsonMappingHelper.CreateFromFile(file, destination), - _ => throw new InvalidOperationException($"Invalid Type of Language File at {file.FullName}.") - } - : extension switch + if (file.Directory!.Name == "lang") + { + switch(extension) { - // 已知的文本文件类型 - ".txt" or ".json" or ".md" => TextFile.Create(file, destination), - _ => new RawFile(file, destination) + case ".json": return JsonMappingHelper.CreateFromFile(file, destination); + case ".lang": return LangMappingHelper.CreateFromFile(file, destination); }; + } + return extension switch + { + // 已知的文本文件类型 + ".txt" or ".json" or ".md" => TextFile.Create(file, destination), + _ => new RawFile(file, destination) + }; } internal static bool DoesOverride(ParameterType? parameters) diff --git a/src/Packer/Models/Config.cs b/src/Packer/Models/Config.cs index c19c488b175f..45aeb8bf2b31 100644 --- a/src/Packer/Models/Config.cs +++ b/src/Packer/Models/Config.cs @@ -1,13 +1,15 @@ using System.Collections.Generic; using System.Linq; -using System.Text.Json.Serialization; + +// 要null就抛异常吧(逃) +#nullable disable namespace Packer { /// /// 配置项 /// - public struct Config + public class Config { /// /// 基础配置,版本唯一 @@ -23,12 +25,11 @@ public struct Config /// public Config Modify(FloatingConfig? floatingConfig) { - // 好家伙 这玩意还是个Nullable - if (!floatingConfig.HasValue) return this; + if (floatingConfig is null) return this; return new() { Base = Base, - Floating = Floating.Merge(floatingConfig.Value) + Floating = Floating.Merge(floatingConfig) }; } } @@ -36,7 +37,7 @@ public Config Modify(FloatingConfig? floatingConfig) /// /// 基础配置,版本唯一 /// - public struct BaseConfig + public class BaseConfig { /// /// 打包的目标版本 @@ -62,7 +63,7 @@ public struct BaseConfig /// /// 浮动配置,可与命名空间下的文件合并 /// - public struct FloatingConfig + public class FloatingConfig { /// /// 强制包含的domain @@ -84,7 +85,7 @@ public struct FloatingConfig /// /// 文本字符替换表 /// - public Dictionary CharatcerReplacement { get; set; } + public Dictionary CharacterReplacement { get; set; } /// /// 内容替换表 /// @@ -99,7 +100,7 @@ public struct FloatingConfig ExclusionDomains = ExclusionDomains.Concat(other.ExclusionDomains).Distinct(), InclusionDomains = InclusionDomains.Concat(other.InclusionDomains).Distinct(), InclusionPaths = InclusionPaths.Concat(other.InclusionPaths).Distinct(), - CharatcerReplacement = CharatcerReplacement.Concat(other.CharatcerReplacement).DistinctBy(_ => _.Key) + CharacterReplacement = CharacterReplacement.Concat(other.CharacterReplacement).DistinctBy(_ => _.Key) .ToDictionary(_ => _.Key, _ => _.Value), DestinationReplacement = DestinationReplacement.Concat(other.DestinationReplacement).DistinctBy(_ => _.Key) .ToDictionary(_ => _.Key, _ => _.Value) diff --git a/src/Packer/Models/Providers/CompositionHelper.cs b/src/Packer/Models/Providers/CompositionHelper.cs index 5fed86a38e78..704bf65fd1a3 100644 --- a/src/Packer/Models/Providers/CompositionHelper.cs +++ b/src/Packer/Models/Providers/CompositionHelper.cs @@ -63,7 +63,8 @@ from template in templates internal static IEnumerable, IEnumerable>> CrossMap(this IEnumerable>> origin) => origin.Aggregate( - seed: Enumerable.Empty, IEnumerable>>(), + seed: new[] { KeyValuePair.Create(Enumerable.Empty(), Enumerable.Empty()) } + as IEnumerable, IEnumerable>>, // 这都需要手写... (accumulate, next) => from incomingPair in next join existingGroup in accumulate on true equals true select KeyValuePair.Create( diff --git a/src/Packer/Models/Providers/McMetaProvider.cs b/src/Packer/Models/Providers/McMetaProvider.cs index c6dcab9b8e50..a0616ebec22d 100644 --- a/src/Packer/Models/Providers/McMetaProvider.cs +++ b/src/Packer/Models/Providers/McMetaProvider.cs @@ -49,7 +49,7 @@ public override async Task WriteToArchive(ZipArchive archive) using var writer = new StreamWriter( archive.CreateEntry(destination) .Open(), - Encoding.UTF8); + new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); await writer.WriteAsync(content); } } diff --git a/src/Packer/Models/Providers/TermMappingProvider.cs b/src/Packer/Models/Providers/TermMappingProvider.cs index 3dcac7a057ed..13ebf32577dc 100644 --- a/src/Packer/Models/Providers/TermMappingProvider.cs +++ b/src/Packer/Models/Providers/TermMappingProvider.cs @@ -144,14 +144,15 @@ public TermMappingProvider(ITermDictionary map, string destination) /// public IResourceFileProvider ApplyTo(IResourceFileProvider? incoming, bool overrideExisting = false) { - if (incoming is not TermMappingProvider) + if (incoming is null) return this; + if (incoming is not TermMappingProvider inProvider) throw new ArgumentException($"Argument not an instance of {typeof(TermMappingProvider)}.", nameof(incoming)); - var inProvider = incoming as TermMappingProvider; + //var inProvider = incoming as TermMappingProvider; - if (inProvider is null) throw new ArgumentNullException(nameof(incoming)); + //if (inProvider is null) throw new ArgumentNullException(nameof(incoming)); - var (baseMap, inMap) = !overrideExisting + var (baseMap, inMap) = overrideExisting ? (Map, inProvider.Map) : (inProvider.Map, Map); // 交换顺序 @@ -189,7 +190,7 @@ public async Task WriteToArchive(ZipArchive archive) using var writer = new StreamWriter( archive.CreateEntry(destination) .Open(), - Encoding.UTF8); + new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); await writer.WriteAsync(Map.ProvideStringContent()); } } diff --git a/src/Packer/Models/Providers/TextFile.cs b/src/Packer/Models/Providers/TextFile.cs index 408e1add8c63..c6207b5a5323 100644 --- a/src/Packer/Models/Providers/TextFile.cs +++ b/src/Packer/Models/Providers/TextFile.cs @@ -54,7 +54,7 @@ public virtual IResourceFileProvider ReplaceContent(string searchPattern, string searchPattern, replacement, RegexOptions.Singleline), - Content); + Destination); /// public virtual IResourceFileProvider ReplaceDestination(string searchPattern, string replacement) => new TextFile(Content, @@ -73,7 +73,7 @@ public virtual async Task WriteToArchive(ZipArchive archive) using var writer = new StreamWriter( archive.CreateEntry(destination) .Open(), - Encoding.UTF8); + new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); await writer.WriteAsync(Content); } } diff --git a/src/Packer/Program.cs b/src/Packer/Program.cs index 777b8305d36f..1f819dd467ff 100644 --- a/src/Packer/Program.cs +++ b/src/Packer/Program.cs @@ -25,14 +25,14 @@ public static async Task Main(string version, string[]? targets) var config = await Utils.RetrieveConfig(configTemplate: "./config/packer/{0}.json", version: version); - Log.Information("开始对版本 {0} 的打包", config.Base.Version); var query = // 这就是查询表达式吗( from modDirectory in new DirectoryInfo($"./projects/{config.Base.Version}/assets") .EnumerateDirectories() let modIdentifier = modDirectory.Name - where targetModIdentifiers is null // 未提供列表,全部打包 + where targetModIdentifiers is null + || targetModIdentifiers.Count() == 0 // 未提供列表,全部打包 || targetModIdentifiers.Contains(modIdentifier) // 有列表,仅打包列表中的项 where !config.Base.ExclusionMods.Contains(modIdentifier) // 没有被明确排除 from namespaceDirectory in modDirectory.EnumerateDirectories() @@ -47,7 +47,7 @@ select destinationGroup => next.ApplyTo( accumulate, overrideExisting: false)) into provider - select config.Floating.CharatcerReplacement // 内容的字符替换 + select config.Floating.CharacterReplacement // 内容的字符替换 .Aggregate(seed: provider, (accumulate, replacement) => accumulate.ReplaceContent( @@ -56,11 +56,10 @@ select config.Floating.CharatcerReplacement // 内容的 select config.Floating.DestinationReplacement // 全局路径替换:预留 .Aggregate(seed: provider, (accumulate, replacement) - => accumulate.ReplaceContent( + => accumulate.ReplaceDestination( replacement.Key, replacement.Value)); - var initialsQuery = from file in new DirectoryInfo($"./projects/{config.Base.Version}") .EnumerateFiles() select (file.Name == "pack.mcmeta") @@ -76,8 +75,9 @@ await Task.WhenAll(from provider in query.Concat(initialsQuery) select provider.WriteToArchive(archive)); } - Log.Information("对版本 {0} 的打包结束。共写入了 {1} 个文件", + Log.Information("对版本 {0} 的打包结束。共写入了 {1} + {2} 个文件", config.Base.Version, + initialsQuery.Count(), query.Count()); var md5 = stream.ComputeMD5(); diff --git a/src/Packer/Utils.cs b/src/Packer/Utils.cs index 4b980619a184..38beb8a4cd3a 100644 --- a/src/Packer/Utils.cs +++ b/src/Packer/Utils.cs @@ -50,7 +50,7 @@ public static async Task RetrieveConfig(string configTemplate, string ve var content = await File.ReadAllBytesAsync(configPath); return JsonSerializer.Deserialize( content, - new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase })!; } /// @@ -74,6 +74,7 @@ public static List RetrieveStrategy(DirectoryInfo directory) reader.ReadToEnd(), new JsonSerializerOptions { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) } }); if (result is null) From 4fc31780b61d1f0650ad8461a08e11918471b76e Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sun, 1 Oct 2023 23:11:35 +0800 Subject: [PATCH 09/22] Migration Phase II --- config/packer/1.12.2.json | 79 +++++------ config/packer/1.16-fabric.json | 73 ++++++----- config/packer/1.16.json | 74 ++++++----- config/packer/1.18-fabric.json | 77 ++++++----- config/packer/1.18.json | 83 ++++++------ config/packer/1.19.json | 79 ++++++----- .../thebetweenlands/lang/zh_cn.lang | 1 - .../assets/rftools/rftools/lang/zh_cn.lang | 2 +- .../tinkerscompendium/lang/zh_cn.lang | 4 +- projects/1.12.2/pack.mcmeta | 10 +- .../cloth-config2/packer-policy.json | 7 +- .../ironfurnaces/packer-policy.json | 10 +- .../minecraft/minecraft/packer-policy.json | 8 +- projects/1.16-fabric/pack.mcmeta | 10 +- .../alexs-mobs/alexsmobs/local-config.json | 10 ++ .../corail_recycler/packer-policy.json | 7 +- .../craftingtweaks/packer-policy.json | 11 +- .../assets/laser-mod/lasermod/lang/zh_cn.json | 2 +- .../tool-kit/toolkit/packer-policy.json | 7 +- projects/1.16/pack.mcmeta | 10 +- .../cloth-config2/packer-policy.json | 7 +- .../exlinecopperequipment/packer-policy.json | 7 +- .../assets/goodall/goodall/packer-policy.json | 5 +- .../ironfurnaces/packer-policy.json | 10 +- .../assets/jei/jei/packer-policy.json | 10 +- .../minecraft/minecraft/packer-policy.json | 10 +- .../opulence/opulence/packer-policy.json | 10 +- .../rottencreatures/packer-policy.json | 6 +- projects/1.18-fabric/pack.mcmeta | 12 +- .../craftingtweaks/packer-policy.json | 11 +- .../1.18/assets/jei/jei/packer-policy.json | 10 +- .../minecraft/minecraft/packer-policy.json | 13 +- projects/1.18/pack.mcmeta | 12 +- .../armor-poser/armorposer/packer-policy.json | 10 +- .../hourglass/hourglass/packer-policy.json | 10 +- .../minecraft/minecraft/packer-policy.json | 13 +- .../shieldexp/packer-policy.json | 10 +- projects/1.19/pack.mcmeta | 10 +- .../Models/Providers/TermMappingProvider.cs | 123 +++++++++++------- 39 files changed, 497 insertions(+), 366 deletions(-) create mode 100644 projects/1.16/assets/alexs-mobs/alexsmobs/local-config.json diff --git a/config/packer/1.12.2.json b/config/packer/1.12.2.json index 600a5bd57981..65a4c9b6b38f 100644 --- a/config/packer/1.12.2.json +++ b/config/packer/1.12.2.json @@ -1,40 +1,45 @@ { - "targetVersion": "1.12.2", - "targetLanguage": [ - "zh_cn" - ], - "additionalContent": [ - "LICENSE", - "pack.mcmeta", - "pack.png", - "README.txt" - ], - "modNameBlackList": [ - "gregtechce" - ], - "domainBlackList": [ - "srparasites" - ], - "noProcessNamespace": [ - "font", - "textures" - ], - "replacementMap": { - "[[钅卢]]": "\ue900", - "[[钅杜]]": "\ue901", - "[[钅喜]]": "\ue902", - "[[钅波]]": "\ue903", - "[[钅黑]]": "\ue904", - "[[钅麦]]": "\u9fcf", - "[[钅达]]": "\ue906", - "[[钅仑]]": "\ue907", - "[[钅哥]]": "\u9fd4", - "[[钅尔]]": "\u9fed", - "[[钅夫]]": "\ue90a", - "[[钅立]]": "\ue90c", - "[[石田]]": "\u9fec", - "[[奥气]]": "\u9feb", - "[[气奥]]": "\u9feb", - "……": "\u22ef\u22ef" + "base": { + "version": "1.12.2", + "targetLanguages": [ + "zh_cn" + ], + "exclusionMods": [ + "gregtechce" + ], + "exclusionNamespaces": [ + "srparasites" + ] + }, + "floating": { + "inclusionDomains": [ + "font", + "textures" + ], + "exclusionDomains": [], + "exclusionPaths": [ + "packer-policy.json", + "local-config.json" + ], + "inclusionPaths": [], + "characterReplacement": { + "[[钅卢]]": "\ue900", + "[[钅杜]]": "\ue901", + "[[钅喜]]": "\ue902", + "[[钅波]]": "\ue903", + "[[钅黑]]": "\ue904", + "[[钅麦]]": "\u9fcf", + "[[钅达]]": "\ue906", + "[[钅仑]]": "\ue907", + "[[钅哥]]": "\u9fd4", + "[[钅尔]]": "\u9fed", + "[[钅夫]]": "\ue90a", + "[[钅立]]": "\ue90c", + "[[石田]]": "\u9fec", + "[[奥气]]": "\u9feb", + "[[气奥]]": "\u9feb", + "……": "\u22ef\u22ef" + }, + "destinationReplacement": {} } } \ No newline at end of file diff --git a/config/packer/1.16-fabric.json b/config/packer/1.16-fabric.json index 923a5fb678ae..366a34c4e619 100644 --- a/config/packer/1.16-fabric.json +++ b/config/packer/1.16-fabric.json @@ -1,37 +1,42 @@ { - "targetVersion": "1.16-fabric", - "targetLanguage": [ - "zh_cn" - ], - "additionalContent": [ - "LICENSE", - "pack.mcmeta", - "pack.png", - "README.txt" - ], - "modNameBlackList": [], - "domainBlackList": [], - "noProcessNamespace": [ - "font", - "textures" - ], - "replacementMap": { - "[[钅卢]]": "\ud872\udf3b", - "[[钅杜]]": "\ud872\udf4a", - "[[钅喜]]": "\ud872\udf73", - "[[钅波]]": "\ud872\udf5b", - "[[钅黑]]": "\ud872\udf76", - "[[钅麦]]": "\u9fcf", - "[[钅达]]": "\ud86d\udffc", - "[[钅仑]]": "\ud872\udf2d", - "[[钅哥]]": "\u9fd4", - "[[钅尔]]": "\u9fed", - "[[钅夫]]": "\ud86d\udce7", - "[[钅立]]": "\ud86d\udff7", - "[[石田]]": "\u9fec", - "[[奥气]]": "\u9feb", - "[[气奥]]": "\u9feb", - "……": "\u22ef\u22ef", - "——": "\u2e3a" + "base": { + "version": "1.16-fabric", + "targetLanguages": [ + "zh_cn" + ], + "exclusionMods": [], + "exclusionNamespaces": [] + }, + "floating": { + "inclusionDomains": [ + "font", + "textures" + ], + "exclusionDomains": [], + "exclusionPaths": [ + "packer-policy.json", + "local-config.json" + ], + "inclusionPaths": [], + "characterReplacement": { + "[[钅卢]]": "\ud872\udf3b", + "[[钅杜]]": "\ud872\udf4a", + "[[钅喜]]": "\ud872\udf73", + "[[钅波]]": "\ud872\udf5b", + "[[钅黑]]": "\ud872\udf76", + "[[钅麦]]": "\u9fcf", + "[[钅达]]": "\ud86d\udffc", + "[[钅仑]]": "\ud872\udf2d", + "[[钅哥]]": "\u9fd4", + "[[钅尔]]": "\u9fed", + "[[钅夫]]": "\ud86d\udce7", + "[[钅立]]": "\ud86d\udff7", + "[[石田]]": "\u9fec", + "[[奥气]]": "\u9feb", + "[[气奥]]": "\u9feb", + "……": "\u22ef\u22ef", + "——": "\u2e3f" + }, + "destinationReplacement": {} } } \ No newline at end of file diff --git a/config/packer/1.16.json b/config/packer/1.16.json index 968d642b296d..3d2413cc2849 100644 --- a/config/packer/1.16.json +++ b/config/packer/1.16.json @@ -1,38 +1,42 @@ { - "targetVersion": "1.16", - "targetLanguage": [ - "zh_cn" - ], - "additionalContent": [ - "LICENSE", - "pack.mcmeta", - "pack.png", - "README.txt", - "assets/alexs-mobs/alexsmobs/lang/en_us.json" - ], - "modNameBlackList": [], - "domainBlackList": [], - "noProcessNamespace": [ - "font", - "textures" - ], - "replacementMap": { - "[[钅卢]]": "\ud872\udf3b", - "[[钅杜]]": "\ud872\udf4a", - "[[钅喜]]": "\ud872\udf73", - "[[钅波]]": "\ud872\udf5b", - "[[钅黑]]": "\ud872\udf76", - "[[钅麦]]": "\u9fcf", - "[[钅达]]": "\ud86d\udffc", - "[[钅仑]]": "\ud872\udf2d", - "[[钅哥]]": "\u9fd4", - "[[钅尔]]": "\u9fed", - "[[钅夫]]": "\ud86d\udce7", - "[[钅立]]": "\ud86d\udff7", - "[[石田]]": "\u9fec", - "[[奥气]]": "\u9feb", - "[[气奥]]": "\u9feb", - "……": "\u22ef\u22ef", - "——": "\u2e3a" + "base": { + "version": "1.16", + "targetLanguages": [ + "zh_cn" + ], + "exclusionMods": [], + "exclusionNamespaces": [] + }, + "floating": { + "inclusionDomains": [ + "font", + "textures" + ], + "exclusionDomains": [], + "exclusionPaths": [ + "packer-policy.json", + "local-config.json" + ], + "inclusionPaths": [], + "characterReplacement": { + "[[钅卢]]": "\ud872\udf3b", + "[[钅杜]]": "\ud872\udf4a", + "[[钅喜]]": "\ud872\udf73", + "[[钅波]]": "\ud872\udf5b", + "[[钅黑]]": "\ud872\udf76", + "[[钅麦]]": "\u9fcf", + "[[钅达]]": "\ud86d\udffc", + "[[钅仑]]": "\ud872\udf2d", + "[[钅哥]]": "\u9fd4", + "[[钅尔]]": "\u9fed", + "[[钅夫]]": "\ud86d\udce7", + "[[钅立]]": "\ud86d\udff7", + "[[石田]]": "\u9fec", + "[[奥气]]": "\u9feb", + "[[气奥]]": "\u9feb", + "……": "\u22ef\u22ef", + "——": "\u2e3f" + }, + "destinationReplacement": {} } } \ No newline at end of file diff --git a/config/packer/1.18-fabric.json b/config/packer/1.18-fabric.json index 7716ffdbb028..e8ed4e63ad12 100644 --- a/config/packer/1.18-fabric.json +++ b/config/packer/1.18-fabric.json @@ -1,39 +1,44 @@ { - "targetVersion": "1.18-fabric", - "targetLanguage": [ - "zh_cn" - ], - "additionalContent": [ - "LICENSE", - "pack.mcmeta", - "pack.png", - "README.txt" - ], - "modNameBlackList": [], - "domainBlackList": [ - "litematica" - ], - "noProcessNamespace": [ - "font", - "textures" - ], - "replacementMap": { - "[[钅卢]]": "\ud872\udf3b", - "[[钅杜]]": "\ud872\udf4a", - "[[钅喜]]": "\ud872\udf73", - "[[钅波]]": "\ud872\udf5b", - "[[钅黑]]": "\ud872\udf76", - "[[钅麦]]": "\u9fcf", - "[[钅达]]": "\ud86d\udffc", - "[[钅仑]]": "\ud872\udf2d", - "[[钅哥]]": "\u9fd4", - "[[钅尔]]": "\u9fed", - "[[钅夫]]": "\ud86d\udce7", - "[[钅立]]": "\ud86d\udff7", - "[[石田]]": "\u9fec", - "[[奥气]]": "\u9feb", - "[[气奥]]": "\u9feb", - "……": "\u22ef\u22ef", - "——": "\u2e3a" + "base": { + "version": "1.18-fabric", + "targetLanguages": [ + "zh_cn" + ], + "exclusionMods": [], + "exclusionNamespaces": [ + "litematica" + ] + }, + "floating": { + "inclusionDomains": [ + "font", + "textures" + ], + "exclusionDomains": [], + "exclusionPaths": [ + "packer-policy.json", + "local-config.json" + ], + "inclusionPaths": [], + "characterReplacement": { + "[[钅卢]]": "\ud872\udf3b", + "[[钅杜]]": "\ud872\udf4a", + "[[钅喜]]": "\ud872\udf73", + "[[钅波]]": "\ud872\udf5b", + "[[钅黑]]": "\ud872\udf76", + "[[钅麦]]": "\u9fcf", + "[[钅达]]": "\ud86d\udffc", + "[[钅仑]]": "\ud872\udf2d", + "[[钅哥]]": "\u9fd4", + "[[钅尔]]": "\u9fed", + "[[钅夫]]": "\ud86d\udce7", + "[[钅立]]": "\ud86d\udff7", + "[[石田]]": "\u9fec", + "[[奥气]]": "\u9feb", + "[[气奥]]": "\u9feb", + "……": "\u22ef\u22ef", + "——": "\u2e3f" + }, + "destinationReplacement": {} } } \ No newline at end of file diff --git a/config/packer/1.18.json b/config/packer/1.18.json index caf2693faa93..c64eb1651dd3 100644 --- a/config/packer/1.18.json +++ b/config/packer/1.18.json @@ -1,42 +1,47 @@ { - "targetVersion": "1.18", - "targetLanguage": [ - "zh_cn" - ], - "additionalContent": [ - "LICENSE", - "pack.mcmeta", - "pack.png", - "README.txt" - ], - "modNameBlackList": [ - "create" - ], - "domainBlackList": [ - "urushi", - "thermal" - ], - "noProcessNamespace": [ - "font", - "textures" - ], - "replacementMap": { - "[[钅卢]]": "\ud872\udf3b", - "[[钅杜]]": "\ud872\udf4a", - "[[钅喜]]": "\ud872\udf73", - "[[钅波]]": "\ud872\udf5b", - "[[钅黑]]": "\ud872\udf76", - "[[钅麦]]": "\u9fcf", - "[[钅达]]": "\ud86d\udffc", - "[[钅仑]]": "\ud872\udf2d", - "[[钅哥]]": "\u9fd4", - "[[钅尔]]": "\u9fed", - "[[钅夫]]": "\ud86d\udce7", - "[[钅立]]": "\ud86d\udff7", - "[[石田]]": "\u9fec", - "[[奥气]]": "\u9feb", - "[[气奥]]": "\u9feb", - "……": "\u22ef\u22ef", - "——": "\u2e3a" + "base": { + "version": "1.18", + "targetLanguages": [ + "zh_cn" + ], + "exclusionMods": [ + "create" + ], + "exclusionNamespaces": [ + "urushi", + "thermal" + ] + }, + "floating": { + "inclusionDomains": [ + "font", + "textures" + ], + "exclusionDomains": [], + "exclusionPaths": [ + "packer-policy.json", + "local-config.json" + ], + "inclusionPaths": [], + "characterReplacement": { + "[[钅卢]]": "\ud872\udf3b", + "[[钅杜]]": "\ud872\udf4a", + "[[钅喜]]": "\ud872\udf73", + "[[钅波]]": "\ud872\udf5b", + "[[钅黑]]": "\ud872\udf76", + "[[钅麦]]": "\u9fcf", + "[[钅达]]": "\ud86d\udffc", + "[[钅仑]]": "\ud872\udf2d", + "[[钅哥]]": "\u9fd4", + "[[钅尔]]": "\u9fed", + "[[钅夫]]": "\ud86d\udce7", + "[[钅立]]": "\ud86d\udff7", + "[[石田]]": "\u9fec", + "[[奥气]]": "\u9feb", + "[[气奥]]": "\u9feb", + "……": "\u22ef\u22ef", + "——": "\u2e3f" + }, + "destinationReplacement": {} } } \ No newline at end of file diff --git a/config/packer/1.19.json b/config/packer/1.19.json index cb35ec2feec1..7c7eb46ead6f 100644 --- a/config/packer/1.19.json +++ b/config/packer/1.19.json @@ -1,43 +1,42 @@ { - "targetVersion": "1.19", - "targetLanguage": [ - "zh_cn" - ], - "additionalContent": [ - "LICENSE", - "pack.mcmeta", - "pack.png", - "README.txt" - ], - "modNameBlackList": [ - "0-example-nop", - "0-example-patch", - "0-example-simple-clone", - "0-example-mixed-clone", - "0-example-port" - ], - "domainBlackList": [], - "noProcessNamespace": [ - "font", - "textures" - ], - "replacementMap": { - "[[钅卢]]": "\ud872\udf3b", - "[[钅杜]]": "\ud872\udf4a", - "[[钅喜]]": "\ud872\udf73", - "[[钅波]]": "\ud872\udf5b", - "[[钅黑]]": "\ud872\udf76", - "[[钅麦]]": "\u9fcf", - "[[钅达]]": "\ud86d\udffc", - "[[钅仑]]": "\ud872\udf2d", - "[[钅哥]]": "\u9fd4", - "[[钅尔]]": "\u9fed", - "[[钅夫]]": "\ud86d\udce7", - "[[钅立]]": "\ud86d\udff7", - "[[石田]]": "\u9fec", - "[[奥气]]": "\u9feb", - "[[气奥]]": "\u9feb", - "……": "\u22ef\u22ef", - "——": "\u2e3a" + "base": { + "version": "1.19", + "targetLanguages": [ + "zh_cn" + ], + "exclusionMods": [], + "exclusionNamespaces": [] + }, + "floating": { + "inclusionDomains": [ + "font", + "textures" + ], + "exclusionDomains": [], + "exclusionPaths": [ + "packer-policy.json", + "local-config.json" + ], + "inclusionPaths": [], + "characterReplacement": { + "[[钅卢]]": "\ud872\udf3b", + "[[钅杜]]": "\ud872\udf4a", + "[[钅喜]]": "\ud872\udf73", + "[[钅波]]": "\ud872\udf5b", + "[[钅黑]]": "\ud872\udf76", + "[[钅麦]]": "\u9fcf", + "[[钅达]]": "\ud86d\udffc", + "[[钅仑]]": "\ud872\udf2d", + "[[钅哥]]": "\u9fd4", + "[[钅尔]]": "\u9fed", + "[[钅夫]]": "\ud86d\udce7", + "[[钅立]]": "\ud86d\udff7", + "[[石田]]": "\u9fec", + "[[奥气]]": "\u9feb", + "[[气奥]]": "\u9feb", + "……": "\u22ef\u22ef", + "——": "\u2e3f" + }, + "destinationReplacement": {} } } \ No newline at end of file diff --git a/projects/1.12.2/assets/angry-pixel-the-betweenlands-mod/thebetweenlands/lang/zh_cn.lang b/projects/1.12.2/assets/angry-pixel-the-betweenlands-mod/thebetweenlands/lang/zh_cn.lang index 754a3f5d9972..a6af23a9c2af 100644 --- a/projects/1.12.2/assets/angry-pixel-the-betweenlands-mod/thebetweenlands/lang/zh_cn.lang +++ b/projects/1.12.2/assets/angry-pixel-the-betweenlands-mod/thebetweenlands/lang/zh_cn.lang @@ -2231,7 +2231,6 @@ blsubtitles.misc.gears=齿轮:旋转 blsubtitles.misc.wall_slide=墙:滑移 blsubtitles.misc.wall_slam=墙:撞击 blsubtitles.misc.poop_jet=污泥:被喷射 -blsubtitles.misc.pit_fall blsubtitles.misc.zap=电击 blsubtitles.misc.chirobarb_erupter=翼手钩发射器:发射 blsubtitles.misc.simulacrum_break=远处传来神秘的噪声 diff --git a/projects/1.12.2/assets/rftools/rftools/lang/zh_cn.lang b/projects/1.12.2/assets/rftools/rftools/lang/zh_cn.lang index 62da0521f3b6..30ec563b22fc 100644 --- a/projects/1.12.2/assets/rftools/rftools/lang/zh_cn.lang +++ b/projects/1.12.2/assets/rftools/rftools/lang/zh_cn.lang @@ -260,7 +260,7 @@ message.rftools.remote_scanner=\ @f该方块可以扫描一个区域,\n\ @f并将其与塑形卡片链接。\n\ @f所链接的塑形卡片也\n\ - @f可以在构建器中使用 + @f可以在构建器中使用\ @6该版本的机器可以通过\n\ @6放置在其上方的\n\ @6已建立链接的物质传输器来扫描 diff --git a/projects/1.12.2/assets/tinkers-compendium/tinkerscompendium/lang/zh_cn.lang b/projects/1.12.2/assets/tinkers-compendium/tinkerscompendium/lang/zh_cn.lang index c5e84a0af239..86ddebea4c93 100644 --- a/projects/1.12.2/assets/tinkers-compendium/tinkerscompendium/lang/zh_cn.lang +++ b/projects/1.12.2/assets/tinkers-compendium/tinkerscompendium/lang/zh_cn.lang @@ -986,7 +986,7 @@ modifier.td_novel.desc=武器和护甲都讲述了一个故事,其中一些比 #Sponge modifier.td_soggy.name=浸水 modifier.td_soggy.desc=保留水有其好处。 -/Firewood +#Firewood modifier.td_hothead.name=急躁 modifier.td_hothead.desc=被击中让我生气! modifier.td_toasty.name=烤面包 @@ -1010,7 +1010,7 @@ modifier.td_hog.name=肥猪 modifier.td_hog.desc=我的护甲吃掉了我的作业…… modifier.td_sounder.name=肥猪 modifier.td_trotters.name=猪蹄 -/Knightslime +#Knightslime modifier.td_shifting.name=移位 modifier.td_shifting.desc=它喜欢自己行动。 modifier.td_gumshoe2.name=口香糖鞋 II diff --git a/projects/1.12.2/pack.mcmeta b/projects/1.12.2/pack.mcmeta index 311c7c618a1e..ec41c11f1d23 100644 --- a/projects/1.12.2/pack.mcmeta +++ b/projects/1.12.2/pack.mcmeta @@ -1,6 +1,6 @@ -{ - "pack": { +{{ + "pack": {{ "pack_format": 3, - "description": "汉化万用包,仅限1.12.2" - } -} + "description": "汉化万用包,仅限1.12.2/n打包时间:{0:yyyy-MM-ddTHH:mm:ssZ}" + }} +}} diff --git a/projects/1.16-fabric/assets/cloth-config/cloth-config2/packer-policy.json b/projects/1.16-fabric/assets/cloth-config/cloth-config2/packer-policy.json index 34b2ca268dbc..fea12dde5c74 100644 --- a/projects/1.16-fabric/assets/cloth-config/cloth-config2/packer-policy.json +++ b/projects/1.16-fabric/assets/cloth-config/cloth-config2/packer-policy.json @@ -1 +1,6 @@ -{"type":"plainclone","source":"./projects/1.16/assets/cloth-config/cloth-config2"} +[ + { + "type": "indirect", + "source": "./projects/1.16/assets/cloth-config/cloth-config2" + } +] \ No newline at end of file diff --git a/projects/1.16-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json b/projects/1.16-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json index 2c9196ef57d8..d81675a62bcc 100644 --- a/projects/1.16-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json +++ b/projects/1.16-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json @@ -1,4 +1,6 @@ -{ - "type": "plainclone", - "source": "./projects/1.16/assets/iron-furnaces/ironfurnaces" -} \ No newline at end of file +[ + { + "type": "indirect", + "source": "./projects/1.16/assets/iron-furnaces/ironfurnaces" + } +] \ No newline at end of file diff --git a/projects/1.16-fabric/assets/minecraft/minecraft/packer-policy.json b/projects/1.16-fabric/assets/minecraft/minecraft/packer-policy.json index 75b22dfd6411..ca88d9799a3c 100644 --- a/projects/1.16-fabric/assets/minecraft/minecraft/packer-policy.json +++ b/projects/1.16-fabric/assets/minecraft/minecraft/packer-policy.json @@ -1,4 +1,6 @@ -{ - "type": "plainclone", +[ + { + "type": "indirect", "source": "./projects/1.16/assets/minecraft/minecraft" -} \ No newline at end of file + } +] \ No newline at end of file diff --git a/projects/1.16-fabric/pack.mcmeta b/projects/1.16-fabric/pack.mcmeta index 0a695a8a1c65..81488da86f03 100644 --- a/projects/1.16-fabric/pack.mcmeta +++ b/projects/1.16-fabric/pack.mcmeta @@ -1,6 +1,6 @@ -{ - "pack": { +{{ + "pack": {{ "pack_format": 6, - "description": "汉化万用包,仅供1.16Fabric使用(目前版本1.16.5)" - } -} \ No newline at end of file + "description": "汉化万用包,仅供1.16Fabric使用(目前版本1.16.5)/n打包时间:{0:yyyy-MM-ddTHH:mm:ssZ}" + }} +}} \ No newline at end of file diff --git a/projects/1.16/assets/alexs-mobs/alexsmobs/local-config.json b/projects/1.16/assets/alexs-mobs/alexsmobs/local-config.json new file mode 100644 index 000000000000..d21a6af44a1c --- /dev/null +++ b/projects/1.16/assets/alexs-mobs/alexsmobs/local-config.json @@ -0,0 +1,10 @@ +{ + "inclusionDomains": [], + "exclusionDomains": [], + "exclusionPaths": [], + "inclusionPaths": [ + "lang/en_us.json" + ], + "characterReplacement": {}, + "destinationReplacement": {} +} \ No newline at end of file diff --git a/projects/1.16/assets/corail-recycler/corail_recycler/packer-policy.json b/projects/1.16/assets/corail-recycler/corail_recycler/packer-policy.json index 3c186f16b573..cc120ff0d580 100644 --- a/projects/1.16/assets/corail-recycler/corail_recycler/packer-policy.json +++ b/projects/1.16/assets/corail-recycler/corail_recycler/packer-policy.json @@ -1 +1,6 @@ -{"type":"plainclone","source":"./projects/1.18/assets/corail-recycler/corail_recycler"} +[ + { + "type": "indirect", + "source": "./projects/1.18/assets/corail-recycler/corail_recycler" + } +] \ No newline at end of file diff --git a/projects/1.16/assets/crafting-tweaks/craftingtweaks/packer-policy.json b/projects/1.16/assets/crafting-tweaks/craftingtweaks/packer-policy.json index 4569f083c88f..86c8bed1dd41 100644 --- a/projects/1.16/assets/crafting-tweaks/craftingtweaks/packer-policy.json +++ b/projects/1.16/assets/crafting-tweaks/craftingtweaks/packer-policy.json @@ -1 +1,10 @@ -{"type":"backport","source":"./projects/1.19/assets/crafting-tweaks/craftingtweaks"} +[ + { + "type": "direct" + }, + { + "type": "indirect", + "source": "./projects/1.19/assets/crafting-tweaks/craftingtweaks", + "overrides": true + } +] \ No newline at end of file diff --git a/projects/1.16/assets/laser-mod/lasermod/lang/zh_cn.json b/projects/1.16/assets/laser-mod/lasermod/lang/zh_cn.json index 5fc5d317aeb6..bd89d85c75d7 100644 --- a/projects/1.16/assets/laser-mod/lasermod/lang/zh_cn.json +++ b/projects/1.16/assets/laser-mod/lasermod/lang/zh_cn.json @@ -45,7 +45,7 @@ "container.lasermod.laser.button.options": "选项", "container.lasermod.laser.red": "红(R)", "container.lasermod.laser.green": "绿(G)", - "container.lasermod.laser.blue": "蓝(B)" + "container.lasermod.laser.blue": "蓝(B)" , "death.block.laser": "%s被激光烧毁了", diff --git a/projects/1.16/assets/tool-kit/toolkit/packer-policy.json b/projects/1.16/assets/tool-kit/toolkit/packer-policy.json index 5397cfe7f514..91e6926ddcdf 100644 --- a/projects/1.16/assets/tool-kit/toolkit/packer-policy.json +++ b/projects/1.16/assets/tool-kit/toolkit/packer-policy.json @@ -1 +1,6 @@ -{"type":"plainclone","source":"./projects/1.18/assets/tool-kit/toolkit"} +[ + { + "type": "indirect", + "source": "./projects/1.18/assets/tool-kit/toolkit" + } +] \ No newline at end of file diff --git a/projects/1.16/pack.mcmeta b/projects/1.16/pack.mcmeta index e64ec481812a..61658bebd3d2 100644 --- a/projects/1.16/pack.mcmeta +++ b/projects/1.16/pack.mcmeta @@ -1,6 +1,6 @@ -{ - "pack": { +{{ + "pack": {{ "pack_format": 6, - "description": "汉化万用包,仅供1.16Forge使用(目前版本1.16.5)" - } -} \ No newline at end of file + "description": "汉化万用包,仅供1.16Forge使用(目前版本1.16.5)/n打包时间:{0:yyyy-MM-ddTHH:mm:ssZ}" + }} +}} \ No newline at end of file diff --git a/projects/1.18-fabric/assets/cloth-config/cloth-config2/packer-policy.json b/projects/1.18-fabric/assets/cloth-config/cloth-config2/packer-policy.json index 0b78380bd704..f117285a0270 100644 --- a/projects/1.18-fabric/assets/cloth-config/cloth-config2/packer-policy.json +++ b/projects/1.18-fabric/assets/cloth-config/cloth-config2/packer-policy.json @@ -1 +1,6 @@ -{"type":"plainclone","source":"./projects/1.18/assets/cloth-config/cloth-config2"} +[ + { + "type": "indirect", + "source": "./projects/1.18/assets/cloth-config/cloth-config2" + } +] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/copper-equipment/exlinecopperequipment/packer-policy.json b/projects/1.18-fabric/assets/copper-equipment/exlinecopperequipment/packer-policy.json index 7ed58570b1b3..4394bfad29a3 100644 --- a/projects/1.18-fabric/assets/copper-equipment/exlinecopperequipment/packer-policy.json +++ b/projects/1.18-fabric/assets/copper-equipment/exlinecopperequipment/packer-policy.json @@ -1 +1,6 @@ -{"type":"plainclone","source":"./projects/1.18/assets/copper-equipment/exlinecopperequipment"} +[ + { + "type": "indirect", + "source": "./projects/1.18/assets/copper-equipment/exlinecopperequipment" + } +] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/goodall/goodall/packer-policy.json b/projects/1.18-fabric/assets/goodall/goodall/packer-policy.json index 602c22da5d7e..3a8ca12c508d 100644 --- a/projects/1.18-fabric/assets/goodall/goodall/packer-policy.json +++ b/projects/1.18-fabric/assets/goodall/goodall/packer-policy.json @@ -1 +1,4 @@ -{"type":"plainclone","source":"./projects/1.18/assets/goodall/goodall"} +[{ + "type": "indirect", + "source": "./projects/1.18/assets/goodall/goodall" +}] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json b/projects/1.18-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json index 29d95fbd0aae..8ee1a3a68b3a 100644 --- a/projects/1.18-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json +++ b/projects/1.18-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json @@ -1,4 +1,6 @@ -{ - "type": "plainclone", - "source": "./projects/1.18/assets/iron-furnaces/ironfurnaces" -} \ No newline at end of file +[ + { + "type": "indirect", + "source": "./projects/1.18/assets/iron-furnaces/ironfurnaces" + } +] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/jei/jei/packer-policy.json b/projects/1.18-fabric/assets/jei/jei/packer-policy.json index 1e668dc475c8..1279d7723e5f 100644 --- a/projects/1.18-fabric/assets/jei/jei/packer-policy.json +++ b/projects/1.18-fabric/assets/jei/jei/packer-policy.json @@ -1,4 +1,6 @@ -{ - "type": "plainclone", - "source": "./projects/1.19/assets/jei/jei" -} \ No newline at end of file +[ + { + "type": "indirect", + "source": "./projects/1.19/assets/jei/jei" + } +] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/minecraft/minecraft/packer-policy.json b/projects/1.18-fabric/assets/minecraft/minecraft/packer-policy.json index 85deacc1c0bc..a1ea3f19be38 100644 --- a/projects/1.18-fabric/assets/minecraft/minecraft/packer-policy.json +++ b/projects/1.18-fabric/assets/minecraft/minecraft/packer-policy.json @@ -1,4 +1,6 @@ -{ - "type": "plainclone", - "source": "./projects/1.18/assets/minecraft/minecraft" -} \ No newline at end of file +[ + { + "type": "indirect", + "source": "./projects/1.18/assets/minecraft/minecraft" + } +] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/opulence/opulence/packer-policy.json b/projects/1.18-fabric/assets/opulence/opulence/packer-policy.json index f2703e04267e..92158592d167 100644 --- a/projects/1.18-fabric/assets/opulence/opulence/packer-policy.json +++ b/projects/1.18-fabric/assets/opulence/opulence/packer-policy.json @@ -1,4 +1,6 @@ -{ - "type": "plainclone", - "source": "./projects/1.18/assets/opulence/opulence" -} \ No newline at end of file +[ + { + "type": "indirect", + "source": "./projects/1.18/assets/opulence/opulence" + } +] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/rotten-creatures/rottencreatures/packer-policy.json b/projects/1.18-fabric/assets/rotten-creatures/rottencreatures/packer-policy.json index 62326ec5325d..55fbf7e28f8a 100644 --- a/projects/1.18-fabric/assets/rotten-creatures/rottencreatures/packer-policy.json +++ b/projects/1.18-fabric/assets/rotten-creatures/rottencreatures/packer-policy.json @@ -1,4 +1,4 @@ -{ - "type": "plainclone", +[{ + "type": "indirect", "source": "./projects/1.18/assets/rotten-creatures/rottencreatures" -} \ No newline at end of file +}] \ No newline at end of file diff --git a/projects/1.18-fabric/pack.mcmeta b/projects/1.18-fabric/pack.mcmeta index dc999fa90fb9..758d59f822d8 100644 --- a/projects/1.18-fabric/pack.mcmeta +++ b/projects/1.18-fabric/pack.mcmeta @@ -1,6 +1,6 @@ -{ - "pack": { - "pack_format": 8, - "description": "汉化万用包,仅供1.18Fabric使用" - } -} \ No newline at end of file +{{ + "pack": {{ + "pack_format": 8, + "description": "汉化万用包,仅供1.18Fabric使用/n打包时间:{0:yyyy-MM-ddTHH:mm:ssZ}" + }} +}} \ No newline at end of file diff --git a/projects/1.18/assets/crafting-tweaks/craftingtweaks/packer-policy.json b/projects/1.18/assets/crafting-tweaks/craftingtweaks/packer-policy.json index 4569f083c88f..86c8bed1dd41 100644 --- a/projects/1.18/assets/crafting-tweaks/craftingtweaks/packer-policy.json +++ b/projects/1.18/assets/crafting-tweaks/craftingtweaks/packer-policy.json @@ -1 +1,10 @@ -{"type":"backport","source":"./projects/1.19/assets/crafting-tweaks/craftingtweaks"} +[ + { + "type": "direct" + }, + { + "type": "indirect", + "source": "./projects/1.19/assets/crafting-tweaks/craftingtweaks", + "overrides": true + } +] \ No newline at end of file diff --git a/projects/1.18/assets/jei/jei/packer-policy.json b/projects/1.18/assets/jei/jei/packer-policy.json index 1e668dc475c8..1279d7723e5f 100644 --- a/projects/1.18/assets/jei/jei/packer-policy.json +++ b/projects/1.18/assets/jei/jei/packer-policy.json @@ -1,4 +1,6 @@ -{ - "type": "plainclone", - "source": "./projects/1.19/assets/jei/jei" -} \ No newline at end of file +[ + { + "type": "indirect", + "source": "./projects/1.19/assets/jei/jei" + } +] \ No newline at end of file diff --git a/projects/1.18/assets/minecraft/minecraft/packer-policy.json b/projects/1.18/assets/minecraft/minecraft/packer-policy.json index 88d41319434e..36653b700ae5 100644 --- a/projects/1.18/assets/minecraft/minecraft/packer-policy.json +++ b/projects/1.18/assets/minecraft/minecraft/packer-policy.json @@ -1,4 +1,9 @@ -{ - "type": "clonemissing", - "source": "./projects/1.16/assets/minecraft/minecraft" -} \ No newline at end of file +[ + { + "type": "direct" + }, + { + "type": "indirect", + "source": "./projects/1.16/assets/minecraft/minecraft" + } +] \ No newline at end of file diff --git a/projects/1.18/pack.mcmeta b/projects/1.18/pack.mcmeta index 732aec859891..d59e05b3e937 100644 --- a/projects/1.18/pack.mcmeta +++ b/projects/1.18/pack.mcmeta @@ -1,6 +1,6 @@ -{ - "pack": { - "pack_format": 8, - "description": "汉化万用包,仅供1.18Forge使用" - } -} \ No newline at end of file +{{ + "pack": {{ + "pack_format": 8, + "description": "汉化万用包,仅供1.18Forge使用/n打包时间:{0:yyyy-MM-ddTHH:mm:ssZ}" + }} +}} \ No newline at end of file diff --git a/projects/1.19/assets/armor-poser/armorposer/packer-policy.json b/projects/1.19/assets/armor-poser/armorposer/packer-policy.json index 29880705a989..9bd62a8b19c5 100644 --- a/projects/1.19/assets/armor-poser/armorposer/packer-policy.json +++ b/projects/1.19/assets/armor-poser/armorposer/packer-policy.json @@ -1,4 +1,6 @@ -{ - "type": "plainclone", - "source": "./projects/1.18/assets/armor-poser/armorposer" -} \ No newline at end of file +[ + { + "type": "indirect", + "source": "./projects/1.18/assets/armor-poser/armorposer" + } +] \ No newline at end of file diff --git a/projects/1.19/assets/hourglass/hourglass/packer-policy.json b/projects/1.19/assets/hourglass/hourglass/packer-policy.json index ef13d58a6b5f..76baceff7578 100644 --- a/projects/1.19/assets/hourglass/hourglass/packer-policy.json +++ b/projects/1.19/assets/hourglass/hourglass/packer-policy.json @@ -1,4 +1,6 @@ -{ - "type": "plainclone", - "source": "./projects/1.18/assets/hourglass/hourglass" -} \ No newline at end of file +[ + { + "type": "indirect", + "source": "./projects/1.18/assets/hourglass/hourglass" + } +] \ No newline at end of file diff --git a/projects/1.19/assets/minecraft/minecraft/packer-policy.json b/projects/1.19/assets/minecraft/minecraft/packer-policy.json index 88d41319434e..36653b700ae5 100644 --- a/projects/1.19/assets/minecraft/minecraft/packer-policy.json +++ b/projects/1.19/assets/minecraft/minecraft/packer-policy.json @@ -1,4 +1,9 @@ -{ - "type": "clonemissing", - "source": "./projects/1.16/assets/minecraft/minecraft" -} \ No newline at end of file +[ + { + "type": "direct" + }, + { + "type": "indirect", + "source": "./projects/1.16/assets/minecraft/minecraft" + } +] \ No newline at end of file diff --git a/projects/1.19/assets/shield-expansion/shieldexp/packer-policy.json b/projects/1.19/assets/shield-expansion/shieldexp/packer-policy.json index 85161b17e85f..eab3d9593b71 100644 --- a/projects/1.19/assets/shield-expansion/shieldexp/packer-policy.json +++ b/projects/1.19/assets/shield-expansion/shieldexp/packer-policy.json @@ -1,4 +1,6 @@ -{ - "type": "plainclone", - "source": "./projects/1.18/assets/shield-expansion/shieldexp" -} \ No newline at end of file +[ + { + "type": "indirect", + "source": "./projects/1.18/assets/shield-expansion/shieldexp" + } +] \ No newline at end of file diff --git a/projects/1.19/pack.mcmeta b/projects/1.19/pack.mcmeta index d31a3c5da190..6694effb280d 100644 --- a/projects/1.19/pack.mcmeta +++ b/projects/1.19/pack.mcmeta @@ -1,6 +1,6 @@ -{ - "pack": { +{{ + "pack": {{ "pack_format": 13, - "description": "汉化万用包,仅供1.19.4使用" - } -} \ No newline at end of file + "description": "汉化万用包,仅供1.19.4使用/n打包时间:{0:yyyy-MM-ddTHH:mm:ssZ}" + }} +}} \ No newline at end of file diff --git a/src/Packer/Models/Providers/TermMappingProvider.cs b/src/Packer/Models/Providers/TermMappingProvider.cs index 13ebf32577dc..755d25620d52 100644 --- a/src/Packer/Models/Providers/TermMappingProvider.cs +++ b/src/Packer/Models/Providers/TermMappingProvider.cs @@ -4,18 +4,18 @@ using System.Collections.Generic; using System.IO; using System.IO.Compression; -using System.Text.Encodings.Web; +using System.Linq; using System.Text; +using System.Text.Encodings.Web; using System.Text.Json; +using System.Text.Json.Nodes; using System.Text.RegularExpressions; using System.Threading.Tasks; -using System.Text.Json.Nodes; -using System.Linq; namespace Packer.Models.Providers { - using LangMappingProvider = TermMappingProvider; using JsonMappingProvider = TermMappingProvider; + using LangMappingProvider = TermMappingProvider; #region termDictionary /// @@ -126,7 +126,7 @@ public class TermMappingProvider : IResourceFileProvider /// 语言文件所表示的映射表 /// public ITermDictionary Map { get; } - + /// public string Destination { get; } @@ -212,62 +212,80 @@ public static LangMappingProvider CreateFromFile(FileInfo file, string destinati using var stream = file.OpenRead(); using var reader = new StreamReader(stream, Encoding.UTF8); var content = reader.ReadToEnd(); - return new (new LangDictionaryWrapper(DeserializeFromLang(content)), destination); + return new(new LangDictionaryWrapper(DeserializeFromLang(content)), destination); } - // RAW - // TODO:仔细检查一遍 - // TODO:PARSE-ESCAPE internal static Dictionary DeserializeFromLang(string content) { - // 甚至不是自动机...所以不敢多用,否则会炸 - - // 下面的 Verbose 仅供调试,不会在 log 里出现 - // .lang的格式真的乱... - Log.Verbose("开始反序列化 .lang 文件"); - // #PARSE_ESCAPE就算了吧 var result = new Dictionary(); var isInComment = false; // 处理多行注释 - new List(content.Split(Environment.NewLine, - StringSplitOptions.RemoveEmptyEntries)) - .ForEach(line => + var isParseEscape = false; + var isLineContinuation = false; + var pendingKey = ""; + var pendingValue = ""; + + foreach (var line in content.AsSpan().EnumerateLines()) + { + if (isLineContinuation) // 行尾转义符,用于换行 { - var isSingleLineComment = false; - new List { "//", "#" } - .ForEach(_ => { isSingleLineComment |= line.StartsWith(_); }); - if (isSingleLineComment) + if (line.EndsWith("\\")) { - Log.Verbose("跳过了单行注释:{0}", line); + pendingValue += line[..^1].ToString(); } - else if (isInComment) // 多行注释内 + else { - Log.Verbose("{0}", line); - if (line.Trim() - .EndsWith("*/")) - { - isInComment = false; // 跳出注释 - } - } - else if (line.StartsWith("/*")) // 开始多行注释 - { - Log.Verbose("跳过了多行注释:{0}", line); - } - else // 真正的条目 - { - Log.Verbose("添加对应映射:{0}", line); - var spiltPosition = line.IndexOf('='); - try - { - result.Add(line[..spiltPosition], line[(spiltPosition + 1)..]); - } - catch (Exception e) - { - Log.Warning(e.ToString()); - } + pendingValue += ("\\n" + line.ToString()); + result.TryAdd(pendingKey, pendingValue); + isLineContinuation = false; } + continue; + } + + if (!isParseEscape && line.Equals("#PARSE_ESCAPES", StringComparison.Ordinal)) + { + isParseEscape = true; + continue; + } + + if (isInComment) + { // 多行注释内 + if (line.Trim() + .EndsWith("*/")) + isInComment = false; // 跳出注释 + continue; + } + + if (line.StartsWith("//") | line.StartsWith("#") | line.StartsWith("<")) + continue; + + if (line.StartsWith("/*")) + { // 开始多行注释 + isInComment = true; + continue; } - ); - Log.Verbose("反序列化完成"); + + if (line.IsEmpty || line.IsWhiteSpace()) // 空行需去 + continue; + + // 基础条目 + var splitPosition = line.IndexOf('='); + + var key = line[..splitPosition]; + var value = splitPosition + 1 < line.Length + ? line[(splitPosition + 1)..] + : ""; + if (isParseEscape && value.EndsWith("\\")) + { + isLineContinuation = true; + pendingKey = key.ToString(); + pendingValue = value[..^1].ToString(); + } + else + { + result.TryAdd(key.ToString(), value.ToString()); + } + } + return result; } } @@ -285,7 +303,12 @@ public static partial class JsonMappingHelper public static JsonMappingProvider CreateFromFile(FileInfo file, string destination) { using var stream = file.OpenRead(); - return new(new JsonDictionaryWrapper(JsonNode.Parse(stream)!.AsObject()!), destination); + return new( + new JsonDictionaryWrapper( + JsonSerializer.Deserialize>( + stream, + new JsonSerializerOptions { ReadCommentHandling = JsonCommentHandling.Skip })!), + destination); } } #endregion From 987ffdba3c98a9d5ed2f613dfb6275d67240fecb Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Mon, 2 Oct 2023 11:35:50 +0800 Subject: [PATCH 10/22] Post-work support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 支持部分文件打包 (把测试的那一堆commit合进来了) --- .github/workflows/packer.yml | 29 ++- .github/workflows/pr-packer.yml | 39 ++-- .gitignore | 4 + src/Packer/Extensions/DirectoryExtension.cs | 7 +- .../{Utils.cs => Helpers/ConfigHelpers.cs} | 168 +++++++++--------- src/Packer/Helpers/GitHelpers.cs | 41 +++++ src/Packer/Packer.csproj | 2 +- src/Packer/Program.cs | 14 +- 8 files changed, 190 insertions(+), 114 deletions(-) rename src/Packer/{Utils.cs => Helpers/ConfigHelpers.cs} (93%) create mode 100644 src/Packer/Helpers/GitHelpers.cs diff --git a/.github/workflows/packer.yml b/.github/workflows/packer.yml index 3befb16abed5..78e7bccbb36c 100644 --- a/.github/workflows/packer.yml +++ b/.github/workflows/packer.yml @@ -17,7 +17,10 @@ jobs: name: Build / Cache Packer runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + sparse-checkout: src # 缓存程序。一方面,在不同job之间需要这么做;另一方面,大约可以改善运行时间? # actions/cache的逻辑会在job末尾缓存打包程序;如果不命中,就自行构造程序。 @@ -25,13 +28,15 @@ jobs: id: cache-packer uses: actions/cache@v3 with: - key: ${{ runner.os }}-${{ hashFiles('src/Pakcer/**') }} - path: Packer.exe + key: ${{ runner.os }}-Packer-${{ hashFiles('src/Packer/**') }} + path: | + Packer.exe + git2-*.dll lookup-only: true # 构造程序 - name: Build Packer if not cached - if: steps.cache-packer.outputs.cache_hit != 'true' + if: steps.cache-packer.outputs.cache-hit != 'true' run: dotnet publish .\src\Packer\Packer.csproj -o ./ -r win-x64 -p:PublishSingleFile=true build-uploader: @@ -39,7 +44,10 @@ jobs: name: Build / Cache Uploader runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + sparse-checkout: src # 缓存程序。一方面,在不同job之间需要这么做;另一方面,大约可以改善运行时间? # actions/cache的逻辑会在job末尾缓存打包程序;如果不命中,就自行构造程序。 @@ -47,13 +55,13 @@ jobs: id: cache-uploader uses: actions/cache@v3 with: - key: ${{ runner.os }}-${{ hashFiles('src/Uploader/**') }} + key: ${{ runner.os }}-Uploader-${{ hashFiles('src/Uploader/**') }} path: Uploader.exe lookup-only: true # 构造程序 - name: Build Uploader if not cached - if: steps.cache-uploader.outputs.cache_hit != 'true' + if: steps.cache-uploader.outputs.cache-hit != 'true' run: dotnet publish .\src\Uploader\Uploader.csproj -o ./ -r win-x64 -p:PublishSingeFile=true initialize-release: @@ -102,8 +110,10 @@ jobs: id: cache-restore uses: actions/cache/restore@v3 with: - key: ${{ runner.os }}-${{ hashFiles('source/Pakcer/**') }} - path: Packer.exe + key: ${{ runner.os }}-${{ hashFiles('source/Packer/**') }} + path: | + Packer.exe + git2-*.dll fail-on-cache-miss: true # 前一步理应构造过的。如果不命中,肯定有问题,不如直接挂掉。 - name: Check changed path on ${{ matrix.version }} @@ -117,6 +127,7 @@ jobs: src/** - name: Run Packer for ${{ matrix.version }} + # 分发包中应当包含全部内容 run: ./Packer --version="${{ matrix.version }}" # 运行逻辑:内容有更改 或 手动运行 if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' diff --git a/.github/workflows/pr-packer.yml b/.github/workflows/pr-packer.yml index ae2dbde072d6..47713231591d 100644 --- a/.github/workflows/pr-packer.yml +++ b/.github/workflows/pr-packer.yml @@ -17,7 +17,11 @@ jobs: name: Build / Cache Packer runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + sparse-checkout: src + # 缓存程序。一方面,在不同job之间需要这么做;另一方面,大约可以改善运行时间? # actions/cache的逻辑会在job末尾缓存打包程序;如果不命中,就自行构造程序。 @@ -25,13 +29,15 @@ jobs: id: cache-packer uses: actions/cache@v3 with: - key: ${{ runner.os }}-${{ hashFiles('src/Pakcer/**') }} - path: Packer.exe + key: ${{ runner.os }}-Packer-${{ hashFiles('src/Packer/**') }} + path: | + Packer.exe + git2-*.dll lookup-only: true # 构造程序 - name: Build Packer if not cached - if: steps.cache-packer.outputs.cache_hit != 'true' + if: steps.cache-packer.outputs.cache-hit != 'true' run: dotnet publish .\src\Packer\Packer.csproj -o ./ -r win-x64 -p:PublishSingleFile=true @@ -48,15 +54,18 @@ jobs: steps: - uses: actions/checkout@v2 with: - fetch-depth: 20 # 显然,需要有提交历史才能比较提交。20这个数是任意的。 + fetch-depth: 2 + - run: git fetch --depth=1 origin main # 由于Github的限制,这里需要重新拉取打包程序。 - name: Restore Packer id: cache-restore uses: actions/cache/restore@v3 with: - key: ${{ runner.os }}-${{ hashFiles('src/Pakcer/**') }} - path: Packer.exe + key: ${{ runner.os }}-${{ hashFiles('src/Packer/**') }} + path: | + Packer.exe + git2-*.dll fail-on-cache-miss: true # 前一步理应构造过的。如果不命中,肯定有问题,不如直接挂掉。 - name: Check changed path on ${{ matrix.version }} @@ -65,16 +74,26 @@ jobs: with: # 判断位置:该版本文件、该版本配置、代码 paths: > - projects/${{ matrix.version }} + projects/${{ matrix.version }}/** + config/packer/${{ matrix.version }}.json + src/** + + - name: Check critical path on ${{ matrix.version }} + uses: MarceloPrado/has-changed-path@v1.0 + id: check-critical-changes + with: + # 判断位置:该版本配置、代码 + paths: > config/packer/${{ matrix.version }}.json src/** - name: Run Packer for ${{ matrix.version }} - run: ./Packer --version="${{ matrix.version }}" + # 部分包原则:Packer和配置均没有改动 + run: ./Packer --version="${{ matrix.version }}" --increment=${{ !steps.check-critical-changes.outputs.changed }} # 运行逻辑:内容有更改 或 手动运行 if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch' - # 额 要两分半才能传完 然而 GitHub actions 直接传的话 会压成 zip 内套 zip 就这样了吧 --cy + # 额 要两分半才能传完 然而 GitHub actions 直接传的话 会压成 zip 内套 zip 就这样了吧 --cy - name: Unzip Files run: unzip -q Minecraft-Mod-Language-Package-${{ matrix.version }}.zip -d Minecraft-Mod-Language-Package-${{ matrix.version }} || echo 0 shell: bash diff --git a/.gitignore b/.gitignore index 3d152dd748ea..8b53ce563096 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,10 @@ coreclr.dll mscordaccore.dll /src/Packer/Properties/launchSettings.json +# libgit2sharp + +git2-*.dll + # artifact temporary files artifacts/ diff --git a/src/Packer/Extensions/DirectoryExtension.cs b/src/Packer/Extensions/DirectoryExtension.cs index 0fcabea233ce..822a7875f1df 100644 --- a/src/Packer/Extensions/DirectoryExtension.cs +++ b/src/Packer/Extensions/DirectoryExtension.cs @@ -1,4 +1,5 @@ -using Packer.Models; +using Packer.Helpers; +using Packer.Models; using Packer.Models.Providers; using Serilog; using System; @@ -60,7 +61,7 @@ select providerGroup.Aggregate( /// 遍历未经合并的文件,用于递归调用 /// internal static EvaluatorReturnType EnumerateRawProviders(this DirectoryInfo namespaceDirectory, Config config) - => from policy in Utils.RetrieveStrategy(namespaceDirectory) + => from policy in ConfigHelpers.RetrieveStrategy(namespaceDirectory) from enumeratedPair in functionTable[policy.Type].Invoke( namespaceDirectory, config, policy.Parameters) select enumeratedPair; @@ -70,7 +71,7 @@ internal static EvaluatorReturnType FromCurrentDirectory(DirectoryInfo namespace Config config, ParameterType? parameters) { - var floatingConfig = Utils.RetrieveLocalConfig(namespaceDirectory); + var floatingConfig = ConfigHelpers.RetrieveLocalConfig(namespaceDirectory); var localConfig = config.Modify(floatingConfig); return from candidate in namespaceDirectory.EnumerateFiles("*", SearchOption.AllDirectories) diff --git a/src/Packer/Utils.cs b/src/Packer/Helpers/ConfigHelpers.cs similarity index 93% rename from src/Packer/Utils.cs rename to src/Packer/Helpers/ConfigHelpers.cs index 38beb8a4cd3a..173513314bf4 100644 --- a/src/Packer/Utils.cs +++ b/src/Packer/Helpers/ConfigHelpers.cs @@ -1,85 +1,83 @@ -using Packer.Models; -using Serilog; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.Encodings.Web; -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Threading.Tasks; - - -namespace Packer -{ - /// - /// 杂项工具类 - /// - public static class Utils - { - /// - /// 从给定的命名空间获取局域配置 - /// - /// 命名空间目录 - /// 若文件存在,返回;否则,返回 - public static FloatingConfig? RetrieveLocalConfig(DirectoryInfo directory) - { - var configFile = directory.GetFiles("local-config.json").FirstOrDefault(); - - if (configFile is null) return null; - - using var reader = configFile.OpenText(); - return JsonSerializer.Deserialize( - reader.ReadToEnd(), - new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); - } - - /// - /// 从仓库根目录获取全局配置 - /// - /// 配置路径模板 - /// 打包版本,用于定位全局配置 - public static async Task RetrieveConfig(string configTemplate, string version) - { - Log.Information("正在获取配置。目标版本:{0}", version); - - var configPath = string.Format(configTemplate, version); - - Log.Information("配置位置:{0}", configPath); - - var content = await File.ReadAllBytesAsync(configPath); - return JsonSerializer.Deserialize( - content, - new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase })!; - } - - /// - /// 从给定的命名空间获取策略内容 - /// - /// 命名空间目录 - /// 若文件存在,返回对应的内容;否则,返回Direct - /// 策略文件非法 - public static List RetrieveStrategy(DirectoryInfo directory) - { - var file = directory.GetFiles("packer-policy.json").FirstOrDefault(); - - if (file is null) - return new List - { - new PackerPolicy { Type = PackerPolicyType.Direct } - }; - - using var reader = file.OpenText(); - var result = JsonSerializer.Deserialize>( - reader.ReadToEnd(), - new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) } - }); - if (result is null) - throw new InvalidDataException($"The policy file {file.FullName} cannot have null values."); - return result; - } - } -} +using Packer.Models; +using Serilog; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + + +namespace Packer.Helpers +{ + /// + /// 配置相关的工具类 + /// + public static class ConfigHelpers + { + /// + /// 从给定的命名空间获取局域配置 + /// + /// 命名空间目录 + /// 若文件存在,返回;否则,返回 + public static FloatingConfig? RetrieveLocalConfig(DirectoryInfo directory) + { + var configFile = directory.GetFiles("local-config.json").FirstOrDefault(); + + if (configFile is null) return null; + + using var reader = configFile.OpenText(); + return JsonSerializer.Deserialize( + reader.ReadToEnd(), + new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + } + + /// + /// 从仓库根目录获取全局配置 + /// + /// 配置路径模板 + /// 打包版本,用于定位全局配置 + public static async Task RetrieveConfig(string configTemplate, string version) + { + Log.Information("正在获取配置。目标版本:{0}", version); + + var configPath = string.Format(configTemplate, version); + + Log.Information("配置位置:{0}", configPath); + + var content = await File.ReadAllBytesAsync(configPath); + return JsonSerializer.Deserialize( + content, + new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase })!; + } + + /// + /// 从给定的命名空间获取策略内容 + /// + /// 命名空间目录 + /// 若文件存在,返回对应的内容;否则,返回Direct + /// 策略文件非法 + public static List RetrieveStrategy(DirectoryInfo directory) + { + var file = directory.GetFiles("packer-policy.json").FirstOrDefault(); + + if (file is null) + return new List + { + new PackerPolicy { Type = PackerPolicyType.Direct } + }; + + using var reader = file.OpenText(); + var result = JsonSerializer.Deserialize>( + reader.ReadToEnd(), + new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) } + }); + if (result is null) + throw new InvalidDataException($"The policy file {file.FullName} cannot have null values."); + return result; + } + } +} diff --git a/src/Packer/Helpers/GitHelpers.cs b/src/Packer/Helpers/GitHelpers.cs new file mode 100644 index 000000000000..5651dbb2d03c --- /dev/null +++ b/src/Packer/Helpers/GitHelpers.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using LibGit2Sharp; +using Serilog; + +namespace Packer.Helpers +{ + /// + /// Git操作相关的工具类 + /// + public static class GitHelpers + { + /// + /// 枚举相对与主分支main,给定版本下有更改的模组。 + /// + public static IEnumerable EnumerateChangedMods(string version) + { + Log.Information("对版本 {0} 加载更改模组", version); + using var repo = new Repository("."); + var headTree = repo.Head.Tip.Tree; + var baseTree = repo.Branches["origin/main"].Tip.Tree; + var changedFiles = repo.Diff.Compare(baseTree, headTree); + var query = from change in changedFiles + from path in new List { change.Path, change.OldPath } + where path.IsInTargetVersion(version) + select path.ExtractModIdentifier(version); + var result = query.Distinct(); + Log.Information("更改模组列表:{0}", result); + return result; + } + + internal static bool IsInTargetVersion(this string location, string version) + => location.StartsWith($"projects/{version}/assets"); + + internal static string ExtractModIdentifier(this string location, string version) + => Path.GetRelativePath($"projects/{version}/assets", location) + .Split(Path.DirectorySeparatorChar)[0]; + + } +} diff --git a/src/Packer/Packer.csproj b/src/Packer/Packer.csproj index 3e7ae5065b02..718ec94626ad 100644 --- a/src/Packer/Packer.csproj +++ b/src/Packer/Packer.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Packer/Program.cs b/src/Packer/Program.cs index 1f819dd467ff..e135e8646f5e 100644 --- a/src/Packer/Program.cs +++ b/src/Packer/Program.cs @@ -1,8 +1,10 @@ using Packer.Extensions; +using Packer.Helpers; using Packer.Models; using Packer.Models.Providers; using Serilog; using System; +using System.Collections; using System.IO; using System.IO.Compression; using System.Linq; @@ -13,7 +15,7 @@ namespace Packer class Program { // System.CommandLine.DragonFruit支持 - public static async Task Main(string version, string[]? targets) + public static async Task Main(string version, bool increment = false) { Log.Logger = new LoggerConfiguration() .Enrich.FromLogContext() @@ -21,18 +23,18 @@ public static async Task Main(string version, string[]? targets) .MinimumLevel.Information() // 以便 debug 时修改这一等级 .CreateLogger(); - var targetModIdentifiers = targets?.ToList(); - - var config = await Utils.RetrieveConfig(configTemplate: "./config/packer/{0}.json", + var config = await ConfigHelpers.RetrieveConfig(configTemplate: "./config/packer/{0}.json", version: version); Log.Information("开始对版本 {0} 的打包", config.Base.Version); + var targetModIdentifiers = increment ? GitHelpers.EnumerateChangedMods(config.Base.Version) + : Enumerable.Empty(); + var query = // 这就是查询表达式吗( from modDirectory in new DirectoryInfo($"./projects/{config.Base.Version}/assets") .EnumerateDirectories() let modIdentifier = modDirectory.Name - where targetModIdentifiers is null - || targetModIdentifiers.Count() == 0 // 未提供列表,全部打包 + where targetModIdentifiers.Count() == 0 // 未提供列表,全部打包 || targetModIdentifiers.Contains(modIdentifier) // 有列表,仅打包列表中的项 where !config.Base.ExclusionMods.Contains(modIdentifier) // 没有被明确排除 from namespaceDirectory in modDirectory.EnumerateDirectories() From a38267087a8999f66fd82218d429100b7e03dffe Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sun, 22 Oct 2023 11:34:41 +0800 Subject: [PATCH 11/22] Modify behaviors on merging files --- Packer-Doc.md | 55 +- .../craftingtweaks/packer-policy.json | 2 +- .../craftingtweaks/packer-policy.json | 2 +- .../mcwfurnitures/lang/zh_cn-base.json | 7 + .../mcwfurnitures/lang/zh_cn-composition.json | 53 ++ .../mcwfurnitures/lang/zh_cn.json | 493 ------------------ .../mcwfurnitures/local-config.json | 10 + .../mcwfurnitures/packer-policy.json | 12 + src/Packer/Extensions/ContentExtension.cs | 3 +- src/Packer/Extensions/DirectoryExtension.cs | 53 +- src/Packer/Helpers/ConfigHelpers.cs | 2 +- src/Packer/Helpers/GitHelpers.cs | 8 +- src/Packer/Models/Config.cs | 2 +- src/Packer/Models/IResourceFileProvider.cs | 35 +- src/Packer/Models/PackerPolicy.cs | 6 +- .../Models/Providers/CompositionHelper.cs | 2 +- .../Models/Providers/TermMappingProvider.cs | 38 +- src/Packer/Models/Providers/TextFile.cs | 22 +- src/Packer/Program.cs | 4 +- 19 files changed, 238 insertions(+), 571 deletions(-) create mode 100644 projects/1.18/assets/macaws-furniture/mcwfurnitures/lang/zh_cn-base.json create mode 100644 projects/1.18/assets/macaws-furniture/mcwfurnitures/lang/zh_cn-composition.json delete mode 100644 projects/1.18/assets/macaws-furniture/mcwfurnitures/lang/zh_cn.json create mode 100644 projects/1.18/assets/macaws-furniture/mcwfurnitures/local-config.json create mode 100644 projects/1.18/assets/macaws-furniture/mcwfurnitures/packer-policy.json diff --git a/Packer-Doc.md b/Packer-Doc.md index 0f1e18b78d0e..1092b4fee0ea 100644 --- a/Packer-Doc.md +++ b/Packer-Doc.md @@ -2,11 +2,15 @@ ## 注意事项 - 文件地址中,目录分隔符**一律使用正斜杠**! -- 下述说明中,**完整地址**永远指从**仓库根目录**算起的地址,例如根目录下的`CONTRIBUTING.md`即为`CONTRIBUTING.md`,1.12版本资源包的`pack.png`即为`projects/1.12.2/pack.png`。 -- 下述说明中,**相对地址**永远指从**特定命名空间的文件夹**算起的地址,例如仓库中的`projects/1.18/assets/minecraft/minecraft/font/default.json`即为`font/default.json`。 -- 下述说明中,**目标地址**永远指分发的资源包中,该文件应当被放置的位置,例如上一条中提及的文件就是`assets/minecraft/font/default.json`。 -- 本次打包器更新以后,对于**非文本文件**无需特殊处理;打包器会将所有*未知的*拓展名按照非文本文件处理,无需特殊配置。 - - 目前而言,打包器会将`lang/`下的`.lang`和`.json`作为语言文件,其余的`.txt`, `.md`, `.json`作为普通文本文件,其余文件都作为非文本文件。
如果出现其他格式,可以后续添加——尽管这一部分没有添加显式的配置项。 +- 地址相关 + - 下述说明中,**完整地址**永远指从**仓库根目录**算起的地址,例如对根目录下的`CONTRIBUTING.md`应为`CONTRIBUTING.md`,1.12版本资源包的`pack.png`应为`projects/1.12.2/pack.png`。 + - 下述说明中,**相对地址**永远指从**特定命名空间的文件夹**算起的地址,例如对仓库中的`projects/1.18/assets/minecraft/minecraft/font/default.json`应为`font/default.json`。 + - 下述说明中,**目标地址**永远指**分发的资源包中**,该文件应当被放置的位置,例如上一条中提及的文件应为`assets/minecraft/font/default.json`。 +- 文件相关 + - 下述说明中,**语言文件**永远指可以被打包器解读为**映射表**的文件。这包括了所有 **`lang/`下的`.lang`和`.json`文件**。 + - 下述说明中,**文本文件**永远指含有**文本内容**,但**不属于语言文件**的文件。这包括了非语言文件的`.txt`、`.md`、`.json`文件。 + - 下述说明中,**非文本文件**永远指**不属于以上两类**的文件,如图片或其他二进制文件。 +- 本次打包器更新以后,对于**非文本文件**无需特殊处理:打包器会按照文件拓展名自动识别文件类型。 @@ -18,6 +22,8 @@ ### 文件格式 +目前而言,所有配置文件都需要填写全部项——无关项可以填写空集合,但不能不填,更不能写null。有计划在将来优化这一行为。 + **全局**配置文件`./config/packer/.json`的格式如下: - 根标签 object @@ -40,10 +46,10 @@ - string
强制包含的文件的**相对地址**。 - `characterReplacement` object
打包时采用的字符替换表。用于将部分字符替换至特殊位点,也可单纯用于简化输入。目前而言,包含了字体修复的有关内容。 - `<查询语句>` string
用以替换**正则表达式**`<查询语句>`匹配对象的内容,可以是一个或多个字符,甚至可以在这里用**正则替换语句**。
主要用于*字体修复包*所需的**符号替换**,此时,查询语句通常是字面量,替换内容一般而言总是以四位*Unicode转义码*填写;对于**基础多语种平面(BMP)**以外的字符,最好用**UTF-16代理对**书写。 - - `destinationReplacement` object
打包时采用的目标地址替换。
可以用于移动文件,但暂时闲置。 + - `destinationReplacement` object
打包时采用的目标地址替换。
可以用于移动文件,但暂时闲置;使用**检索策略**中的`singleton`也可以实现地址替换,但需要在每个模组下配置。 - `<查询语句>` string
用以替换**正则表达式**`<查询语句>`匹配对象的内容,可以是一个或多个字符,甚至可以在这里用**正则替换语句**。 -**局域**配置文件`./projects//assets///local-config.json`的格式与全局配置文件中,`floating`标签下的内容(*浮动配置*)一致。 +**局域**配置文件`./projects//assets///local-config.json`的格式与全局配置文件中,`floating`标签下的内容(*可变配置*)一致。 ### 文件容斥顺序 @@ -59,20 +65,21 @@ - 如果在某个命名空间内检测到存在`local-config.json`,打包器将会在全局配置的基础上,在其*可变配置*中**添加**该文件中的内容,并用这一修改后的配置执行**该命名空间下的**检索工作。 - 最好不要与全局配置中的内容重复。尽管理论上这样子可以运行,但是重复项保留哪一个或许不容易断定。 -- 需要注意的是,如果通过*检索策略***引用其他命名空间**,打包器**只**会加载目标命名空间的局域配置,而**不会**加载原空间的局域配置;不过,在原位进行的检索工作不受影响。 +- 需要注意的是,如果通过*检索策略*来**引用其他命名空间**,打包器**只**会加载目标命名空间的局域配置,而**不会**加载原空间的局域配置;不过,在原位进行的检索工作不受影响。 ## 检索策略 -对于每个**命名空间文件夹**(注意这个概念和**命名空间**有着细微差别),打包器除了可以原位检索文件以外,还可以**使用不同的检索方式**。目前,可用的检索方式有两种: -1. **引用**给定的命名空间。 -2. 从给定的**组合**文件,直接生成语言文件(或部分)。 +对于每个**命名空间文件夹**,打包器除了可以原位检索文件以外,还可以**使用不同的检索方式**。目前,可用的检索方式有四种: +1. **原位**检索文件。 +2. **引用**给定的命名空间。 +3. 从给定的**组合**文件,直接生成语言文件(或部分)。 +4. 引用**单个**文件。 -计划中,将对*非语言文件的文本文件*添加一个**修改包**策略,但是这个策略暂时还没实现,部分原因是在上一版打包器中,这个策略还没被用过。 +> 计划中,将对*非语言文件的文本文件*添加一个**修改包**策略,但是这个策略暂时还没实现,部分原因是在上一版打包器中,这个策略还没被用过。 -单独看起来,这或许没什么用(Packer的上一版中,功能还要多些);但有一点很重要: -这些加载策略(包括**原位**加载)是可以**串联**、**递归**的!于是,通过这三种策略,应该可以满足许多需求。 +单独看起来,这或许没什么用(Packer的上一版中,功能还要多些);但有一点很重要:这些加载策略是可以**串联**、**递归**的!于是,通过这些策略,应该可以满足许多需求。 -- **串联**:在一个策略文件中,可以放置**多条策略**。策略将会从前往后执行,**前者**优先——和*Minecraft资源包*顺序差不多。不过,如果有需要,在策略文件中也预留了一个字段,用来**覆盖**前序文件。 +- **串联**:在一个策略文件中,可以放置**多条策略**。策略将会从前往后执行,**前者**优先——和*Minecraft资源包*顺序差不多。不过,在文件冲突时,也提供了一些特殊的冲突解决选项。 - **递归**:如果**引用**了其他命名空间文件夹,那里的策略文件**也会生效**。这意味着可以实现*连续引用*——尽管前提是不出现**循环引用**。 部分案例被放在了`./projects/packer-example/`这一虚拟的“版本”下。很明显,我们**并不会**分发这一版本,但如果有条件,可以在本地构造打包器,并用这一版本做试验。 @@ -82,34 +89,40 @@ #### packer-policy.json 对于每个**命名空间文件夹**,策略文件为`./projects//assets///packer-policy.json`。 -若找不到该策略,默认策略文件内容为`[{"type": "direct"}]`。 +若找不到该文件,默认策略内容为`[{"type": "direct"}]`,也就是**原位**加载,没有特殊配置。 - 根标签 list
打包器需要执行的策略,**从前往后执行**。如果有冲突内容,默认以**前者**优先——当然这是可以配置的。 - object
单项策略。部分参数可变。 - - `overrides` bool
是否可以用本步的文件覆盖前序文件。如果无此项,默认为`false`。
关于这里的“覆盖”,对于**非语言文件**(不在`lang\`下),指的是**全文**覆盖;对于**语言文件**,则是**按条目**覆盖。 - `type` string
策略的类型。可为以下选项之一: - `direct` 默认选项。不进行特殊处理,直接按照此处的文件结构打包。 - `indirect` 引用给定的命名空间。对于这些文件,其*目标地址*中的*命名空间*将会自动替换为本策略所在的命名空间。 - `source` string
引用命名空间所在文件夹的**完整地址**。 - `composition`
从给定的*组合文件*,直接生成语言文件(或部分)。
这些组合文件可能不会被自动排除;可以考虑使用*局域配置*处理。 - - `source` string
引用组合文件的**完整位置**。 + - `source` string
引用组合文件的**完整地址**。 - `destType` string
需要生成的语言文件的类型。可以为`json`或`lang`。 + - `singleton`
引用给定的单个文件。
理论上该操作可以选取任何位置的文件,只要目标位置填写正确;不过,一般建议放在*合理的位置*。 + - `source` string
引用文件所在的**完整地址**。 + - `relativePath`
文件需要被放置的**相对地址**。考虑到连续引用,这里不宜使用**目标地址**。 + - **通用参数** + - `modifyOnly` bool
默认为`false`。
对于**语言文件**,若本项为`true`,对于已有的键,若在该步中提供了新的值,则将会用新值替换旧值;**不会**包含本步中新出现的键。
对于其他文件,本项无效。 + - `append` bool
默认为`false`。
对于**文本文件**,将会在已有的文本内容之后**换行**,然后连接本步的内容。
对于其他文件,本项无效。 #### [组合文件].json - 根标签 object - `target` string
生成的语言文件的**目标地址**。 - * `entries` list
需要生成的组合项。这些项将会分别执行组合以后,连接起来。
**如果存在键冲突,打包器会在此崩溃!**有计划在后期更改这一行为。 + * `entries` list
需要生成的组合项。这些项将会分别执行组合以后,连接起来。
**如果存在键冲突,打包器会在此崩溃!**有计划在后期更改这一行为;目前而言,可以使用多个组合文件绕过这个限制。 * object
单项策略。 - * `templates` object
组合所用的模板。所有内容采用**C#格式化模式**填写。
粗略地说,其中的格式符有形式`{0}, {1}, {2},...`;完整的定义可见 *.net文档*。 + * `templates` object
组合所用的模板。所有内容采用**C#格式化模式**填写。
粗略地说,其中的格式符有形式`{0}, {1}, {2},...`,字面量花括号需要用`{{`和`}}`转义;完整的定义可见 *[.net文档/Composite Formatting](https://learn.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting)*。 - `<键模板>` string
`<键模板>`对应的值模板。 - * `parameters` list
组合所用的参数表。参数按照模板中的**索引**顺序排列。不支持嵌套,必须字面量。 + * `parameters` list
组合所用的参数表。参数按照模板中的**索引**顺序排列。不支持嵌套,必须用字面量。 * object
每个索引位置上可用的参数。 - `<键参数>` string
`<键参数>`对应的值参数。 ### 组合文件 组合文件用来生成“组合型”的**语言文件/语言文件片段**,也就是那些有大量重复文本、有明显的格式的语言文件片段。 + 组合文件的工作原理如下: 1. 获取`entries`中的全部条目,每个条目代表一种组合模式。 2. 每个条目中,由`templates`中的所有条目充当模板,`parameters`中的所有条目充当参数,生成若干组合后的条目。 diff --git a/projects/1.16/assets/crafting-tweaks/craftingtweaks/packer-policy.json b/projects/1.16/assets/crafting-tweaks/craftingtweaks/packer-policy.json index 86c8bed1dd41..85f92e2f4564 100644 --- a/projects/1.16/assets/crafting-tweaks/craftingtweaks/packer-policy.json +++ b/projects/1.16/assets/crafting-tweaks/craftingtweaks/packer-policy.json @@ -5,6 +5,6 @@ { "type": "indirect", "source": "./projects/1.19/assets/crafting-tweaks/craftingtweaks", - "overrides": true + "modifyOnly": true } ] \ No newline at end of file diff --git a/projects/1.18/assets/crafting-tweaks/craftingtweaks/packer-policy.json b/projects/1.18/assets/crafting-tweaks/craftingtweaks/packer-policy.json index 86c8bed1dd41..85f92e2f4564 100644 --- a/projects/1.18/assets/crafting-tweaks/craftingtweaks/packer-policy.json +++ b/projects/1.18/assets/crafting-tweaks/craftingtweaks/packer-policy.json @@ -5,6 +5,6 @@ { "type": "indirect", "source": "./projects/1.19/assets/crafting-tweaks/craftingtweaks", - "overrides": true + "modifyOnly": true } ] \ No newline at end of file diff --git a/projects/1.18/assets/macaws-furniture/mcwfurnitures/lang/zh_cn-base.json b/projects/1.18/assets/macaws-furniture/mcwfurnitures/lang/zh_cn-base.json new file mode 100644 index 000000000000..87e0e008c36d --- /dev/null +++ b/projects/1.18/assets/macaws-furniture/mcwfurnitures/lang/zh_cn-base.json @@ -0,0 +1,7 @@ +{ + "itemGroup.furnitures": "Macaw的家具", + "mcwfurnitures.container.threerows": "家具", + "item.mcwfurnitures.cabinet_door": "橱柜门", + "item.mcwfurnitures.cabinet_drawer": "橱柜抽屉", + "mcwfurnitures.furnitureitem.desc": "合成原料" +} \ No newline at end of file diff --git a/projects/1.18/assets/macaws-furniture/mcwfurnitures/lang/zh_cn-composition.json b/projects/1.18/assets/macaws-furniture/mcwfurnitures/lang/zh_cn-composition.json new file mode 100644 index 000000000000..9974971609e3 --- /dev/null +++ b/projects/1.18/assets/macaws-furniture/mcwfurnitures/lang/zh_cn-composition.json @@ -0,0 +1,53 @@ +{ + "target": "assets/mcwfurnitures/lang/zh_cn.json", + "entries": [ + { + "templates": { + "block.mcwfurnitures.{0}{1}_wardrobe": "{0}{1}衣柜", + "block.mcwfurnitures.{0}{1}_modern_wardrobe": "{0}{1}现代风格衣柜", + "block.mcwfurnitures.{0}{1}_double_wardrobe": "{0}{1}双门衣柜", + "block.mcwfurnitures.{0}{1}_bookshelf": "{0}{1}书架", + "block.mcwfurnitures.{0}{1}_bookshelf_cupboard": "{0}{1}带橱柜书架", + "block.mcwfurnitures.{0}{1}_drawer": "{0}{1}抽屉", + "block.mcwfurnitures.{0}{1}_double_drawer": "{0}{1}双层抽屉", + "block.mcwfurnitures.{0}{1}_bookshelf_drawer": "{0}{1}带书架抽屉", + "block.mcwfurnitures.{0}{1}_lower_bookshelf_drawer": "{0}{1}带下层书架抽屉", + "block.mcwfurnitures.{0}{1}_large_drawer": "{0}{1}大型抽屉柜", + "block.mcwfurnitures.{0}{1}_lower_triple_drawer": "{0}{1}倒品字抽屉", + "block.mcwfurnitures.{0}{1}_triple_drawer": "{0}{1}品字抽屉", + "block.mcwfurnitures.{0}{1}_desk": "{0}{1}书桌", + "block.mcwfurnitures.{0}{1}_covered_desk": "{0}{1}带挡板书桌", + "block.mcwfurnitures.{0}{1}_modern_desk": "{0}{1}现代风格书桌", + "block.mcwfurnitures.{0}{1}_table": "{0}{1}桌", + "block.mcwfurnitures.{0}{1}_end_table": "{0}{1}搁板桌", + "block.mcwfurnitures.{0}{1}_coffee_table": "{0}{1}高脚桌", + "block.mcwfurnitures.{0}{1}_glass_table": "{0}{1}玻璃桌", + "block.mcwfurnitures.{0}{1}_chair": "{0}{1}椅子", + "block.mcwfurnitures.{0}{1}_modern_chair": "{0}{1}现代风格椅子", + "block.mcwfurnitures.{0}{1}_striped_chair": "{0}{1}竖纹靠背椅", + "block.mcwfurnitures.{0}{1}_stool_chair": "{0}{1}凳子", + "block.mcwfurnitures.{0}{1}_counter": "{0}{1}台桌", + "block.mcwfurnitures.{0}{1}_drawer_counter": "{0}{1}抽屉台桌", + "block.mcwfurnitures.{0}{1}_double_drawer_counter": "{0}{1}双层抽屉台桌", + "block.mcwfurnitures.{0}{1}_cupboard_counter": "{0}{1}橱柜台桌" + }, + "parameters": [ + { + "": "", + "stripped_": "去皮" + }, + { + "oak": "橡木", + "birch": "白桦木", + "spruce": "云杉木", + "jungle": "丛林木", + "acacia": "金合欢木", + "dark_oak": "深色橡木", + "crimson": "绯红木", + "warped": "诡异木", + "mangrove": "红树木" + } + ] + } + ] +} \ No newline at end of file diff --git a/projects/1.18/assets/macaws-furniture/mcwfurnitures/lang/zh_cn.json b/projects/1.18/assets/macaws-furniture/mcwfurnitures/lang/zh_cn.json deleted file mode 100644 index ff984b9e464d..000000000000 --- a/projects/1.18/assets/macaws-furniture/mcwfurnitures/lang/zh_cn.json +++ /dev/null @@ -1,493 +0,0 @@ -{ - "itemGroup.furnitures": "Macaw的家具", - "mcwfurnitures.container.threerows": "家具", - "item.mcwfurnitures.cabinet_door": "橱柜门", - "item.mcwfurnitures.cabinet_drawer": "橱柜抽屉", - "mcwfurnitures.furnitureitem.desc": "合成原料", - "block.mcwfurnitures.oak_wardrobe": "橡木衣柜", - "block.mcwfurnitures.oak_modern_wardrobe": "橡木现代风格衣柜", - "block.mcwfurnitures.oak_double_wardrobe": "橡木双门衣柜", - "block.mcwfurnitures.oak_bookshelf": "橡木书架", - "block.mcwfurnitures.oak_bookshelf_cupboard": "橡木带橱柜书架", - "block.mcwfurnitures.oak_drawer": "橡木抽屉", - "block.mcwfurnitures.oak_double_drawer": "橡木双层抽屉", - "block.mcwfurnitures.oak_bookshelf_drawer": "橡木带书架抽屉", - "block.mcwfurnitures.oak_lower_bookshelf_drawer": "橡木带下层书架抽屉", - "block.mcwfurnitures.oak_large_drawer": "橡木大型抽屉柜", - "block.mcwfurnitures.oak_lower_triple_drawer": "橡木倒品字抽屉", - "block.mcwfurnitures.oak_triple_drawer": "橡木品字抽屉", - "block.mcwfurnitures.oak_desk": "橡木书桌", - "block.mcwfurnitures.oak_covered_desk": "橡木带挡板书桌", - "block.mcwfurnitures.oak_modern_desk": "橡木现代风格书桌", - "block.mcwfurnitures.oak_table": "橡木桌", - "block.mcwfurnitures.oak_end_table": "橡木搁板桌", - "block.mcwfurnitures.oak_coffee_table": "橡木高脚桌", - "block.mcwfurnitures.oak_glass_table": "橡木玻璃桌", - "block.mcwfurnitures.oak_chair": "橡木椅子", - "block.mcwfurnitures.oak_modern_chair": "橡木现代风格椅子", - "block.mcwfurnitures.oak_striped_chair": "橡木竖纹靠背椅", - "block.mcwfurnitures.oak_stool_chair": "橡木凳子", - "block.mcwfurnitures.oak_counter": "橡木台桌", - "block.mcwfurnitures.oak_drawer_counter": "橡木抽屉台桌", - "block.mcwfurnitures.oak_double_drawer_counter": "橡木双层抽屉台桌", - "block.mcwfurnitures.oak_cupboard_counter": "橡木橱柜台桌", - "block.mcwfurnitures.birch_wardrobe": "白桦木衣柜", - "block.mcwfurnitures.birch_modern_wardrobe": "白桦木现代风格衣柜", - "block.mcwfurnitures.birch_double_wardrobe": "白桦木双门衣柜", - "block.mcwfurnitures.birch_bookshelf": "白桦木书架", - "block.mcwfurnitures.birch_bookshelf_cupboard": "白桦木带橱柜书架", - "block.mcwfurnitures.birch_drawer": "白桦木抽屉", - "block.mcwfurnitures.birch_double_drawer": "白桦木双层抽屉", - "block.mcwfurnitures.birch_bookshelf_drawer": "白桦木带书架抽屉", - "block.mcwfurnitures.birch_lower_bookshelf_drawer": "白桦木带下层书架抽屉", - "block.mcwfurnitures.birch_large_drawer": "白桦木大型抽屉柜", - "block.mcwfurnitures.birch_lower_triple_drawer": "白桦木倒品字抽屉", - "block.mcwfurnitures.birch_triple_drawer": "白桦木品字抽屉", - "block.mcwfurnitures.birch_desk": "白桦木书桌", - "block.mcwfurnitures.birch_covered_desk": "白桦木带挡板书桌", - "block.mcwfurnitures.birch_modern_desk": "白桦木现代风格书桌", - "block.mcwfurnitures.birch_table": "白桦木桌", - "block.mcwfurnitures.birch_end_table": "白桦木搁板桌", - "block.mcwfurnitures.birch_coffee_table": "白桦木高脚桌", - "block.mcwfurnitures.birch_glass_table": "白桦木玻璃桌", - "block.mcwfurnitures.birch_chair": "白桦木椅子", - "block.mcwfurnitures.birch_modern_chair": "白桦木现代风格椅子", - "block.mcwfurnitures.birch_striped_chair": "白桦木竖纹靠背椅", - "block.mcwfurnitures.birch_stool_chair": "白桦木凳子", - "block.mcwfurnitures.birch_counter": "白桦木台桌", - "block.mcwfurnitures.birch_drawer_counter": "白桦木抽屉台桌", - "block.mcwfurnitures.birch_double_drawer_counter": "白桦木双层抽屉台桌", - "block.mcwfurnitures.birch_cupboard_counter": "白桦木橱柜台桌", - "block.mcwfurnitures.spruce_wardrobe": "云杉木衣柜", - "block.mcwfurnitures.spruce_modern_wardrobe": "云杉木现代风格衣柜", - "block.mcwfurnitures.spruce_double_wardrobe": "云杉木双门衣柜", - "block.mcwfurnitures.spruce_bookshelf": "云杉木书架", - "block.mcwfurnitures.spruce_bookshelf_cupboard": "云杉木带橱柜书架", - "block.mcwfurnitures.spruce_drawer": "云杉木抽屉", - "block.mcwfurnitures.spruce_double_drawer": "云杉木双层抽屉", - "block.mcwfurnitures.spruce_bookshelf_drawer": "云杉木带书架抽屉", - "block.mcwfurnitures.spruce_lower_bookshelf_drawer": "云杉木带下层书架抽屉", - "block.mcwfurnitures.spruce_large_drawer": "云杉木大型抽屉柜", - "block.mcwfurnitures.spruce_lower_triple_drawer": "云杉木倒品字抽屉", - "block.mcwfurnitures.spruce_triple_drawer": "云杉木品字抽屉", - "block.mcwfurnitures.spruce_desk": "云杉木书桌", - "block.mcwfurnitures.spruce_covered_desk": "云杉木带挡板书桌", - "block.mcwfurnitures.spruce_modern_desk": "云杉木现代风格书桌", - "block.mcwfurnitures.spruce_table": "云杉木桌", - "block.mcwfurnitures.spruce_end_table": "云杉木搁板桌", - "block.mcwfurnitures.spruce_coffee_table": "云杉木高脚桌", - "block.mcwfurnitures.spruce_glass_table": "云杉木玻璃桌", - "block.mcwfurnitures.spruce_chair": "云杉木椅子", - "block.mcwfurnitures.spruce_modern_chair": "云杉木现代风格椅子", - "block.mcwfurnitures.spruce_striped_chair": "云杉木竖纹靠背椅", - "block.mcwfurnitures.spruce_stool_chair": "云杉木凳子", - "block.mcwfurnitures.spruce_counter": "云杉木台桌", - "block.mcwfurnitures.spruce_drawer_counter": "云杉木抽屉台桌", - "block.mcwfurnitures.spruce_double_drawer_counter": "云杉木双层抽屉台桌", - "block.mcwfurnitures.spruce_cupboard_counter": "云杉木橱柜台桌", - "block.mcwfurnitures.jungle_wardrobe": "丛林木衣柜", - "block.mcwfurnitures.jungle_modern_wardrobe": "丛林木现代风格衣柜", - "block.mcwfurnitures.jungle_double_wardrobe": "丛林木双门衣柜", - "block.mcwfurnitures.jungle_bookshelf": "丛林木书架", - "block.mcwfurnitures.jungle_bookshelf_cupboard": "丛林木带橱柜书架", - "block.mcwfurnitures.jungle_drawer": "丛林木抽屉", - "block.mcwfurnitures.jungle_double_drawer": "丛林木双层抽屉", - "block.mcwfurnitures.jungle_bookshelf_drawer": "丛林木带书架抽屉", - "block.mcwfurnitures.jungle_lower_bookshelf_drawer": "丛林木带下层书架抽屉", - "block.mcwfurnitures.jungle_large_drawer": "丛林木大型抽屉柜", - "block.mcwfurnitures.jungle_lower_triple_drawer": "丛林木倒品字抽屉", - "block.mcwfurnitures.jungle_triple_drawer": "丛林木品字抽屉", - "block.mcwfurnitures.jungle_desk": "丛林木书桌", - "block.mcwfurnitures.jungle_covered_desk": "丛林木带挡板书桌", - "block.mcwfurnitures.jungle_modern_desk": "丛林木现代风格书桌", - "block.mcwfurnitures.jungle_table": "丛林木桌", - "block.mcwfurnitures.jungle_end_table": "丛林木搁板桌", - "block.mcwfurnitures.jungle_coffee_table": "丛林木高脚桌", - "block.mcwfurnitures.jungle_glass_table": "丛林木玻璃桌", - "block.mcwfurnitures.jungle_chair": "丛林木椅子", - "block.mcwfurnitures.jungle_modern_chair": "丛林木现代风格椅子", - "block.mcwfurnitures.jungle_striped_chair": "丛林木竖纹靠背椅", - "block.mcwfurnitures.jungle_stool_chair": "丛林木凳子", - "block.mcwfurnitures.jungle_counter": "丛林木台桌", - "block.mcwfurnitures.jungle_drawer_counter": "丛林木抽屉台桌", - "block.mcwfurnitures.jungle_double_drawer_counter": "丛林木双层抽屉台桌", - "block.mcwfurnitures.jungle_cupboard_counter": "丛林木橱柜台桌", - "block.mcwfurnitures.acacia_wardrobe": "金合欢木衣柜", - "block.mcwfurnitures.acacia_modern_wardrobe": "金合欢木现代风格衣柜", - "block.mcwfurnitures.acacia_double_wardrobe": "金合欢木双门衣柜", - "block.mcwfurnitures.acacia_bookshelf": "金合欢木书架", - "block.mcwfurnitures.acacia_bookshelf_cupboard": "金合欢木带橱柜书架", - "block.mcwfurnitures.acacia_drawer": "金合欢木抽屉", - "block.mcwfurnitures.acacia_double_drawer": "金合欢木双层抽屉", - "block.mcwfurnitures.acacia_bookshelf_drawer": "金合欢木带书架抽屉", - "block.mcwfurnitures.acacia_lower_bookshelf_drawer": "金合欢木带下层书架抽屉", - "block.mcwfurnitures.acacia_large_drawer": "金合欢木大型抽屉柜", - "block.mcwfurnitures.acacia_lower_triple_drawer": "金合欢木倒品字抽屉", - "block.mcwfurnitures.acacia_triple_drawer": "金合欢木品字抽屉", - "block.mcwfurnitures.acacia_desk": "金合欢木书桌", - "block.mcwfurnitures.acacia_covered_desk": "金合欢木带挡板书桌", - "block.mcwfurnitures.acacia_modern_desk": "金合欢木现代风格书桌", - "block.mcwfurnitures.acacia_table": "金合欢木桌", - "block.mcwfurnitures.acacia_end_table": "金合欢木搁板桌", - "block.mcwfurnitures.acacia_coffee_table": "金合欢木高脚桌", - "block.mcwfurnitures.acacia_glass_table": "金合欢木玻璃桌", - "block.mcwfurnitures.acacia_chair": "金合欢木椅子", - "block.mcwfurnitures.acacia_modern_chair": "金合欢木现代风格椅子", - "block.mcwfurnitures.acacia_striped_chair": "金合欢木竖纹靠背椅", - "block.mcwfurnitures.acacia_stool_chair": "金合欢木凳子", - "block.mcwfurnitures.acacia_counter": "金合欢木台桌", - "block.mcwfurnitures.acacia_drawer_counter": "金合欢木抽屉台桌", - "block.mcwfurnitures.acacia_double_drawer_counter": "金合欢木双层抽屉台桌", - "block.mcwfurnitures.acacia_cupboard_counter": "金合欢木橱柜台桌", - "block.mcwfurnitures.dark_oak_wardrobe": "深色橡木衣柜", - "block.mcwfurnitures.dark_oak_modern_wardrobe": "深色橡木现代风格衣柜", - "block.mcwfurnitures.dark_oak_double_wardrobe": "深色橡木双门衣柜", - "block.mcwfurnitures.dark_oak_bookshelf": "深色橡木书架", - "block.mcwfurnitures.dark_oak_bookshelf_cupboard": "深色橡木带橱柜书架", - "block.mcwfurnitures.dark_oak_drawer": "深色橡木抽屉", - "block.mcwfurnitures.dark_oak_double_drawer": "深色橡木双层抽屉", - "block.mcwfurnitures.dark_oak_bookshelf_drawer": "深色橡木带书架抽屉", - "block.mcwfurnitures.dark_oak_lower_bookshelf_drawer": "深色橡木带下层书架抽屉", - "block.mcwfurnitures.dark_oak_large_drawer": "深色橡木大型抽屉柜", - "block.mcwfurnitures.dark_oak_lower_triple_drawer": "深色橡木倒品字抽屉", - "block.mcwfurnitures.dark_oak_triple_drawer": "深色橡木品字抽屉", - "block.mcwfurnitures.dark_oak_desk": "深色橡木书桌", - "block.mcwfurnitures.dark_oak_covered_desk": "深色橡木带挡板书桌", - "block.mcwfurnitures.dark_oak_modern_desk": "深色橡木现代风格书桌", - "block.mcwfurnitures.dark_oak_table": "深色橡木桌", - "block.mcwfurnitures.dark_oak_end_table": "深色橡木搁板桌", - "block.mcwfurnitures.dark_oak_coffee_table": "深色橡木高脚桌", - "block.mcwfurnitures.dark_oak_glass_table": "深色橡木玻璃桌", - "block.mcwfurnitures.dark_oak_chair": "深色橡木椅子", - "block.mcwfurnitures.dark_oak_modern_chair": "深色橡木现代风格椅子", - "block.mcwfurnitures.dark_oak_striped_chair": "深色橡木竖纹靠背椅", - "block.mcwfurnitures.dark_oak_stool_chair": "深色橡木凳子", - "block.mcwfurnitures.dark_oak_counter": "深色橡木台桌", - "block.mcwfurnitures.dark_oak_drawer_counter": "深色橡木抽屉台桌", - "block.mcwfurnitures.dark_oak_double_drawer_counter": "深色橡木双层抽屉台桌", - "block.mcwfurnitures.dark_oak_cupboard_counter": "深色橡木橱柜台桌", - "block.mcwfurnitures.crimson_wardrobe": "绯红木衣柜", - "block.mcwfurnitures.crimson_modern_wardrobe": "绯红木现代风格衣柜", - "block.mcwfurnitures.crimson_double_wardrobe": "绯红木双门衣柜", - "block.mcwfurnitures.crimson_bookshelf": "绯红木书架", - "block.mcwfurnitures.crimson_bookshelf_cupboard": "绯红木带橱柜书架", - "block.mcwfurnitures.crimson_drawer": "绯红木抽屉", - "block.mcwfurnitures.crimson_double_drawer": "绯红木双层抽屉", - "block.mcwfurnitures.crimson_bookshelf_drawer": "绯红木带书架抽屉", - "block.mcwfurnitures.crimson_lower_bookshelf_drawer": "绯红木带下层书架抽屉", - "block.mcwfurnitures.crimson_large_drawer": "绯红木大型抽屉柜", - "block.mcwfurnitures.crimson_lower_triple_drawer": "绯红木倒品字抽屉", - "block.mcwfurnitures.crimson_triple_drawer": "绯红木品字抽屉", - "block.mcwfurnitures.crimson_desk": "绯红木书桌", - "block.mcwfurnitures.crimson_covered_desk": "绯红木带挡板书桌", - "block.mcwfurnitures.crimson_modern_desk": "绯红木现代风格书桌", - "block.mcwfurnitures.crimson_table": "绯红木桌", - "block.mcwfurnitures.crimson_end_table": "绯红木搁板桌", - "block.mcwfurnitures.crimson_coffee_table": "绯红木高脚桌", - "block.mcwfurnitures.crimson_glass_table": "绯红木玻璃桌", - "block.mcwfurnitures.crimson_chair": "绯红木椅子", - "block.mcwfurnitures.crimson_modern_chair": "绯红木现代风格椅子", - "block.mcwfurnitures.crimson_striped_chair": "绯红木竖纹靠背椅", - "block.mcwfurnitures.crimson_stool_chair": "绯红木凳子", - "block.mcwfurnitures.crimson_counter": "绯红木台桌", - "block.mcwfurnitures.crimson_drawer_counter": "绯红木抽屉台桌", - "block.mcwfurnitures.crimson_double_drawer_counter": "绯红木双层抽屉台桌", - "block.mcwfurnitures.crimson_cupboard_counter": "绯红木橱柜台桌", - "block.mcwfurnitures.warped_wardrobe": "诡异木衣柜", - "block.mcwfurnitures.warped_modern_wardrobe": "诡异木现代风格衣柜", - "block.mcwfurnitures.warped_double_wardrobe": "诡异木双门衣柜", - "block.mcwfurnitures.warped_bookshelf": "诡异木书架", - "block.mcwfurnitures.warped_bookshelf_cupboard": "诡异木带橱柜书架", - "block.mcwfurnitures.warped_drawer": "诡异木抽屉", - "block.mcwfurnitures.warped_double_drawer": "诡异木双层抽屉", - "block.mcwfurnitures.warped_bookshelf_drawer": "诡异木带书架抽屉", - "block.mcwfurnitures.warped_lower_bookshelf_drawer": "诡异木带下层书架抽屉", - "block.mcwfurnitures.warped_large_drawer": "诡异木大型抽屉柜", - "block.mcwfurnitures.warped_lower_triple_drawer": "诡异木倒品字抽屉", - "block.mcwfurnitures.warped_triple_drawer": "诡异木品字抽屉", - "block.mcwfurnitures.warped_desk": "诡异木书桌", - "block.mcwfurnitures.warped_covered_desk": "诡异木带挡板书桌", - "block.mcwfurnitures.warped_modern_desk": "诡异木现代风格书桌", - "block.mcwfurnitures.warped_table": "诡异木桌", - "block.mcwfurnitures.warped_end_table": "诡异木搁板桌", - "block.mcwfurnitures.warped_coffee_table": "诡异木高脚桌", - "block.mcwfurnitures.warped_glass_table": "诡异木玻璃桌", - "block.mcwfurnitures.warped_chair": "诡异木椅子", - "block.mcwfurnitures.warped_modern_chair": "诡异木现代风格椅子", - "block.mcwfurnitures.warped_striped_chair": "诡异木竖纹靠背椅", - "block.mcwfurnitures.warped_stool_chair": "诡异木凳子", - "block.mcwfurnitures.warped_counter": "诡异木台桌", - "block.mcwfurnitures.warped_drawer_counter": "诡异木抽屉台桌", - "block.mcwfurnitures.warped_double_drawer_counter": "诡异木双层抽屉台桌", - "block.mcwfurnitures.warped_cupboard_counter": "诡异木橱柜台桌", - "block.mcwfurnitures.mangrove_wardrobe": "红树木衣柜", - "block.mcwfurnitures.mangrove_modern_wardrobe": "红树木现代风格衣柜", - "block.mcwfurnitures.mangrove_double_wardrobe": "红树木双门衣柜", - "block.mcwfurnitures.mangrove_bookshelf": "红树木书架", - "block.mcwfurnitures.mangrove_bookshelf_cupboard": "红树木带橱柜书架", - "block.mcwfurnitures.mangrove_drawer": "红树木抽屉", - "block.mcwfurnitures.mangrove_double_drawer": "红树木双层抽屉", - "block.mcwfurnitures.mangrove_bookshelf_drawer": "红树木书架抽屉", - "block.mcwfurnitures.mangrove_lower_bookshelf_drawer": "红树木带下层书架抽屉", - "block.mcwfurnitures.mangrove_large_drawer": "红树木大型抽屉", - "block.mcwfurnitures.mangrove_lower_triple_drawer": "红树木倒品字抽屉", - "block.mcwfurnitures.mangrove_triple_drawer": "红树木品字抽屉", - "block.mcwfurnitures.mangrove_desk": "红树木书桌", - "block.mcwfurnitures.mangrove_covered_desk": "红树木带挡板书桌", - "block.mcwfurnitures.mangrove_modern_desk": "红树木现代风格书桌", - "block.mcwfurnitures.mangrove_table": "红树木桌", - "block.mcwfurnitures.mangrove_end_table": "红树木搁板桌", - "block.mcwfurnitures.mangrove_coffee_table": "红树木高脚桌", - "block.mcwfurnitures.mangrove_glass_table": "红树木玻璃桌", - "block.mcwfurnitures.mangrove_chair": "红树木椅子", - "block.mcwfurnitures.mangrove_modern_chair": "红树木现代风格椅子", - "block.mcwfurnitures.mangrove_striped_chair": "红树木竖纹靠背椅", - "block.mcwfurnitures.mangrove_stool_chair": "红树木凳子", - "block.mcwfurnitures.mangrove_counter": "红树木台桌", - "block.mcwfurnitures.mangrove_drawer_counter": "红树木抽屉台桌", - "block.mcwfurnitures.mangrove_double_drawer_counter": "红树木双层抽屉台桌", - "block.mcwfurnitures.mangrove_cupboard_counter": "红树木橱柜台桌", - "block.mcwfurnitures.stripped_oak_wardrobe": "去皮橡木衣柜", - "block.mcwfurnitures.stripped_oak_modern_wardrobe": "去皮橡木现代风格衣柜", - "block.mcwfurnitures.stripped_oak_double_wardrobe": "去皮橡木双门衣柜", - "block.mcwfurnitures.stripped_oak_bookshelf": "去皮橡木书架", - "block.mcwfurnitures.stripped_oak_bookshelf_cupboard": "去皮橡木带橱柜书架", - "block.mcwfurnitures.stripped_oak_drawer": "去皮橡木抽屉", - "block.mcwfurnitures.stripped_oak_double_drawer": "去皮橡木双层抽屉", - "block.mcwfurnitures.stripped_oak_bookshelf_drawer": "去皮橡木带书架抽屉", - "block.mcwfurnitures.stripped_oak_lower_bookshelf_drawer": "去皮橡木带下层书架抽屉", - "block.mcwfurnitures.stripped_oak_large_drawer": "去皮橡木大型抽屉柜", - "block.mcwfurnitures.stripped_oak_lower_triple_drawer": "去皮橡木倒品字抽屉", - "block.mcwfurnitures.stripped_oak_triple_drawer": "去皮橡木品字抽屉", - "block.mcwfurnitures.stripped_oak_desk": "去皮橡木书桌", - "block.mcwfurnitures.stripped_oak_covered_desk": "去皮橡木带挡板书桌", - "block.mcwfurnitures.stripped_oak_modern_desk": "去皮橡木现代风格书桌", - "block.mcwfurnitures.stripped_oak_table": "去皮橡木桌", - "block.mcwfurnitures.stripped_oak_end_table": "去皮橡木搁板桌", - "block.mcwfurnitures.stripped_oak_coffee_table": "去皮橡木高脚桌", - "block.mcwfurnitures.stripped_oak_glass_table": "去皮橡木玻璃桌", - "block.mcwfurnitures.stripped_oak_chair": "去皮橡木椅子", - "block.mcwfurnitures.stripped_oak_modern_chair": "去皮橡木现代风格椅子", - "block.mcwfurnitures.stripped_oak_striped_chair": "去皮橡木竖纹靠背椅", - "block.mcwfurnitures.stripped_oak_stool_chair": "去皮橡木凳子", - "block.mcwfurnitures.stripped_oak_counter": "去皮橡木台桌", - "block.mcwfurnitures.stripped_oak_drawer_counter": "去皮橡木抽屉台桌", - "block.mcwfurnitures.stripped_oak_double_drawer_counter": "去皮橡木双层抽屉台桌", - "block.mcwfurnitures.stripped_oak_cupboard_counter": "去皮橡木橱柜台桌", - "block.mcwfurnitures.stripped_birch_wardrobe": "去皮白桦木衣柜", - "block.mcwfurnitures.stripped_birch_modern_wardrobe": "去皮白桦木现代风格衣柜", - "block.mcwfurnitures.stripped_birch_double_wardrobe": "去皮白桦木双门衣柜", - "block.mcwfurnitures.stripped_birch_bookshelf": "去皮白桦木书架", - "block.mcwfurnitures.stripped_birch_bookshelf_cupboard": "去皮白桦木带橱柜书架", - "block.mcwfurnitures.stripped_birch_drawer": "去皮白桦木抽屉", - "block.mcwfurnitures.stripped_birch_double_drawer": "去皮白桦木双层抽屉", - "block.mcwfurnitures.stripped_birch_bookshelf_drawer": "去皮白桦木带书架抽屉", - "block.mcwfurnitures.stripped_birch_lower_bookshelf_drawer": "去皮白桦木带下层书架抽屉", - "block.mcwfurnitures.stripped_birch_large_drawer": "去皮白桦木大型抽屉柜", - "block.mcwfurnitures.stripped_birch_lower_triple_drawer": "去皮白桦木倒品字抽屉", - "block.mcwfurnitures.stripped_birch_triple_drawer": "去皮白桦木品字抽屉", - "block.mcwfurnitures.stripped_birch_desk": "去皮白桦木书桌", - "block.mcwfurnitures.stripped_birch_covered_desk": "去皮白桦木带挡板书桌", - "block.mcwfurnitures.stripped_birch_modern_desk": "去皮白桦木现代风格书桌", - "block.mcwfurnitures.stripped_birch_table": "去皮白桦木桌", - "block.mcwfurnitures.stripped_birch_end_table": "去皮白桦木搁板桌", - "block.mcwfurnitures.stripped_birch_coffee_table": "去皮白桦木高脚桌", - "block.mcwfurnitures.stripped_birch_glass_table": "去皮白桦木玻璃桌", - "block.mcwfurnitures.stripped_birch_chair": "去皮白桦木椅子", - "block.mcwfurnitures.stripped_birch_modern_chair": "去皮白桦木现代风格椅子", - "block.mcwfurnitures.stripped_birch_striped_chair": "去皮白桦木竖纹靠背椅", - "block.mcwfurnitures.stripped_birch_stool_chair": "去皮白桦木凳子", - "block.mcwfurnitures.stripped_birch_counter": "去皮白桦木台桌", - "block.mcwfurnitures.stripped_birch_drawer_counter": "去皮白桦木抽屉台桌", - "block.mcwfurnitures.stripped_birch_double_drawer_counter": "去皮白桦木双层抽屉台桌", - "block.mcwfurnitures.stripped_birch_cupboard_counter": "去皮白桦木橱柜台桌", - "block.mcwfurnitures.stripped_spruce_wardrobe": "去皮云杉木衣柜", - "block.mcwfurnitures.stripped_spruce_modern_wardrobe": "去皮云杉木现代风格衣柜", - "block.mcwfurnitures.stripped_spruce_double_wardrobe": "去皮云杉木双门衣柜", - "block.mcwfurnitures.stripped_spruce_bookshelf": "去皮云杉木书架", - "block.mcwfurnitures.stripped_spruce_bookshelf_cupboard": "去皮云杉木带橱柜书架", - "block.mcwfurnitures.stripped_spruce_drawer": "去皮云杉木抽屉", - "block.mcwfurnitures.stripped_spruce_double_drawer": "去皮云杉木双层抽屉", - "block.mcwfurnitures.stripped_spruce_bookshelf_drawer": "去皮云杉木带书架抽屉", - "block.mcwfurnitures.stripped_spruce_lower_bookshelf_drawer": "去皮云杉木带下层书架抽屉", - "block.mcwfurnitures.stripped_spruce_large_drawer": "去皮云杉木大型抽屉柜", - "block.mcwfurnitures.stripped_spruce_lower_triple_drawer": "去皮云杉木倒品字抽屉", - "block.mcwfurnitures.stripped_spruce_triple_drawer": "去皮云杉木品字抽屉", - "block.mcwfurnitures.stripped_spruce_desk": "去皮云杉木书桌", - "block.mcwfurnitures.stripped_spruce_covered_desk": "去皮云杉木带挡板书桌", - "block.mcwfurnitures.stripped_spruce_modern_desk": "去皮云杉木现代风格书桌", - "block.mcwfurnitures.stripped_spruce_table": "去皮云杉木桌", - "block.mcwfurnitures.stripped_spruce_end_table": "去皮云杉木搁板桌", - "block.mcwfurnitures.stripped_spruce_coffee_table": "去皮云杉木高脚桌", - "block.mcwfurnitures.stripped_spruce_glass_table": "去皮云杉木玻璃桌", - "block.mcwfurnitures.stripped_spruce_chair": "去皮云杉木椅子", - "block.mcwfurnitures.stripped_spruce_modern_chair": "去皮云杉木现代风格椅子", - "block.mcwfurnitures.stripped_spruce_striped_chair": "去皮云杉木竖纹靠背椅", - "block.mcwfurnitures.stripped_spruce_stool_chair": "去皮云杉木凳子", - "block.mcwfurnitures.stripped_spruce_counter": "去皮云杉木台桌", - "block.mcwfurnitures.stripped_spruce_drawer_counter": "去皮云杉木抽屉台桌", - "block.mcwfurnitures.stripped_spruce_double_drawer_counter": "去皮云杉木双层抽屉台桌", - "block.mcwfurnitures.stripped_spruce_cupboard_counter": "去皮云杉木橱柜台桌", - "block.mcwfurnitures.stripped_jungle_wardrobe": "去皮丛林木衣柜", - "block.mcwfurnitures.stripped_jungle_modern_wardrobe": "去皮丛林木现代风格衣柜", - "block.mcwfurnitures.stripped_jungle_double_wardrobe": "去皮丛林木双门衣柜", - "block.mcwfurnitures.stripped_jungle_bookshelf": "去皮丛林木书架", - "block.mcwfurnitures.stripped_jungle_bookshelf_cupboard": "去皮丛林木带橱柜书架", - "block.mcwfurnitures.stripped_jungle_drawer": "去皮丛林木抽屉", - "block.mcwfurnitures.stripped_jungle_double_drawer": "去皮丛林木双层抽屉", - "block.mcwfurnitures.stripped_jungle_bookshelf_drawer": "去皮丛林木带书架抽屉", - "block.mcwfurnitures.stripped_jungle_lower_bookshelf_drawer": "去皮丛林木带下层书架抽屉", - "block.mcwfurnitures.stripped_jungle_large_drawer": "去皮丛林木大型抽屉柜", - "block.mcwfurnitures.stripped_jungle_lower_triple_drawer": "去皮丛林木倒品字抽屉", - "block.mcwfurnitures.stripped_jungle_triple_drawer": "去皮丛林木品字抽屉", - "block.mcwfurnitures.stripped_jungle_desk": "去皮丛林木书桌", - "block.mcwfurnitures.stripped_jungle_covered_desk": "去皮丛林木带挡板书桌", - "block.mcwfurnitures.stripped_jungle_modern_desk": "去皮丛林木现代风格书桌", - "block.mcwfurnitures.stripped_jungle_table": "去皮丛林木桌", - "block.mcwfurnitures.stripped_jungle_end_table": "去皮丛林木搁板桌", - "block.mcwfurnitures.stripped_jungle_coffee_table": "去皮丛林木高脚桌", - "block.mcwfurnitures.stripped_jungle_glass_table": "去皮丛林木玻璃桌", - "block.mcwfurnitures.stripped_jungle_chair": "去皮丛林木椅子", - "block.mcwfurnitures.stripped_jungle_modern_chair": "去皮丛林木现代风格椅子", - "block.mcwfurnitures.stripped_jungle_striped_chair": "去皮丛林木竖纹靠背椅", - "block.mcwfurnitures.stripped_jungle_stool_chair": "去皮丛林木凳子", - "block.mcwfurnitures.stripped_jungle_counter": "去皮丛林木台桌", - "block.mcwfurnitures.stripped_jungle_drawer_counter": "去皮丛林木抽屉台桌", - "block.mcwfurnitures.stripped_jungle_double_drawer_counter": "去皮丛林木双层抽屉台桌", - "block.mcwfurnitures.stripped_jungle_cupboard_counter": "去皮丛林木橱柜台桌", - "block.mcwfurnitures.stripped_acacia_wardrobe": "去皮金合欢木衣柜", - "block.mcwfurnitures.stripped_acacia_modern_wardrobe": "去皮金合欢木现代风格衣柜", - "block.mcwfurnitures.stripped_acacia_double_wardrobe": "去皮金合欢木双门衣柜", - "block.mcwfurnitures.stripped_acacia_bookshelf": "去皮金合欢木书架", - "block.mcwfurnitures.stripped_acacia_bookshelf_cupboard": "去皮金合欢木带橱柜书架", - "block.mcwfurnitures.stripped_acacia_drawer": "去皮金合欢木抽屉", - "block.mcwfurnitures.stripped_acacia_double_drawer": "去皮金合欢木双层抽屉", - "block.mcwfurnitures.stripped_acacia_bookshelf_drawer": "去皮金合欢木带书架抽屉", - "block.mcwfurnitures.stripped_acacia_lower_bookshelf_drawer": "去皮金合欢木带下层书架抽屉", - "block.mcwfurnitures.stripped_acacia_large_drawer": "去皮金合欢木大型抽屉柜", - "block.mcwfurnitures.stripped_acacia_lower_triple_drawer": "去皮金合欢木倒品字抽屉", - "block.mcwfurnitures.stripped_acacia_triple_drawer": "去皮金合欢木品字抽屉", - "block.mcwfurnitures.stripped_acacia_desk": "去皮金合欢木书桌", - "block.mcwfurnitures.stripped_acacia_covered_desk": "去皮金合欢木带挡板书桌", - "block.mcwfurnitures.stripped_acacia_modern_desk": "去皮金合欢木现代风格书桌", - "block.mcwfurnitures.stripped_acacia_table": "去皮金合欢木桌", - "block.mcwfurnitures.stripped_acacia_end_table": "去皮金合欢木搁板桌", - "block.mcwfurnitures.stripped_acacia_coffee_table": "去皮金合欢木高脚桌", - "block.mcwfurnitures.stripped_acacia_glass_table": "去皮金合欢木玻璃桌", - "block.mcwfurnitures.stripped_acacia_chair": "去皮金合欢木椅子", - "block.mcwfurnitures.stripped_acacia_modern_chair": "去皮金合欢木现代风格椅子", - "block.mcwfurnitures.stripped_acacia_striped_chair": "去皮金合欢木竖纹靠背椅", - "block.mcwfurnitures.stripped_acacia_stool_chair": "去皮金合欢木凳子", - "block.mcwfurnitures.stripped_acacia_counter": "去皮金合欢木台桌", - "block.mcwfurnitures.stripped_acacia_drawer_counter": "去皮金合欢木抽屉台桌", - "block.mcwfurnitures.stripped_acacia_double_drawer_counter": "去皮金合欢木双层抽屉台桌", - "block.mcwfurnitures.stripped_acacia_cupboard_counter": "去皮金合欢木橱柜台桌", - "block.mcwfurnitures.stripped_dark_oak_wardrobe": "去皮深色橡木衣柜", - "block.mcwfurnitures.stripped_dark_oak_modern_wardrobe": "去皮深色橡木现代风格衣柜", - "block.mcwfurnitures.stripped_dark_oak_double_wardrobe": "去皮深色橡木双门衣柜", - "block.mcwfurnitures.stripped_dark_oak_bookshelf": "去皮深色橡木书架", - "block.mcwfurnitures.stripped_dark_oak_bookshelf_cupboard": "去皮深色橡木带橱柜书架", - "block.mcwfurnitures.stripped_dark_oak_drawer": "去皮深色橡木抽屉", - "block.mcwfurnitures.stripped_dark_oak_double_drawer": "去皮深色橡木双层抽屉", - "block.mcwfurnitures.stripped_dark_oak_bookshelf_drawer": "去皮深色橡木带书架抽屉", - "block.mcwfurnitures.stripped_dark_oak_lower_bookshelf_drawer": "去皮深色橡木带下层书架抽屉", - "block.mcwfurnitures.stripped_dark_oak_large_drawer": "去皮深色橡木大型抽屉柜", - "block.mcwfurnitures.stripped_dark_oak_lower_triple_drawer": "去皮深色橡木倒品字抽屉", - "block.mcwfurnitures.stripped_dark_oak_triple_drawer": "去皮深色橡木品字抽屉", - "block.mcwfurnitures.stripped_dark_oak_desk": "去皮深色橡木书桌", - "block.mcwfurnitures.stripped_dark_oak_covered_desk": "去皮深色橡木带挡板书桌", - "block.mcwfurnitures.stripped_dark_oak_modern_desk": "去皮深色橡木现代风格书桌", - "block.mcwfurnitures.stripped_dark_oak_table": "去皮深色橡木桌", - "block.mcwfurnitures.stripped_dark_oak_end_table": "去皮深色橡木搁板桌", - "block.mcwfurnitures.stripped_dark_oak_coffee_table": "去皮深色橡木高脚桌", - "block.mcwfurnitures.stripped_dark_oak_glass_table": "去皮深色橡木玻璃桌", - "block.mcwfurnitures.stripped_dark_oak_chair": "去皮深色橡木椅子", - "block.mcwfurnitures.stripped_dark_oak_modern_chair": "去皮深色橡木现代风格椅子", - "block.mcwfurnitures.stripped_dark_oak_striped_chair": "去皮深色橡木竖纹靠背椅", - "block.mcwfurnitures.stripped_dark_oak_stool_chair": "去皮深色橡木凳子", - "block.mcwfurnitures.stripped_dark_oak_counter": "去皮深色橡木台桌", - "block.mcwfurnitures.stripped_dark_oak_drawer_counter": "去皮深色橡木抽屉台桌", - "block.mcwfurnitures.stripped_dark_oak_double_drawer_counter": "去皮深色橡木双层抽屉台桌", - "block.mcwfurnitures.stripped_dark_oak_cupboard_counter": "去皮深色橡木橱柜台桌", - "block.mcwfurnitures.stripped_crimson_wardrobe": "去皮绯红木衣柜", - "block.mcwfurnitures.stripped_crimson_modern_wardrobe": "去皮绯红木现代风格衣柜", - "block.mcwfurnitures.stripped_crimson_double_wardrobe": "去皮绯红木双门衣柜", - "block.mcwfurnitures.stripped_crimson_bookshelf": "去皮绯红木书架", - "block.mcwfurnitures.stripped_crimson_bookshelf_cupboard": "去皮绯红木带橱柜书架", - "block.mcwfurnitures.stripped_crimson_drawer": "去皮绯红木抽屉", - "block.mcwfurnitures.stripped_crimson_double_drawer": "去皮绯红木双层抽屉", - "block.mcwfurnitures.stripped_crimson_bookshelf_drawer": "去皮绯红木带书架抽屉", - "block.mcwfurnitures.stripped_crimson_lower_bookshelf_drawer": "去皮绯红木带下层书架抽屉", - "block.mcwfurnitures.stripped_crimson_large_drawer": "去皮绯红木大型抽屉柜", - "block.mcwfurnitures.stripped_crimson_lower_triple_drawer": "去皮绯红木倒品字抽屉", - "block.mcwfurnitures.stripped_crimson_triple_drawer": "去皮绯红木品字抽屉", - "block.mcwfurnitures.stripped_crimson_desk": "去皮绯红木书桌", - "block.mcwfurnitures.stripped_crimson_covered_desk": "去皮绯红木带挡板书桌", - "block.mcwfurnitures.stripped_crimson_modern_desk": "去皮绯红木现代风格书桌", - "block.mcwfurnitures.stripped_crimson_table": "去皮绯红木桌", - "block.mcwfurnitures.stripped_crimson_end_table": "去皮绯红木搁板桌", - "block.mcwfurnitures.stripped_crimson_coffee_table": "去皮绯红木高脚桌", - "block.mcwfurnitures.stripped_crimson_glass_table": "去皮绯红木玻璃桌", - "block.mcwfurnitures.stripped_crimson_chair": "去皮绯红木椅子", - "block.mcwfurnitures.stripped_crimson_modern_chair": "去皮绯红木现代风格椅子", - "block.mcwfurnitures.stripped_crimson_striped_chair": "去皮绯红木竖纹靠背椅", - "block.mcwfurnitures.stripped_crimson_stool_chair": "去皮绯红木凳子", - "block.mcwfurnitures.stripped_crimson_counter": "去皮绯红木台桌", - "block.mcwfurnitures.stripped_crimson_drawer_counter": "去皮绯红木抽屉台桌", - "block.mcwfurnitures.stripped_crimson_double_drawer_counter": "去皮绯红木双层抽屉台桌", - "block.mcwfurnitures.stripped_crimson_cupboard_counter": "去皮绯红木橱柜台桌", - "block.mcwfurnitures.stripped_warped_wardrobe": "去皮诡异木衣柜", - "block.mcwfurnitures.stripped_warped_modern_wardrobe": "去皮诡异木现代风格衣柜", - "block.mcwfurnitures.stripped_warped_double_wardrobe": "去皮诡异木双门衣柜", - "block.mcwfurnitures.stripped_warped_bookshelf": "去皮诡异木书架", - "block.mcwfurnitures.stripped_warped_bookshelf_cupboard": "去皮诡异木带橱柜书架", - "block.mcwfurnitures.stripped_warped_drawer": "去皮诡异木抽屉", - "block.mcwfurnitures.stripped_warped_double_drawer": "去皮诡异木双层抽屉", - "block.mcwfurnitures.stripped_warped_bookshelf_drawer": "去皮诡异木带书架抽屉", - "block.mcwfurnitures.stripped_warped_lower_bookshelf_drawer": "去皮诡异木带下层书架抽屉", - "block.mcwfurnitures.stripped_warped_large_drawer": "去皮诡异木大型抽屉柜", - "block.mcwfurnitures.stripped_warped_lower_triple_drawer": "去皮诡异木倒品字抽屉", - "block.mcwfurnitures.stripped_warped_triple_drawer": "去皮诡异木品字抽屉", - "block.mcwfurnitures.stripped_warped_desk": "去皮诡异木书桌", - "block.mcwfurnitures.stripped_warped_covered_desk": "去皮诡异木带挡板书桌", - "block.mcwfurnitures.stripped_warped_modern_desk": "去皮诡异木现代风格书桌", - "block.mcwfurnitures.stripped_warped_table": "去皮诡异木桌", - "block.mcwfurnitures.stripped_warped_end_table": "去皮诡异木搁板桌", - "block.mcwfurnitures.stripped_warped_coffee_table": "去皮诡异木高脚桌", - "block.mcwfurnitures.stripped_warped_glass_table": "去皮诡异木玻璃桌", - "block.mcwfurnitures.stripped_warped_chair": "去皮诡异木椅子", - "block.mcwfurnitures.stripped_warped_modern_chair": "去皮诡异木现代风格椅子", - "block.mcwfurnitures.stripped_warped_striped_chair": "去皮诡异木竖纹靠背椅", - "block.mcwfurnitures.stripped_warped_stool_chair": "去皮诡异木凳子", - "block.mcwfurnitures.stripped_warped_counter": "去皮诡异木台桌", - "block.mcwfurnitures.stripped_warped_drawer_counter": "去皮诡异木抽屉台桌", - "block.mcwfurnitures.stripped_warped_double_drawer_counter": "去皮诡异木双层抽屉台桌", - "block.mcwfurnitures.stripped_warped_cupboard_counter": "去皮诡异木橱柜台桌", - "block.mcwfurnitures.stripped_mangrove_wardrobe": "去皮红树木衣柜", - "block.mcwfurnitures.stripped_mangrove_modern_wardrobe": "去皮红树木现代风格衣柜", - "block.mcwfurnitures.stripped_mangrove_double_wardrobe": "去皮红树木双门衣柜", - "block.mcwfurnitures.stripped_mangrove_bookshelf": "去皮红树木书架", - "block.mcwfurnitures.stripped_mangrove_bookshelf_cupboard": "去皮红树木带橱柜书架", - "block.mcwfurnitures.stripped_mangrove_drawer": "去皮红树木抽屉", - "block.mcwfurnitures.stripped_mangrove_double_drawer": "去皮红树木双层抽屉", - "block.mcwfurnitures.stripped_mangrove_bookshelf_drawer": "去皮红树木书架抽屉", - "block.mcwfurnitures.stripped_mangrove_lower_bookshelf_drawer": "去皮红树木带下层书架抽屉", - "block.mcwfurnitures.stripped_mangrove_large_drawer": "去皮红树木大型抽屉柜", - "block.mcwfurnitures.stripped_mangrove_lower_triple_drawer": "去皮红树木倒品字抽屉", - "block.mcwfurnitures.stripped_mangrove_triple_drawer": "去皮红树木品字抽屉", - "block.mcwfurnitures.stripped_mangrove_desk": "去皮红树木书桌", - "block.mcwfurnitures.stripped_mangrove_covered_desk": "去皮红树木带挡板书桌", - "block.mcwfurnitures.stripped_mangrove_modern_desk": "去皮红树木现代风格书桌", - "block.mcwfurnitures.stripped_mangrove_table": "去皮红树木桌", - "block.mcwfurnitures.stripped_mangrove_end_table": "去皮红树木搁板桌", - "block.mcwfurnitures.stripped_mangrove_coffee_table": "去皮红树木高脚桌", - "block.mcwfurnitures.stripped_mangrove_glass_table": "去皮红树木玻璃桌", - "block.mcwfurnitures.stripped_mangrove_chair": "去皮红树木椅子", - "block.mcwfurnitures.stripped_mangrove_modern_chair": "去皮红树木现代风格椅子", - "block.mcwfurnitures.stripped_mangrove_striped_chair": "去皮红树木竖纹靠背椅", - "block.mcwfurnitures.stripped_mangrove_stool_chair": "去皮红树木凳子", - "block.mcwfurnitures.stripped_mangrove_counter": "去皮红树木台桌", - "block.mcwfurnitures.stripped_mangrove_drawer_counter": "去皮红树木抽屉台桌", - "block.mcwfurnitures.stripped_mangrove_double_drawer_counter": "去皮红树木双层抽屉台桌", - "block.mcwfurnitures.stripped_mangrove_cupboard_counter": "去皮红树木橱柜台桌" -} \ No newline at end of file diff --git a/projects/1.18/assets/macaws-furniture/mcwfurnitures/local-config.json b/projects/1.18/assets/macaws-furniture/mcwfurnitures/local-config.json new file mode 100644 index 000000000000..ced98770fc4a --- /dev/null +++ b/projects/1.18/assets/macaws-furniture/mcwfurnitures/local-config.json @@ -0,0 +1,10 @@ +{ + "inclusionDomains": [], + "exclusionDomains": [], + "exclusionPaths": [ + "lang/zh_cn.json-composition.json" + ], + "inclusionPaths": [], + "characterReplacement": {}, + "destinationReplacement": {} +} \ No newline at end of file diff --git a/projects/1.18/assets/macaws-furniture/mcwfurnitures/packer-policy.json b/projects/1.18/assets/macaws-furniture/mcwfurnitures/packer-policy.json new file mode 100644 index 000000000000..fd9da0e334c4 --- /dev/null +++ b/projects/1.18/assets/macaws-furniture/mcwfurnitures/packer-policy.json @@ -0,0 +1,12 @@ +[ + { + "type": "singleton", + "source": "projects/1.18/assets/macaws-furniture/mcwfurnitures/lang/zh_cn-base.json", + "relativePath": "lang/zh_cn.json" + }, + { + "type": "composition", + "destType": "json", + "source": "projects/1.18/assets/macaws-furniture/mcwfurnitures/lang/zh_cn-composition.json" + } +] \ No newline at end of file diff --git a/src/Packer/Extensions/ContentExtension.cs b/src/Packer/Extensions/ContentExtension.cs index 811ff75f676a..bac9be751178 100644 --- a/src/Packer/Extensions/ContentExtension.cs +++ b/src/Packer/Extensions/ContentExtension.cs @@ -1,5 +1,4 @@ -using Serilog; -using System; +using System; using System.IO; using System.Linq; using System.Security.Cryptography; diff --git a/src/Packer/Extensions/DirectoryExtension.cs b/src/Packer/Extensions/DirectoryExtension.cs index 822a7875f1df..4706e2604542 100644 --- a/src/Packer/Extensions/DirectoryExtension.cs +++ b/src/Packer/Extensions/DirectoryExtension.cs @@ -1,7 +1,6 @@ using Packer.Helpers; using Packer.Models; using Packer.Models.Providers; -using Serilog; using System; using System.Collections.Generic; using System.IO; @@ -10,7 +9,7 @@ namespace Packer.Extensions { - using EvaluatorReturnType = IEnumerable<(IResourceFileProvider provider, bool overrides)>; + using EvaluatorReturnType = IEnumerable<(IResourceFileProvider provider, ApplyOptions options)>; using ParameterType = Dictionary; @@ -34,11 +33,12 @@ public delegate EvaluatorReturnType /// /// 从到加载方法的查询表 /// - internal static Dictionary functionTable = new() + internal static Dictionary evaluatorPolicyMap = new() { { PackerPolicyType.Direct, FromCurrentDirectory }, // 现场生成 { PackerPolicyType.Indirect, FromSpecifiedDirectory }, // 给定目录 - { PackerPolicyType.Composition, FromComposition } // 组合生成 + { PackerPolicyType.Composition, FromComposition }, // 组合生成 + { PackerPolicyType.Singleton, FromSingleton }, // 单项文件 }; /// @@ -55,14 +55,14 @@ group enumeratedPair by enumeratedPair.provider.Destination into providerGroup select providerGroup.Aggregate( seed: null as IResourceFileProvider, (accumulate, next) - => next.provider.ApplyTo(accumulate, next.overrides)); + => next.provider.ApplyTo(accumulate, next.options)); /// /// 遍历未经合并的文件,用于递归调用 /// internal static EvaluatorReturnType EnumerateRawProviders(this DirectoryInfo namespaceDirectory, Config config) - => from policy in ConfigHelpers.RetrieveStrategy(namespaceDirectory) - from enumeratedPair in functionTable[policy.Type].Invoke( + => from policy in ConfigHelpers.RetrievePolicy(namespaceDirectory) + from enumeratedPair in evaluatorPolicyMap[policy.Type].Invoke( namespaceDirectory, config, policy.Parameters) select enumeratedPair; @@ -73,14 +73,13 @@ internal static EvaluatorReturnType FromCurrentDirectory(DirectoryInfo namespace { var floatingConfig = ConfigHelpers.RetrieveLocalConfig(namespaceDirectory); var localConfig = config.Modify(floatingConfig); - + return from candidate in namespaceDirectory.EnumerateFiles("*", SearchOption.AllDirectories) let relativePath = Path.GetRelativePath(namespaceDirectory.FullName, candidate.FullName) .NormalizePath() let fullPath = Path.GetRelativePath(".", candidate.FullName) - let destination = Path.Combine( - "assets", namespaceDirectory.Name, relativePath) + let destination = Path.Combine("assets", namespaceDirectory.Name, relativePath) .NormalizePath() where !relativePath.IsPathForceExcluded(localConfig) // [1] 排除路径 -- packer-policy等 where (relativePath.IsPathForceIncluded(localConfig) // [2] 包含路径 [单列] @@ -88,7 +87,7 @@ internal static EvaluatorReturnType FromCurrentDirectory(DirectoryInfo namespace || (destination.IsInTargetLanguage(localConfig) // [4] 语言标记 -- 含zh_cn的 && !relativePath.IsDomainForceExcluded(localConfig))) // [5] 排除domain [暂无] let provider = CreateProviderFromFile(candidate, destination, localConfig) - select (provider, DoesOverride(parameters)); + select (provider, GetOptions(parameters)); } internal static EvaluatorReturnType FromSpecifiedDirectory(DirectoryInfo namespaceDirectory, @@ -103,7 +102,7 @@ internal static EvaluatorReturnType FromSpecifiedDirectory(DirectoryInfo namespa let provider = candidate.provider .ReplaceDestination(@"(?<=^assets/)[^/]*(?=/)", namespaceName) - select (provider, DoesOverride(parameters)); + select (provider, GetOptions(parameters)); } internal static EvaluatorReturnType FromComposition(DirectoryInfo namespaceDirectory, @@ -119,7 +118,20 @@ internal static EvaluatorReturnType FromComposition(DirectoryInfo namespaceDirec "json" => JsonMappingHelper.CreateFromComposition(compositionFile), _ => throw new InvalidOperationException($"Unexpected Type parameter at {namespaceDirectory.FullName}.") }; - yield return (provider, DoesOverride(parameters)); + yield return (provider, GetOptions(parameters)); + } + + internal static EvaluatorReturnType FromSingleton(DirectoryInfo namespaceDirectory, + Config config, + ParameterType? parameters) + { + var singletonPath = parameters!["source"].GetString()!; + var relativePath = parameters!["relativePath"].GetString()!; + var destination = Path.Combine("assets", namespaceDirectory.Name, relativePath) + .NormalizePath(); + var file = new FileInfo(singletonPath!); + var provider = CreateProviderFromFile(file, destination, config); + yield return (provider, GetOptions(parameters)); } @@ -128,7 +140,7 @@ internal static IResourceFileProvider CreateProviderFromFile(FileInfo file, stri var extension = file.Extension; if (file.Directory!.Name == "lang") { - switch(extension) + switch (extension) { case ".json": return JsonMappingHelper.CreateFromFile(file, destination); case ".lang": return LangMappingHelper.CreateFromFile(file, destination); @@ -142,11 +154,16 @@ internal static IResourceFileProvider CreateProviderFromFile(FileInfo file, stri }; } - internal static bool DoesOverride(ParameterType? parameters) + internal static ApplyOptions GetOptions(ParameterType? parameters) { - if (parameters is null) return false; - var hasKey = parameters.TryGetValue("overrides", out var element); - return hasKey ? element.GetBoolean() : false; + if (parameters is null) return default; + return new(GetBoolOrDefalut("modifyOnly"), GetBoolOrDefalut("append")); + + bool GetBoolOrDefalut(string key) + { + if (!parameters.ContainsKey(key)) return false; + return parameters[key].GetBoolean(); + } } } } \ No newline at end of file diff --git a/src/Packer/Helpers/ConfigHelpers.cs b/src/Packer/Helpers/ConfigHelpers.cs index 173513314bf4..ae2b89e79a4b 100644 --- a/src/Packer/Helpers/ConfigHelpers.cs +++ b/src/Packer/Helpers/ConfigHelpers.cs @@ -57,7 +57,7 @@ public static async Task RetrieveConfig(string configTemplate, string ve /// 命名空间目录 /// 若文件存在,返回对应的内容;否则,返回Direct /// 策略文件非法 - public static List RetrieveStrategy(DirectoryInfo directory) + public static List RetrievePolicy(DirectoryInfo directory) { var file = directory.GetFiles("packer-policy.json").FirstOrDefault(); diff --git a/src/Packer/Helpers/GitHelpers.cs b/src/Packer/Helpers/GitHelpers.cs index 5651dbb2d03c..5b078ec4e801 100644 --- a/src/Packer/Helpers/GitHelpers.cs +++ b/src/Packer/Helpers/GitHelpers.cs @@ -1,8 +1,8 @@ -using System.Collections.Generic; +using LibGit2Sharp; +using Serilog; +using System.Collections.Generic; using System.IO; using System.Linq; -using LibGit2Sharp; -using Serilog; namespace Packer.Helpers { @@ -36,6 +36,6 @@ internal static bool IsInTargetVersion(this string location, string version) internal static string ExtractModIdentifier(this string location, string version) => Path.GetRelativePath($"projects/{version}/assets", location) .Split(Path.DirectorySeparatorChar)[0]; - + } } diff --git a/src/Packer/Models/Config.cs b/src/Packer/Models/Config.cs index 45aeb8bf2b31..a3141e7578b3 100644 --- a/src/Packer/Models/Config.cs +++ b/src/Packer/Models/Config.cs @@ -23,7 +23,7 @@ public class Config /// /// 从命名空间下的局域配置加载内容。 /// - public Config Modify(FloatingConfig? floatingConfig) + public Config Modify(FloatingConfig floatingConfig) { if (floatingConfig is null) return this; return new() diff --git a/src/Packer/Models/IResourceFileProvider.cs b/src/Packer/Models/IResourceFileProvider.cs index 76255e044182..ef010b6aaca4 100644 --- a/src/Packer/Models/IResourceFileProvider.cs +++ b/src/Packer/Models/IResourceFileProvider.cs @@ -17,14 +17,12 @@ public interface IResourceFileProvider /// /// 在本提供器的基础上,尝试添加新提供器中的内容 /// - /// 需要添加的新 - /// 冲突解决方案。若为,保留本文件的内容;否则,保留新文件的内容 + /// 需要添加的新 + /// 冲突解决选项 /// 合并得到的新 - public IResourceFileProvider ApplyTo(IResourceFileProvider? incoming, bool overrideExisting = false) - // 默认实现 - => !overrideExisting - ? (incoming ?? this) // 如果来源是null,无论冲突配置如何,都不应返回null - : this; + public IResourceFileProvider ApplyTo(IResourceFileProvider? baseProvider, ApplyOptions options = default) + // 默认实现;如果来源是null,无论冲突配置如何,都不应返回null + => baseProvider ?? this; /// /// 在该提供器的内容中执行替换 @@ -56,4 +54,27 @@ public IResourceFileProvider ReplaceContent(string searchPattern, string replace /// public string Destination { get; } } + + /// + /// 在合并供应器时,使用的选项。理论上可以拓展,只要加默认值。 + /// + public readonly struct ApplyOptions + { +#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释 + public ApplyOptions(bool modifyOnly, bool append) + { + ModifyOnly = modifyOnly; + Append = append; + } +#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释 + + /// + /// 对于,是否包含选入的新键。 + /// + public bool ModifyOnly { get; } = false; + /// + /// 对于,是否将文本相连。 + /// + public bool Append { get; } = false; + } } diff --git a/src/Packer/Models/PackerPolicy.cs b/src/Packer/Models/PackerPolicy.cs index fb86d121b3ef..981db5c445ba 100644 --- a/src/Packer/Models/PackerPolicy.cs +++ b/src/Packer/Models/PackerPolicy.cs @@ -20,7 +20,11 @@ public enum PackerPolicyType /// /// 从组合文件创建指定语言文件。 /// - Composition + Composition, + /// + /// 加载单个文件。 + /// + Singleton } /// diff --git a/src/Packer/Models/Providers/CompositionHelper.cs b/src/Packer/Models/Providers/CompositionHelper.cs index 704bf65fd1a3..4bb2febac28d 100644 --- a/src/Packer/Models/Providers/CompositionHelper.cs +++ b/src/Packer/Models/Providers/CompositionHelper.cs @@ -6,8 +6,8 @@ namespace Packer.Models.Providers { - using LangMappingProvider = TermMappingProvider; using JsonMappingProvider = TermMappingProvider; + using LangMappingProvider = TermMappingProvider; public static partial class LangMappingHelper { diff --git a/src/Packer/Models/Providers/TermMappingProvider.cs b/src/Packer/Models/Providers/TermMappingProvider.cs index 755d25620d52..41973f6bdeb8 100644 --- a/src/Packer/Models/Providers/TermMappingProvider.cs +++ b/src/Packer/Models/Providers/TermMappingProvider.cs @@ -75,7 +75,8 @@ public JsonDictionaryWrapper(IDictionary dictionary) : base(di public string ProvideStringContent() => JsonSerializer.Serialize(this, new JsonSerializerOptions() { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + WriteIndented = true }); public ITermDictionary ReplaceContent(string searchPattern, string replacement) @@ -142,26 +143,35 @@ public TermMappingProvider(ITermDictionary map, string destination) } /// - public IResourceFileProvider ApplyTo(IResourceFileProvider? incoming, bool overrideExisting = false) + public IResourceFileProvider ApplyTo(IResourceFileProvider? baseProvider, ApplyOptions options) { - if (incoming is null) return this; - if (incoming is not TermMappingProvider inProvider) + if (baseProvider is null) return this; + + if (baseProvider is not TermMappingProvider baseMapping) throw new ArgumentException($"Argument not an instance of {typeof(TermMappingProvider)}.", - nameof(incoming)); - //var inProvider = incoming as TermMappingProvider; + nameof(baseProvider)); - //if (inProvider is null) throw new ArgumentNullException(nameof(incoming)); - var (baseMap, inMap) = overrideExisting - ? (Map, inProvider.Map) - : (inProvider.Map, Map); // 交换顺序 + var baseMap = baseMapping.Map; - foreach (var pair in inMap) + if (options.ModifyOnly) + { + foreach (var pair in Map) + { + if (baseMap.ContainsKey(pair.Key)) + baseMap[pair.Key] = pair.Value; + } + return new TermMappingProvider(baseMap, Destination); + } + else { - baseMap.TryAdd(pair.Key, pair.Value); + foreach (var pair in Map) + { + baseMap.TryAdd(pair.Key, pair.Value); + } + return new TermMappingProvider(baseMap, Destination); } - return new TermMappingProvider(baseMap, Destination); } /// @@ -263,7 +273,7 @@ internal static Dictionary DeserializeFromLang(string content) isInComment = true; continue; } - + if (line.IsEmpty || line.IsWhiteSpace()) // 空行需去 continue; diff --git a/src/Packer/Models/Providers/TextFile.cs b/src/Packer/Models/Providers/TextFile.cs index c6207b5a5323..f24ef147ee63 100644 --- a/src/Packer/Models/Providers/TextFile.cs +++ b/src/Packer/Models/Providers/TextFile.cs @@ -1,5 +1,6 @@ using Packer.Extensions; using Serilog; +using System; using System.IO; using System.IO.Compression; using System.Text; @@ -20,7 +21,7 @@ public class TextFile : IResourceFileProvider /// 提供器所携带的文本内容 /// public virtual string Content { get; } - + /// public virtual string Destination { get; } @@ -42,12 +43,27 @@ public static TextFile Create(FileInfo file, string destination) /// /// 来源文本 /// 目标地址 - public TextFile(string content, string destination) - { + public TextFile(string content, string destination) + { Content = content; Destination = destination; } + /// + public virtual IResourceFileProvider ApplyTo(IResourceFileProvider? baseProvider, ApplyOptions options) + { + if (baseProvider is null) return this; + + if (!options.Append) return baseProvider; + + if (baseProvider is not TextFile baseTextFile) + throw new ArgumentException($"Argument not an instance of {typeof(TextFile)}.", + nameof(baseProvider)); + var baseText = baseTextFile.Content; + var appendedText = string.Concat(baseText, Environment.NewLine, Content); + return new TextFile(appendedText, Destination); + } + /// public virtual IResourceFileProvider ReplaceContent(string searchPattern, string replacement) => new TextFile(Regex.Replace(Content, diff --git a/src/Packer/Program.cs b/src/Packer/Program.cs index e135e8646f5e..99924b13a965 100644 --- a/src/Packer/Program.cs +++ b/src/Packer/Program.cs @@ -4,7 +4,6 @@ using Packer.Models.Providers; using Serilog; using System; -using System.Collections; using System.IO; using System.IO.Compression; using System.Linq; @@ -47,8 +46,7 @@ select destinationGroup .Aggregate(seed: null as IResourceFileProvider, // 合并文件 (accumulate, next) => next.ApplyTo( - accumulate, - overrideExisting: false)) into provider + accumulate)) into provider select config.Floating.CharacterReplacement // 内容的字符替换 .Aggregate(seed: provider, (accumulate, replacement) From 5cf9749cb137edd0ffc42d659349636ddc72424c Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sat, 28 Oct 2023 22:52:24 +0800 Subject: [PATCH 12/22] hotfix1 --- .github/workflows/packer.yml | 4 ++-- .github/workflows/pr-packer.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/packer.yml b/.github/workflows/packer.yml index 78e7bccbb36c..8d281598a51e 100644 --- a/.github/workflows/packer.yml +++ b/.github/workflows/packer.yml @@ -110,7 +110,7 @@ jobs: id: cache-restore uses: actions/cache/restore@v3 with: - key: ${{ runner.os }}-${{ hashFiles('source/Packer/**') }} + key: ${{ runner.os }}-Packer-${{ hashFiles('source/Packer/**') }} path: | Packer.exe git2-*.dll @@ -168,7 +168,7 @@ jobs: id: cache-restore uses: actions/cache/restore@v3 with: - key: ${{ runner.os }}-${{ hashFiles('source/Uploader/**') }} + key: ${{ runner.os }}-Uploader-${{ hashFiles('source/Uploader/**') }} path: Uploader.exe fail-on-cache-miss: true # 前一步理应构造过的。如果不命中,肯定有问题,不如直接挂掉。 diff --git a/.github/workflows/pr-packer.yml b/.github/workflows/pr-packer.yml index 47713231591d..d9f855c6c172 100644 --- a/.github/workflows/pr-packer.yml +++ b/.github/workflows/pr-packer.yml @@ -62,7 +62,7 @@ jobs: id: cache-restore uses: actions/cache/restore@v3 with: - key: ${{ runner.os }}-${{ hashFiles('src/Packer/**') }} + key: ${{ runner.os }}-Packer-${{ hashFiles('src/Packer/**') }} path: | Packer.exe git2-*.dll From 42280d53f1356993ae6182aa0932b50a2d16f689 Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sat, 4 Nov 2023 19:19:36 +0800 Subject: [PATCH 13/22] test1 --- .../minecraft/minecraft/packer-policy.json | 2 +- src/Packer/Extensions/ContentExtension.cs | 19 +++++++++++++++++- src/Packer/Extensions/DirectoryExtension.cs | 10 ++++++++++ src/Packer/Helpers/ConfigHelpers.cs | 13 ++++++++---- src/Packer/Program.cs | 20 +++++++++++++------ 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/projects/1.20-fabric/assets/minecraft/minecraft/packer-policy.json b/projects/1.20-fabric/assets/minecraft/minecraft/packer-policy.json index a0802b736d3f..ba5e3dd5673d 100644 --- a/projects/1.20-fabric/assets/minecraft/minecraft/packer-policy.json +++ b/projects/1.20-fabric/assets/minecraft/minecraft/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.20/assets/minecraft/minecraft" + "source": "projects/1.20/assets/minecraft/minecraft" } ] \ No newline at end of file diff --git a/src/Packer/Extensions/ContentExtension.cs b/src/Packer/Extensions/ContentExtension.cs index bac9be751178..936e0cfab327 100644 --- a/src/Packer/Extensions/ContentExtension.cs +++ b/src/Packer/Extensions/ContentExtension.cs @@ -1,4 +1,5 @@ -using System; +using Serilog; +using System; using System.IO; using System.Linq; using System.Security.Cryptography; @@ -81,6 +82,22 @@ public static bool IsPathForceExcluded(this string location, Config config) public static bool IsPathForceIncluded(this string location, Config config) => config.Floating.InclusionPaths.Contains(location); + /// + /// 将字符串输出到调试日志,然后返回该字符串 + /// + public static string LogToDebug(this string message, string template) + { + Log.Debug(template, message); + return message; + } + /// + /// 将字符串输出到调试日志,然后返回该字符串 + /// + public static string LogToDebug(this string message) + { + Log.Debug(message); + return message; + } // 临时方法 /// diff --git a/src/Packer/Extensions/DirectoryExtension.cs b/src/Packer/Extensions/DirectoryExtension.cs index 4706e2604542..39d65ac00d23 100644 --- a/src/Packer/Extensions/DirectoryExtension.cs +++ b/src/Packer/Extensions/DirectoryExtension.cs @@ -1,6 +1,7 @@ using Packer.Helpers; using Packer.Models; using Packer.Models.Providers; +using Serilog; using System; using System.Collections.Generic; using System.IO; @@ -98,6 +99,8 @@ internal static EvaluatorReturnType FromSpecifiedDirectory(DirectoryInfo namespa var namespaceName = namespaceDirectory.Name; var redirectDirectory = new DirectoryInfo(redirect!); + Log.Debug("[Policy:Indirect]目标:{0},源:{1}", namespaceName, redirect); + return from candidate in redirectDirectory.EnumerateRawProviders(config) let provider = candidate.provider .ReplaceDestination(@"(?<=^assets/)[^/]*(?=/)", @@ -112,6 +115,9 @@ internal static EvaluatorReturnType FromComposition(DirectoryInfo namespaceDirec var compositionPath = parameters!["source"].GetString(); var type = parameters["destType"].GetString(); var compositionFile = new FileInfo(compositionPath!); + + Log.Debug("[Policy:Composition]目标:{0},源:{1}", namespaceDirectory.Name, compositionPath); + IResourceFileProvider provider = type switch // 类型推断不出要用接口 { "lang" => LangMappingHelper.CreateFromComposition(compositionFile), @@ -129,8 +135,12 @@ internal static EvaluatorReturnType FromSingleton(DirectoryInfo namespaceDirecto var relativePath = parameters!["relativePath"].GetString()!; var destination = Path.Combine("assets", namespaceDirectory.Name, relativePath) .NormalizePath(); + + Log.Debug("[Policy:Singleton]目标:{0},源:{1}", destination, singletonPath); + var file = new FileInfo(singletonPath!); var provider = CreateProviderFromFile(file, destination, config); + yield return (provider, GetOptions(parameters)); } diff --git a/src/Packer/Helpers/ConfigHelpers.cs b/src/Packer/Helpers/ConfigHelpers.cs index ae2b89e79a4b..7ca78ba37375 100644 --- a/src/Packer/Helpers/ConfigHelpers.cs +++ b/src/Packer/Helpers/ConfigHelpers.cs @@ -1,4 +1,5 @@ -using Packer.Models; +using Packer.Extensions; +using Packer.Models; using Serilog; using System.Collections.Generic; using System.IO; @@ -26,9 +27,11 @@ public static class ConfigHelpers if (configFile is null) return null; + configFile.FullName.LogToDebug("读取文件:{0}"); + using var reader = configFile.OpenText(); return JsonSerializer.Deserialize( - reader.ReadToEnd(), + reader.ReadToEnd().LogToDebug(), new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); } @@ -55,7 +58,7 @@ public static async Task RetrieveConfig(string configTemplate, string ve /// 从给定的命名空间获取策略内容 /// /// 命名空间目录 - /// 若文件存在,返回对应的内容;否则,返回Direct + /// 若文件存在,返回对应的内容;否则,返回[Direct] /// 策略文件非法 public static List RetrievePolicy(DirectoryInfo directory) { @@ -67,9 +70,11 @@ public static List RetrievePolicy(DirectoryInfo directory) new PackerPolicy { Type = PackerPolicyType.Direct } }; + file.FullName.LogToDebug("读取文件:{0}"); + using var reader = file.OpenText(); var result = JsonSerializer.Deserialize>( - reader.ReadToEnd(), + reader.ReadToEnd().LogToDebug(), new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, diff --git a/src/Packer/Program.cs b/src/Packer/Program.cs index 99924b13a965..3c2ff88990a9 100644 --- a/src/Packer/Program.cs +++ b/src/Packer/Program.cs @@ -16,12 +16,18 @@ class Program // System.CommandLine.DragonFruit支持 public static async Task Main(string version, bool increment = false) { + var levelSwitch = new Serilog.Core.LoggingLevelSwitch(); + Log.Logger = new LoggerConfiguration() .Enrich.FromLogContext() .WriteTo.Console() - .MinimumLevel.Information() // 以便 debug 时修改这一等级 + .MinimumLevel.ControlledBy(levelSwitch) // 以便 debug 时修改这一等级 .CreateLogger(); + // 若开启了debug logging,显示更多日志(包括IEnumerable里的东西) + if (Environment.GetEnvironmentVariable("ACTIONS_STEP_DEBUG") == "true") + levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Debug; + var config = await ConfigHelpers.RetrieveConfig(configTemplate: "./config/packer/{0}.json", version: version); Log.Information("开始对版本 {0} 的打包", config.Base.Version); @@ -66,19 +72,21 @@ select config.Floating.DestinationReplacement // 全局路 ? McMetaProvider.Create(file, file.Name) // 类型推断不出要用接口 : new RawFile(file, file.Name) as IResourceFileProvider; + var totalQuery = query.Concat(initialsQuery); + string packName = $"./Minecraft-Mod-Language-Package-{config.Base.Version}.zip"; await using var stream = File.Create(packName); using (var archive = new ZipArchive(stream, ZipArchiveMode.Update, leaveOpen: true)) { - await Task.WhenAll(from provider in query.Concat(initialsQuery) + await Task.WhenAll(from provider in totalQuery select provider.WriteToArchive(archive)); } - Log.Information("对版本 {0} 的打包结束。共写入了 {1} + {2} 个文件", - config.Base.Version, - initialsQuery.Count(), - query.Count()); + Log.Information("对版本 {0} 的打包结束。", version); + if (totalQuery.TryGetNonEnumeratedCount(out var count)) + Log.Information("文件总数:{0}", count); + var md5 = stream.ComputeMD5(); Log.Information("打包文件的 MD5 值:{0}", md5); From 509c428982aefe1aa4a7a23ab509ade134f55e37 Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sat, 4 Nov 2023 20:55:59 +0800 Subject: [PATCH 14/22] test2 --- src/Packer/Program.cs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/Packer/Program.cs b/src/Packer/Program.cs index 3c2ff88990a9..367111587bb7 100644 --- a/src/Packer/Program.cs +++ b/src/Packer/Program.cs @@ -16,18 +16,12 @@ class Program // System.CommandLine.DragonFruit支持 public static async Task Main(string version, bool increment = false) { - var levelSwitch = new Serilog.Core.LoggingLevelSwitch(); - Log.Logger = new LoggerConfiguration() .Enrich.FromLogContext() .WriteTo.Console() - .MinimumLevel.ControlledBy(levelSwitch) // 以便 debug 时修改这一等级 + .MinimumLevel.Debug() .CreateLogger(); - // 若开启了debug logging,显示更多日志(包括IEnumerable里的东西) - if (Environment.GetEnvironmentVariable("ACTIONS_STEP_DEBUG") == "true") - levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Debug; - var config = await ConfigHelpers.RetrieveConfig(configTemplate: "./config/packer/{0}.json", version: version); Log.Information("开始对版本 {0} 的打包", config.Base.Version); @@ -72,20 +66,17 @@ select config.Floating.DestinationReplacement // 全局路 ? McMetaProvider.Create(file, file.Name) // 类型推断不出要用接口 : new RawFile(file, file.Name) as IResourceFileProvider; - var totalQuery = query.Concat(initialsQuery); - string packName = $"./Minecraft-Mod-Language-Package-{config.Base.Version}.zip"; await using var stream = File.Create(packName); using (var archive = new ZipArchive(stream, ZipArchiveMode.Update, leaveOpen: true)) { - await Task.WhenAll(from provider in totalQuery + await Task.WhenAll(from provider in query.Concat(initialsQuery) select provider.WriteToArchive(archive)); - } + + } Log.Information("对版本 {0} 的打包结束。", version); - if (totalQuery.TryGetNonEnumeratedCount(out var count)) - Log.Information("文件总数:{0}", count); var md5 = stream.ComputeMD5(); From 1d890e27aa0b6b929baa7e044c303fc6abf1ec1c Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sat, 4 Nov 2023 21:10:21 +0800 Subject: [PATCH 15/22] fix policies --- .../assets/cloth-config/cloth-config2/packer-policy.json | 2 +- .../assets/iron-furnaces/ironfurnaces/packer-policy.json | 2 +- .../assets/minecraft/minecraft/packer-policy.json | 2 +- .../corail-recycler/corail_recycler/packer-policy.json | 2 +- .../crafting-tweaks/craftingtweaks/packer-policy.json | 2 +- projects/1.16/assets/tool-kit/toolkit/packer-policy.json | 2 +- .../assets/cloth-config/cloth-config2/packer-policy.json | 2 +- .../exlinecopperequipment/packer-policy.json | 2 +- .../1.18-fabric/assets/goodall/goodall/packer-policy.json | 2 +- .../assets/iron-furnaces/ironfurnaces/packer-policy.json | 2 +- projects/1.18-fabric/assets/jei/jei/packer-policy.json | 2 +- .../assets/minecraft/minecraft/packer-policy.json | 2 +- .../assets/opulence/opulence/packer-policy.json | 2 +- .../rotten-creatures/rottencreatures/packer-policy.json | 2 +- .../crafting-tweaks/craftingtweaks/packer-policy.json | 2 +- projects/1.18/assets/jei/jei/packer-policy.json | 2 +- .../1.18/assets/minecraft/minecraft/packer-policy.json | 2 +- .../1.19/assets/armor-poser/armorposer/packer-policy.json | 2 +- .../1.19/assets/hourglass/hourglass/packer-policy.json | 2 +- .../1.19/assets/minecraft/minecraft/packer-policy.json | 2 +- .../assets/shield-expansion/shieldexp/packer-policy.json | 2 +- .../explorers-compass/explorerscompass/packer-policy.json | 7 ++++++- 22 files changed, 27 insertions(+), 22 deletions(-) diff --git a/projects/1.16-fabric/assets/cloth-config/cloth-config2/packer-policy.json b/projects/1.16-fabric/assets/cloth-config/cloth-config2/packer-policy.json index fea12dde5c74..e6cb6e43589f 100644 --- a/projects/1.16-fabric/assets/cloth-config/cloth-config2/packer-policy.json +++ b/projects/1.16-fabric/assets/cloth-config/cloth-config2/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.16/assets/cloth-config/cloth-config2" + "source": "projects/1.16/assets/cloth-config/cloth-config2" } ] \ No newline at end of file diff --git a/projects/1.16-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json b/projects/1.16-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json index d81675a62bcc..25aa1595911f 100644 --- a/projects/1.16-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json +++ b/projects/1.16-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.16/assets/iron-furnaces/ironfurnaces" + "source": "projects/1.16/assets/iron-furnaces/ironfurnaces" } ] \ No newline at end of file diff --git a/projects/1.16-fabric/assets/minecraft/minecraft/packer-policy.json b/projects/1.16-fabric/assets/minecraft/minecraft/packer-policy.json index ca88d9799a3c..0c83b1555036 100644 --- a/projects/1.16-fabric/assets/minecraft/minecraft/packer-policy.json +++ b/projects/1.16-fabric/assets/minecraft/minecraft/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.16/assets/minecraft/minecraft" + "source": "projects/1.16/assets/minecraft/minecraft" } ] \ No newline at end of file diff --git a/projects/1.16/assets/corail-recycler/corail_recycler/packer-policy.json b/projects/1.16/assets/corail-recycler/corail_recycler/packer-policy.json index cc120ff0d580..f210706ee6c6 100644 --- a/projects/1.16/assets/corail-recycler/corail_recycler/packer-policy.json +++ b/projects/1.16/assets/corail-recycler/corail_recycler/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.18/assets/corail-recycler/corail_recycler" + "source": "projects/1.18/assets/corail-recycler/corail_recycler" } ] \ No newline at end of file diff --git a/projects/1.16/assets/crafting-tweaks/craftingtweaks/packer-policy.json b/projects/1.16/assets/crafting-tweaks/craftingtweaks/packer-policy.json index 85f92e2f4564..8ecf622e8f89 100644 --- a/projects/1.16/assets/crafting-tweaks/craftingtweaks/packer-policy.json +++ b/projects/1.16/assets/crafting-tweaks/craftingtweaks/packer-policy.json @@ -4,7 +4,7 @@ }, { "type": "indirect", - "source": "./projects/1.19/assets/crafting-tweaks/craftingtweaks", + "source": "projects/1.19/assets/crafting-tweaks/craftingtweaks", "modifyOnly": true } ] \ No newline at end of file diff --git a/projects/1.16/assets/tool-kit/toolkit/packer-policy.json b/projects/1.16/assets/tool-kit/toolkit/packer-policy.json index 91e6926ddcdf..fd36ae124a5e 100644 --- a/projects/1.16/assets/tool-kit/toolkit/packer-policy.json +++ b/projects/1.16/assets/tool-kit/toolkit/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.18/assets/tool-kit/toolkit" + "source": "projects/1.18/assets/tool-kit/toolkit" } ] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/cloth-config/cloth-config2/packer-policy.json b/projects/1.18-fabric/assets/cloth-config/cloth-config2/packer-policy.json index f117285a0270..cd1ca5600f4f 100644 --- a/projects/1.18-fabric/assets/cloth-config/cloth-config2/packer-policy.json +++ b/projects/1.18-fabric/assets/cloth-config/cloth-config2/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.18/assets/cloth-config/cloth-config2" + "source": "projects/1.18/assets/cloth-config/cloth-config2" } ] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/copper-equipment/exlinecopperequipment/packer-policy.json b/projects/1.18-fabric/assets/copper-equipment/exlinecopperequipment/packer-policy.json index 4394bfad29a3..0741a6ca82ee 100644 --- a/projects/1.18-fabric/assets/copper-equipment/exlinecopperequipment/packer-policy.json +++ b/projects/1.18-fabric/assets/copper-equipment/exlinecopperequipment/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.18/assets/copper-equipment/exlinecopperequipment" + "source": "projects/1.18/assets/copper-equipment/exlinecopperequipment" } ] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/goodall/goodall/packer-policy.json b/projects/1.18-fabric/assets/goodall/goodall/packer-policy.json index 3a8ca12c508d..01da4b200516 100644 --- a/projects/1.18-fabric/assets/goodall/goodall/packer-policy.json +++ b/projects/1.18-fabric/assets/goodall/goodall/packer-policy.json @@ -1,4 +1,4 @@ [{ "type": "indirect", - "source": "./projects/1.18/assets/goodall/goodall" + "source": "projects/1.18/assets/goodall/goodall" }] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json b/projects/1.18-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json index 8ee1a3a68b3a..001a18455870 100644 --- a/projects/1.18-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json +++ b/projects/1.18-fabric/assets/iron-furnaces/ironfurnaces/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.18/assets/iron-furnaces/ironfurnaces" + "source": "projects/1.18/assets/iron-furnaces/ironfurnaces" } ] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/jei/jei/packer-policy.json b/projects/1.18-fabric/assets/jei/jei/packer-policy.json index 1279d7723e5f..0ecc1085a3e1 100644 --- a/projects/1.18-fabric/assets/jei/jei/packer-policy.json +++ b/projects/1.18-fabric/assets/jei/jei/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.19/assets/jei/jei" + "source": "projects/1.19/assets/jei/jei" } ] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/minecraft/minecraft/packer-policy.json b/projects/1.18-fabric/assets/minecraft/minecraft/packer-policy.json index a1ea3f19be38..da8cef2e0145 100644 --- a/projects/1.18-fabric/assets/minecraft/minecraft/packer-policy.json +++ b/projects/1.18-fabric/assets/minecraft/minecraft/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.18/assets/minecraft/minecraft" + "source": "projects/1.18/assets/minecraft/minecraft" } ] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/opulence/opulence/packer-policy.json b/projects/1.18-fabric/assets/opulence/opulence/packer-policy.json index 92158592d167..6b86124664d5 100644 --- a/projects/1.18-fabric/assets/opulence/opulence/packer-policy.json +++ b/projects/1.18-fabric/assets/opulence/opulence/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.18/assets/opulence/opulence" + "source": "projects/1.18/assets/opulence/opulence" } ] \ No newline at end of file diff --git a/projects/1.18-fabric/assets/rotten-creatures/rottencreatures/packer-policy.json b/projects/1.18-fabric/assets/rotten-creatures/rottencreatures/packer-policy.json index 55fbf7e28f8a..a1d193d5c8e7 100644 --- a/projects/1.18-fabric/assets/rotten-creatures/rottencreatures/packer-policy.json +++ b/projects/1.18-fabric/assets/rotten-creatures/rottencreatures/packer-policy.json @@ -1,4 +1,4 @@ [{ "type": "indirect", - "source": "./projects/1.18/assets/rotten-creatures/rottencreatures" + "source": "projects/1.18/assets/rotten-creatures/rottencreatures" }] \ No newline at end of file diff --git a/projects/1.18/assets/crafting-tweaks/craftingtweaks/packer-policy.json b/projects/1.18/assets/crafting-tweaks/craftingtweaks/packer-policy.json index 85f92e2f4564..8ecf622e8f89 100644 --- a/projects/1.18/assets/crafting-tweaks/craftingtweaks/packer-policy.json +++ b/projects/1.18/assets/crafting-tweaks/craftingtweaks/packer-policy.json @@ -4,7 +4,7 @@ }, { "type": "indirect", - "source": "./projects/1.19/assets/crafting-tweaks/craftingtweaks", + "source": "projects/1.19/assets/crafting-tweaks/craftingtweaks", "modifyOnly": true } ] \ No newline at end of file diff --git a/projects/1.18/assets/jei/jei/packer-policy.json b/projects/1.18/assets/jei/jei/packer-policy.json index 1279d7723e5f..0ecc1085a3e1 100644 --- a/projects/1.18/assets/jei/jei/packer-policy.json +++ b/projects/1.18/assets/jei/jei/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.19/assets/jei/jei" + "source": "projects/1.19/assets/jei/jei" } ] \ No newline at end of file diff --git a/projects/1.18/assets/minecraft/minecraft/packer-policy.json b/projects/1.18/assets/minecraft/minecraft/packer-policy.json index 36653b700ae5..9e4e33dd9895 100644 --- a/projects/1.18/assets/minecraft/minecraft/packer-policy.json +++ b/projects/1.18/assets/minecraft/minecraft/packer-policy.json @@ -4,6 +4,6 @@ }, { "type": "indirect", - "source": "./projects/1.16/assets/minecraft/minecraft" + "source": "projects/1.16/assets/minecraft/minecraft" } ] \ No newline at end of file diff --git a/projects/1.19/assets/armor-poser/armorposer/packer-policy.json b/projects/1.19/assets/armor-poser/armorposer/packer-policy.json index 9bd62a8b19c5..749708c93270 100644 --- a/projects/1.19/assets/armor-poser/armorposer/packer-policy.json +++ b/projects/1.19/assets/armor-poser/armorposer/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.18/assets/armor-poser/armorposer" + "source": "projects/1.18/assets/armor-poser/armorposer" } ] \ No newline at end of file diff --git a/projects/1.19/assets/hourglass/hourglass/packer-policy.json b/projects/1.19/assets/hourglass/hourglass/packer-policy.json index 76baceff7578..8831f8bc1e2e 100644 --- a/projects/1.19/assets/hourglass/hourglass/packer-policy.json +++ b/projects/1.19/assets/hourglass/hourglass/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.18/assets/hourglass/hourglass" + "source": "projects/1.18/assets/hourglass/hourglass" } ] \ No newline at end of file diff --git a/projects/1.19/assets/minecraft/minecraft/packer-policy.json b/projects/1.19/assets/minecraft/minecraft/packer-policy.json index 36653b700ae5..9e4e33dd9895 100644 --- a/projects/1.19/assets/minecraft/minecraft/packer-policy.json +++ b/projects/1.19/assets/minecraft/minecraft/packer-policy.json @@ -4,6 +4,6 @@ }, { "type": "indirect", - "source": "./projects/1.16/assets/minecraft/minecraft" + "source": "projects/1.16/assets/minecraft/minecraft" } ] \ No newline at end of file diff --git a/projects/1.19/assets/shield-expansion/shieldexp/packer-policy.json b/projects/1.19/assets/shield-expansion/shieldexp/packer-policy.json index eab3d9593b71..0521033b4c42 100644 --- a/projects/1.19/assets/shield-expansion/shieldexp/packer-policy.json +++ b/projects/1.19/assets/shield-expansion/shieldexp/packer-policy.json @@ -1,6 +1,6 @@ [ { "type": "indirect", - "source": "./projects/1.18/assets/shield-expansion/shieldexp" + "source": "projects/1.18/assets/shield-expansion/shieldexp" } ] \ No newline at end of file diff --git a/projects/1.20-fabric/assets/explorers-compass/explorerscompass/packer-policy.json b/projects/1.20-fabric/assets/explorers-compass/explorerscompass/packer-policy.json index 97ec6dcc95d5..0c62950853af 100644 --- a/projects/1.20-fabric/assets/explorers-compass/explorerscompass/packer-policy.json +++ b/projects/1.20-fabric/assets/explorers-compass/explorerscompass/packer-policy.json @@ -1 +1,6 @@ -{"type":"plainclone","source":"./projects/1.20/assets/explorers-compass/explorerscompass"} \ No newline at end of file +[ + { + "type": "indirect", + "source": "projects/1.20/assets/explorers-compass/explorerscompass" + } +] \ No newline at end of file From d07265925b96e4d4e25b213a41446e3a2e33d3dc Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sat, 11 Nov 2023 15:11:39 +0800 Subject: [PATCH 16/22] Misc1 --- Packer-Doc.md | 31 ++++++++++++++---- config/packer/1.12.2.json | 3 +- config/packer/1.16-fabric.json | 3 +- config/packer/1.16.json | 3 +- config/packer/1.18-fabric.json | 3 +- config/packer/1.18.json | 3 +- config/packer/1.19.json | 3 +- config/packer/1.20-fabric.json | 3 +- config/packer/1.20.json | 3 +- .../assets/minecraft/minecraft/README.md | 12 +++++++ .../1.16/assets/minecraft/minecraft/README.md | 16 +++++++++ .../font-source-file.psd} | Bin .../minecraft/minecraft/local-config.json | 10 ++++++ .../1.16/assets/minecraft/minecraft/readme.md | 24 -------------- .../assets/minecraft/minecraft/README.md | 12 +++++++ .../macaws-furniture/mcwfurnitures/README.md | 7 ++++ .../1.18/assets/minecraft/minecraft/README.md | 14 ++++++++ .../1.19/assets/minecraft/minecraft/README.md | 14 ++++++++ .../assets/minecraft/minecraft/README.md | 12 +++++++ .../1.20/assets/minecraft/minecraft/README.md | 19 +++++++++++ .../font/include/cjk-punctuations.json | 27 +++++++++++++-- .../minecraft/minecraft/packer-policy.json | 9 +++++ .../1.20/assets/minecraft/minecraft/readme.md | 24 -------------- .../minecraft/textures/font/2em_dash.png | Bin 2829 -> 0 bytes .../textures/font/cjk_punctuations.png | Bin 3275 -> 0 bytes .../minecraft/textures/font/ellipsis.png | Bin 2843 -> 0 bytes src/Packer/Models/IResourceFileProvider.cs | 1 + src/Packer/Models/Providers/McMetaProvider.cs | 2 +- src/Packer/Models/Providers/RawFile.cs | 2 +- .../Models/Providers/TermMappingProvider.cs | 6 ++-- src/Packer/Models/Providers/TextFile.cs | 2 +- src/Packer/Program.cs | 9 ++--- 32 files changed, 202 insertions(+), 75 deletions(-) create mode 100644 projects/1.16-fabric/assets/minecraft/minecraft/README.md create mode 100644 projects/1.16/assets/minecraft/minecraft/README.md rename projects/1.16/assets/minecraft/{cjk-workspace.psd => minecraft/font-source-file.psd} (100%) create mode 100644 projects/1.16/assets/minecraft/minecraft/local-config.json delete mode 100644 projects/1.16/assets/minecraft/minecraft/readme.md create mode 100644 projects/1.18-fabric/assets/minecraft/minecraft/README.md create mode 100644 projects/1.18/assets/macaws-furniture/mcwfurnitures/README.md create mode 100644 projects/1.18/assets/minecraft/minecraft/README.md create mode 100644 projects/1.19/assets/minecraft/minecraft/README.md create mode 100644 projects/1.20-fabric/assets/minecraft/minecraft/README.md create mode 100644 projects/1.20/assets/minecraft/minecraft/README.md create mode 100644 projects/1.20/assets/minecraft/minecraft/packer-policy.json delete mode 100644 projects/1.20/assets/minecraft/minecraft/readme.md delete mode 100644 projects/1.20/assets/minecraft/minecraft/textures/font/2em_dash.png delete mode 100644 projects/1.20/assets/minecraft/minecraft/textures/font/cjk_punctuations.png delete mode 100644 projects/1.20/assets/minecraft/minecraft/textures/font/ellipsis.png diff --git a/Packer-Doc.md b/Packer-Doc.md index 1092b4fee0ea..45f35d40067a 100644 --- a/Packer-Doc.md +++ b/Packer-Doc.md @@ -3,16 +3,16 @@ ## 注意事项 - 文件地址中,目录分隔符**一律使用正斜杠**! - 地址相关 - - 下述说明中,**完整地址**永远指从**仓库根目录**算起的地址,例如对根目录下的`CONTRIBUTING.md`应为`CONTRIBUTING.md`,1.12版本资源包的`pack.png`应为`projects/1.12.2/pack.png`。 - - 下述说明中,**相对地址**永远指从**特定命名空间的文件夹**算起的地址,例如对仓库中的`projects/1.18/assets/minecraft/minecraft/font/default.json`应为`font/default.json`。 - - 下述说明中,**目标地址**永远指**分发的资源包中**,该文件应当被放置的位置,例如上一条中提及的文件应为`assets/minecraft/font/default.json`。 + - 下述说明中,**完整地址**永远指从**仓库根目录**算起的地址,例如对根目录下的`CONTRIBUTING.md`,应为`CONTRIBUTING.md`;对1.12版本资源包的`pack.png`,应为`projects/1.12.2/pack.png`。 + - 下述说明中,**相对地址**永远指从**特定命名空间的文件夹**算起的地址,例如对仓库中的`projects/1.18/assets/minecraft/minecraft/font/default.json`,应为`font/default.json`。 + - 下述说明中,**目标地址**永远指**分发的资源包中**,该文件应当被放置的位置,例如对上一条中提及的文件,应为`assets/minecraft/font/default.json`。 - 文件相关 - 下述说明中,**语言文件**永远指可以被打包器解读为**映射表**的文件。这包括了所有 **`lang/`下的`.lang`和`.json`文件**。 - 下述说明中,**文本文件**永远指含有**文本内容**,但**不属于语言文件**的文件。这包括了非语言文件的`.txt`、`.md`、`.json`文件。 - 下述说明中,**非文本文件**永远指**不属于以上两类**的文件,如图片或其他二进制文件。 - 本次打包器更新以后,对于**非文本文件**无需特殊处理:打包器会按照文件拓展名自动识别文件类型。 - + ## 配置文件 @@ -24,6 +24,8 @@ 目前而言,所有配置文件都需要填写全部项——无关项可以填写空集合,但不能不填,更不能写null。有计划在将来优化这一行为。 +#### 全局配置文件 + **全局**配置文件`./config/packer/.json`的格式如下: - 根标签 object @@ -36,7 +38,7 @@ - `exclusionNamespaces` list
被打包器排除的 **[namespace]** | **(命名空间)**。
暂时闲置,以待后续需求。 - string
排除的命名空间。 - `floating` object
打包流程中的*可变配置*,可能被文件结构中的**局域配置文件**改写。包含的内容都是**低于**命名空间层级的,因为局域配置文件就是放在命名空间一级中的。 - - `inclusionDomains` list
强制包含的 **[domain]**。
一般而言,用于通常不会包含**语言标识符**的`domain`。
一般而言会包含`font`与`textures`,因为这两处往往包含非文本文件(尽管也可能有文本文件),且字体修复已经需要用到这两个domain;其他内容多半会出现在*局域配置*中。 + - `inclusionDomains` list
强制包含的 **[domain]**。
一般而言,用于通常不会包含**语言标识符**的`domain`。
一般而言会包含`font`与`textures`,因为这两处往往不带语言标识符,且字体修复已经需要用到这两个domain;其他内容多半会出现在*局域配置*中。 - string
强制包含的domain名称。 - `exclusionDomains` list
强制排除的 **[domain]**。
暂时闲置,或可用于排除一些策略相关的零散文件。 - string
强制排除的domain名称。 @@ -49,13 +51,15 @@ - `destinationReplacement` object
打包时采用的目标地址替换。
可以用于移动文件,但暂时闲置;使用**检索策略**中的`singleton`也可以实现地址替换,但需要在每个模组下配置。 - `<查询语句>` string
用以替换**正则表达式**`<查询语句>`匹配对象的内容,可以是一个或多个字符,甚至可以在这里用**正则替换语句**。 +#### 局域配置文件 + **局域**配置文件`./projects//assets///local-config.json`的格式与全局配置文件中,`floating`标签下的内容(*可变配置*)一致。 ### 文件容斥顺序 介于在配置文件中出现了多种包含/排除文件的配置项,有必要说明以下这些项生效的顺序: 1. `exclusionMods`和`exclusionNamespaces`在进入命名空间前即会排除相应的文件夹——甚至不会加载其中的`local-config.json`。
当然,如果是通过*检索策略*访问的,则这一项不会生效。 -2. 在剩下的命名空间中,检索文件。下面的配置项可能会被*局域配置*修改,除了`targetLanguages`以外。 +2. 在剩下的命名空间中,检索文件。下面的配置项可能会被当地的*局域配置*修改,除了`targetLanguages`以外。 3. 在所有检索到的文件中,排除掉`exclusionPaths`指定的文件,即便是通过*检索策略*访问的。 4. 在剩下的文件中,直接包含`inclusionPaths`和`inclusionDomains`指定的文件。 5. 在剩下的文件中,排除掉`exclusionDomains`指定的文件。 @@ -133,4 +137,17 @@ 组合文件可以和其他打包策略混合使用,以修改组合中效果不好的部分,或者添加非组合的内容。 -组合文件理论上可以放在任何位置,使用任何名称;因此,打包器的*基础配置*没有办法排除掉这些文件。不过,为了方便,最好将其汇总在一个位置,采用明确的名称,以便在*局域配置*中排除。 \ No newline at end of file +组合文件理论上可以放在任何位置,使用任何名称;因此,打包器的*基础配置*没有办法排除掉这些文件。不过,为了方便,最好将其汇总在一个位置,采用明确的名称,以便在*局域配置*中排除。 + +## 配置注解 + +上述配置全部采用`json`格式书写;这导致的一个问题就是,`json`格式严格意义上是**不支持注释**的! +为了解决这一问题,在使用这些内容时,最好在对应的命名空间内附上**注解文件**。当然,这不是必须的,但最好这么做。 +同时,也可以在此写下对该目录内容的特殊注释。 + +原则上注解文件可以采用任何形式,但建议写到*命名空间目录下的`README.md`文件*中——打包的全局配置默认会排除这一文件。 +同样的,注解文件的形式也没有特殊限定,但尽量统一为佳。 + +一些注解文件的例子为[这个](projects/1.16/assets/minecraft/minecraft/README.md)、[这个](projects/1.18/assets/minecraft/minecraft/README.md)[这个](projects/1.18/assets/macaws-furniture/mcwfurnitures/README.md)。 + +> 原则上,这些注解甚至可以自动生成。 \ No newline at end of file diff --git a/config/packer/1.12.2.json b/config/packer/1.12.2.json index 65a4c9b6b38f..197945701372 100644 --- a/config/packer/1.12.2.json +++ b/config/packer/1.12.2.json @@ -19,7 +19,8 @@ "exclusionDomains": [], "exclusionPaths": [ "packer-policy.json", - "local-config.json" + "local-config.json", + "README.md" ], "inclusionPaths": [], "characterReplacement": { diff --git a/config/packer/1.16-fabric.json b/config/packer/1.16-fabric.json index 366a34c4e619..c1f8a3827dde 100644 --- a/config/packer/1.16-fabric.json +++ b/config/packer/1.16-fabric.json @@ -15,7 +15,8 @@ "exclusionDomains": [], "exclusionPaths": [ "packer-policy.json", - "local-config.json" + "local-config.json", + "README.md" ], "inclusionPaths": [], "characterReplacement": { diff --git a/config/packer/1.16.json b/config/packer/1.16.json index 3d2413cc2849..f77f0fde502a 100644 --- a/config/packer/1.16.json +++ b/config/packer/1.16.json @@ -15,7 +15,8 @@ "exclusionDomains": [], "exclusionPaths": [ "packer-policy.json", - "local-config.json" + "local-config.json", + "README.md" ], "inclusionPaths": [], "characterReplacement": { diff --git a/config/packer/1.18-fabric.json b/config/packer/1.18-fabric.json index e8ed4e63ad12..1888fc66019a 100644 --- a/config/packer/1.18-fabric.json +++ b/config/packer/1.18-fabric.json @@ -17,7 +17,8 @@ "exclusionDomains": [], "exclusionPaths": [ "packer-policy.json", - "local-config.json" + "local-config.json", + "README.md" ], "inclusionPaths": [], "characterReplacement": { diff --git a/config/packer/1.18.json b/config/packer/1.18.json index c64eb1651dd3..18825996a081 100644 --- a/config/packer/1.18.json +++ b/config/packer/1.18.json @@ -20,7 +20,8 @@ "exclusionDomains": [], "exclusionPaths": [ "packer-policy.json", - "local-config.json" + "local-config.json", + "README.md" ], "inclusionPaths": [], "characterReplacement": { diff --git a/config/packer/1.19.json b/config/packer/1.19.json index 7c7eb46ead6f..169a88a228c8 100644 --- a/config/packer/1.19.json +++ b/config/packer/1.19.json @@ -15,7 +15,8 @@ "exclusionDomains": [], "exclusionPaths": [ "packer-policy.json", - "local-config.json" + "local-config.json", + "README.md" ], "inclusionPaths": [], "characterReplacement": { diff --git a/config/packer/1.20-fabric.json b/config/packer/1.20-fabric.json index 072d278bdaa2..22c6f035d630 100644 --- a/config/packer/1.20-fabric.json +++ b/config/packer/1.20-fabric.json @@ -15,7 +15,8 @@ "exclusionDomains": [], "exclusionPaths": [ "packer-policy.json", - "local-config.json" + "local-config.json", + "README.md" ], "inclusionPaths": [], "characterReplacement": { diff --git a/config/packer/1.20.json b/config/packer/1.20.json index 8cf5760bd3f0..2a8d9c75219c 100644 --- a/config/packer/1.20.json +++ b/config/packer/1.20.json @@ -15,7 +15,8 @@ "exclusionDomains": [], "exclusionPaths": [ "packer-policy.json", - "local-config.json" + "local-config.json", + "README.md" ], "inclusionPaths": [], "characterReplacement": { diff --git a/projects/1.16-fabric/assets/minecraft/minecraft/README.md b/projects/1.16-fabric/assets/minecraft/minecraft/README.md new file mode 100644 index 000000000000..ebbb5ba92146 --- /dev/null +++ b/projects/1.16-fabric/assets/minecraft/minecraft/README.md @@ -0,0 +1,12 @@ +## 概述 + +该命名空间存放了用于`Minecraft-Mod-Language-Package`汉化资源包的字体修正包。内容主要包括: +- 基于1.16+对拓展区的支持,直接实现**元素符号**正常显示。 +- 全面调整了**各类标点符号**的宽度。 +- 针对**省略号**、**破折号**的显示做了特别优化: + - **省略号**现在可以*模拟*等距点——虽说不是完美等距,但看起来差不多。 + - 单个**破折号**在显示时可以*连起来*了。 + +### 局部配置参考 + +- `indirect`@`projects/1.16/assets/minecraft/minecraft`
直接引用了[1.16处的字体修正包](../../../../1.16/assets/minecraft/minecraft/README.md)。 \ No newline at end of file diff --git a/projects/1.16/assets/minecraft/minecraft/README.md b/projects/1.16/assets/minecraft/minecraft/README.md new file mode 100644 index 000000000000..482f00ca8b03 --- /dev/null +++ b/projects/1.16/assets/minecraft/minecraft/README.md @@ -0,0 +1,16 @@ +## 概述 + +该命名空间存放了用于`Minecraft-Mod-Language-Package`汉化资源包的字体修正包。内容主要包括: +- 基于1.16+对拓展区的支持,直接实现**元素符号**正常显示。 +- 全面调整了**各类标点符号**的宽度。 +- 针对**省略号**、**破折号**的显示做了特别优化: + - **省略号**现在可以*模拟*等距点——虽说不是完美等距,但看起来差不多。 + - 单个**破折号**在显示时可以*连起来*了。 + +--- + +部分“工程文件”(其实就是个ps文件,因为这里的“字体”严格来说只是一些贴图罢了)放在了该目录下,打包时会特别忽略这些文件。 + +### 局部配置参考 + +- `exclusionPaths`
排除了存放在根目录的工程文件。 \ No newline at end of file diff --git a/projects/1.16/assets/minecraft/cjk-workspace.psd b/projects/1.16/assets/minecraft/minecraft/font-source-file.psd similarity index 100% rename from projects/1.16/assets/minecraft/cjk-workspace.psd rename to projects/1.16/assets/minecraft/minecraft/font-source-file.psd diff --git a/projects/1.16/assets/minecraft/minecraft/local-config.json b/projects/1.16/assets/minecraft/minecraft/local-config.json new file mode 100644 index 000000000000..1b1604459667 --- /dev/null +++ b/projects/1.16/assets/minecraft/minecraft/local-config.json @@ -0,0 +1,10 @@ +{ + "inclusionDomains": [], + "exclusionDomains": [], + "exclusionPaths": [ + "font-source-file.psd" + ], + "inclusionPaths": [], + "characterReplacement": {}, + "destinationReplacement": {} +} \ No newline at end of file diff --git a/projects/1.16/assets/minecraft/minecraft/readme.md b/projects/1.16/assets/minecraft/minecraft/readme.md deleted file mode 100644 index 1efc216f6cdc..000000000000 --- a/projects/1.16/assets/minecraft/minecraft/readme.md +++ /dev/null @@ -1,24 +0,0 @@ -# 全角字符修正与特殊字符补充 -- 本包添加了几个特殊字符字体,用于补充部分新确定的元素名称 -- 本包修正了中文全角字符的宽度和位置问题。 - -## 本包建议翻译文本采用左侧书写,在打包阶段使用脚本转换成右侧字符 - -| 翻译文本 | 转换字符 | 备注 | -| :------: | :------------: | :----------------------------------: | -| [[钅卢]] | `\ue900` | | -| [[钅杜]] | `\ue901` | | -| [[钅喜]] | `\ue902` | | -| [[钅波]] | `\ue903` | | -| [[钅黑]] | `\ue904` | | -| [[钅麦]] | `\u9fcf` | | -| [[钅达]] | `\ue906` | | -| [[钅仑]] | `\ue907` | | -| [[钅哥]] | `\u9fd4` | | -| [[钅尔]] | `\u9fed` | | -| [[钅夫]] | `\ue90a` | | -| 镆 | `\u9546` | 此元素名已存在对应字符,无需修改替换 | -| [[钅立]] | `\ue90c` | | -| [[石田]] | `\u9fec` | | -| [[奥气]] | `\u9feb` | | -| …… | `\ue908\ue909` | 全角省略号的修改 | \ No newline at end of file diff --git a/projects/1.18-fabric/assets/minecraft/minecraft/README.md b/projects/1.18-fabric/assets/minecraft/minecraft/README.md new file mode 100644 index 000000000000..514945a494c1 --- /dev/null +++ b/projects/1.18-fabric/assets/minecraft/minecraft/README.md @@ -0,0 +1,12 @@ +## 概述 + +该命名空间存放了用于`Minecraft-Mod-Language-Package`汉化资源包的字体修正包。内容主要包括: +- 基于1.16+对拓展区的支持,直接实现**元素符号**正常显示。 +- 全面调整了**各类标点符号**的宽度。 +- 针对**省略号**、**破折号**的显示做了特别优化: + - **省略号**现在可以*模拟*等距点——虽说不是完美等距,但看起来差不多。 + - 单个**破折号**在显示时可以*连起来*了。 + +### 局部配置参考 + +- `indirect`@`projects/1.18/assets/minecraft/minecraft`
直接引用了[1.18处的字体修正包](../../../../1.18/assets/minecraft/minecraft/README.md)。 \ No newline at end of file diff --git a/projects/1.18/assets/macaws-furniture/mcwfurnitures/README.md b/projects/1.18/assets/macaws-furniture/mcwfurnitures/README.md new file mode 100644 index 000000000000..2943f233e67b --- /dev/null +++ b/projects/1.18/assets/macaws-furniture/mcwfurnitures/README.md @@ -0,0 +1,7 @@ +## 概述 + +### 加载结构参考 + +- `lang/zh_cn.json` + - `singleton`@`zh_cn-base.json`
基础文件,包括模组名、物品栏标签名等。 + - `composition`@`zh_cn.composition.json`
组合文件;将木材名与家具名拆分。 \ No newline at end of file diff --git a/projects/1.18/assets/minecraft/minecraft/README.md b/projects/1.18/assets/minecraft/minecraft/README.md new file mode 100644 index 000000000000..fe6f7088b363 --- /dev/null +++ b/projects/1.18/assets/minecraft/minecraft/README.md @@ -0,0 +1,14 @@ +## 概述 + +该命名空间存放了用于`Minecraft-Mod-Language-Package`汉化资源包的字体修正包。内容主要包括: +- 基于1.16+对拓展区的支持,直接实现**元素符号**正常显示。 +- 全面调整了**各类标点符号**的宽度。 +- 针对**省略号**、**破折号**的显示做了特别优化: + - **省略号**现在可以*模拟*等距点——虽说不是完美等距,但看起来差不多。 + - 单个**破折号**在显示时可以*连起来*了。 + +### 加载结构参考 + +- `direct`
1.18特定的字体描述文件;此文件在1.16->1.18的更新中有所改动。 +- `indirect`@`projects/1.16/assets/minecraft/minecraft`
引用[1.16处的字体修正包](../../../../1.16/assets/minecraft/minecraft/README.md),以获取字体资源。 + - **合并行为**:所有的字体描述文件都会被上一步完全覆盖。 \ No newline at end of file diff --git a/projects/1.19/assets/minecraft/minecraft/README.md b/projects/1.19/assets/minecraft/minecraft/README.md new file mode 100644 index 000000000000..3b06e555b954 --- /dev/null +++ b/projects/1.19/assets/minecraft/minecraft/README.md @@ -0,0 +1,14 @@ +## 概述 + +该命名空间存放了用于`Minecraft-Mod-Language-Package`汉化资源包的字体修正包。内容主要包括: +- 基于1.16+对拓展区的支持,直接实现**元素符号**正常显示。 +- 全面调整了**各类标点符号**的宽度。 +- 针对**省略号**、**破折号**的显示做了特别优化: + - **省略号**现在可以*模拟*等距点——虽说不是完美等距,但看起来差不多。 + - 单个**破折号**在显示时可以*连起来*了。 + +### 加载结构参考 + +- `direct`
1.19特定的字体描述文件;此文件在1.16->1.19的更新中有所改动。 +- `indirect`@`projects/1.16/assets/minecraft/minecraft`
引用[1.16处的字体修正包](../../../../1.16/assets/minecraft/minecraft/README.md),以获取字体资源。 + - **合并行为**:所有的字体描述文件都会被上一步完全覆盖。 \ No newline at end of file diff --git a/projects/1.20-fabric/assets/minecraft/minecraft/README.md b/projects/1.20-fabric/assets/minecraft/minecraft/README.md new file mode 100644 index 000000000000..7fe26b054f14 --- /dev/null +++ b/projects/1.20-fabric/assets/minecraft/minecraft/README.md @@ -0,0 +1,12 @@ +## 概述 + +该命名空间存放了用于`Minecraft-Mod-Language-Package`汉化资源包的字体修正包。内容主要包括: +- 基于1.16+对拓展区的支持,直接实现**元素符号**正常显示。 +- 全面调整了**各类标点符号**的宽度。 +- 针对**省略号**、**破折号**的显示做了特别优化: + - **省略号**现在可以*模拟*等距点——虽说不是完美等距,但看起来差不多。 + - 单个**破折号**在显示时可以*连起来*了。 + +### 局部配置参考 + +- `indirect`@`projects/1.20/assets/minecraft/minecraft`
直接引用了[1.20处的字体修正包](../../../../1.20/assets/minecraft/minecraft/README.md)。 \ No newline at end of file diff --git a/projects/1.20/assets/minecraft/minecraft/README.md b/projects/1.20/assets/minecraft/minecraft/README.md new file mode 100644 index 000000000000..1b9f8873eb35 --- /dev/null +++ b/projects/1.20/assets/minecraft/minecraft/README.md @@ -0,0 +1,19 @@ +## 概述 + +该命名空间存放了用于`Minecraft-Mod-Language-Package`汉化资源包的字体修正包。内容主要包括: +- 基于1.16+对拓展区的支持,直接实现**元素符号**正常显示。 +- 全面调整了**各类标点符号**的宽度。 +- 针对**省略号**、**破折号**的显示做了特别优化: + - **省略号**现在可以*模拟*等距点——虽说不是完美等距,但看起来差不多。 + - 单个**破折号**在显示时可以*连起来*了。 + +--- + +1.20版本中,由于Minecraft全面修改了使用的Unifont字体,**标点符号宽度**部分的大多内容已经不需要了。尽管如此,引用时仍然引用了整张贴图,因为懒得裁剪了。 +尽管1.20**名义上**提供了原生的**元素符号**支持,但实测表明,提供的字形*存在严重*偏移,看着非常不顺眼,故元素符号替换仍然保留。 + +### 加载结构参考 + +- `direct`
1.18特定的字体描述文件;此文件在1.16->1.18的更新中有所改动。 +- `indirect`@`projects/1.16/assets/minecraft/minecraft`
引用[1.16处的字体修正包](../../../../1.16/assets/minecraft/minecraft/README.md),以获取字体资源。 + - **合并行为**:所有的字体描述文件都会被上一步完全覆盖。 \ No newline at end of file diff --git a/projects/1.20/assets/minecraft/minecraft/font/include/cjk-punctuations.json b/projects/1.20/assets/minecraft/minecraft/font/include/cjk-punctuations.json index 8a18537c968a..b382b75d54b1 100644 --- a/projects/1.20/assets/minecraft/minecraft/font/include/cjk-punctuations.json +++ b/projects/1.20/assets/minecraft/minecraft/font/include/cjk-punctuations.json @@ -1,12 +1,35 @@ { "providers":[ + { + "type":"bitmap", + "file": "minecraft:font/element_ideographs.png", + "ascent": 7, + "chars": [ + "\ud872\udf3b\ud872\udf4a\ud872\udf73\ud872\udf5b\ud872\udf76\u9fcf\ud86d\udffc", + "\ud872\udf2d\u9fd4\ud86d\udce7\ud86d\udff7\u9feb\u9fec\u9fed" + ] + }, { "type":"bitmap", "file": "minecraft:font/cjk_punctuations.png", "ascent": 7, "chars": [ - "\u3001\u3002\u300a\u300b\u3010\u3011\u2018\u2019\u201c\u0000\u3008\u3009\u0000\u0000\u0000\u0000", - "\u201d\uff01\uff08\uff09\uff0c\uff1a\uff1b\uff1f\u2014\u00b7\u0000\u0000\u0000\u0000\u0000\u0000" + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\uff0b\u0000\u0000\u0000\u0000", + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\uff5f", + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", + "\u0000\u0000\u3012\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", + "\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u0000\u0000\u0000\u0000\u0000", + "\u0000\u0000\u0000\u0000\u2014\u0000\u0000\u0000\u2018\u2019\u0000\u0000\u201c\u201d\u0000\u0000", + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u00b7" ] }, { diff --git a/projects/1.20/assets/minecraft/minecraft/packer-policy.json b/projects/1.20/assets/minecraft/minecraft/packer-policy.json new file mode 100644 index 000000000000..9e4e33dd9895 --- /dev/null +++ b/projects/1.20/assets/minecraft/minecraft/packer-policy.json @@ -0,0 +1,9 @@ +[ + { + "type": "direct" + }, + { + "type": "indirect", + "source": "projects/1.16/assets/minecraft/minecraft" + } +] \ No newline at end of file diff --git a/projects/1.20/assets/minecraft/minecraft/readme.md b/projects/1.20/assets/minecraft/minecraft/readme.md deleted file mode 100644 index 019ec9e42ef4..000000000000 --- a/projects/1.20/assets/minecraft/minecraft/readme.md +++ /dev/null @@ -1,24 +0,0 @@ -# 全角字符修正与特殊字符补充 -- 本包添加了几个特殊字符字体,用于补充部分新确定的元素名称 -- 本包修正了中文全角字符的宽度和位置问题。 - -## 本包建议翻译文本采用左侧书写,在打包阶段使用脚本转换成右侧字符 - -| 翻译文本 | 转换字符 | 备注 | -| :------: | :------------: | :----------------------------------: | -| [[钅卢]] | `\ue900` | | -| [[钅杜]] | `\ue901` | | -| [[钅喜]] | `\ue902` | | -| [[钅波]] | `\ue903` | | -| [[钅黑]] | `\ue904` | | -| [[钅麦]] | `\u9fcf` | | -| [[钅达]] | `\ue906` | | -| [[钅仑]] | `\ue907` | | -| [[钅哥]] | `\u9fd4` | | -| [[钅尔]] | `\u9fed` | | -| [[钅夫]] | `\ue90a` | | -| 镆 | `\u9546` | 此元素名已存在对应字符,无需修改替换 | -| [[钅立]] | `\ue90c` | | -| [[石田]] | `\u9fec` | | -| [[奥气]] | `\u9feb` | | -| …… | `\ue908\ue909` | 全角省略号的修改 | \ No newline at end of file diff --git a/projects/1.20/assets/minecraft/minecraft/textures/font/2em_dash.png b/projects/1.20/assets/minecraft/minecraft/textures/font/2em_dash.png deleted file mode 100644 index e8291ce5ab02b1c27575af310e60ba5fce84d609..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2829 zcmV+o3-a`dP)KLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z06IxTK~#9!?9s6e03Zy+zz?E@{kJt6&?bdF!AUOQq`8#=i4ZXoQ2^bDo#eVhga{Fz f9smFU|NjF3p~nX`ac_7%00000NkvXXu0mjfPikIH diff --git a/projects/1.20/assets/minecraft/minecraft/textures/font/cjk_punctuations.png b/projects/1.20/assets/minecraft/minecraft/textures/font/cjk_punctuations.png deleted file mode 100644 index 7ad25d1665c0b495cb66debcce5793e9f135cae7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3275 zcmV;+3^enJP)KLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z0r*KoK~#9!?3_`q!XOYu)%g2n|LdF$^!+wOD-6sq&~p+Kqg4zrmwU18^Ei&b2LRlX z*J8g{8=sGCw|rQR0spxG8w)@dr1CZIiT_Q6BHGo-#Vf)0YCz`qCwFJHgy0kt9pxD zfS7nvIs&Vm_l^xX0DuVs;gRVneuD!Tk(azqM5%EB5v#urItKhQJ;iSn0O>4XE$kjZ zv5Xjqic42vGb31fVCYogKvP1ECauDiNUgjXb#=7yt*b`s&Ln z43IzoG@$so805NtxE}#j^DYXv=j<&dk4-OrX%tMr0emcUS!9Ca0k6-xCz6WqNxMM{nvLhCvG4B&_B^7xcDhf z1OOndAVSa{K=uJ|&GbYOfC&Py`hU*5oI!{9LAU_uCL%CXKsbdLmK6X=5(9ed|1K*h zA_80O0Ynx~@4f3JLH`i}V2S`lWLtGE;FSdkpoxC~009600|2_Yomcs9WKIA8002ov JPDHLkV1gIaCsqIe diff --git a/projects/1.20/assets/minecraft/minecraft/textures/font/ellipsis.png b/projects/1.20/assets/minecraft/minecraft/textures/font/ellipsis.png deleted file mode 100644 index 70a21a0b5e077b47e5379817048b33ade3d7c8ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2843 zcmV+$3*_{PP)KLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z07ywhK~#9!?AEaj03ZkeL9loKJzW4B2Qaa~;y$6HxKNQ*HKVZ+%>e)a0001d30P-t tdfsinKzc|3000000J;Gi009600{|g53;#YOj(z|D002ovPDHLkV1g8uUnc+n diff --git a/src/Packer/Models/IResourceFileProvider.cs b/src/Packer/Models/IResourceFileProvider.cs index ef010b6aaca4..521c0470c939 100644 --- a/src/Packer/Models/IResourceFileProvider.cs +++ b/src/Packer/Models/IResourceFileProvider.cs @@ -60,6 +60,7 @@ public IResourceFileProvider ReplaceContent(string searchPattern, string replace ///
public readonly struct ApplyOptions { + // CS8983 具有字段初始值设定项的“结构”必须包含显式声明的构造函数。 #pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释 public ApplyOptions(bool modifyOnly, bool append) { diff --git a/src/Packer/Models/Providers/McMetaProvider.cs b/src/Packer/Models/Providers/McMetaProvider.cs index a0616ebec22d..0ad3431f2f4a 100644 --- a/src/Packer/Models/Providers/McMetaProvider.cs +++ b/src/Packer/Models/Providers/McMetaProvider.cs @@ -40,7 +40,7 @@ public override IResourceFileProvider ReplaceDestination(string searchPattern, s public override async Task WriteToArchive(ZipArchive archive) { var destination = Destination.NormalizePath(); - Log.Information("正在添加 {0}", destination); + Log.Debug("[McMetaProvider]写入路径 {0}", destination); var content = string.Format(Content, DateTime.UtcNow.AddHours(8) /* UTC +8:00 */); diff --git a/src/Packer/Models/Providers/RawFile.cs b/src/Packer/Models/Providers/RawFile.cs index 101fcf8bfac5..1c282d7242d2 100644 --- a/src/Packer/Models/Providers/RawFile.cs +++ b/src/Packer/Models/Providers/RawFile.cs @@ -47,7 +47,7 @@ public IResourceFileProvider ReplaceDestination(string searchPattern, string rep public async Task WriteToArchive(ZipArchive archive) { var destination = Destination.NormalizePath(); - Log.Information("正在添加 {0}", destination); + Log.Debug("[RawFile]写入路径 {0}", destination); archive.ValidateEntryDistinctness(destination); diff --git a/src/Packer/Models/Providers/TermMappingProvider.cs b/src/Packer/Models/Providers/TermMappingProvider.cs index 41973f6bdeb8..089547f70342 100644 --- a/src/Packer/Models/Providers/TermMappingProvider.cs +++ b/src/Packer/Models/Providers/TermMappingProvider.cs @@ -193,7 +193,7 @@ public IResourceFileProvider ReplaceDestination(string searchPattern, string rep public async Task WriteToArchive(ZipArchive archive) { var destination = Destination.NormalizePath(); - Log.Information("正在添加 {0}", destination); + Log.Debug("[TermMappingProvider`1]写入路径 {0}", destination); archive.ValidateEntryDistinctness(destination); @@ -240,11 +240,11 @@ internal static Dictionary DeserializeFromLang(string content) { if (line.EndsWith("\\")) { - pendingValue += line[..^1].ToString(); + pendingValue += line.TrimStart()[..^1].ToString(); } else { - pendingValue += ("\\n" + line.ToString()); + pendingValue += line.TrimStart().ToString(); result.TryAdd(pendingKey, pendingValue); isLineContinuation = false; } diff --git a/src/Packer/Models/Providers/TextFile.cs b/src/Packer/Models/Providers/TextFile.cs index f24ef147ee63..61c329189ac2 100644 --- a/src/Packer/Models/Providers/TextFile.cs +++ b/src/Packer/Models/Providers/TextFile.cs @@ -82,7 +82,7 @@ public virtual IResourceFileProvider ReplaceDestination(string searchPattern, st public virtual async Task WriteToArchive(ZipArchive archive) { var destination = Destination.NormalizePath(); - Log.Information("正在添加 {0}", destination); + Log.Debug("[TextFile]写入路径 {0}", destination); archive.ValidateEntryDistinctness(destination); diff --git a/src/Packer/Program.cs b/src/Packer/Program.cs index 367111587bb7..e327eb8ee3ac 100644 --- a/src/Packer/Program.cs +++ b/src/Packer/Program.cs @@ -29,17 +29,19 @@ public static async Task Main(string version, bool increment = false) var targetModIdentifiers = increment ? GitHelpers.EnumerateChangedMods(config.Base.Version) : Enumerable.Empty(); - var query = // 这就是查询表达式吗( + var query = // 在这里加日志似乎开销太大了。暂时注释掉 from modDirectory in new DirectoryInfo($"./projects/{config.Base.Version}/assets") .EnumerateDirectories() let modIdentifier = modDirectory.Name + //.LogToDebug("[Enumerable]当前模组:{0}") where targetModIdentifiers.Count() == 0 // 未提供列表,全部打包 || targetModIdentifiers.Contains(modIdentifier) // 有列表,仅打包列表中的项 where !config.Base.ExclusionMods.Contains(modIdentifier) // 没有被明确排除 from namespaceDirectory in modDirectory.EnumerateDirectories() let namespaceName = namespaceDirectory.Name where !config.Base.ExclusionNamespaces.Contains(namespaceName) // 没有被明确排除 - where namespaceName.ValidateNamespace() // 不是非法名称 + where namespaceName/*.LogToDebug("[Enumerable]当前命名空间:{0}")*/ + .ValidateNamespace() // 不是非法名称 from provider in namespaceDirectory.EnumerateProviders(config) group provider by provider.Destination into destinationGroup select destinationGroup @@ -73,9 +75,8 @@ select config.Floating.DestinationReplacement // 全局路 { await Task.WhenAll(from provider in query.Concat(initialsQuery) select provider.WriteToArchive(archive)); - - } + Log.Information("对版本 {0} 的打包结束。", version); var md5 = stream.ComputeMD5(); From 197ddf7a983d31d0c9a8c03cd1b22f77d6994f51 Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sat, 25 Nov 2023 21:33:40 +0800 Subject: [PATCH 17/22] patch fail-on-cache-miss --- .github/workflows/packer.yml | 3 ++- .github/workflows/pr-packer.yml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/packer.yml b/.github/workflows/packer.yml index 8d281598a51e..86455bf64f40 100644 --- a/.github/workflows/packer.yml +++ b/.github/workflows/packer.yml @@ -108,7 +108,8 @@ jobs: # 由于Github的限制,这里需要重新拉取打包程序。 - name: Restore Packer id: cache-restore - uses: actions/cache/restore@v3 + # https://github.com/actions/cache/issues/1265#issuecomment-1819612829 `fail-on-cache-miss` for restore action not failing the workflow + uses: actions/cache/restore@v3.3.1 with: key: ${{ runner.os }}-Packer-${{ hashFiles('source/Packer/**') }} path: | diff --git a/.github/workflows/pr-packer.yml b/.github/workflows/pr-packer.yml index d9f855c6c172..6d28d01c08fa 100644 --- a/.github/workflows/pr-packer.yml +++ b/.github/workflows/pr-packer.yml @@ -60,7 +60,8 @@ jobs: # 由于Github的限制,这里需要重新拉取打包程序。 - name: Restore Packer id: cache-restore - uses: actions/cache/restore@v3 + # https://github.com/actions/cache/issues/1265#issuecomment-1819612829 `fail-on-cache-miss` for restore action not failing the workflow + uses: actions/cache/restore@v3.3.1 with: key: ${{ runner.os }}-Packer-${{ hashFiles('src/Packer/**') }} path: | From bf5f573a105dce7cfc82275acef7cd049946fced Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sun, 3 Dec 2023 14:06:03 +0800 Subject: [PATCH 18/22] Update Matrix Logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现在,(如果我没写错的话)一个版本崩溃不会炸掉所有版本了。 此外,根据反馈,恢复了chinjufu里的大括号;不过打包文件里的括号可能留不下来了。 --- .github/workflows/packer.yml | 1 + .github/workflows/pr-packer.yml | 1 + src/Packer/Models/Providers/TermMappingProvider.cs | 10 ++++++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/packer.yml b/.github/workflows/packer.yml index 86455bf64f40..0bd2800a9468 100644 --- a/.github/workflows/packer.yml +++ b/.github/workflows/packer.yml @@ -95,6 +95,7 @@ jobs: name: Pack Resources and Upload Artifacts/Releases needs: [ build-packer, initialize-release ] # 显然,需要存在打包程序,才能打包。 strategy: + fail-fast: false # 把正常的文件先打包了,避免一处错误阻塞整个仓库。 matrix: # 版本列表。将对这里的每个版本判断,按需打包。 # 如需添加新版本,在这里添加即可。 diff --git a/.github/workflows/pr-packer.yml b/.github/workflows/pr-packer.yml index 6d28d01c08fa..ac766ab98fe6 100644 --- a/.github/workflows/pr-packer.yml +++ b/.github/workflows/pr-packer.yml @@ -46,6 +46,7 @@ jobs: name: Pack Resources and Upload Artifacts needs: build # 显然,需要存在缓存/已经构造,才能打包。 strategy: + fail-fast: false # 某版本失败其实不影响其他版本。 matrix: # 支持版本列表。将对这里的每个版本判断,按需打包。 # 如需添加新版本,在这里添加即可。 diff --git a/src/Packer/Models/Providers/TermMappingProvider.cs b/src/Packer/Models/Providers/TermMappingProvider.cs index 089547f70342..d55750db8c49 100644 --- a/src/Packer/Models/Providers/TermMappingProvider.cs +++ b/src/Packer/Models/Providers/TermMappingProvider.cs @@ -236,7 +236,7 @@ internal static Dictionary DeserializeFromLang(string content) foreach (var line in content.AsSpan().EnumerateLines()) { - if (isLineContinuation) // 行尾转义符,用于换行 + if (isLineContinuation) // 行尾转义符,用于换行;在PARSE_ESCAPE下使用 { if (line.EndsWith("\\")) { @@ -251,6 +251,7 @@ internal static Dictionary DeserializeFromLang(string content) continue; } + // PARSE_ESCAPES支持 if (!isParseEscape && line.Equals("#PARSE_ESCAPES", StringComparison.Ordinal)) { isParseEscape = true; @@ -265,7 +266,7 @@ internal static Dictionary DeserializeFromLang(string content) continue; } - if (line.StartsWith("//") | line.StartsWith("#") | line.StartsWith("<")) + if (line.StartsWith("//") || line.StartsWith("#") || line.StartsWith("<")) continue; if (line.StartsWith("/*")) @@ -277,6 +278,11 @@ internal static Dictionary DeserializeFromLang(string content) if (line.IsEmpty || line.IsWhiteSpace()) // 空行需去 continue; + // 1.12/assets/chinjufumod + // https://github.com/CFPAOrg/Minecraft-Mod-Language-Package/pull/3875#issuecomment-1826453830 + if (line.Equals("{", StringComparison.Ordinal) || line.Equals("}", StringComparison.Ordinal)) + continue; + // 基础条目 var splitPosition = line.IndexOf('='); From 1d370689ff085c033e35340c307e163a85ecf078 Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sun, 3 Dec 2023 14:19:51 +0800 Subject: [PATCH 19/22] Fix Policies --- .../shield-expansion/shieldexp/packer-policy.json | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/projects/1.20/assets/shield-expansion/shieldexp/packer-policy.json b/projects/1.20/assets/shield-expansion/shieldexp/packer-policy.json index 85161b17e85f..0521033b4c42 100644 --- a/projects/1.20/assets/shield-expansion/shieldexp/packer-policy.json +++ b/projects/1.20/assets/shield-expansion/shieldexp/packer-policy.json @@ -1,4 +1,6 @@ -{ - "type": "plainclone", - "source": "./projects/1.18/assets/shield-expansion/shieldexp" -} \ No newline at end of file +[ + { + "type": "indirect", + "source": "projects/1.18/assets/shield-expansion/shieldexp" + } +] \ No newline at end of file From 99111cd47938577b3bfcb73e3986d1f7115b4ee3 Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sat, 9 Dec 2023 21:21:55 +0800 Subject: [PATCH 20/22] Fix 2-EM Hyphen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 天,我怎么写成2e3f的... --- config/packer/1.16-fabric.json | 2 +- config/packer/1.16.json | 2 +- config/packer/1.18-fabric.json | 2 +- config/packer/1.18.json | 2 +- config/packer/1.19.json | 2 +- config/packer/1.20-fabric.json | 2 +- config/packer/1.20.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/config/packer/1.16-fabric.json b/config/packer/1.16-fabric.json index c1f8a3827dde..476edd0b5683 100644 --- a/config/packer/1.16-fabric.json +++ b/config/packer/1.16-fabric.json @@ -36,7 +36,7 @@ "[[奥气]]": "\u9feb", "[[气奥]]": "\u9feb", "……": "\u22ef\u22ef", - "——": "\u2e3f" + "——": "\u2e3a" }, "destinationReplacement": {} } diff --git a/config/packer/1.16.json b/config/packer/1.16.json index f77f0fde502a..e71705732551 100644 --- a/config/packer/1.16.json +++ b/config/packer/1.16.json @@ -36,7 +36,7 @@ "[[奥气]]": "\u9feb", "[[气奥]]": "\u9feb", "……": "\u22ef\u22ef", - "——": "\u2e3f" + "——": "\u2e3a" }, "destinationReplacement": {} } diff --git a/config/packer/1.18-fabric.json b/config/packer/1.18-fabric.json index 1888fc66019a..bd7fc0730a79 100644 --- a/config/packer/1.18-fabric.json +++ b/config/packer/1.18-fabric.json @@ -38,7 +38,7 @@ "[[奥气]]": "\u9feb", "[[气奥]]": "\u9feb", "……": "\u22ef\u22ef", - "——": "\u2e3f" + "——": "\u2e3a" }, "destinationReplacement": {} } diff --git a/config/packer/1.18.json b/config/packer/1.18.json index 18825996a081..e5c20b2d2888 100644 --- a/config/packer/1.18.json +++ b/config/packer/1.18.json @@ -41,7 +41,7 @@ "[[奥气]]": "\u9feb", "[[气奥]]": "\u9feb", "……": "\u22ef\u22ef", - "——": "\u2e3f" + "——": "\u2e3a" }, "destinationReplacement": {} } diff --git a/config/packer/1.19.json b/config/packer/1.19.json index 169a88a228c8..7b2dda7100f2 100644 --- a/config/packer/1.19.json +++ b/config/packer/1.19.json @@ -36,7 +36,7 @@ "[[奥气]]": "\u9feb", "[[气奥]]": "\u9feb", "……": "\u22ef\u22ef", - "——": "\u2e3f" + "——": "\u2e3a" }, "destinationReplacement": {} } diff --git a/config/packer/1.20-fabric.json b/config/packer/1.20-fabric.json index 22c6f035d630..34ebfb7220ec 100644 --- a/config/packer/1.20-fabric.json +++ b/config/packer/1.20-fabric.json @@ -36,7 +36,7 @@ "[[奥气]]": "\u9feb", "[[气奥]]": "\u9feb", "……": "\u22ef\u22ef", - "——": "\u2e3f" + "——": "\u2e3a" }, "destinationReplacement": {} } diff --git a/config/packer/1.20.json b/config/packer/1.20.json index 2a8d9c75219c..dee478bbb627 100644 --- a/config/packer/1.20.json +++ b/config/packer/1.20.json @@ -36,7 +36,7 @@ "[[奥气]]": "\u9feb", "[[气奥]]": "\u9feb", "……": "\u22ef\u22ef", - "——": "\u2e3f" + "——": "\u2e3a" }, "destinationReplacement": {} } From abd13f7cc20a3de3789e8e77fdcf8b1d878c3ae2 Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sat, 9 Dec 2023 21:23:19 +0800 Subject: [PATCH 21/22] Update projects/1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json Co-authored-by: Cactus_student <97865546+Cactusstudent@users.noreply.github.com> --- .../1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json b/projects/1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json index 6496e10d5ff2..b8ee28a5d50d 100644 --- a/projects/1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json +++ b/projects/1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json @@ -4,7 +4,7 @@ "item.morecrossbows.golden_crossbow": "金弩", "item.morecrossbows.emerald_crossbow": "绿宝石弩", "item.morecrossbows.diamond_crossbow": "钻石弩", - "item.morecrossbows。netherite_crossbow": "下界合金弩", + "item.morecrossbows.netherite_crossbow": "下界合金弩", "item.morecrossbows.gilded_netherite_crossbow": "镀金下界合金弩", "item.morecrossbows.enderite_crossbow": "末影合金弩", "item.morecrossbows.gilded_enderite_crossbow": "镀金末影合金弩", From e02f99df39b2d95ffddfdfbd08fa730de9f657d0 Mon Sep 17 00:00:00 2001 From: dovisutu <40313014+dovisutu@users.noreply.github.com> Date: Sat, 9 Dec 2023 21:23:29 +0800 Subject: [PATCH 22/22] Update projects/1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json Co-authored-by: Cactus_student <97865546+Cactusstudent@users.noreply.github.com> --- .../assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json b/projects/1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json index b8ee28a5d50d..4aa74e7a981a 100644 --- a/projects/1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json +++ b/projects/1.20/assets/more-crossbows-cj/morecrossbows/lang/zh_cn.json @@ -1,6 +1,6 @@ { - "item。morecrossbows.copper_crossbow": "铜弩", - "item。morecrossbows.iron_crossbow": "铁弩", + "item.morecrossbows.copper_crossbow": "铜弩", + "item.morecrossbows.iron_crossbow": "铁弩", "item.morecrossbows.golden_crossbow": "金弩", "item.morecrossbows.emerald_crossbow": "绿宝石弩", "item.morecrossbows.diamond_crossbow": "钻石弩",