├── .clang-format ├── .clang-tidy ├── .clangd ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── feature_request.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── build.yml │ ├── release.yml │ └── test_build.yml ├── CHANGELOG.md ├── COPYING ├── COPYING.LESSER ├── README.md ├── manifest.json ├── src ├── more_dimensions │ ├── MemoryOperators.cpp │ ├── MoreDimenison.cpp │ ├── MoreDimenison.h │ ├── api │ │ └── dimension │ │ │ ├── CustomDimensionManager.cpp │ │ │ ├── CustomDimensionManager.h │ │ │ ├── SimpleCustomDimension.cpp │ │ │ └── SimpleCustomDimension.h │ └── core │ │ ├── Macros.h │ │ └── dimension │ │ ├── CustomDimensionConfig.cpp │ │ ├── CustomDimensionConfig.h │ │ ├── FakeDimensionId.cpp │ │ ├── FakeDimensionId.h │ │ └── MoreDimensionsPatch.h └── test │ ├── TestCustomDimension.cpp │ ├── generator │ ├── flat-gen-village │ │ ├── FlatVillageDimension.cpp │ │ ├── FlatVillageDimension.h │ │ ├── FlatVillageGenerator.cpp │ │ └── FlatVillageGenerator.h │ ├── generator-custom-structure │ │ ├── CustomStructure.cpp │ │ ├── CustomStructure.h │ │ ├── README.md │ │ ├── dimension │ │ │ ├── CustomStructureDimension.cpp │ │ │ └── CustomStructureDimension.h │ │ ├── generator │ │ │ ├── CustomStructureGenerator.cpp │ │ │ └── CustomStructureGenerator.h │ │ ├── structure-files │ │ │ ├── README.md │ │ │ └── custom │ │ │ │ ├── 21room.mcstructure │ │ │ │ ├── beds5x5int.mcstructure │ │ │ │ ├── chestcarpet5x5int.mcstructure │ │ │ │ ├── ewcap.mcstructure │ │ │ │ ├── ewhall.mcstructure │ │ │ │ ├── kitchen5x5int.mcstructure │ │ │ │ ├── nbt │ │ │ │ ├── back_bridge_bottom.nbt │ │ │ │ ├── back_bridge_top.nbt │ │ │ │ └── bridge.nbt │ │ │ │ ├── nscap.mcstructure │ │ │ │ └── nshall.mcstructure │ │ └── structure │ │ │ ├── CustomStructureFeature.cpp │ │ │ ├── CustomStructureFeature.h │ │ │ ├── CustomStructurePiece.cpp │ │ │ ├── CustomStructurePiece.h │ │ │ ├── CustomStructureStart.cpp │ │ │ └── CustomStructureStart.h │ └── generator-terrain │ │ ├── NxnBorderTerrainDimension.cpp │ │ ├── NxnBorderTerrainDimension.h │ │ ├── NxnBorderTerrainGenerator.cpp │ │ └── NxnBorderTerrainGenerator.h │ └── mc │ ├── FixedBiomeSource.h │ ├── JigsawJunction.h │ ├── JigsawPlacement.h │ ├── PoolAliasBinding.h │ ├── PoolElementStructurePiece.h │ ├── StructurePiece.h │ ├── StructurePoolBlockPredicateBlockMatchRandom.h │ ├── StructurePoolBlockRule.h │ ├── StructureTemplatePool.h │ ├── StructureTemplateRegistrationContext.h │ └── WeightedStructureTemplateRegistration.h ├── tooth.json └── xmake.lua /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | AccessModifierOffset: -4 3 | AlignAfterOpenBracket: BlockIndent 4 | AlignArrayOfStructures: Left 5 | AlignConsecutiveDeclarations: 6 | Enabled: true 7 | AcrossEmptyLines: false 8 | AcrossComments: false 9 | AlignConsecutiveAssignments: 10 | Enabled: true 11 | AcrossEmptyLines: false 12 | AcrossComments: false 13 | AlignCompound: true 14 | PadOperators: true 15 | AlignConsecutiveMacros: 16 | Enabled: true 17 | AcrossEmptyLines: false 18 | AcrossComments: false 19 | AllowAllParametersOfDeclarationOnNextLine: false 20 | AllowAllArgumentsOnNextLine: false 21 | AlignOperands: AlignAfterOperator 22 | AlignConsecutiveBitFields: 23 | Enabled: true 24 | AcrossEmptyLines: false 25 | AcrossComments: false 26 | AllowShortLambdasOnASingleLine: All 27 | AllowShortBlocksOnASingleLine: Empty 28 | AllowShortIfStatementsOnASingleLine: AllIfsAndElse 29 | AllowShortLoopsOnASingleLine: true 30 | AlwaysBreakAfterDefinitionReturnType: None 31 | AlwaysBreakTemplateDeclarations: "Yes" 32 | BinPackArguments: false 33 | BinPackParameters: false 34 | BreakBeforeBraces: Custom 35 | BreakBeforeBinaryOperators: NonAssignment 36 | ColumnLimit: 120 37 | CommentPragmas: "^ IWYU pragma:" 38 | ConstructorInitializerIndentWidth: 0 39 | IndentWidth: 4 40 | Language: Cpp 41 | MaxEmptyLinesToKeep: 2 42 | PackConstructorInitializers: CurrentLine 43 | PointerAlignment: Left 44 | TabWidth: 4 45 | UseTab: Never 46 | SortIncludes: CaseSensitive 47 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | --- 2 | Checks: '-*, 3 | bugprone-argument-comment, 4 | bugprone-assert-side-effect, 5 | bugprone-bad-signal-to-kill-thread, 6 | bugprone-branch-clone, 7 | bugprone-copy-constructor-init, 8 | bugprone-dangling-handle, 9 | bugprone-dynamic-static-initializers, 10 | bugprone-fold-init-type, 11 | bugprone-forward-declaration-namespace, 12 | bugprone-forwarding-reference-overload, 13 | bugprone-inaccurate-erase, 14 | bugprone-incorrect-roundings, 15 | bugprone-integer-division, 16 | bugprone-lambda-function-name, 17 | bugprone-macro-parentheses, 18 | bugprone-macro-repeated-side-effects, 19 | bugprone-misplaced-operator-in-strlen-in-alloc, 20 | bugprone-misplaced-pointer-arithmetic-in-alloc, 21 | bugprone-misplaced-widening-cast, 22 | bugprone-move-forwarding-reference, 23 | bugprone-multiple-statement-macro, 24 | bugprone-no-escape, 25 | bugprone-not-null-terminated-result, 26 | bugprone-parent-virtual-call, 27 | bugprone-posix-return, 28 | bugprone-reserved-identifier, 29 | bugprone-sizeof-container, 30 | bugprone-sizeof-expression, 31 | bugprone-spuriously-wake-up-functions, 32 | bugprone-string-constructor, 33 | bugprone-string-integer-assignment, 34 | bugprone-string-literal-with-embedded-nul, 35 | bugprone-suspicious-enum-usage, 36 | bugprone-suspicious-include, 37 | bugprone-suspicious-memory-comparison, 38 | bugprone-suspicious-memset-usage, 39 | bugprone-suspicious-missing-comma, 40 | bugprone-suspicious-semicolon, 41 | bugprone-suspicious-string-compare, 42 | bugprone-swapped-arguments, 43 | bugprone-terminating-continue, 44 | bugprone-throw-keyword-missing, 45 | bugprone-too-small-loop-variable, 46 | bugprone-undefined-memory-manipulation, 47 | bugprone-undelegated-constructor, 48 | bugprone-unhandled-self-assignment, 49 | bugprone-unused-raii, 50 | bugprone-unused-return-value, 51 | bugprone-use-after-move, 52 | bugprone-virtual-near-miss, 53 | cert-dcl21-cpp, 54 | cert-dcl58-cpp, 55 | cert-err34-c, 56 | cert-err52-cpp, 57 | cert-err60-cpp, 58 | cert-flp30-c, 59 | cert-msc50-cpp, 60 | cert-msc51-cpp, 61 | cert-str34-c, 62 | cppcoreguidelines-interfaces-global-init, 63 | cppcoreguidelines-narrowing-conversions, 64 | cppcoreguidelines-pro-type-member-init, 65 | cppcoreguidelines-slicing, 66 | google-default-arguments, 67 | google-explicit-constructor, 68 | google-runtime-operator, 69 | hicpp-exception-baseclass, 70 | hicpp-multiway-paths-covered, 71 | misc-misplaced-const, 72 | misc-new-delete-overloads, 73 | misc-non-copyable-objects, 74 | misc-throw-by-value-catch-by-reference, 75 | misc-unconventional-assign-operator, 76 | misc-uniqueptr-reset-release, 77 | modernize-avoid-bind, 78 | modernize-concat-nested-namespaces, 79 | modernize-deprecated-headers, 80 | modernize-deprecated-ios-base-aliases, 81 | modernize-loop-convert, 82 | modernize-make-shared, 83 | modernize-make-unique, 84 | modernize-pass-by-value, 85 | modernize-raw-string-literal, 86 | modernize-redundant-void-arg, 87 | modernize-replace-auto-ptr, 88 | modernize-replace-disallow-copy-and-assign-macro, 89 | modernize-replace-random-shuffle, 90 | modernize-return-braced-init-list, 91 | modernize-shrink-to-fit, 92 | modernize-unary-static-assert, 93 | modernize-use-auto, 94 | modernize-use-bool-literals, 95 | modernize-use-emplace, 96 | modernize-use-equals-default, 97 | modernize-use-equals-delete, 98 | modernize-use-nodiscard, 99 | modernize-use-noexcept, 100 | modernize-use-nullptr, 101 | modernize-use-override, 102 | modernize-use-transparent-functors, 103 | modernize-use-uncaught-exceptions, 104 | mpi-buffer-deref, 105 | mpi-type-mismatch, 106 | openmp-use-default-none, 107 | performance-faster-string-find, 108 | performance-for-range-copy, 109 | performance-implicit-conversion-in-loop, 110 | performance-inefficient-algorithm, 111 | performance-inefficient-string-concatenation, 112 | performance-inefficient-vector-operation, 113 | performance-move-const-arg, 114 | performance-move-constructor-init, 115 | performance-no-automatic-move, 116 | performance-noexcept-move-constructor, 117 | performance-trivially-destructible, 118 | performance-type-promotion-in-math-fn, 119 | performance-unnecessary-copy-initialization, 120 | performance-unnecessary-value-param, 121 | portability-simd-intrinsics, 122 | readability-avoid-const-params-in-decls, 123 | readability-const-return-type, 124 | readability-container-size-empty, 125 | readability-delete-null-pointer, 126 | readability-deleted-default, 127 | readability-inconsistent-declaration-parameter-name, 128 | readability-make-member-function-const, 129 | readability-misleading-indentation, 130 | readability-misplaced-array-index, 131 | readability-non-const-parameter, 132 | readability-redundant-control-flow, 133 | readability-redundant-declaration, 134 | readability-redundant-function-ptr-dereference, 135 | readability-redundant-smartptr-get, 136 | readability-redundant-string-cstr, 137 | readability-redundant-string-init, 138 | readability-simplify-subscript-expr, 139 | readability-static-accessed-through-instance, 140 | readability-static-definition-in-anonymous-namespace, 141 | readability-string-compare, 142 | readability-uniqueptr-delete-release, 143 | readability-use-anyofallof' 144 | ... 145 | -------------------------------------------------------------------------------- /.clangd: -------------------------------------------------------------------------------- 1 | Diagnostics: 2 | Suppress: 3 | - "-Wmicrosoft-enum-forward-reference" 4 | - "-Wc++11-narrowing" 5 | - "-Wc++2b-extensions" 6 | - "-Wmicrosoft-cast" 7 | CompileFlags: 8 | Add: 9 | - "-ferror-limit=0" 10 | - '-D__FUNCTION__="dummy"' 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Create a report to help us improve 3 | title: "[Bug]: " 4 | labels: ["bug"] 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: Describe the bug 9 | description: A clear and concise description of what the bug is. 10 | validations: 11 | required: true 12 | 13 | - type: textarea 14 | attributes: 15 | label: To Reproduce 16 | description: Steps to reproduce the behavior. 17 | validations: 18 | required: true 19 | 20 | - type: textarea 21 | attributes: 22 | label: Expected behavior 23 | description: A clear and concise description of what you expected to happen. 24 | validations: 25 | required: true 26 | 27 | - type: textarea 28 | attributes: 29 | label: Screenshots 30 | description: If applicable, add screenshots to help explain your problem. 31 | 32 | - type: input 33 | attributes: 34 | label: Platform 35 | description: The platform you are using. (e.g. Windows 10) 36 | 37 | - type: input 38 | attributes: 39 | label: BDS Version 40 | description: The version of BDS you are using. (e.g. 1.20.32.1) 41 | 42 | - type: input 43 | attributes: 44 | label: LeviLamina Version 45 | description: The version of LeviLamina you are using. (e.g. 1.0.0) 46 | 47 | - type: input 48 | attributes: 49 | label: Version 50 | description: The version of the plugin you are using. (e.g. 1.0.0) 51 | 52 | - type: textarea 53 | attributes: 54 | label: Additional context 55 | description: Add any other context about the problem here. 56 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea for this project 3 | title: "[Feature]: " 4 | labels: ["enhancement"] 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: Is your feature request related to a problem? Please describe. 9 | description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 10 | validations: 11 | required: true 12 | 13 | - type: textarea 14 | attributes: 15 | label: Describe the solution you'd like 16 | description: A clear and concise description of what you want to happen. 17 | validations: 18 | required: true 19 | 20 | - type: textarea 21 | attributes: 22 | label: Describe alternatives you've considered 23 | description: A clear and concise description of any alternative solutions or features you've considered. 24 | 25 | - type: textarea 26 | attributes: 27 | label: Additional context 28 | description: Add any other context or screenshots about the feature request here. 29 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## What does this PR do? 2 | 3 | 4 | 5 | ## Which issues does this PR resolve? 6 | 7 | 8 | 9 | ## Checklist before merging 10 | 11 | Thank you for your contribution to the repository. 12 | Before submitting this PR, please make sure: 13 | 14 | - [ ] Your code builds clean without any errors or warnings 15 | - [ ] Your code follows [LeviLamina C++ Style Guide](https://github.com/LiteLDev/LeviLamina/wiki/CPP-Style-Guide) 16 | - [ ] You have tested all functions 17 | - [ ] You have not used code without license 18 | - [ ] You have added statement for third-party code 19 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | push: 4 | paths: 5 | - 'src/more_dimensions/**.cpp' 6 | - 'src/more_dimensions/**.h' 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | runs-on: windows-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | 15 | - uses: xmake-io/github-action-setup-xmake@v1 16 | 17 | - uses: actions/cache@v4 18 | with: 19 | path: | 20 | ~/AppData/Local/.xmake 21 | key: xmake-${{ hashFiles('xmake.lua') }} 22 | restore-keys: | 23 | xmake- 24 | 25 | - run: | 26 | xmake repo -u 27 | 28 | - run: | 29 | xmake f -a x64 -m release -p windows -v -y 30 | 31 | - run: | 32 | xmake -v -w -y 33 | 34 | - uses: actions/upload-artifact@v4 35 | with: 36 | name: more-dimensions-windows-x64-${{ github.sha }} 37 | path: | 38 | bin/ 39 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - "v*.*.*" 5 | 6 | jobs: 7 | build: 8 | runs-on: windows-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | 12 | - uses: xmake-io/github-action-setup-xmake@v1 13 | 14 | - uses: actions/cache@v4 15 | with: 16 | path: | 17 | ~/AppData/Local/.xmake 18 | key: xmake-${{ hashFiles('xmake.lua') }} 19 | restore-keys: | 20 | xmake- 21 | 22 | - run: | 23 | xmake repo -u 24 | 25 | - run: | 26 | xmake f -a x64 -m release -p windows -v -y 27 | 28 | - run: | 29 | xmake -v -w -y 30 | 31 | - uses: actions/upload-artifact@v4 32 | with: 33 | name: more-dimensions-windows-x64-${{ github.sha }} 34 | path: | 35 | bin/ 36 | 37 | update-release-notes: 38 | permissions: 39 | contents: write 40 | runs-on: ubuntu-latest 41 | steps: 42 | - uses: actions/checkout@v4 43 | 44 | - id: extract-release-notes 45 | uses: ffurrer2/extract-release-notes@v2 46 | 47 | - uses: softprops/action-gh-release@v1 48 | with: 49 | body: | 50 | ${{ steps.extract-release-notes.outputs.release_notes }} 51 | 52 | upload-to-release: 53 | needs: 54 | - build 55 | - update-release-notes 56 | permissions: 57 | contents: write 58 | runs-on: ubuntu-latest 59 | steps: 60 | - uses: actions/checkout@v4 61 | 62 | - uses: actions/download-artifact@v4 63 | with: 64 | name: more-dimensions-windows-x64-${{ github.sha }} 65 | path: artifact 66 | 67 | - run: | 68 | cp CHANGELOG.md COPYING COPYING.LESSER README.md artifact/ 69 | 70 | - run: | 71 | zip -r ../more-dimensions-windows-x64-${{ github.ref_name }}.zip * 72 | working-directory: artifact 73 | 74 | - uses: softprops/action-gh-release@v1 75 | with: 76 | files: | 77 | more-dimensions-windows-x64-${{ github.ref_name }}.zip 78 | -------------------------------------------------------------------------------- /.github/workflows/test_build.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | paths: 4 | - 'src/test/**.cpp' 5 | - 'src/test/**.h' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - uses: xmake-io/github-action-setup-xmake@v1 15 | 16 | - uses: actions/cache@v4 17 | with: 18 | path: | 19 | ~/AppData/Local/.xmake 20 | key: xmake-${{ hashFiles('xmake.lua') }} 21 | restore-keys: | 22 | xmake- 23 | 24 | - run: | 25 | xmake repo -u 26 | 27 | - run: | 28 | xmake f --tests=y -a x64 -m release -p windows -v -y 29 | 30 | - run: | 31 | xmake -v -w -y 32 | 33 | - uses: actions/upload-artifact@v4 34 | with: 35 | name: more-dimensions-test-windows-x64-${{ github.sha }} 36 | path: | 37 | bin/ 38 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [0.7.0] - 2025-06-02 11 | 12 | ### Changed 13 | 14 | - Adapt to LeviLamina 1.2.0(BDS-1.21.70.04) 15 | - Deprecate `base64Nbt` in `dimension_config.json` files and add `sNbt` configuration. Improve the readability of configuration files 16 | 17 | ## [0.6.1] - 2025-03-05 18 | 19 | ### Fixed 20 | 21 | - Fixed tooth 22 | 23 | ## [0.6.0] - 2025-03-04 24 | 25 | ### Changed 26 | 27 | - Adapt to LeviLamina 1.1.0 28 | 29 | ## [0.5.0] - 2025-02-01 30 | 31 | ### Changed 32 | 33 | - Adapt to LeviLamina 1.0.0 34 | 35 | ## [0.4.1] - 2024-07-24 36 | 37 | ### Changed 38 | 39 | - Adapt to LeviLamina 0.13.4 40 | 41 | ## [0.4.0] - 2024-06-19 42 | 43 | ### Added 44 | 45 | - Adapt to LeviLamina 0.13.x 46 | 47 | ## [0.3.1] - 2024-06-02 48 | 49 | ### Fixed 50 | 51 | - Fix vanilla dimension can't create when the number of dimensions exceeds nine. 52 | 53 | ## [0.3.0] - 2024-06-01 54 | 55 | ### Added 56 | 57 | - Adapted to LeviLamina `0.12.x` 58 | 59 | ## [0.2.1] - 2024-04-13 60 | 61 | ### Added 62 | 63 | - Adapted to LeviLamina `0.11.x` 64 | 65 | ## [0.2.0] - 2024-03-27 66 | 67 | ### Added 68 | 69 | - Adapted to BDS version `1.20.7x` 70 | - Support Levilamina `v0.10.x` 71 | 72 | ### Changed 73 | 74 | - Changed namespace `ll::dimension` to `more_dimensions`. 75 | - Use new plugin template. 76 | 77 | ### Fixed 78 | 79 | - Fix `PropertiesSettings::isClientSideGenEnabled` hook no trigger. 80 | 81 | ## [0.1.2] - 2024-03-10 82 | 83 | ### Fixed 84 | 85 | - Fix: fix api symbols exports error 86 | 87 | ## [0.1.1] - 2024-03-10 88 | 89 | ### Fixed 90 | 91 | - Fix: fix xmake packages install directory no files 92 | 93 | ## [0.1.0] - 2024-03-07 94 | 95 | ### Added 96 | 97 | - Release the first version 98 | 99 | [Unreleased]: https://github.com/LiteLDev/MoreDimensions/compare/v0.7.0...HEAD 100 | [0.7.0]: https://github.com/LiteLDev/MoreDimensions/compare/v0.6.1...v0.7.0 101 | [0.6.1]: https://github.com/LiteLDev/MoreDimensions/compare/v0.6.0...v0.6.1 102 | [0.6.0]: https://github.com/LiteLDev/MoreDimensions/compare/v0.5.0...v0.6.0 103 | [0.5.0]: https://github.com/LiteLDev/MoreDimensions/compare/v0.4.1...v0.5.0 104 | [0.4.1]: https://github.com/LiteLDev/MoreDimensions/compare/v0.4.0...v0.4.1 105 | [0.4.0]: https://github.com/LiteLDev/MoreDimensions/compare/v0.3.1...v0.4.0 106 | [0.3.1]: https://github.com/LiteLDev/MoreDimensions/compare/v0.3.0...v0.3.1 107 | [0.3.0]: https://github.com/LiteLDev/MoreDimensions/compare/v0.2.1...v0.3.0 108 | [0.2.1]: https://github.com/LiteLDev/MoreDimensions/compare/v0.2.0...v0.2.1 109 | [0.2.0]: https://github.com/LiteLDev/MoreDimensions/compare/v0.1.2...v0.2.0 110 | [0.1.2]: https://github.com/LiteLDev/MoreDimensions/compare/v0.1.1...v0.1.2 111 | [0.1.1]: https://github.com/LiteLDev/MoreDimensions/compare/v0.1.0...v0.1.1 112 | [0.1.0]: https://github.com/LiteLDev/MoreDimensions/releases/tag/v0.1.0 113 | -------------------------------------------------------------------------------- /COPYING.LESSER: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MoreDimensions 2 | 3 | More than three dimensions on BDS! 4 | 5 | **Note: This mod only provides API. If you only install this mod, the dimensions will not be created.** 6 | 7 | ## Install 8 | 9 | Install with [lip](https://github.com/futrime/lip): 10 | 11 | ```sh 12 | lip install github.com/LiteLDev/MoreDimensions 13 | ``` 14 | 15 | ## Usage 16 | 17 | Wiki: [Chinese and English](https://github.com/LiteLDev/MoreDimensions/wiki) 18 | 19 | ## Contributing 20 | 21 | Ask questions by creating an issue. 22 | 23 | PRs accepted. 24 | 25 | ## License 26 | 27 | LGPL-3.0-or-later © LeviMC(LiteLDev) 28 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "${modName}", 3 | "entry": "${modFile}", 4 | "type": "native", 5 | "version": "${modVersion}", 6 | "author": "LiteLDev" 7 | } 8 | -------------------------------------------------------------------------------- /src/more_dimensions/MemoryOperators.cpp: -------------------------------------------------------------------------------- 1 | // This file will make your plugin use LeviLamina's memory operators by default. 2 | // This improves the memory management of your plugin and is recommended to use. 3 | 4 | #define LL_MEMORY_OPERATORS 5 | 6 | #include "ll/api/memory/MemoryOperators.h" // IWYU pragma: keep 7 | -------------------------------------------------------------------------------- /src/more_dimensions/MoreDimenison.cpp: -------------------------------------------------------------------------------- 1 | #include "MoreDimenison.h" 2 | 3 | #include "ll/api/Versions.h" 4 | #include "ll/api/mod/RegisterHelper.h" 5 | #include "more_dimensions/core/dimension/MoreDimensionsPatch.h" 6 | 7 | namespace more_dimensions { 8 | 9 | MoreDimenison& MoreDimenison::getInstance() { 10 | static MoreDimenison instance; 11 | return instance; 12 | } 13 | 14 | bool MoreDimenison::load() { 15 | getSelf().getLogger().info("Loading..."); 16 | if (ll::getLoaderVersion() < ll::data::Version{0, 8, 3}) { 17 | getSelf().getLogger().error( 18 | "The LeviLamina version requires 0.8.3 or higher, now is {}", 19 | ll::getLoaderVersion().to_string() 20 | ); 21 | return false; 22 | } 23 | injectNaticeCode(); 24 | getSelf().getLogger().info("More dimension is loaded"); 25 | getSelf().getLogger().info("Version: {}, Developer: LiteLDev", getSelf().getManifest().version->to_string()); 26 | return true; 27 | } 28 | 29 | bool MoreDimenison::enable() { 30 | getSelf().getLogger().info("Enabling..."); 31 | return true; 32 | } 33 | 34 | bool MoreDimenison::disable() { 35 | getSelf().getLogger().info("Disabling..."); 36 | return true; 37 | } 38 | 39 | } // namespace more_dimensions 40 | 41 | LL_REGISTER_MOD(more_dimensions::MoreDimenison, more_dimensions::MoreDimenison::getInstance()); 42 | -------------------------------------------------------------------------------- /src/more_dimensions/MoreDimenison.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ll/api/mod/NativeMod.h" 4 | 5 | namespace more_dimensions { 6 | 7 | class MoreDimenison { 8 | 9 | public: 10 | static MoreDimenison& getInstance(); 11 | 12 | MoreDimenison() : mSelf(*ll::mod::NativeMod::current()) {} 13 | 14 | [[nodiscard]] ll::mod::NativeMod& getSelf() const { return mSelf; } 15 | 16 | /// @return True if the plugin is loaded successfully. 17 | bool load(); 18 | 19 | /// @return True if the plugin is enabled successfully. 20 | bool enable(); 21 | 22 | /// @return True if the plugin is disabled successfully. 23 | bool disable(); 24 | 25 | // TODO: Implement this method if you need to unload the plugin. 26 | // /// @return True if the plugin is unloaded successfully. 27 | // bool unload(); 28 | 29 | private: 30 | ll::mod::NativeMod& mSelf; 31 | }; 32 | 33 | } // namespace more_dimensions 34 | -------------------------------------------------------------------------------- /src/more_dimensions/api/dimension/CustomDimensionManager.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "CustomDimensionManager.h" 3 | 4 | #include "mc/nbt/Tag.h" 5 | #include "more_dimensions/MoreDimenison.h" 6 | #include "more_dimensions/core/dimension/CustomDimensionConfig.h" 7 | #include "more_dimensions/core/dimension/FakeDimensionId.h" 8 | 9 | #include "snappy.h" 10 | 11 | #include "ll/api/command/CommandRegistrar.h" 12 | #include "ll/api/memory/Hook.h" 13 | #include "ll/api/service/Bedrock.h" 14 | #include "ll/api/utils/Base64Utils.h" 15 | #include "ll/api/utils/StringUtils.h" 16 | 17 | #include "mc/deps/core/math/Vec3.h" 18 | #include "mc/server/DedicatedServer.h" 19 | #include "mc/server/PropertiesSettings.h" 20 | #include "mc/util/BidirectionalUnorderedMap.h" 21 | #include "mc/world/actor/player/Player.h" 22 | #include "mc/world/level/Level.h" 23 | #include "mc/world/level/dimension/Dimension.h" 24 | #include "mc/world/level/dimension/VanillaDimensions.h" 25 | #include "mc/world/level/storage/LevelStorage.h" 26 | 27 | 28 | class Scheduler; 29 | 30 | namespace more_dimensions { 31 | 32 | std::string compress(std::string_view sv) { 33 | std::string res; 34 | snappy::Compress(sv.data(), sv.size(), &res); 35 | return res; 36 | } 37 | 38 | std::string decompress(std::string_view sv) { 39 | std::string res; 40 | snappy::Uncompress(sv.data(), sv.size(), &res); 41 | return res; 42 | } 43 | 44 | // static ll::Logger loggerMoreDimMag("CustomDimensionManager"); 45 | auto& loggerMoreDimMag = MoreDimenison::getInstance().getSelf().getLogger(); 46 | 47 | namespace CustomDimensionHookList { 48 | LL_TYPE_STATIC_HOOK( 49 | VanillaDimensionsConverHook, 50 | HookPriority::Normal, 51 | VanillaDimensions, 52 | VanillaDimensions::convertPointBetweenDimensions, 53 | bool, 54 | Vec3 const& oldPos, 55 | Vec3& toPos, 56 | DimensionType oldDim, 57 | DimensionType toDim, 58 | DimensionConversionData const& data 59 | ) { 60 | if (oldDim <= 2 && toDim <= 2) return origin(oldPos, toPos, oldDim, toDim, data); 61 | toPos = oldPos; 62 | return true; 63 | }; 64 | 65 | LL_TYPE_STATIC_HOOK( 66 | VanillaDimensionsFromSerializedIntHook, 67 | HookPriority::Normal, 68 | VanillaDimensions, 69 | VanillaDimensions::fromSerializedInt, 70 | Bedrock::Result, 71 | Bedrock::Result&& dim 72 | ) { 73 | if (!VanillaDimensions::DimensionMap().mLeft.contains(*dim)) { 74 | return VanillaDimensions::Undefined(); 75 | } 76 | return *dim; 77 | }; 78 | 79 | LL_TYPE_STATIC_HOOK( 80 | VanillaDimensionsFromSerializedIntHookI, 81 | HookPriority::Normal, 82 | VanillaDimensions, 83 | VanillaDimensions::fromSerializedInt, 84 | DimensionType, 85 | int dimId 86 | ) { 87 | if (!VanillaDimensions::DimensionMap().mLeft.contains(dimId)) { 88 | return VanillaDimensions::Undefined(); 89 | } 90 | return {dimId}; 91 | } 92 | 93 | // inline function use patch 94 | // -->PropertiesSettingsisClientSideGenEnabledHook 95 | // 96 | // LL_TYPE_STATIC_HOOK( 97 | // VanillaDimensionsToSerializedIntHook, 98 | // HookPriority::Normal, 99 | // VanillaDimensions, 100 | // VanillaDimensions::toSerializedInt, 101 | // int, 102 | // DimensionType const& dim 103 | // ) { 104 | // if (dim <= 2) return origin(dim); 105 | // return dim.id; 106 | // } 107 | 108 | // 当玩家加入服务器时,生成时的维度不存在,并且维度id不是Undefined时,把玩家放到主世界 109 | LL_TYPE_INSTANCE_HOOK( 110 | LevelStorageloadServerPlayerDataHook, 111 | HookPriority::Normal, 112 | LevelStorage, 113 | &LevelStorage::loadServerPlayerData, 114 | std::unique_ptr, 115 | Player const& client, 116 | bool isXboxLive 117 | ) { 118 | 119 | auto result = origin(client, isXboxLive); 120 | if (!result) return result; 121 | auto spawnDimension = result->at("DimensionId"); 122 | if (!VanillaDimensions::DimensionMap().mLeft.contains(AutomaticID(spawnDimension))) { 123 | result->at("Pos")[1] = FloatTag{0x7fff}; 124 | } 125 | return result; 126 | } 127 | 128 | // 由于这个的调用在维度注册之前,所以使用AUTO 129 | LL_AUTO_TYPE_INSTANCE_HOOK( 130 | PropertiesSettingsisClientSideGenEnabledHook, 131 | HookPriority::Normal, 132 | DedicatedServer, 133 | &DedicatedServer::runDedicatedServerLoop, 134 | DedicatedServer::StartResult, 135 | Core::FilePathManager& filePathManager, 136 | PropertiesSettings& properties, 137 | LevelSettings& settings, 138 | AllowListFile& userAllowList, 139 | std::unique_ptr& permissionsFile, 140 | Bedrock::ActivationArguments const& args, 141 | TestConfig& testConfig 142 | ) { 143 | properties.mClientSideGenerationEnabled = false; 144 | return origin(filePathManager, properties, settings, userAllowList, permissionsFile, args, testConfig); 145 | } 146 | 147 | // 1.21.50.10 unnecessary 148 | // registry dimensoin when in ll, must reload Dimension::getWeakRef 149 | // LL_TYPE_INSTANCE_HOOK(DimensionGetWeakRefHook, HookPriority::Normal, Dimension, &Dimension::getWeakRef, 150 | // WeakRef) { 151 | // if (getDimensionId().id > 2 && getDimensionId() != VanillaDimensions::Undefined()) return weak_from_this(); 152 | // return origin(); 153 | // }; 154 | 155 | using HookReg = ll::memory::HookRegistrar< 156 | VanillaDimensionsConverHook, 157 | VanillaDimensionsFromSerializedIntHook, 158 | VanillaDimensionsFromSerializedIntHookI, 159 | // VanillaDimensionsToSerializedIntHook, 160 | LevelStorageloadServerPlayerDataHook, 161 | PropertiesSettingsisClientSideGenEnabledHook>; 162 | 163 | } // namespace CustomDimensionHookList 164 | 165 | struct CustomDimensionManager::Impl { 166 | std::atomic mNewDimensionId{3}; 167 | std::mutex mMapMutex; 168 | 169 | struct DimensionInfo { 170 | DimensionType id; 171 | CompoundTag nbt; 172 | }; 173 | std::unordered_map customDimensionMap; 174 | std::unordered_set registeredDimension; 175 | }; 176 | 177 | CustomDimensionManager::CustomDimensionManager() : impl(std::make_unique()) { 178 | std::lock_guard lock{impl->mMapMutex}; 179 | CustomDimensionConfig::setDimensionConfigPath(); 180 | CustomDimensionConfig::loadConfigFile(); 181 | if (!CustomDimensionConfig::getConfig().dimensionList.empty()) { 182 | for (auto& [name, info] : CustomDimensionConfig::getConfig().dimensionList) { 183 | impl->customDimensionMap.emplace( 184 | name, 185 | Impl::DimensionInfo{ 186 | info.dimId, 187 | *CompoundTag::fromSnbt(info.sNbt) 188 | } 189 | ); 190 | } 191 | impl->mNewDimensionId += static_cast(impl->customDimensionMap.size()); 192 | } 193 | FakeDimensionId::getInstance(); 194 | CustomDimensionHookList::HookReg::hook(); 195 | }; 196 | 197 | CustomDimensionManager::~CustomDimensionManager() { CustomDimensionHookList::HookReg::unhook(); } 198 | 199 | CustomDimensionManager& CustomDimensionManager::getInstance() { 200 | static CustomDimensionManager instance{}; 201 | return instance; 202 | } 203 | 204 | DimensionType CustomDimensionManager::getDimensionIdFromName(std::string const& dimName) { 205 | return VanillaDimensions::fromString(dimName); 206 | } 207 | 208 | DimensionType CustomDimensionManager::addDimension( 209 | std::string const& dimName, 210 | std::function factory, 211 | std::function const& data 212 | ) { 213 | std::lock_guard lock{impl->mMapMutex}; 214 | Impl::DimensionInfo info; 215 | bool newDim{}; 216 | if (impl->customDimensionMap.contains(dimName)) { 217 | info = impl->customDimensionMap.at(dimName); 218 | loggerMoreDimMag.info( 219 | "The dimension already registry. use old id, name: {}, id: {}, \ndata: {}", 220 | dimName, 221 | info.id.id, 222 | info.nbt.toSnbt() 223 | ); 224 | } else { 225 | // Assign new id 226 | info.id = impl->mNewDimensionId++; 227 | info.nbt = data(); 228 | newDim = true; 229 | loggerMoreDimMag 230 | .info("registry new dimension, name: {}, id: {}, \ndata: {}", dimName, info.id.id, info.nbt.toSnbt()); 231 | }; 232 | 233 | // registry create dimension function 234 | if (!ll::service::getLevel()) { 235 | throw std::runtime_error("Level is nullptr, cannot registry new dimension " + dimName); 236 | } 237 | ll::service::getLevel()->getDimensionFactory().mFactoryMap.emplace( 238 | dimName, 239 | [dimName, info, factory = std::move(factory)](ILevel& ilevel, Scheduler& scheduler) -> OwnerPtr { 240 | loggerMoreDimMag.debug("Create dimension, name: {}, id: {}", dimName, info.id.id); 241 | return factory(DimensionFactoryInfo{ilevel, scheduler, info.nbt, info.id}); 242 | } 243 | ); 244 | 245 | // modify default dimension map 246 | loggerMoreDimMag.debug("Add new dimension to DimensionMap"); 247 | ll::memory::modify(VanillaDimensions::DimensionMap(), [&](auto& dimMap) { 248 | loggerMoreDimMag.debug("Add new dimension: name->{}, id->{} to DimensionMap", dimName, info.id.id); 249 | dimMap.insert_or_assign(dimName, info.id); 250 | }); 251 | 252 | // modify default Undefined dimension id 253 | ll::memory::modify(VanillaDimensions::Undefined(), [&](auto& uid) { 254 | uid.id = impl->mNewDimensionId; 255 | loggerMoreDimMag.debug("Set VanillaDimensions::Undefined to {}", uid.id); 256 | loggerMoreDimMag.debug("Now VanillaDimensions::Undefined is {}", VanillaDimensions::Undefined().id); 257 | }); 258 | 259 | // config 260 | impl->registeredDimension.emplace(dimName); 261 | if (newDim) { 262 | impl->customDimensionMap.emplace(dimName, info); 263 | CustomDimensionConfig::getConfig().dimensionList.emplace( 264 | dimName, 265 | CustomDimensionConfig::Config::Info{info.id, info.nbt.toSnbt(SnbtFormat::Minimize)} 266 | ); 267 | CustomDimensionConfig::saveConfigFile(); 268 | } 269 | 270 | // add to command enum 271 | 272 | ll::command::CommandRegistrar::getInstance().addEnumValues( 273 | "Dimension", 274 | { 275 | {dimName, info.id} 276 | }, 277 | Bedrock::type_id() 278 | ); 279 | 280 | return info.id; 281 | } 282 | } // namespace more_dimensions 283 | -------------------------------------------------------------------------------- /src/more_dimensions/api/dimension/CustomDimensionManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "more_dimensions/core/Macros.h" 4 | 5 | #include "mc/deps/core/utility/AutomaticID.h" 6 | #include "mc/nbt/CompoundTag.h" 7 | #include "mc/world/level/GeneratorType.h" 8 | 9 | class Dimension; 10 | class ILevel; 11 | class Scheduler; 12 | 13 | namespace more_dimensions { 14 | 15 | struct DimensionFactoryInfo { 16 | ILevel& level; 17 | Scheduler& scheduler; 18 | CompoundTag const& data; 19 | DimensionType dimId; 20 | }; 21 | 22 | class CustomDimensionManager { 23 | struct Impl; 24 | std::unique_ptr impl; 25 | 26 | CustomDimensionManager(); 27 | ~CustomDimensionManager(); 28 | 29 | public: 30 | using DimensionFactoryT = std::shared_ptr(DimensionFactoryInfo const&); 31 | 32 | protected: 33 | MORE_DIMENSIONS_API DimensionType addDimension( 34 | std::string const& dimName, 35 | std::function factory, 36 | std::function const& newData 37 | ); 38 | 39 | public: 40 | MORE_DIMENSIONS_API static CustomDimensionManager& getInstance(); 41 | 42 | [[deprecated("please use VanillaDimensions::fromString")]] MORE_DIMENSIONS_API static DimensionType 43 | getDimensionIdFromName(std::string const& dimName); 44 | 45 | template D, class... Args> 46 | DimensionType addDimension(std::string const& dimName, Args&&... args) { 47 | return addDimension( 48 | dimName, 49 | [dimName](more_dimensions::DimensionFactoryInfo const& info) -> std::shared_ptr { 50 | return std::make_shared(dimName, info); 51 | }, 52 | [&] { return D::generateNewData(std::forward(args)...); } 53 | ); 54 | } 55 | }; 56 | 57 | // Dimension need to test virtual tables 58 | 59 | /* Dimension related virtual tables 60 | * 61 | * ∕-- IDimension 62 | * OverworldDimension --∖ ∕-- LevelListener --- BlockSourceListener 63 | * NetherDimension --- Dimension --- SavedData 64 | * TheEndDimension --∕ ∖-- Bedrock::EnableNonOwnerReferences 65 | * ∖-- std::enable_shared_from_this 66 | * 67 | */ 68 | 69 | /* WorldGenerator related virtual tables 70 | * 71 | * FlatWorldGenerator --∖ 72 | * NetherGenerator --∖ 73 | * OverworldGenerator2d --- OverworldGenerator2d --- WorldGenerator --- ChunkSource --- 74 | * Bedrock::EnableNonOwnerReferences TheEndGenerator --∕ ∖-- IPreliminarySurfaceProvider 75 | * VoidGenerator --∕ 76 | * 77 | */ 78 | 79 | /* DimensionBrightnessRamp related virtual tables 80 | * 81 | * NetherBrightnessRamp --∖ 82 | * OverworldBrightnessRamp --- DimensionBrightnessRamp 83 | * 84 | */ 85 | 86 | /* BlockSource related virtual tables 87 | * 88 | * BlockSource --- IBlockSource --- IConstBlockSource 89 | * ∖-- std::enable_shared_from_this 90 | * 91 | */ 92 | 93 | /* BiomeSource related virtual tables 94 | * 95 | * FixedBiomeSource --- BiomeSource 96 | * 97 | */ 98 | 99 | } // namespace more_dimensions 100 | -------------------------------------------------------------------------------- /src/more_dimensions/api/dimension/SimpleCustomDimension.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "SimpleCustomDimension.h" 3 | 4 | #include "more_dimensions/MoreDimenison.h" 5 | 6 | #include "magic_enum.hpp" 7 | 8 | #include "ll/api/memory/Memory.h" 9 | #include "ll/api/service/Bedrock.h" 10 | 11 | #include "mc/common/Brightness.h" 12 | #include "mc/common/BrightnessPair.h" 13 | #include "mc/deps/core/math/Color.h" 14 | #include "mc/deps/core/string/HashedString.h" 15 | #include "mc/world/level/BlockSource.h" 16 | #include "mc/world/level/DimensionConversionData.h" 17 | #include "mc/world/level/Level.h" 18 | #include "mc/world/level/LevelSeed64.h" 19 | #include "mc/world/level/biome/registry/BiomeRegistry.h" 20 | #include "mc/world/level/biome/registry/VanillaBiomeNames.h" 21 | #include "mc/world/level/biome/source/BiomeSource.h" 22 | #include "mc/world/level/biome/source/FixedBiomeSource.h" 23 | #include "mc/world/level/block/BlockVolume.h" 24 | #include "mc/world/level/chunk/vanilla_level_chunk_upgrade/VanillaLevelChunkUpgrade.h" 25 | #include "mc/world/level/dimension/DimensionHeightRange.h" 26 | #include "mc/world/level/dimension/NetherBrightnessRamp.h" 27 | #include "mc/world/level/dimension/OverworldBrightnessRamp.h" 28 | #include "mc/world/level/dimension/VanillaDimensions.h" 29 | #include "mc/world/level/levelgen/flat/FlatWorldGenerator.h" 30 | #include "mc/world/level/levelgen/structure/EndCityFeature.h" 31 | #include "mc/world/level/levelgen/structure/StructureFeatureRegistry.h" 32 | #include "mc/world/level/levelgen/structure/registry/StructureSetRegistry.h" 33 | #include "mc/world/level/levelgen/synth/PerlinNoise.h" 34 | #include "mc/world/level/levelgen/synth/PerlinSimplexNoise.h" 35 | #include "mc/world/level/levelgen/synth/SimplexNoise.h" 36 | #include "mc/world/level/levelgen/v1/NetherGenerator.h" 37 | #include "mc/world/level/levelgen/v1/OverworldGeneratorMultinoise.h" 38 | #include "mc/world/level/levelgen/v1/TheEndGenerator.h" 39 | #include "mc/world/level/levelgen/v1/VoidGenerator.h" 40 | #include "mc/world/level/levelgen/v2/ChunkGeneratorStructureState.h" 41 | #include "mc/world/level/storage/Experiments.h" 42 | #include "mc/world/level/storage/LevelData.h" 43 | 44 | #include 45 | #include 46 | 47 | 48 | namespace more_dimensions { 49 | 50 | 51 | namespace { 52 | using namespace ll::memory_literals; 53 | 54 | DWORD overworld_addStructureFeatures_rva = 0x2C6640; 55 | DWORD nethrer_addStructureFeatures_rva = 0x2C4F90; 56 | 57 | HMODULE hModule = GetModuleHandle(L"bedrock_server_mod.exe"); 58 | 59 | static void* overworldAddress = (void*)((BYTE*)hModule + overworld_addStructureFeatures_rva); 60 | static void* netherAddress = (void*)((BYTE*)hModule + nethrer_addStructureFeatures_rva); 61 | 62 | // static auto* overworldAddress = 63 | // "`anonymous namespace'::unity_5c986e6b9d6571cc96912b0bfa0329e2::addStructureFeatures"_symp; 64 | // static auto* netherAddress = "`anonymous namespace'::unity_3da1d4c9fa90b4b1becbca96840255a5::addStructureFeatures"_symp; 65 | 66 | void overworldAddStructureFeatures( 67 | StructureFeatureRegistry& registry, 68 | uint seed, 69 | bool isLegacy, 70 | BaseGameVersion const& baseGameVersion 71 | ) { 72 | ll::memory::addressCall( 73 | overworldAddress, 74 | registry, 75 | seed, 76 | isLegacy, 77 | baseGameVersion 78 | ); 79 | }; 80 | 81 | void netherAddStructureFeatures( 82 | StructureFeatureRegistry& registry, 83 | uint seed, 84 | BaseGameVersion const& baseGameVersion, 85 | Experiments const& experiments 86 | ) { 87 | ll::memory::addressCall( 88 | netherAddress, 89 | registry, 90 | seed, 91 | baseGameVersion, 92 | experiments 93 | ); 94 | }; 95 | } // namespace 96 | 97 | // static ll::Logger loggerMoreDim("SimpleCustomDim"); 98 | auto& loggerMoreDim = MoreDimenison::getInstance().getSelf().getLogger(); 99 | 100 | SimpleCustomDimension::SimpleCustomDimension(std::string const& name, DimensionFactoryInfo const& info) 101 | : Dimension(info.level, info.dimId, {-64, 320}, info.scheduler, name) { 102 | loggerMoreDim.debug("{} dimension name:{}", __FUNCTION__, name); 103 | mDefaultBrightness->sky = Brightness::MAX(); 104 | generatorType = *magic_enum::enum_cast((std::string_view)info.data["generatorType"]); 105 | seed = info.data["seed"]; 106 | switch (generatorType) { 107 | case GeneratorType::TheEnd: { 108 | mSeaLevel = 63; 109 | mHasWeather = false; 110 | mDimensionBrightnessRamp = std::make_unique(); 111 | } 112 | case GeneratorType::Nether: { 113 | mSeaLevel = 32; 114 | mHasWeather = false; 115 | mDimensionBrightnessRamp = std::make_unique(); 116 | } 117 | default: 118 | mSeaLevel = 63; 119 | mHasWeather = true; 120 | mDimensionBrightnessRamp = std::make_unique(); 121 | } 122 | mDimensionBrightnessRamp->buildBrightnessRamp(); 123 | } 124 | 125 | CompoundTag SimpleCustomDimension::generateNewData(uint seed, GeneratorType generatorType) { 126 | CompoundTag result; 127 | result["seed"] = seed; 128 | result["generatorType"] = magic_enum::enum_name(generatorType); 129 | return result; 130 | } 131 | 132 | void SimpleCustomDimension::init(br::worldgen::StructureSetRegistry const& structureSetRegistry) { 133 | loggerMoreDim.debug(__FUNCTION__); 134 | mHasSkylight = false; 135 | Dimension::init(structureSetRegistry); 136 | } 137 | 138 | std::unique_ptr 139 | SimpleCustomDimension::createGenerator(br::worldgen::StructureSetRegistry const& structureSetRegistry) { 140 | loggerMoreDim.debug(__FUNCTION__); 141 | auto& level = mLevel; 142 | auto& levelData = level.getLevelData(); 143 | auto biome = level.getBiomeRegistry().lookupByName(levelData.mBiomeOverride); 144 | 145 | std::unique_ptr worldGenerator; 146 | 147 | switch (generatorType) { 148 | case GeneratorType::Overworld: { 149 | worldGenerator = std::make_unique(*this, LevelSeed64{seed}, biome); 150 | worldGenerator->mStructureFeatureRegistry->mGeneratorState = 151 | br::worldgen::ChunkGeneratorStructureState::createNormal( 152 | seed, 153 | worldGenerator->getBiomeSource(), 154 | structureSetRegistry 155 | ); 156 | overworldAddStructureFeatures( 157 | *worldGenerator->mStructureFeatureRegistry, 158 | seed, 159 | false, 160 | levelData.getBaseGameVersion() 161 | ); 162 | break; 163 | } 164 | case GeneratorType::Nether: { 165 | worldGenerator = std::make_unique(*this, seed, biome); 166 | worldGenerator->mStructureFeatureRegistry->mGeneratorState = 167 | br::worldgen::ChunkGeneratorStructureState::createNormal( 168 | seed, 169 | worldGenerator->getBiomeSource(), 170 | structureSetRegistry 171 | ); 172 | netherAddStructureFeatures( 173 | *worldGenerator->mStructureFeatureRegistry, 174 | seed, 175 | levelData.getBaseGameVersion(), 176 | static_cast(levelData.mExperiments.get()) 177 | ); 178 | break; 179 | } 180 | case GeneratorType::TheEnd: { 181 | worldGenerator = std::make_unique(*this, seed, biome); 182 | worldGenerator->mStructureFeatureRegistry->mGeneratorState = 183 | br::worldgen::ChunkGeneratorStructureState::createNormal( 184 | seed, 185 | worldGenerator->getBiomeSource(), 186 | structureSetRegistry 187 | ); 188 | 189 | // worldGenerator->mStructureFeatureRegistry->mStructureFeatures->emplace_back( 190 | // std::make_unique(*this, seed) 191 | // ); 192 | break; 193 | } 194 | case GeneratorType::Flat: { 195 | worldGenerator = std::make_unique(*this, seed, levelData.mFlatWorldOptions); 196 | worldGenerator->mStructureFeatureRegistry->mGeneratorState = 197 | br::worldgen::ChunkGeneratorStructureState::createFlat(seed, worldGenerator->getBiomeSource(), {}); 198 | break; 199 | } 200 | default: { 201 | auto generator = std::make_unique(*this); 202 | generator->mBiome = level.getBiomeRegistry().lookupByHash(VanillaBiomeNames::Ocean()); 203 | worldGenerator = std::move(generator); 204 | worldGenerator->mStructureFeatureRegistry->mGeneratorState->mLevelSeed = seed; 205 | worldGenerator->mStructureFeatureRegistry->mGeneratorState->mRingsSeed = seed; 206 | } 207 | } 208 | // worldGenerator->init(); 209 | return std::move(worldGenerator); 210 | } 211 | 212 | void SimpleCustomDimension::upgradeLevelChunk(ChunkSource& cs, LevelChunk& lc, LevelChunk& generatedChunk) { 213 | loggerMoreDim.debug(__FUNCTION__); 214 | auto blockSource = BlockSource(static_cast(mLevel), *this, cs, false, true, false); 215 | VanillaLevelChunkUpgrade::_upgradeLevelChunkViaMetaData(lc, generatedChunk, blockSource); 216 | VanillaLevelChunkUpgrade::_upgradeLevelChunkLegacy(lc, blockSource); 217 | } 218 | 219 | void SimpleCustomDimension::fixWallChunk(ChunkSource& cs, LevelChunk& lc) { 220 | loggerMoreDim.debug(__FUNCTION__); 221 | auto blockSource = BlockSource(static_cast(mLevel), *this, cs, false, true, false); 222 | VanillaLevelChunkUpgrade::fixWallChunk(lc, blockSource); 223 | } 224 | 225 | bool SimpleCustomDimension::levelChunkNeedsUpgrade(LevelChunk const& lc) const { 226 | loggerMoreDim.debug(__FUNCTION__); 227 | return VanillaLevelChunkUpgrade::levelChunkNeedsUpgrade(lc); 228 | } 229 | void SimpleCustomDimension::_upgradeOldLimboEntity(CompoundTag& tag, ::LimboEntitiesVersion vers) { 230 | loggerMoreDim.debug(__FUNCTION__); 231 | auto isTemplate = mLevel.getLevelData().mIsFromLockedTemplate; 232 | return VanillaLevelChunkUpgrade::upgradeOldLimboEntity(tag, vers, isTemplate); 233 | } 234 | 235 | Vec3 SimpleCustomDimension::translatePosAcrossDimension(Vec3 const& fromPos, DimensionType fromId) const { 236 | loggerMoreDim.debug(__FUNCTION__); 237 | Vec3 topos; 238 | VanillaDimensions::convertPointBetweenDimensions(fromPos, topos, fromId, mId, mLevel.getDimensionConversionData()); 239 | constexpr auto clampVal = 32000000.0f - 128.0f; 240 | 241 | topos.x = std::clamp(topos.x, -clampVal, clampVal); 242 | topos.z = std::clamp(topos.z, -clampVal, clampVal); 243 | 244 | return topos; 245 | } 246 | 247 | short SimpleCustomDimension::getCloudHeight() const { return 192; } 248 | 249 | 250 | std::unique_ptr 251 | SimpleCustomDimension::_wrapStorageForVersionCompatibility(std::unique_ptr cs, ::StorageVersion /*ver*/) { 252 | loggerMoreDim.debug(__FUNCTION__); 253 | return cs; 254 | } 255 | 256 | mce::Color SimpleCustomDimension::getBrightnessDependentFogColor(mce::Color const& color, float brightness) const { 257 | loggerMoreDim.debug(__FUNCTION__); 258 | float temp = (brightness * 0.94f) + 0.06f; 259 | float temp2 = (brightness * 0.91f) + 0.09f; 260 | auto result = color; 261 | result.r = color.r * temp; 262 | result.g = color.g * temp; 263 | result.b = color.b * temp2; 264 | return result; 265 | }; 266 | 267 | } // namespace more_dimensions 268 | -------------------------------------------------------------------------------- /src/more_dimensions/api/dimension/SimpleCustomDimension.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "more_dimensions/api/dimension/CustomDimensionManager.h" 4 | #include "more_dimensions/core/Macros.h" 5 | 6 | #include "mc/world/level/dimension/Dimension.h" 7 | 8 | 9 | class ChunkSource; 10 | class LevelChunk; 11 | 12 | namespace more_dimensions { 13 | 14 | class SimpleCustomDimension : public Dimension { 15 | uint seed; 16 | GeneratorType generatorType; 17 | 18 | public: 19 | MORE_DIMENSIONS_API SimpleCustomDimension(std::string const& name, DimensionFactoryInfo const& info); 20 | 21 | MORE_DIMENSIONS_API static CompoundTag 22 | generateNewData(uint seed = 123, GeneratorType generatorType = GeneratorType::Overworld); 23 | 24 | MORE_DIMENSIONS_API void init(br::worldgen::StructureSetRegistry const&) override; 25 | 26 | MORE_DIMENSIONS_API std::unique_ptr 27 | createGenerator(br::worldgen::StructureSetRegistry const&) override; 28 | 29 | MORE_DIMENSIONS_API void upgradeLevelChunk(ChunkSource& chunkSource, LevelChunk& oldLc, LevelChunk& newLc) override; 30 | 31 | MORE_DIMENSIONS_API void fixWallChunk(ChunkSource& cs, LevelChunk& lc) override; 32 | 33 | MORE_DIMENSIONS_API bool levelChunkNeedsUpgrade(LevelChunk const& lc) const override; 34 | 35 | MORE_DIMENSIONS_API void _upgradeOldLimboEntity(CompoundTag& tag, ::LimboEntitiesVersion vers) override; 36 | 37 | MORE_DIMENSIONS_API Vec3 translatePosAcrossDimension(Vec3 const& pos, DimensionType did) const override; 38 | 39 | MORE_DIMENSIONS_API std::unique_ptr 40 | _wrapStorageForVersionCompatibility(std::unique_ptr cs, ::StorageVersion ver) override; 41 | 42 | MORE_DIMENSIONS_API mce::Color 43 | getBrightnessDependentFogColor(mce::Color const& color, float brightness) const override; 44 | 45 | MORE_DIMENSIONS_API short getCloudHeight() const override; 46 | 47 | }; 48 | } // namespace more_dimensions 49 | -------------------------------------------------------------------------------- /src/more_dimensions/core/Macros.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef MORE_DIMENSIONS_EXPORTS 4 | 5 | #define MORE_DIMENSIONS_API __declspec(dllexport) 6 | 7 | #else 8 | 9 | #define MORE_DIMENSIONS_API __declspec(dllimport) 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/more_dimensions/core/dimension/CustomDimensionConfig.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "CustomDimensionConfig.h" 3 | 4 | #include "mc/nbt/Tag.h" 5 | #include "more_dimensions/MoreDimenison.h" 6 | 7 | #include "snappy.h" 8 | 9 | #include "ll/api/Config.h" 10 | #include "ll/api/service/Bedrock.h" 11 | #include "ll/api/utils/Base64Utils.h" 12 | #include "ll/api/utils/ErrorUtils.h" 13 | 14 | #include "mc/nbt/CompoundTag.h" 15 | #include "mc/server/PropertiesSettings.h" 16 | 17 | 18 | namespace more_dimensions::CustomDimensionConfig { 19 | 20 | // static ll::Logger logger("CustomDimensionConfig"); 21 | auto& logger = MoreDimenison::getInstance().getSelf().getLogger(); 22 | 23 | std::string compress(std::string_view sv) { 24 | std::string res; 25 | snappy::Compress(sv.data(), sv.size(), &res); 26 | return res; 27 | } 28 | 29 | std::string decompress(std::string_view sv) { 30 | std::string res; 31 | snappy::Uncompress(sv.data(), sv.size(), &res); 32 | return res; 33 | } 34 | 35 | static std::filesystem::path dimensionConfigPath{u8"./worlds"}; 36 | 37 | void setDimensionConfigPath() { 38 | if (!ll::service::getLevel()) { 39 | throw std::runtime_error("Level nullptr"); 40 | } 41 | dimensionConfigPath /= ll::string_utils::str2u8str(ll::service::getPropertiesSettings()->mLevelName); 42 | dimensionConfigPath /= u8"dimension_config.json"; 43 | } 44 | 45 | bool loadConfigFile() { 46 | if (std::ifstream(dimensionConfigPath).good()) { 47 | try { 48 | if (ll::config::loadConfig( 49 | getConfig(), 50 | dimensionConfigPath, 51 | [](Config& config, nlohmann::ordered_json& data) { 52 | if (data["version"] < config.version) { 53 | for (auto& item : data["dimensionList"]) { 54 | item["sNbt"] = 55 | CompoundTag::fromBinaryNbt(decompress(ll::base64_utils::decode(item["base64Nbt"]))) 56 | ->toSnbt(SnbtFormat::Minimize); 57 | item.erase("base64Nbt"); 58 | } 59 | } 60 | data.erase("version"); 61 | auto patch = ll::reflection::serialize(config); 62 | patch.value().merge_patch(data); 63 | data = *std::move(patch); 64 | return true; 65 | } 66 | )) { 67 | logger.info("Config file load success!"); 68 | return true; 69 | } 70 | } catch (...) { 71 | logger.error("Config file load fail, will rewrite!"); 72 | ll::error_utils::printCurrentException(logger); 73 | } 74 | } 75 | try { 76 | if (ll::config::saveConfig(getConfig(), dimensionConfigPath)) { 77 | logger.warn("Config file rewrite success!"); 78 | return true; 79 | } else { 80 | logger.error("Config rewrite failed!"); 81 | } 82 | } catch (...) { 83 | logger.error("Config rewrite failed!"); 84 | ll::error_utils::printCurrentException(logger); 85 | } 86 | return false; 87 | } 88 | 89 | bool saveConfigFile() { 90 | bool result{}; 91 | try { 92 | result = ll::config::saveConfig(getConfig(), dimensionConfigPath); 93 | } catch (...) { 94 | result = false; 95 | ll::error_utils::printCurrentException(logger); 96 | } 97 | if (!result) { 98 | logger.error("Config file save fail!"); 99 | return false; 100 | } 101 | return true; 102 | } 103 | 104 | // void updateConfigVersion() { 105 | // if (getConfig().version < 4) { 106 | // logger.info("Config need update"); 107 | // auto config = getConfig(); 108 | // for (auto& item : config.dimensionList) { 109 | // auto oldStrNbt = item.second.base64Nbt; 110 | // item.second.base64Nbt = CompoundTag::fromBinaryNbt(decompress(ll::base64_utils::decode(oldStrNbt))) 111 | // ->toSnbt(SnbtFormat::Minimize); 112 | // } 113 | // saveConfigFile(); 114 | // } 115 | // } 116 | } // namespace more_dimensions::CustomDimensionConfig 117 | -------------------------------------------------------------------------------- /src/more_dimensions/core/dimension/CustomDimensionConfig.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace more_dimensions::CustomDimensionConfig { 8 | struct Config { 9 | struct Info { 10 | int dimId{}; 11 | std::string sNbt; 12 | }; 13 | int version = 4; 14 | std::unordered_map dimensionList{}; 15 | }; 16 | 17 | inline Config& getConfig() { 18 | static Config instance; 19 | return instance; 20 | } 21 | 22 | void setDimensionConfigPath(); 23 | bool loadConfigFile(); 24 | bool saveConfigFile(); 25 | }; // namespace more_dimensions::CustomDimensionConfig 26 | -------------------------------------------------------------------------------- /src/more_dimensions/core/dimension/FakeDimensionId.cpp: -------------------------------------------------------------------------------- 1 | #include "FakeDimensionId.h" 2 | 3 | #include "more_dimensions//api/dimension/CustomDimensionManager.h" 4 | #include "more_dimensions/MoreDimenison.h" 5 | 6 | #include "ll/api/memory/Hook.h" 7 | #include "ll/api/service/Bedrock.h" 8 | 9 | #include "mc/deps/core/math/Vec3.h" 10 | #include "mc/deps/core/utility/BinaryStream.h" 11 | #include "mc/deps/ecs/gamerefs_entity/EntityContext.h" 12 | #include "mc/entity/components/IPlayerTickPolicy.h" 13 | #include "mc/entity/components/MovementPackets.h" 14 | #include "mc/entity/components/ServerPlayerMovementComponent.h" 15 | #include "mc/legacy/ActorRuntimeID.h" 16 | #include "mc/legacy/ActorUniqueID.h" 17 | #include "mc/network//LoopbackPacketSender.h" 18 | #include "mc/network/MinecraftPacketIds.h" 19 | #include "mc/network/NetworkBlockPosition.h" 20 | #include "mc/network/NetworkIdentifierWithSubId.h" 21 | #include "mc/network/ServerNetworkHandler.h" 22 | #include "mc/network/packet/AddVolumeEntityPacket.h" 23 | #include "mc/network/packet/ChangeDimensionPacket.h" 24 | #include "mc/network/packet/InteractPacket.h" 25 | #include "mc/network/packet/InventoryTransactionPacket.h" 26 | #include "mc/network/packet/LevelChunkPacket.h" 27 | #include "mc/network/packet/PlayerActionPacket.h" 28 | #include "mc/network/packet/PlayerActionType.h" 29 | #include "mc/network/packet/PlayerAuthInputPacket.h" 30 | #include "mc/network/packet/RemoveVolumeEntityPacket.h" 31 | #include "mc/network/packet/SpawnParticleEffectPacket.h" 32 | #include "mc/network/packet/StartGamePacket.h" 33 | #include "mc/network/packet/SubChunkPacket.h" 34 | #include "mc/network/packet/SubChunkRequestPacket.h" 35 | #include "mc/network/packet/UpdateBlockPacket.h" 36 | #include "mc/server/ServerPlayer.h" 37 | #include "mc/util/MolangVariableMap.h" 38 | #include "mc/util/VarIntDataOutput.h" 39 | #include "mc/world/actor/ActorDataIDs.h" 40 | #include "mc/world/actor/SynchedActorDataEntityWrapper.h" 41 | #include "mc/world/level/ChangeDimensionRequest.h" 42 | #include "mc/world/level/ChunkPos.h" 43 | #include "mc/world/level/Level.h" 44 | #include "mc/world/level/LoadingScreenIdManager.h" 45 | #include "mc/world/level/SpawnSettings.h" 46 | #include "mc/world/level/dimension/VanillaDimensions.h" 47 | #include "mc/world/level/levelSettings.h" 48 | 49 | 50 | // ChangeDimensionPacket.java 51 | // ClientboundMapItemDataPacket.java 52 | // RemoveVolumeEntityPacket.java 53 | // StartGamePacket.java 54 | // AddVolumeEntityPacket.java 55 | // SpawnParticleEffectPacket.java 56 | // SubChunkPacket.java 57 | // SubChunkRequestPacket.java 58 | 59 | namespace more_dimensions { 60 | 61 | // static ll::Logger logger("FakeDimensionId"); 62 | auto& logger = MoreDimenison::getInstance().getSelf().getLogger(); 63 | 64 | static void sendEmptyChunk(const NetworkIdentifier& netId, int chunkX, int chunkZ, bool forceUpdate) { 65 | std::array biome{}; 66 | LevelChunkPacket levelChunkPacket; 67 | BinaryStream binaryStream{levelChunkPacket.mSerializedChunk, false}; 68 | VarIntDataOutput varIntDataOutput(binaryStream); 69 | 70 | varIntDataOutput.writeBytes(&biome, 4096); // write void biome 71 | for (int i = 1; i <= 8; i++) { 72 | varIntDataOutput.writeByte(255ui8); 73 | } 74 | varIntDataOutput.mStream.writeByte(0, "Byte", 0); // write border blocks 75 | 76 | levelChunkPacket.mPos->x = chunkX; 77 | levelChunkPacket.mPos->z = chunkZ; 78 | levelChunkPacket.mDimensionId = FakeDimensionId::temporaryDimId; 79 | levelChunkPacket.mCacheEnabled = false; 80 | levelChunkPacket.mSubChunksCount = 0; 81 | 82 | ll::service::getLevel()->getPacketSender()->sendToClient(netId, levelChunkPacket, SubClientId::PrimaryClient); 83 | 84 | if (forceUpdate) { 85 | NetworkBlockPosition pos{ 86 | BlockPos{chunkX << 4, 80, chunkZ << 4} 87 | }; 88 | UpdateBlockPacket blockPacket; 89 | blockPacket.mPos = pos; 90 | blockPacket.mLayer = 0; 91 | blockPacket.mUpdateFlags = 1; 92 | ll::service::getLevel()->getPacketSender()->sendToClient(netId, blockPacket, SubClientId::PrimaryClient); 93 | } 94 | } 95 | 96 | static void sendEmptyChunks(const NetworkIdentifier& netId, const Vec3& position, int radius, bool forceUpdate) { 97 | int chunkX = (int)(position.x) >> 4; 98 | int chunkZ = (int)(position.z) >> 4; 99 | for (int x = -radius; x <= radius; x++) { 100 | for (int z = -radius; z <= radius; z++) { 101 | sendEmptyChunk(netId, chunkX + x, chunkZ + z, forceUpdate); 102 | } 103 | } 104 | } 105 | 106 | static void fakeChangeDimension( 107 | const NetworkIdentifier& netId, 108 | ActorRuntimeID runtimeId, 109 | DimensionType fakeDimId, 110 | const Vec3& pos, 111 | std::optional screedId 112 | ) { 113 | // ChangeDimensionPacket changeDimensionPacket{fakeDimId, pos, true, {std::nullopt}}; 114 | ChangeDimensionPacket changeDimensionPacket; 115 | changeDimensionPacket.mDimensionId = fakeDimId; 116 | changeDimensionPacket.mPos = pos; 117 | changeDimensionPacket.mRespawn = true; 118 | changeDimensionPacket.mLoadingScreenId = {screedId}; 119 | ll::service::getLevel()->getPacketSender()->sendToClient(netId, changeDimensionPacket, SubClientId::PrimaryClient); 120 | PlayerActionPacket playerActionPacket; 121 | playerActionPacket.mAction = PlayerActionType::ChangeDimensionAck; 122 | playerActionPacket.mRuntimeId = runtimeId; 123 | ll::service::getLevel()->getPacketSender()->sendToClient(netId, playerActionPacket, SubClientId::PrimaryClient); 124 | sendEmptyChunks(netId, pos, 3, true); 125 | } 126 | 127 | namespace CustomDimensionHookList { 128 | 129 | namespace sendpackethook { 130 | 131 | LL_TYPE_INSTANCE_HOOK( 132 | LoopbackPacketSendersendToClientHandler1, 133 | HookPriority::Normal, 134 | LoopbackPacketSender, 135 | &LoopbackPacketSender::$sendToClient, 136 | void, 137 | NetworkIdentifier const& netId, 138 | Packet const& packet, 139 | ::SubClientId subId 140 | ) { 141 | auto player = ll::service::getServerNetworkHandler()->_getServerPlayer(netId, subId); 142 | if (player && player->getDimensionId() >= 3 && packet.getId() != MinecraftPacketIds::ChangeDimension 143 | && packet.getId() != MinecraftPacketIds::PlayerAction 144 | && packet.getId() != MinecraftPacketIds::SpawnParticleEffect) { 145 | FakeDimensionId::changePacketDimension(const_cast(packet)); 146 | } 147 | if (player && player->getDimensionId() >= 3 && packet.getId() == MinecraftPacketIds::FullChunkData) { 148 | auto& modifPacket = (LevelChunkPacket&)packet; 149 | if (modifPacket.mDimensionId->id >= 3) { 150 | modifPacket.mDimensionId = 0; 151 | } 152 | if (modifPacket.mDimensionId->id == VanillaDimensions::Undefined().id) { 153 | modifPacket.mDimensionId->id = 3; 154 | } 155 | if (modifPacket.mClientRequestSubChunkLimit <= 8) { 156 | modifPacket.mClientRequestSubChunkLimit = 11; 157 | } 158 | } 159 | return origin(netId, packet, subId); 160 | }; 161 | 162 | LL_TYPE_INSTANCE_HOOK( 163 | LoopbackPacketSendersendToClientHandler2, 164 | HookPriority::Normal, 165 | LoopbackPacketSender, 166 | &LoopbackPacketSender::$sendToClient, 167 | void, 168 | UserEntityIdentifierComponent const* comp, 169 | Packet const& packet 170 | ) { 171 | auto player = ll::service::getServerNetworkHandler()->_getServerPlayer(comp->mNetworkId, comp->mClientSubId); 172 | if (!player) return origin(comp, packet); 173 | auto uuid = player->getUuid(); 174 | if (player && player->getDimensionId() >= 3 && packet.getId() != MinecraftPacketIds::ChangeDimension 175 | && packet.getId() != MinecraftPacketIds::PlayerAction 176 | && packet.getId() != MinecraftPacketIds::SpawnParticleEffect) { 177 | FakeDimensionId::changePacketDimension(const_cast(packet)); 178 | } 179 | 180 | // remove send changeDimensionPacket to client when player die 181 | if (FakeDimensionId::getInstance().isNeedRemove(uuid) && packet.getId() == MinecraftPacketIds::ChangeDimension) { 182 | return; 183 | } 184 | // remove level event packet, event id is 9801, LevelEvent is SleepingPlayers 185 | if (packet.getId() == MinecraftPacketIds::LevelEventGeneric && FakeDimensionId::getInstance().isNeedRemove(uuid)) { 186 | return; 187 | } 188 | // remove send changedimension success action packet to client when player die 189 | if (FakeDimensionId::getInstance().isNeedRemove(uuid) && packet.getId() == MinecraftPacketIds::PlayerAction) { 190 | auto& actionPacket = (PlayerActionPacket&)packet; 191 | if (actionPacket.mAction == PlayerActionType::ChangeDimensionAck) { 192 | return; 193 | } 194 | } 195 | // use fake dimension id when player go to custom dimension 196 | if (packet.getId() == MinecraftPacketIds::ChangeDimension) { 197 | auto& modifPacket = (ChangeDimensionPacket&)packet; 198 | if (modifPacket.mDimensionId->id > 2) { 199 | modifPacket.mDimensionId->id = FakeDimensionId::fakeDim; 200 | } 201 | } 202 | return origin(comp, packet); 203 | }; 204 | 205 | LL_TYPE_INSTANCE_HOOK( 206 | LoopbackPacketSendersendToClientsHandler, 207 | HookPriority::Normal, 208 | LoopbackPacketSender, 209 | &LoopbackPacketSender::$sendToClients, 210 | void, 211 | std::vector const& subIds, 212 | Packet const& packet 213 | ) { 214 | if (packet.getId() == MinecraftPacketIds::RemoveVolumeEntityPacket 215 | || packet.getId() == MinecraftPacketIds::AddVolumeEntityPacket) { 216 | for (auto& subId : subIds) { 217 | auto player = 218 | ll::service::getServerNetworkHandler()->_getServerPlayer(subId.id, SubClientId::PrimaryClient); 219 | if (player && player->getDimensionId() >= 3) { 220 | FakeDimensionId::changePacketDimension(const_cast(packet)); 221 | } 222 | packet.sendToClient(subId); 223 | } 224 | return; 225 | } 226 | return origin(subIds, packet); 227 | }; 228 | 229 | // StartGamePacket 230 | LL_TYPE_INSTANCE_HOOK( 231 | StartGamePacketHandler, 232 | HookPriority::Normal, 233 | StartGamePacket, 234 | &StartGamePacket::$ctor, 235 | void*, 236 | LevelSettings const& levelSettings, 237 | ActorUniqueID uniqueId, 238 | ActorRuntimeID runtimeId, 239 | ::GameType gameType, 240 | bool unk, 241 | Vec3 const& pos, 242 | Vec2 const& ros, 243 | std::string const& levelId, 244 | std::string const& levelName, 245 | ContentIdentity const& contentIdentity, 246 | std::string const& unk1, 247 | BlockDefinitionGroup const& blockDefinitionGroup, 248 | bool unk2, 249 | CompoundTag compoundTag, 250 | PlayerMovementSettings const& moveSetting, 251 | std::string const& unk3, 252 | mce::UUID const& uuid, 253 | uint64 unk4, 254 | int unk5, 255 | uint64 unk6 256 | ) { 257 | if (levelSettings.getSpawnSettings().dimension->id >= 3) { 258 | SpawnSettings spawnSettings(levelSettings.getSpawnSettings()); 259 | spawnSettings.dimension = FakeDimensionId::fakeDim; 260 | const_cast(levelSettings).setSpawnSettings(spawnSettings); 261 | } 262 | return origin( 263 | levelSettings, 264 | uniqueId, 265 | runtimeId, 266 | gameType, 267 | unk, 268 | pos, 269 | ros, 270 | levelId, 271 | levelName, 272 | contentIdentity, 273 | unk1, 274 | blockDefinitionGroup, 275 | unk2, 276 | std::move(compoundTag), 277 | moveSetting, 278 | unk3, 279 | uuid, 280 | unk4, 281 | unk5, 282 | unk6 283 | ); 284 | } 285 | 286 | // ChangeDimensionPacket 287 | // inline function use seedtoClient -> line 200 288 | // LL_TYPE_INSTANCE_HOOK( 289 | // ChangeDimensionPacketHandler, 290 | // HookPriority::Normal, 291 | // ChangeDimensionPacket, 292 | // &ChangeDimensionPacket::$ctor, 293 | // void*, 294 | // DimensionType dimId, 295 | // Vec3 pos, 296 | // bool respawn, 297 | // NewType<::std::optional> loadingScreenId 298 | // ) { 299 | // if (dimId > 2) { 300 | // dimId = FakeDimensionId::fakeDim; 301 | // } 302 | // return origin(dimId, pos, respawn, loadingScreenId); 303 | // } 304 | 305 | LL_TYPE_INSTANCE_HOOK( 306 | ChangeDimensionPacketHandler, 307 | HookPriority::Normal, 308 | ChangeDimensionPacket, 309 | &ChangeDimensionPacket::$write, 310 | void, 311 | BinaryStream& stream 312 | ) { 313 | stream.writeVarInt( 314 | this->mDimensionId->id, 315 | "Dimension ID", 316 | "Currently supported: (0 -> Overworld, 1 -> Nether, 2 -> The End, 3 -> Undefined)"); 317 | stream.writeFloat(this->mPos->x, "X", 0LL); 318 | stream.writeFloat(this->mPos->y, "Y", 0LL); 319 | stream.writeFloat(this->mPos->z, "Z", 0LL); 320 | stream.writeBool(this->mRespawn, "Respawn", 0LL); 321 | stream.writeBool(this->mLoadingScreenId->mValue.has_value(), "Has Value", "If true, follow with appropriate data type, otherwise nothing"); 322 | if (this->mLoadingScreenId->mValue.has_value()) 323 | stream.writeUnsignedInt(this->mLoadingScreenId->mValue.value(), "Unsigned Int", 0LL); 324 | } 325 | 326 | // SubChunkPacket and SubChunkRequestPacket 327 | LL_TYPE_INSTANCE_HOOK( 328 | SubChunkPacketHandler, 329 | HookPriority::Highest, 330 | ServerNetworkHandler, 331 | &ServerNetworkHandler::_buildSubChunkPacketData, 332 | void, 333 | NetworkIdentifier const& networkIdentifier, 334 | ServerPlayer const* serverPlayer, 335 | SubChunkRequestPacket const& subChunkRequestPacket, 336 | SubChunkPacket& subChunkPacket, 337 | uint count, 338 | bool isCacheEnabled 339 | ) { 340 | auto inDim = serverPlayer->getDimensionId(); 341 | if (inDim >= 3) { 342 | const_cast(subChunkRequestPacket).mDimensionType = inDim; 343 | // dimensionType value of subChunkPacket is not read in this function, so it is changed together. 344 | subChunkPacket.mDimensionType = FakeDimensionId::fakeDim; 345 | }; 346 | return origin(networkIdentifier, serverPlayer, subChunkRequestPacket, subChunkPacket, count, isCacheEnabled); 347 | } 348 | 349 | // SpawnParticleEffectPacket 350 | LL_TYPE_INSTANCE_HOOK( 351 | SpawnParticleEffectPacketHandler, 352 | HookPriority::Normal, 353 | SpawnParticleEffectPacket, 354 | &SpawnParticleEffectPacket::$ctor, 355 | void*, 356 | Vec3 const& pos, 357 | std::string const& particle_name, 358 | uchar dimId, 359 | std::optional molang 360 | ) { 361 | if (dimId >= 3) { 362 | dimId = FakeDimensionId::fakeDim.id; 363 | } 364 | return origin(pos, particle_name, dimId, std::move(molang)); 365 | } 366 | 367 | } // namespace sendpackethook 368 | 369 | LL_TYPE_INSTANCE_HOOK( 370 | PlayerdieHandler, 371 | HookPriority::Normal, 372 | Player, 373 | &Player::$die, 374 | void, 375 | ActorDamageSource const& actorDamageSource 376 | ) { 377 | if (getDimensionId() >= 3) { 378 | logger.debug("Remove set true"); 379 | FakeDimensionId::getInstance().setNeedRemove(getUuid(), true); 380 | } 381 | return origin(actorDamageSource); 382 | } 383 | 384 | namespace receivepackethook { 385 | 386 | // when player in overworld and custom dimension will need 387 | LL_TYPE_INSTANCE_HOOK( 388 | ServerNetworkHandlerPlayerActionPacketHandler, 389 | HookPriority::Normal, 390 | ServerNetworkHandler, 391 | &ServerNetworkHandler::$handle, 392 | void, 393 | NetworkIdentifier const& netId, 394 | PlayerActionPacket const& packet 395 | ) { 396 | auto& handler = ll::memory::dAccess(this, -16); 397 | auto player = handler._getServerPlayer(netId, packet.mSenderSubId); 398 | auto uuid = player->getUuid(); 399 | auto& fakeDimensionId = FakeDimensionId::getInstance(); 400 | if (packet.mAction == PlayerActionType::Respawn) { 401 | // when player go overworld with die 402 | if (!fakeDimensionId.isNeedRemove(uuid)) { 403 | return origin(netId, packet); 404 | } 405 | fakeDimensionId.setNeedRemove(uuid, false); 406 | auto moveComp = player->getEntityContext().tryGetComponent(); 407 | if (moveComp) { 408 | moveComp->mServerHasMovementAuthority = false; 409 | } 410 | fakeDimensionId.onPlayerLeftCustomDimension(uuid, true); 411 | // flash player bounding box 412 | // player->getEntityData().markDirty(fmt::underlying(ActorDataIDs::CollisionBox)); 413 | } 414 | return origin(netId, packet); 415 | }; 416 | } // namespace receivepackethook 417 | 418 | LL_TYPE_INSTANCE_HOOK( 419 | LevelrequestPlayerChangeDimensionHandler, 420 | HookPriority::Normal, 421 | Level, 422 | &Level::$requestPlayerChangeDimension, 423 | void, 424 | Player& player, 425 | ChangeDimensionRequest&& changeRequest 426 | ) { 427 | auto inId = player.getDimensionId(); 428 | if (changeRequest.mToDimensionId->id == 1 || changeRequest.mToDimensionId->id == 2 || inId.id == 1 || inId.id == 2 429 | || player.isDead()) { 430 | return origin(player, std::move(changeRequest)); 431 | }; 432 | // issue #7 433 | auto loadingScreenIdManager = ll::memory::dAccess(&this->mLoadingScreenIdManager, 8); 434 | auto screedId = loadingScreenIdManager->mUnk7db596.as() + 1; 435 | ++loadingScreenIdManager->mUnk7db596.as(); 436 | // screedId.mValue.emplace(screedId.mValue.value() + 1); 437 | 438 | fakeChangeDimension( 439 | player.getNetworkIdentifier(), 440 | player.getRuntimeID(), 441 | more_dimensions::FakeDimensionId::temporaryDimId, 442 | player.getPosition(), 443 | screedId 444 | ); 445 | return origin(player, std::move(changeRequest)); 446 | } 447 | 448 | using HookReg = ll::memory::HookRegistrar< 449 | sendpackethook::LoopbackPacketSendersendToClientHandler1, 450 | sendpackethook::LoopbackPacketSendersendToClientHandler2, 451 | sendpackethook::LoopbackPacketSendersendToClientsHandler, 452 | // sendpackethook::ChangeDimensionPacketHandler, 453 | sendpackethook::SubChunkPacketHandler, 454 | sendpackethook::SpawnParticleEffectPacketHandler, 455 | sendpackethook::StartGamePacketHandler, 456 | PlayerdieHandler, 457 | LevelrequestPlayerChangeDimensionHandler, 458 | receivepackethook::ServerNetworkHandlerPlayerActionPacketHandler>; 459 | 460 | } // namespace CustomDimensionHookList 461 | 462 | FakeDimensionId::FakeDimensionId() { CustomDimensionHookList::HookReg::hook(); } 463 | 464 | FakeDimensionId::~FakeDimensionId() { CustomDimensionHookList::HookReg::unhook(); } 465 | 466 | FakeDimensionId& FakeDimensionId::getInstance() { 467 | static FakeDimensionId ins{}; 468 | return ins; 469 | } 470 | 471 | void FakeDimensionId::changePacketDimension(Packet& packet) { 472 | auto packId = packet.getId(); 473 | switch (packId) { 474 | case MinecraftPacketIds::RemoveVolumeEntityPacket: { 475 | auto& tempP = (RemoveVolumeEntityPacket&)packet; 476 | tempP.mDimensionType = fakeDim; 477 | logger.debug("MinecraftPacketIds::RemoveVolumeEntityPacket: dimId change to {}", fakeDim.id); 478 | } 479 | case MinecraftPacketIds::AddVolumeEntityPacket: { 480 | auto& tempP = (AddVolumeEntityPacket&)packet; 481 | tempP.mDimensionType = fakeDim; 482 | logger.debug("MinecraftPacketIds::AddVolumeEntityPacket: dimId change to {}", fakeDim.id); 483 | } 484 | default: 485 | return; 486 | } 487 | } 488 | 489 | void FakeDimensionId::setNeedRemove(mce::UUID uuid, bool needRemove) { 490 | if (mSettingMap.count(uuid)) { 491 | mSettingMap.at(uuid).needRemovePacket = needRemove; 492 | } else { 493 | mSettingMap.emplace(uuid, CustomDimensionIdSetting{needRemove}); 494 | } 495 | } 496 | 497 | bool FakeDimensionId::isNeedRemove(mce::UUID uuid) { 498 | if (mSettingMap.count(uuid)) { 499 | return mSettingMap.at(uuid).needRemovePacket; 500 | }; 501 | return false; 502 | } 503 | 504 | void FakeDimensionId::onPlayerGoCustomDimension(mce::UUID uuid) { 505 | if (!mSettingMap.count(uuid)) { 506 | std::lock_guard lockGuard{mMapMutex}; 507 | mSettingMap.emplace(uuid, CustomDimensionIdSetting{false}); 508 | } 509 | } 510 | 511 | void FakeDimensionId::onPlayerLeftCustomDimension(mce::UUID uuid, bool isRespawn) { 512 | std::lock_guard lockGuard{mMapMutex}; 513 | if (mSettingMap.count(uuid)) { 514 | if (isRespawn) { 515 | mSettingMap.at(uuid).needRemovePacket = false; 516 | } else { 517 | mSettingMap.erase(uuid); 518 | } 519 | } 520 | } 521 | 522 | } // namespace more_dimensions 523 | -------------------------------------------------------------------------------- /src/more_dimensions/core/dimension/FakeDimensionId.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/deps/core/utility/AutomaticID.h" 4 | #include "mc/network/packet/Packet.h" 5 | #include "mc/platform/UUID.h" 6 | 7 | 8 | #include 9 | #include 10 | 11 | class ServerPlayer; 12 | 13 | namespace more_dimensions { 14 | 15 | class FakeDimensionId { 16 | struct CustomDimensionIdSetting { 17 | bool needRemovePacket{}; 18 | }; 19 | std::mutex mMapMutex; 20 | 21 | std::unordered_map mSettingMap; // save in more dimension player 22 | public: 23 | static constexpr AutomaticID fakeDim = 0; // Overworld, Make the client think of the dimension 24 | static constexpr AutomaticID temporaryDimId = 1; // Dimensions of transit 25 | 26 | static FakeDimensionId& getInstance(); 27 | 28 | FakeDimensionId(); 29 | ~FakeDimensionId(); 30 | static void changePacketDimension(Packet& packet); 31 | void setNeedRemove(mce::UUID uuid, bool needRemove); 32 | bool isNeedRemove(mce::UUID uuid); 33 | void onPlayerGoCustomDimension(mce::UUID uuid); 34 | void onPlayerLeftCustomDimension(mce::UUID uuid, bool isRespawn); 35 | }; 36 | } // namespace more_dimensions 37 | -------------------------------------------------------------------------------- /src/more_dimensions/core/dimension/MoreDimensionsPatch.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | extern "C" { 7 | __declspec(dllimport) bool pl_notice(void* target); 8 | } 9 | namespace { 10 | struct AddressAndReg { 11 | DWORD func_rva; 12 | DWORD func_rva_start; 13 | DWORD func_rva_end; 14 | const std::vector native_code; 15 | }; 16 | 17 | // 0~26 VanillaDimensions::toSerializedInt 18 | // 27~39 VanillaDimensions::fromSerializedInt(int) 19 | std::vector data = { 20 | {0x08440f0, 0x08443cf, 0x08443fa, {0x89, 0xc8} }, 21 | {0x262a500, 0x262a5f5, 0x262a617, {0x89, 0xc3} }, 22 | {0x104de80, 0x104deb7, 0x104dee0, {0x89, 0xc2} }, 23 | {0x10a4f60, 0x10a4fee, 0x10a5017, {0x89, 0xc2} }, 24 | {0x1089720, 0x1089770, 0x1089799, {0x89, 0xc2} }, 25 | {0x108a620, 0x108a655, 0x108a67e, {0x89, 0xc2} }, 26 | {0x0d018e0, 0x0d01ed2, 0x0d01efb, {0x89, 0xc3} }, 27 | {0x1062410, 0x10625e3, 0x1062606, {0x89, 0xc3} }, 28 | {0x0d93460, 0x0d9347f, 0x0d934a8, {0x89, 0xc2} }, 29 | {0x0d71150, 0x0d711a4, 0x0d711cd, {0x89, 0xc2} }, 30 | {0x197e0f0, 0x197e4ab, 0x197e4d3, {0x41, 0x88, 0xc9} }, 31 | {0x197e670, 0x197e76b, 0x197e78e, {0x88, 0xc8} }, 32 | {0x171f790, 0x171fab7, 0x171fadf, {0x41, 0x88, 0xc9} }, 33 | {0x25c0140, 0x25c09c7, 0x25c09f2, {0x89, 0xc3} }, 34 | {0x2569f20, 0x256a388, 0x256a3b3, {0x89, 0xc3} }, 35 | {0x2569f20, 0x256a834, 0x256a860, {0x89, 0xdf} }, 36 | {0x2567090, 0x2567841, 0x2567867, {0x41, 0x89, 0xc6} }, 37 | {0x2582d50, 0x2582e80, 0x2582ea9, {0x89, 0xc3} }, 38 | {0x25825e0, 0x25825f0, 0x258261b, {0x89, 0xd3} }, 39 | {0x2d2ca90, 0x2d2ccb2, 0x2d2cce0, {0x41, 0x89, 0xc6} }, 40 | {0x2d2faf0, 0x2d2fc40, 0x2d2fc64, {0x89, 0xc7} }, 41 | {0x2d3e700, 0x2d3e75e, 0x2d3e781, {0x88, 0xd8} }, 42 | {0x2984bf0, 0x2984cb3, 0x2984cd6, {0x89, 0xc3} }, 43 | {0x30e4420, 0x30e4432, 0x30e4460, {0x41, 0x89, 0xc3} }, 44 | {0x31f7d10, 0x31f7e35, 0x31f7e59, {0x89, 0xcb} }, 45 | {0x31f8e10, 0x31f8e8e, 0x31f8eb3, {0x89, 0xdf} }, 46 | {0x336cb80, 0x336cccd, 0x336ccf5, {0x40, 0x88, 0xc7} }, 47 | {0x25c22a0, 0x25c33dd, 0x25c340d, {0x41, 0x89, 0xc8} }, 48 | {0x25e02f0, 0x25e04bc, 0x25e04e8, {0x89, 0xc8} }, 49 | {0x0b92a60, 0x0b92d10, 0x0b92d60, {0x89, 0x8e, 0x3c, 0x0, 0x0, 0x0}}, 50 | {0x0cbde50, 0x0cbdfc9, 0x0cbdff5, {0x89, 0xcb} }, 51 | {0x0d013f0, 0x0d01657, 0x0d01683, {0x89, 0xcf} }, 52 | {0x10fef90, 0x10ff015, 0x10ff04d, {0x89, 0xc8} }, 53 | {0x25824e0, 0x2582560, 0x25825c2, {0x89, 0xc8} }, 54 | {0x2a572d0, 0x25687a5, 0x25687ea, {0x89, 0x8e, 0xe0, 0xa, 0x0, 0x0}}, 55 | {0x2d2c450, 0x2d2c5c1, 0x2d2c5ed, {0x89, 0xc8} }, 56 | {0x2d2fcd0, 0x2d2fe6e, 0x2d2fe9a, {0x89, 0xc8} }, 57 | {0x31ff0b0, 0x31ff164, 0x31ff190, {0x89, 0xc8} }, 58 | {0x336e8e0, 0x336e998, 0x336e9c7, {} }, 59 | }; 60 | 61 | bool PatchFunction(HMODULE hModule, DWORD faddress_start, DWORD faddress_end, const std::vector& native_code) { 62 | LPVOID patchAddress = (LPVOID)((DWORD_PTR)hModule + faddress_start); 63 | 64 | 65 | // Construct the patch 66 | std::vector patch; 67 | 68 | patch.insert(patch.end(), native_code.begin(), native_code.end()); 69 | 70 | 71 | // jmp faddress_end 72 | // Calculate the relative offset for the jump 73 | DWORD_PTR offset = (DWORD_PTR)hModule + faddress_end 74 | - ((DWORD_PTR)patchAddress + patch.size() + 5); // +5 for the size of the jmp instruction 75 | 76 | patch.push_back(0xE9); // jmp opcode 77 | patch.push_back((BYTE)(offset & 0xFF)); 78 | patch.push_back((BYTE)((offset >> 8) & 0xFF)); 79 | patch.push_back((BYTE)((offset >> 16) & 0xFF)); 80 | patch.push_back((BYTE)((offset >> 24) & 0xFF)); 81 | 82 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); 83 | 84 | // Write the patch to memory 85 | DWORD oldProtect; 86 | if (!VirtualProtect(patchAddress, patch.size(), PAGE_EXECUTE_READWRITE, &oldProtect)) { 87 | std::cerr << "Failed to change memory protection" << std::endl; 88 | return false; 89 | } 90 | 91 | SIZE_T bytesWritten; 92 | if (!WriteProcessMemory(hProcess, patchAddress, patch.data(), patch.size(), &bytesWritten) 93 | || bytesWritten != patch.size()) { 94 | std::cerr << "Failed to write to process memory" << std::endl; 95 | CloseHandle(hProcess); 96 | return false; 97 | } 98 | 99 | if (!VirtualProtect(patchAddress, patch.size(), oldProtect, &oldProtect)) { 100 | std::cerr << "Failed to restore memory protection" << std::endl; 101 | return false; // Though the patch is applied, restoring protection failed. 102 | } 103 | 104 | return true; 105 | } 106 | 107 | void printHexBytes(const void* address, size_t numBytes) { 108 | const unsigned char* start = static_cast(address); 109 | 110 | for (size_t i = 0; i < numBytes; ++i) { 111 | std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast(start[i]) << " "; 112 | // Optionally add a newline after every 16 bytes for better readability 113 | if ((i + 1) % 16 == 0) { 114 | std::cout << std::endl; 115 | } 116 | } 117 | std::cout << std::dec << std::endl; // Reset to decimal output 118 | } 119 | 120 | } // namespace 121 | 122 | 123 | void injectNaticeCode() { 124 | // Calculate the address in the target process 125 | HMODULE hModule = GetModuleHandle(L"bedrock_server_mod.exe"); 126 | if (!hModule) { 127 | std::cerr << "Failed to get module handle for bedrock_server_mod.exe" << std::endl; 128 | return; 129 | } 130 | for (auto& item : data) { 131 | PatchFunction(hModule, item.func_rva_start, item.func_rva_end, item.native_code); 132 | void* funcp = (void*)((BYTE*)hModule + item.func_rva); 133 | pl_notice(funcp); 134 | }; 135 | }; 136 | 137 | // BOOL APIENTRY DllMain(HMODULE hModule, 138 | // DWORD ul_reason_for_call, 139 | // LPVOID lpReserved 140 | // ) 141 | // { 142 | // switch (ul_reason_for_call) 143 | // { 144 | // case DLL_PROCESS_ATTACH: 145 | // injectNaticeCode(); 146 | // break; 147 | // case DLL_THREAD_ATTACH: 148 | // case DLL_THREAD_DETACH: 149 | // case DLL_PROCESS_DETACH: 150 | // break; 151 | // } 152 | // return TRUE; 153 | // } -------------------------------------------------------------------------------- /src/test/TestCustomDimension.cpp: -------------------------------------------------------------------------------- 1 | #include "test/generator/flat-gen-village/FlatVillageDimension.h" 2 | #include "test/generator/generator-custom-structure/dimension/CustomStructureDimension.h" 3 | #include "test/generator/generator-terrain/NxnBorderTerrainDimension.h" 4 | 5 | #include "ll/api/event/EventBus.h" 6 | #include "ll/api/event/server/ServerStartedEvent.h" 7 | 8 | #include "more_dimensions/api/dimension/CustomDimensionManager.h" 9 | #include "more_dimensions/api/dimension/SimpleCustomDimension.h" 10 | 11 | static bool reg = [] { 12 | using namespace ll::event; 13 | EventBus::getInstance().emplaceListener([](ServerStartedEvent&) { 14 | // simplate dimension test 15 | // vanilla overworld type dimension test 16 | more_dimensions::CustomDimensionManager::getInstance().addDimension( 17 | "testNewDimension" 18 | ); 19 | 20 | // vanilla flat type dimension test 21 | more_dimensions::CustomDimensionManager::getInstance() 22 | .addDimension("testNewFlatDimension", 345, GeneratorType::Flat); 23 | 24 | // vanilla nether type dimension test 25 | more_dimensions::CustomDimensionManager::getInstance() 26 | .addDimension("testNewNetherDimension", 345, GeneratorType::Nether); 27 | 28 | // vanilla the end type dimension test 29 | more_dimensions::CustomDimensionManager::getInstance() 30 | .addDimension("testNewTheEndDimension", 345, GeneratorType::TheEnd); 31 | 32 | // vanilla void dimension test 33 | more_dimensions::CustomDimensionManager::getInstance() 34 | .addDimension("testNewVoidDimension", 345, GeneratorType::Void); 35 | 36 | // custom diomension test 37 | // flat type generator village dimension test 38 | more_dimensions::CustomDimensionManager::getInstance() 39 | .addDimension("testFlatVillage"); 40 | 41 | // flat type custom terrain dimension test 42 | more_dimensions::CustomDimensionManager::getInstance() 43 | .addDimension("testFlatTerrain", 5); 44 | 45 | // flat type custom structure dimension test 46 | more_dimensions::CustomDimensionManager::getInstance() 47 | .addDimension("testCustomStructure"); 48 | }); 49 | return true; 50 | }(); 51 | 52 | 53 | // #include "ll/api/memory/Hook.h" 54 | // #include "mc/world/level/DimensionManager.h" 55 | 56 | 57 | // LL_AUTO_TYPE_INSTANCE_HOOK( 58 | // GetOrCreateDimension, 59 | // HookPriority::Normal, 60 | // DimensionManager, 61 | // &DimensionManager::getOrCreateDimension, 62 | // WeakRef, 63 | // DimensionType dim 64 | // ) { 65 | // std::cout << "getOrCreateDimension->" << dim.id << std::endl; 66 | // return origin(dim); 67 | // }; 68 | 69 | // #include "mc/server/commands/standard/TeleportCommand.h" 70 | // #include "mc/server/commands/standard/TeleportTarget.h" 71 | // #include "mc/util/rotation_command_utils/RotationData.h" 72 | // #include "mc/world/level/dimension/VanillaDimensions.h" 73 | // LL_AUTO_TYPE_STATIC_HOOK( 74 | // TeleportCommandTest, 75 | // HookPriority::Normal, 76 | // TeleportCommand, 77 | // &TeleportCommand::computeTarget, 78 | // TeleportTarget, 79 | // ::Actor& victim, 80 | // ::Vec3 destination, 81 | // ::Vec3* facePosition, 82 | // ::DimensionType destinationDimension, 83 | // ::std::optional<::RotationCommandUtils::RotationData> const& rotationData, 84 | // int commandVersion 85 | // ) { 86 | // for(auto& item:VanillaDimensions::DimensionMap().mLeft) { 87 | // std::cout<<"Dimension name: "<" << destinationDimension << std::endl; 93 | // return origin(victim, destination, facePosition, destinationDimension, rotationData, commandVersion); 94 | // }; 95 | 96 | // 97 | // LL_AUTO_TYPE_INSTANCE_HOOK( 98 | // DimensonFactory123, 99 | // HookPriority::Normal, 100 | // DimensionFactory, 101 | // "?create@DimensionFactory@@UEBA?AV?$OwnerPtr@VDimension@@@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z", 102 | // OwnerPtr, 103 | // std::string const &name) { 104 | // std::cout<<"Dimension creative->"<getOrCreateDimension(param.p1); 137 | // if (dim.expired()) { 138 | // std::cout<<"他宝贝的,销毁了"<mName<getDimensionManager(); 144 | // for (auto& item: dimM.mDimensions) { 145 | // std::cout<<"Dimension have->" <"<"<() 154 | // .required("p1") 155 | // .execute(lambda); 156 | // } 157 | 158 | // #include "mc/world/level/LoadingScreenIdManager.h" 159 | // #include "ll/api/memory/Hook.h" 160 | 161 | // LL_AUTO_TYPE_INSTANCE_HOOK( 162 | // ScreenIdHookTest, 163 | // ll::memory::HookPriority::Normal, 164 | // LoadingScreenIdManager, 165 | // &LoadingScreenIdManager::getNextLoadingScreenId, 166 | // NewType<::std::optional>) { 167 | // auto result = origin(); 168 | // if (result.mValue.has_value()){ 169 | // std::cout<<"Test screedId: "<sky = Brightness::MAX(); 30 | mSeaLevel = -61; 31 | mHasWeather = true; 32 | mDimensionBrightnessRamp = std::make_unique(); 33 | mDimensionBrightnessRamp->buildBrightnessRamp(); 34 | } 35 | 36 | CompoundTag FlatVillageDimension::generateNewData() { return {}; } 37 | 38 | std::unique_ptr 39 | FlatVillageDimension::createGenerator(br::worldgen::StructureSetRegistry const& structureSetRegistry) { 40 | std::unique_ptr worldGenerator; 41 | uint seed = 2024; 42 | auto& levelData = mLevel.getLevelData(); 43 | 44 | // 实例化我们写的Generator类 45 | worldGenerator = std::make_unique( 46 | *this, 47 | seed, 48 | levelData.mFlatWorldOptions 49 | ); 50 | // structureSetRegistry里面仅有的土径结构村庄生成需要用到,所以我们拿一下 51 | std::vector> structureMap; 52 | for (auto iter = structureSetRegistry.mStructureSets->begin(); iter != structureSetRegistry.mStructureSets->end(); 53 | iter++) { 54 | structureMap.emplace_back(iter->second); 55 | } 56 | worldGenerator->mStructureFeatureRegistry->mGeneratorState->mSeed = seed; 57 | worldGenerator->mStructureFeatureRegistry->mGeneratorState->mSeed64 = LevelSeed64{seed}; 58 | 59 | // 这个就相当于在这个生成器里注册结构了 60 | // VillageFeature的第二第三个参数是村庄之间的最大间隔与最小间隔 61 | worldGenerator->mStructureFeatureRegistry->mStructureFeatures->emplace_back( 62 | std::make_unique(seed, 34, 8) 63 | ); 64 | // 此为必须,一些结构生成相关 65 | worldGenerator->mStructureFeatureRegistry->mGeneratorState = 66 | br::worldgen::ChunkGeneratorStructureState::createFlat(seed, worldGenerator->getBiomeSource(), structureMap); 67 | 68 | // 必须调用,初始化生成器 69 | // worldGenerator->init(); 70 | return std::move(worldGenerator); 71 | } 72 | 73 | void FlatVillageDimension::upgradeLevelChunk(ChunkSource& cs, LevelChunk& lc, LevelChunk& generatedChunk) { 74 | auto blockSource = BlockSource(static_cast(mLevel), *this, cs, false, true, false); 75 | VanillaLevelChunkUpgrade::_upgradeLevelChunkViaMetaData(lc, generatedChunk, blockSource); 76 | VanillaLevelChunkUpgrade::_upgradeLevelChunkLegacy(lc, blockSource); 77 | } 78 | 79 | void FlatVillageDimension::fixWallChunk(ChunkSource& cs, LevelChunk& lc) { 80 | auto blockSource = BlockSource(static_cast(mLevel), *this, cs, false, true, false); 81 | VanillaLevelChunkUpgrade::fixWallChunk(lc, blockSource); 82 | } 83 | 84 | bool FlatVillageDimension::levelChunkNeedsUpgrade(LevelChunk const& lc) const { 85 | return VanillaLevelChunkUpgrade::levelChunkNeedsUpgrade(lc); 86 | } 87 | void FlatVillageDimension::_upgradeOldLimboEntity(CompoundTag& tag, ::LimboEntitiesVersion vers) { 88 | auto isTemplate = mLevel.getLevelData().mIsFromLockedTemplate; 89 | return VanillaLevelChunkUpgrade::upgradeOldLimboEntity(tag, vers, isTemplate); 90 | } 91 | 92 | std::unique_ptr 93 | FlatVillageDimension::_wrapStorageForVersionCompatibility(std::unique_ptr cs, ::StorageVersion /*ver*/) { 94 | return cs; 95 | } 96 | 97 | Vec3 FlatVillageDimension::translatePosAcrossDimension(Vec3 const& fromPos, DimensionType fromId) const { 98 | Vec3 topos; 99 | VanillaDimensions::convertPointBetweenDimensions( 100 | fromPos, 101 | topos, 102 | fromId, 103 | mId, 104 | mLevel.getDimensionConversionData() 105 | ); 106 | constexpr auto clampVal = 32000000.0f - 128.0f; 107 | 108 | topos.x = std::clamp(topos.x, -clampVal, clampVal); 109 | topos.z = std::clamp(topos.z, -clampVal, clampVal); 110 | 111 | return topos; 112 | } 113 | 114 | short FlatVillageDimension::getCloudHeight() const { return 192; } 115 | 116 | // bool FlatVillageDimension::hasPrecipitationFog() const { return true; } 117 | 118 | } // namespace flat_village_dimension -------------------------------------------------------------------------------- /src/test/generator/flat-gen-village/FlatVillageDimension.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/world/level/dimension/Dimension.h" // 新维度类需要继承的类 4 | #include "more_dimensions/api/dimension/CustomDimensionManager.h" // 引入DimensionFactoryInfo的声明 5 | 6 | // 建议是加一个命名空间,避免与其他插件同类名的情况 7 | namespace flat_village_dimension { 8 | 9 | class FlatVillageDimension : public Dimension { 10 | public: 11 | // 建议固定这样写,DimensionFactoryInfo类里面提供了Dimension实例化的基本数据,name就是维度名,多维度是维度名区分不同维度 12 | FlatVillageDimension(std::string const& name, more_dimensions::DimensionFactoryInfo const& info); 13 | 14 | // 多维度需要的一个方法,参数是你需要处理的数据,比如种子,这里不没有这样的需要,后面说原因 15 | static CompoundTag generateNewData(); 16 | 17 | // 以下六个是必须重写的函数 18 | // 维度地形的生成器,是本教程主要更改的地方 19 | std::unique_ptr createGenerator(br::worldgen::StructureSetRegistry const&) override; 20 | 21 | // 与本教程无关,按照本教程写的就行,无需留意 22 | void upgradeLevelChunk(ChunkSource& chunkSource, LevelChunk& oldLc, LevelChunk& newLc) override; 23 | 24 | // 与本教程无关,按照本教程写的就行,无需留意 25 | void fixWallChunk(ChunkSource& cs, LevelChunk& lc) override; 26 | 27 | // 与本教程无关,按照本教程写的就行,无需留意 28 | bool levelChunkNeedsUpgrade(LevelChunk const& lc) const override; 29 | 30 | // 与本教程无关,按照本教程写的就行,无需留意 31 | void _upgradeOldLimboEntity(CompoundTag& tag, ::LimboEntitiesVersion vers) override; 32 | 33 | // 与本教程无关,按照本教程写的就行,无需留意 34 | std::unique_ptr 35 | _wrapStorageForVersionCompatibility(std::unique_ptr cs, ::StorageVersion ver) override; 36 | 37 | // 当你转到这个维度时,坐标怎么转换,比如主世界与地狱的 38 | Vec3 translatePosAcrossDimension(Vec3 const& pos, DimensionType did) const override; 39 | 40 | // 云高度,默认是y128,但多维度高度范围是在y-64~320,与主世界相同,重写它,放高些 41 | short getCloudHeight() const override; 42 | 43 | // 非必要。下雨时,可视范围的更改 44 | // bool hasPrecipitationFog() const override; 45 | }; 46 | 47 | } // namespace flat_village_dimension -------------------------------------------------------------------------------- /src/test/generator/flat-gen-village/FlatVillageGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include "FlatVillageGenerator.h" 2 | 3 | #include "mc/world/level/chunk/ChunkState.h" 4 | #include "test/mc/FixedBiomeSource.h" 5 | 6 | #include "mc/deps/core/math/Random.h" 7 | #include "mc/platform/threading/Mutex.h" 8 | #include "mc/util/ThreadOwner.h" 9 | #include "mc/world/level/BlockSource.h" 10 | #include "mc/world/level/ChunkPos.h" 11 | #include "mc/world/level/Level.h" 12 | #include "mc/world/level/biome/registry/BiomeRegistry.h" 13 | #include "mc/world/level/biome/registry/VanillaBiomeNames.h" 14 | #include "mc/world/level/chunk/ChunkViewSource.h" 15 | #include "mc/world/level/chunk/LevelChunk.h" 16 | #include "mc/world/level/chunk/PostprocessingManager.h" 17 | #include "mc/world/level/dimension/Dimension.h" 18 | #include "mc/world/level/levelgen/v1/ChunkLocalNoiseCache.h" 19 | 20 | 21 | 22 | 23 | namespace flat_village_generator { 24 | 25 | FlatVillageGenerator::FlatVillageGenerator(Dimension& dimension, uint seed, Json::Value const& generationOptionsJSON) 26 | : FlatWorldGenerator(dimension, seed, generationOptionsJSON) { 27 | // 值得注意的是,我们是继承的FlatWorldGenerator,后续也会使用其内部成员,所以我们需要调用FlatWorldGenerator的构造 28 | random.mRandom->mObject.mSeed = seed; 29 | mSeed = seed; 30 | 31 | mBiome = mLevel->getBiomeRegistry().lookupByHash(VanillaBiomeNames::Plains()); 32 | mBiomeSource = std::make_unique(*mBiome); 33 | } 34 | 35 | bool FlatVillageGenerator::postProcess(ChunkViewSource& neighborhood) { 36 | ChunkPos chunkPos; 37 | chunkPos.x = neighborhood.mArea->mBounds.mMin->x; 38 | chunkPos.z = neighborhood.mArea->mBounds.mMin->z; 39 | auto levelChunk = neighborhood.getExistingChunk(chunkPos); 40 | 41 | auto seed = mSeed; 42 | 43 | // 必须,需要给区块上锁 44 | auto lockChunk = 45 | levelChunk->mDimension.mPostProcessingManager->tryLock(levelChunk->mPosition, neighborhood); 46 | 47 | if (!lockChunk.has_value()) { 48 | return false; 49 | } 50 | BlockSource blockSource(*mLevel, *neighborhood.mDimension, neighborhood, false, true, true); 51 | auto chunkPosL = levelChunk->mPosition; 52 | random.mRandom->mObject.mSeed = seed; 53 | auto one = 2 * (random.nextInt() / 2) + 1; 54 | auto two = 2 * (random.nextInt() / 2) + 1; 55 | random.mRandom->mObject.mSeed = seed ^ (chunkPosL->x * one + chunkPosL->z * two); 56 | // 放置结构体,如果包含有某个结构的区块,就会放置loadChunk准备的结构 57 | WorldGenerator::postProcessStructureFeatures(blockSource, random, chunkPosL->x, chunkPosL->z); 58 | // 处理其它单体结构,比如沉船,这里不是必须 59 | WorldGenerator::postProcessStructures(blockSource, random, chunkPosL->x, chunkPosL->z); 60 | // 1.21.50.10 起,有更改,需添加以下调用 61 | levelChunk->finalizePostProcessing(); 62 | return true; 63 | } 64 | 65 | void FlatVillageGenerator::loadChunk(LevelChunk& levelchunk, bool forceImmediateReplacementDataLoad) { 66 | auto chunkPos = levelchunk.mPosition; 67 | 68 | auto blockPos = BlockPos(chunkPos, 0); 69 | DividedPos2d<4> dividedPos2D; 70 | dividedPos2D.x = (blockPos.x >> 31) - ((blockPos.x >> 31) - blockPos.x) / 4; 71 | dividedPos2D.z = (blockPos.z >> 31) - ((blockPos.z >> 31) - blockPos.z) / 4; 72 | 73 | // 处理其它单体结构,比如沉船,这里不是必须 74 | // WorldGenerator::preProcessStructures(getDimension(), chunkPos, getBiomeSource()); 75 | // 准备要放置的结构,如果是某个某个结构的区块,就会准备结构 76 | WorldGenerator::prepareStructureFeatureBlueprints(*mDimension, chunkPos, getBiomeSource(), *this); 77 | 78 | // 这里并没有放置结构,只有单纯基本地形 79 | levelchunk.setBlockVolume(mPrototype, 0); 80 | 81 | levelchunk.recomputeHeightMap(0); 82 | ChunkLocalNoiseCache chunkLocalNoiseCache(dividedPos2D, 8); 83 | mBiomeSource->fillBiomes(levelchunk, chunkLocalNoiseCache); 84 | levelchunk.setSaved(); 85 | auto loadState = ChunkState::Generating; 86 | levelchunk.mLoadState->compare_exchange_weak(loadState, ChunkState::Generated); 87 | } 88 | 89 | std::optional FlatVillageGenerator::getPreliminarySurfaceLevel(DividedPos2d<4> worldPos) const { 90 | // 超平坦的高度都是一样的,直接返回固定值即可 91 | return -61; 92 | } 93 | 94 | void FlatVillageGenerator::prepareAndComputeHeights( 95 | BlockVolume& box, 96 | ChunkPos const& chunkPos, 97 | std::vector& ZXheights, 98 | bool factorInBeardsAndShavers, 99 | int skipTopN 100 | ) { 101 | auto heightMap = mPrototype->computeHeightMap(); 102 | ZXheights.assign(heightMap->begin(), heightMap->end()); 103 | } 104 | 105 | void FlatVillageGenerator::prepareHeights(BlockVolume& box, ChunkPos const& chunkPos, bool factorInBeardsAndShavers) { 106 | // 在其它类型世界里,这里是需要对box进行处理,生成地形,超平坦没有这个需要,所以直接赋值即可 107 | box = mPrototype; 108 | }; 109 | 110 | HashedString FlatVillageGenerator::findStructureFeatureTypeAt(BlockPos const& blockPos) { 111 | return WorldGenerator::findStructureFeatureTypeAt(blockPos); 112 | }; 113 | 114 | bool FlatVillageGenerator::isStructureFeatureTypeAt(const BlockPos& blockPos, ::HashedString type) const { 115 | return WorldGenerator::isStructureFeatureTypeAt(blockPos, type); 116 | } 117 | 118 | bool FlatVillageGenerator::findNearestStructureFeature( 119 | ::HashedString type, 120 | BlockPos const& blockPos, 121 | BlockPos& blockPos1, 122 | bool mustBeInNewChunks, 123 | std::optional hash 124 | ) { 125 | return WorldGenerator::findNearestStructureFeature(type, blockPos, blockPos1, mustBeInNewChunks, hash); 126 | }; 127 | 128 | void FlatVillageGenerator::garbageCollectBlueprints(buffer_span activeChunks) { 129 | return WorldGenerator::garbageCollectBlueprints(activeChunks); 130 | }; 131 | 132 | } // namespace flat_village_generator 133 | -------------------------------------------------------------------------------- /src/test/generator/flat-gen-village/FlatVillageGenerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/deps/core/string/HashedString.h" 4 | #include "mc/deps/core/utility/buffer_span.h" 5 | #include "mc/util/Random.h" 6 | #include "mc/world/level/BlockPos.h" 7 | #include "mc/world/level/DividedPos2d.h" 8 | #include "mc/world/level/block/BlockVolume.h" 9 | #include "mc/world/level/levelgen/flat/FlatWorldGenerator.h" 10 | 11 | 12 | #include 13 | 14 | class ChunkViewSource; 15 | class LevelChunk; 16 | class ChunkPos; 17 | 18 | // 依旧建议加一个命名空间避免冲突 19 | namespace flat_village_generator { 20 | 21 | // 我们直接继承原版超平坦这个类来写会方便很多 22 | class FlatVillageGenerator : public FlatWorldGenerator { 23 | public: 24 | Random random; // 这个是BDS生成随机数有关的类 25 | uint mSeed; 26 | 27 | // 后面的generationOptionsJSON虽然用不上,但FlatWorldGenerator的实例化需要 28 | FlatVillageGenerator(Dimension& dimension, uint seed, Json::Value const& generationOptionsJSON); 29 | 30 | // 这里是处理结构放置相关的,包括地物,结构,地形 31 | bool postProcess(ChunkViewSource& neighborhood); 32 | 33 | // 这里是初始处理新的单区块的方块生成相关的,比如一些大量的方块(石头,泥土) 34 | void loadChunk(LevelChunk& levelchunk, bool forceImmediateReplacementDataLoad); 35 | 36 | // 判断某个点在哪个结构范围里 37 | HashedString findStructureFeatureTypeAt(BlockPos const&); 38 | 39 | // 判断某个点是否在某个结构范围里 40 | bool isStructureFeatureTypeAt(BlockPos const&, ::HashedString) const; 41 | 42 | // 这里是获取某个坐标的最高方块 43 | std::optional getPreliminarySurfaceLevel(DividedPos2d<4> worldPos) const; 44 | 45 | // 如意,以一个坐标,在一定范围内查找某个类型的结构 46 | bool findNearestStructureFeature(::HashedString, BlockPos const&, BlockPos&, bool, std::optional); 47 | 48 | // 无需在意,照写就行 49 | void garbageCollectBlueprints(buffer_span); 50 | 51 | // 处理地形 52 | void prepareHeights(BlockVolume& box, ChunkPos const& chunkPos, bool factorInBeardsAndShavers); 53 | 54 | // 与prepareHeights一样,不过与之不同的是,还会计算单区块内的高度 55 | void prepareAndComputeHeights( 56 | BlockVolume& box, 57 | ChunkPos const& chunkPos, 58 | std::vector& ZXheights, 59 | bool factorInBeardsAndShavers, 60 | int skipTopN 61 | ); 62 | 63 | // 可选,可以不写 64 | BlockPos findSpawnPosition() const { return BlockPos{0, 16, 0}; }; 65 | }; 66 | 67 | } // namespace flat_village_generator -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/CustomStructure.cpp: -------------------------------------------------------------------------------- 1 | #include "CustomStructure.h" 2 | 3 | #include "ll/api/memory/Hook.h" 4 | 5 | #include "mc/deps/core/threading/WorkerPool.h" 6 | #include "mc/resources/BaseGameVersion.h" 7 | #include "mc/world/level/block/VanillaBlockTypeIds.h" 8 | #include "mc/world/level/block/registry/BlockTypeRegistry.h" 9 | #include "mc/world/level/levelgen/feature/registry/FeatureRegistry.h" 10 | #include "mc/world/level/levelgen/structure/Projection.h" 11 | #include "mc/world/level/levelgen/structure/StructureManager.h" 12 | #include "mc/world/level/levelgen/structure/registry/JigsawStructureBlockRulesRegistry.h" 13 | #include "mc/world/level/levelgen/structure/registry/JigsawStructureElementRegistry.h" 14 | #include "mc/world/level/levelgen/structure/registry/JigsawStructureRegistry.h" 15 | #include "mc/world/level/levelgen/structure/registry/StructurePools.h" 16 | #include "mc/world/level/levelgen/structure/structurepools/StructurePoolBlockPredicateAlwaysTrue.h" 17 | #include "mc/world/level/levelgen/structure/structurepools/StructurePoolElement.h" 18 | #include "mc/world/level/levelgen/structure/structurepools/StructureTemplatePool.h" 19 | #include "mc/world/level/storage/Experiments.h" 20 | #include "test/mc/StructurePoolBlockPredicateBlockMatchRandom.h" 21 | #include "test/mc/StructurePoolBlockRule.h" 22 | 23 | // #include "mc/world/level/storage/Experiments.h" 24 | // #include "test/mc/StructureTemplateRegistrationContext.h" 25 | // #include "test/mc/WeightedStructureTemplateRegistration.h" 26 | 27 | // #include 28 | #include 29 | 30 | namespace custom_structure { 31 | 32 | void CustomJigsawStructureBlockRules::initialize(JigsawStructureRegistry& registry) { 33 | auto& jigsawBlockRulesRegistry = registry.mJigsawBlockRulesRegistry; 34 | 35 | // input_predicate block 36 | auto& stoneBricks = BlockTypeRegistry::getDefaultBlockState(VanillaBlockTypeIds::StoneBricks()); 37 | 38 | // output_state blocks 39 | auto& mossyStoneBricks = BlockTypeRegistry::getDefaultBlockState(VanillaBlockTypeIds::MossyStoneBricks()); 40 | auto& crackedStoneBricks = BlockTypeRegistry::getDefaultBlockState(VanillaBlockTypeIds::CrackedStoneBricks()); 41 | auto& cobblestone = BlockTypeRegistry::getDefaultBlockState(VanillaBlockTypeIds::Cobblestone()); 42 | 43 | // input_predicate 44 | std::unique_ptr sourceBlock_pro1 = 45 | std::make_unique(stoneBricks, 0.2); 46 | std::unique_ptr sourceBlock_pro2 = 47 | std::make_unique(stoneBricks, 0.1); 48 | 49 | std::unique_ptr targetBlock = 50 | std::make_unique(); 51 | 52 | auto blockRule_1 = std::make_unique( 53 | std::move(sourceBlock_pro1), 54 | std::move(targetBlock), 55 | &mossyStoneBricks 56 | ); 57 | auto blockRule_2 = std::make_unique( 58 | std::move(sourceBlock_pro1), 59 | std::move(targetBlock), 60 | &crackedStoneBricks 61 | ); 62 | auto blockRule_3 = 63 | std::make_unique(std::move(sourceBlock_pro2), std::move(targetBlock), &cobblestone); 64 | 65 | 66 | auto ruleList = std::make_unique>>(); 67 | 68 | ruleList->emplace_back(std::move(blockRule_1)); 69 | ruleList->emplace_back(std::move(blockRule_2)); 70 | ruleList->emplace_back(std::move(blockRule_3)); 71 | 72 | jigsawBlockRulesRegistry->registerBlockRules("mike:stone_brick_replacement", std::move(ruleList)); 73 | 74 | // br::worldgen::processors::BlockRules::Test block_test; 75 | // block_test.mData = br::worldgen::processors::BlockRules::RandomBlockMatch(stoneBricks.mLegacyBlock.get(), 0.2); 76 | 77 | // auto blockRule_1 = br::worldgen::processors::RuleSet::from(block_test, mossyStoneBricks); 78 | // auto blockRule_2 = br::worldgen::processors::RuleSet::from(block_test, crackedStoneBricks); 79 | // auto blockRule_3 = br::worldgen::processors::RuleSet::from(block_test, cobblestone); 80 | 81 | // auto ruleList = br::worldgen::StructureProcessor::Rule({blockRule_1, blockRule_2, blockRule_3}); 82 | // auto prot = br::worldgen::StructureProcessor::Protected(VanillaBlockTypeIds::RedstoneBlock()); 83 | // jigsawBlockRulesRegistry->record("mike:stone_brick_replacement", {ruleList, prot}); 84 | } 85 | 86 | void CustomJigsawStructureElements::initialize( 87 | gsl::not_null> manager, 88 | FeatureRegistry& featureRegistry, 89 | JigsawStructureRegistry& jigsawRegistry 90 | ) { 91 | auto& jigsawBlockRulesRegistry = jigsawRegistry.mJigsawBlockRulesRegistry; 92 | auto& jigsawStructureElementRegistry = jigsawRegistry.mJigsawElementRegistry; 93 | auto ruleList = jigsawBlockRulesRegistry->lookupByName("mike:stone_brick_replacement"); 94 | 95 | // 每一个结构nbt文件都得这样注册进来,多个nbt结构文件的可以使用同一个Block Rule 96 | // mike:5x5int 97 | jigsawStructureElementRegistry->registerStructureElement( 98 | "mike:5x5intb", 99 | std::make_unique( 100 | manager, 101 | "custom/beds5x5int", 102 | ruleList, 103 | nullptr, 104 | nullptr, 105 | Projection::TerrainMatching, 106 | PostProcessSettings::Beard 107 | ) 108 | ); 109 | jigsawStructureElementRegistry->registerStructureElement( 110 | "mike:5x5intc", 111 | std::make_unique( 112 | manager, 113 | "custom/chestcarpet5x5int", 114 | ruleList, 115 | nullptr, 116 | nullptr, 117 | Projection::TerrainMatching, 118 | PostProcessSettings::Beard 119 | ) 120 | ); 121 | jigsawStructureElementRegistry->registerStructureElement( 122 | "mike:5x5intk", 123 | std::make_unique( 124 | manager, 125 | "custom/kitchen5x5int", 126 | ruleList, 127 | nullptr, 128 | nullptr, 129 | Projection::TerrainMatching, 130 | PostProcessSettings::Beard 131 | ) 132 | ); 133 | 134 | // mike:ew7x4 135 | jigsawStructureElementRegistry->registerStructureElement( 136 | "mike:ew7x4h", 137 | std::make_unique( 138 | manager, 139 | "custom/ewhall", 140 | ruleList, 141 | nullptr, 142 | nullptr, 143 | Projection::TerrainMatching, 144 | PostProcessSettings::Beard 145 | ) 146 | ); 147 | jigsawStructureElementRegistry->registerStructureElement( 148 | "mike:ew7x4r", 149 | std::make_unique( 150 | manager, 151 | "custom/21room", 152 | ruleList, 153 | nullptr, 154 | nullptr, 155 | Projection::TerrainMatching, 156 | PostProcessSettings::Beard 157 | ) 158 | ); 159 | 160 | // mike:ns7x4 161 | jigsawStructureElementRegistry->registerStructureElement( 162 | "mike:ns7x4h", 163 | std::make_unique( 164 | manager, 165 | "custom/nshall", 166 | ruleList, 167 | nullptr, 168 | nullptr, 169 | Projection::TerrainMatching, 170 | PostProcessSettings::Beard 171 | ) 172 | ); 173 | jigsawStructureElementRegistry->registerStructureElement( 174 | "mike:ns7x4r", 175 | std::make_unique( 176 | manager, 177 | "custom/21room", 178 | ruleList, 179 | nullptr, 180 | nullptr, 181 | Projection::TerrainMatching, 182 | PostProcessSettings::Beard 183 | ) 184 | ); 185 | 186 | // mike:ewcap 187 | jigsawStructureElementRegistry->registerStructureElement( 188 | "mike:ewcap", 189 | std::make_unique( 190 | manager, 191 | "custom/ewcap", 192 | ruleList, 193 | nullptr, 194 | nullptr, 195 | Projection::TerrainMatching, 196 | PostProcessSettings::Beard 197 | ) 198 | ); 199 | 200 | // mike:nacap 201 | jigsawStructureElementRegistry->registerStructureElement( 202 | "mike:nscap", 203 | std::make_unique( 204 | manager, 205 | "custom/nscap", 206 | ruleList, 207 | nullptr, 208 | nullptr, 209 | Projection::TerrainMatching, 210 | PostProcessSettings::Beard 211 | ) 212 | ); 213 | } 214 | 215 | void CustomJigsawStructure::initialize( 216 | Bedrock::NotNullNonOwnerPtr<::StructureManager> manager, 217 | FeatureRegistry& featureRegistry, 218 | JigsawStructureRegistry& registry, 219 | BaseGameVersion const& baseGameVersion, 220 | Experiments const& experiments 221 | ) { 222 | CustomJigsawStructureBlockRules::initialize(registry); 223 | CustomJigsawStructureElements::initialize(manager, featureRegistry, registry); 224 | auto& jigsawStructureElementRegistry = registry.mJigsawElementRegistry; 225 | 226 | // auto ruleList = registry.mJigsawBlockRulesRegistry->lookupByName("mike:stone_brick_replacement"); 227 | 228 | std::vector> templates_5x5{ 229 | {jigsawStructureElementRegistry->lookupByName("mike:5x5intb"), 4}, 230 | {jigsawStructureElementRegistry->lookupByName("mike:5x5intc"), 1}, 231 | {jigsawStructureElementRegistry->lookupByName("mike:5x5intk"), 1} 232 | }; 233 | std::vector> templates_ew{ 234 | {jigsawStructureElementRegistry->lookupByName("mike:ew7x4h"), 4}, 235 | {jigsawStructureElementRegistry->lookupByName("mike:ew7x4r"), 1} 236 | }; 237 | std::vector> templates_ns{ 238 | {jigsawStructureElementRegistry->lookupByName("mike:ns7x4h"), 4}, 239 | {jigsawStructureElementRegistry->lookupByName("mike:ns7x4r"), 1} 240 | }; 241 | std::vector> templates_ewcap{ 242 | {jigsawStructureElementRegistry->lookupByName("mike:ewcap"), 4} 243 | }; 244 | std::vector> templates_nscap{ 245 | {jigsawStructureElementRegistry->lookupByName("mike:nscap"), 4} 246 | }; 247 | 248 | registry.registerPool(std::make_unique("mike:5x5int", "empty", templates_5x5)); 249 | registry.registerPool(std::make_unique("mike:ew7x4", "mike:ewcap", templates_ew)); 250 | registry.registerPool(std::make_unique("mike:ns7x4", "mike:nscap", templates_ns)); 251 | registry.registerPool(std::make_unique("mike:ewcap", "empty", templates_ewcap)); 252 | registry.registerPool(std::make_unique("mike:nscap", "empty", templates_nscap)); 253 | 254 | // StructureTemplateRegistrationContext 255 | // context{manager, jigsawStructureElementRegistry, featureRegistry, baseGameVersion, experiments}; 256 | 257 | // std::initializer_list templates_5x5{ 258 | // {StructurePoolElement::single("mike:5x5intb", ruleList, {}, {}), 4}, 259 | // {StructurePoolElement::single("mike:5x5intc", ruleList, {}, {}), 1}, 260 | // {StructurePoolElement::single("mike:5x5intk", ruleList, {}, {}), 1} 261 | // }; 262 | // std::initializer_list templates_ew{ 263 | // {StructurePoolElement::single("mike:ew7x4h", ruleList, {}, {}), 4}, 264 | // {StructurePoolElement::single("mike:ew7x4r", ruleList, {}, {}), 1} 265 | // }; 266 | // std::initializer_list templates_ns{ 267 | // {StructurePoolElement::single("mike:ns7x4h", ruleList, {}, {}), 4}, 268 | // {StructurePoolElement::single("mike:ns7x4r", ruleList, {}, {}), 1} 269 | // }; 270 | // std::initializer_list templates_ewcap{ 271 | // {StructurePoolElement::single("mike:ewcap", ruleList, {}, {}), 4} 272 | // }; 273 | // std::initializer_list templates_nscap{ 274 | // {StructurePoolElement::single("mike:nscap", ruleList, {}, {}), 4} 275 | // }; 276 | 277 | // registry.registerPool( 278 | // std::make_unique(context, "mike:5x5int", "empty", Projection::Invalid, templates_5x5) 279 | // ); 280 | // registry.registerPool( 281 | // std::make_unique(context, "mike:ew7x4", "mike:ewcap", Projection::Invalid, templates_ew) 282 | // ); 283 | // registry.registerPool( 284 | // std::make_unique(context, "mike:ns7x4", "mike:nscap", Projection::Invalid, templates_ns) 285 | // ); 286 | // registry.registerPool( 287 | // std::make_unique(context, "mike:ewcap", "empty", Projection::Invalid, templates_ewcap) 288 | // ); 289 | // registry.registerPool( 290 | // std::make_unique(context, "mike:nscap", "empty", Projection::Invalid, templates_nscap) 291 | // ); 292 | } 293 | 294 | } // namespace custom_structure 295 | 296 | LL_AUTO_TYPE_STATIC_HOOK( 297 | InitStructure, 298 | HookPriority::Normal, 299 | br::worldgen::StructurePools, 300 | br::worldgen::StructurePools::bootstrap, 301 | void, 302 | Bedrock::NotNullNonOwnerPtr structureManager, 303 | FeatureRegistry& featureRegistry, 304 | JigsawStructureRegistry& jigsawStructureRegistry, 305 | BaseGameVersion const& baseGameVersion, 306 | Experiments const& experiments 307 | ) { 308 | custom_structure::CustomJigsawStructure::initialize( 309 | structureManager, 310 | featureRegistry, 311 | jigsawStructureRegistry, 312 | baseGameVersion, 313 | experiments 314 | ); 315 | origin(structureManager, featureRegistry, jigsawStructureRegistry, baseGameVersion, experiments); 316 | return; 317 | }; -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/CustomStructure.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/deps/core/utility/NonOwnerPointer.h" 4 | 5 | #include "gsl/pointers" 6 | 7 | class FeatureRegistry; 8 | class JigsawStructureRegistry; 9 | class WorkerPool; 10 | class StructureManager; 11 | class BaseGameVersion; 12 | class Experiments; 13 | 14 | namespace custom_structure { 15 | 16 | namespace CustomJigsawStructure { 17 | 18 | // 总注册初始化函数 19 | void initialize( 20 | Bedrock::NotNullNonOwnerPtr<::StructureManager> manager, 21 | FeatureRegistry& featureRegistry, 22 | JigsawStructureRegistry& registry, 23 | BaseGameVersion const& baseGameVersion, 24 | Experiments const& experiments 25 | ); 26 | 27 | } // namespace CustomJigsawStructure 28 | 29 | namespace CustomJigsawStructureBlockRules { 30 | 31 | void initialize(JigsawStructureRegistry& registry); 32 | 33 | } 34 | 35 | namespace CustomJigsawStructureElements { 36 | 37 | void initialize( 38 | gsl::not_null> manager, 39 | FeatureRegistry& featureRegistry, 40 | JigsawStructureRegistry& jigsawRegistry 41 | ); 42 | 43 | } 44 | 45 | } // namespace custom_structure 46 | -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/README.md: -------------------------------------------------------------------------------- 1 | ## You need to copy the files in the `structure-files` folder to this path 2 | 3 | ``` 4 | behavior_packs\vanilla\structures\ 5 | ``` -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/dimension/CustomStructureDimension.cpp: -------------------------------------------------------------------------------- 1 | #include "CustomStructureDimension.h" 2 | 3 | #include "test/generator/generator-custom-structure/generator/CustomStructureGenerator.h" 4 | #include "test/generator/generator-custom-structure/structure/CustomStructureFeature.h" 5 | 6 | #include "mc/common/Brightness.h" 7 | #include "mc/common/BrightnessPair.h" 8 | #include "mc/deps/core/math/Vec3.h" 9 | #include "mc/world/level/BlockSource.h" 10 | #include "mc/world/level/DimensionConversionData.h" 11 | #include "mc/world/level/Level.h" 12 | #include "mc/world/level/LevelSeed64.h" 13 | #include "mc/world/level/chunk/vanilla_level_chunk_upgrade/VanillaLevelChunkUpgrade.h" 14 | #include "mc/world/level/dimension/DimensionBrightnessRamp.h" 15 | #include "mc/world/level/dimension/DimensionHeightRange.h" 16 | #include "mc/world/level/dimension/OverworldBrightnessRamp.h" 17 | #include "mc/world/level/dimension/VanillaDimensions.h" 18 | #include "mc/world/level/levelgen/structure/StructureFeatureRegistry.h" 19 | #include "mc/world/level/levelgen/structure/VillageFeature.h" 20 | #include "mc/world/level/levelgen/structure/registry/StructureSetRegistry.h" 21 | #include "mc/world/level/levelgen/v2/ChunkGeneratorStructureState.h" 22 | #include "mc/world/level/storage/LevelData.h" 23 | 24 | 25 | namespace custom_structure_dimension { 26 | 27 | CustomStructureDimension::CustomStructureDimension( 28 | std::string const& name, 29 | more_dimensions::DimensionFactoryInfo const& info 30 | ) 31 | : Dimension(info.level, info.dimId, {-64, 320}, info.scheduler, name) { 32 | // 这里说明下,在DimensionFactoryInfo里面more-dimensions会提供维度id,请不要使用固定维度id,避免id冲突导致维度注册出现异常 33 | mDefaultBrightness->sky = Brightness::MAX(); 34 | mSeaLevel = -61; 35 | mHasWeather = true; 36 | mDimensionBrightnessRamp = std::make_unique(); 37 | mDimensionBrightnessRamp->buildBrightnessRamp(); 38 | } 39 | 40 | CompoundTag CustomStructureDimension::generateNewData() { return {}; } 41 | 42 | std::unique_ptr 43 | CustomStructureDimension::createGenerator(br::worldgen::StructureSetRegistry const& structureSetRegistry) { 44 | std::unique_ptr worldGenerator; 45 | uint seed = 2025; 46 | auto& levelData = mLevel.getLevelData(); 47 | 48 | // 实例化我们写的Generator类 49 | worldGenerator = std::make_unique( 50 | *this, 51 | seed, 52 | levelData.mFlatWorldOptions 53 | ); 54 | // structureSetRegistry里面仅有的土径结构村庄生成需要用到,所以我们拿一下 55 | std::vector> structureMap; 56 | for (auto iter = structureSetRegistry.mStructureSets->begin(); iter != structureSetRegistry.mStructureSets->end(); iter++) { 57 | structureMap.emplace_back(iter->second); 58 | } 59 | worldGenerator->mStructureFeatureRegistry->mGeneratorState->mSeed = seed; 60 | worldGenerator->mStructureFeatureRegistry->mGeneratorState->mSeed64 = 61 | LevelSeed64(seed); 62 | 63 | // 这个就相当于在这个生成器里注册结构了 64 | // VillageFeature的第二第三个参数是村庄之间的最大间隔与最小间隔 65 | worldGenerator->mStructureFeatureRegistry->mStructureFeatures->emplace_back( 66 | std::make_unique(seed, 34, 8) 67 | ); 68 | worldGenerator->mStructureFeatureRegistry->mStructureFeatures->emplace_back( 69 | std::make_unique(seed, 8, 34) 70 | ); 71 | // 此为必须,一些结构生成相关 72 | worldGenerator->mStructureFeatureRegistry->mGeneratorState = 73 | br::worldgen::ChunkGeneratorStructureState::createFlat(seed, worldGenerator->getBiomeSource(), structureMap); 74 | 75 | return std::move(worldGenerator); 76 | } 77 | 78 | void CustomStructureDimension::upgradeLevelChunk(ChunkSource& cs, LevelChunk& lc, LevelChunk& generatedChunk) { 79 | auto blockSource = BlockSource(static_cast(mLevel), *this, cs, false, true, false); 80 | VanillaLevelChunkUpgrade::_upgradeLevelChunkViaMetaData(lc, generatedChunk, blockSource); 81 | VanillaLevelChunkUpgrade::_upgradeLevelChunkLegacy(lc, blockSource); 82 | } 83 | 84 | void CustomStructureDimension::fixWallChunk(ChunkSource& cs, LevelChunk& lc) { 85 | auto blockSource = BlockSource(static_cast(mLevel), *this, cs, false, true, false); 86 | VanillaLevelChunkUpgrade::fixWallChunk(lc, blockSource); 87 | } 88 | 89 | bool CustomStructureDimension::levelChunkNeedsUpgrade(LevelChunk const& lc) const { 90 | return VanillaLevelChunkUpgrade::levelChunkNeedsUpgrade(lc); 91 | } 92 | void CustomStructureDimension::_upgradeOldLimboEntity(CompoundTag& tag, ::LimboEntitiesVersion vers) { 93 | auto isTemplate = mLevel.getLevelData().mIsFromLockedTemplate; 94 | return VanillaLevelChunkUpgrade::upgradeOldLimboEntity(tag, vers, isTemplate); 95 | } 96 | 97 | std::unique_ptr CustomStructureDimension:: 98 | _wrapStorageForVersionCompatibility(std::unique_ptr cs, ::StorageVersion /*ver*/) { 99 | return cs; 100 | } 101 | 102 | Vec3 CustomStructureDimension::translatePosAcrossDimension(Vec3 const& fromPos, DimensionType fromId) const { 103 | Vec3 topos; 104 | VanillaDimensions::convertPointBetweenDimensions( 105 | fromPos, 106 | topos, 107 | fromId, 108 | mId, 109 | mLevel.getDimensionConversionData() 110 | ); 111 | constexpr auto clampVal = 32000000.0f - 128.0f; 112 | 113 | topos.x = std::clamp(topos.x, -clampVal, clampVal); 114 | topos.z = std::clamp(topos.z, -clampVal, clampVal); 115 | 116 | return topos; 117 | } 118 | 119 | short CustomStructureDimension::getCloudHeight() const { return 192; } 120 | 121 | // bool CustomStructureDimension::hasPrecipitationFog() const { return true; } 122 | 123 | } // namespace custom_structure_dimension -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/dimension/CustomStructureDimension.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/world/level/dimension/Dimension.h" // 新维度类需要继承的类 4 | #include "more_dimensions/api/dimension/CustomDimensionManager.h" // 引入DimensionFactoryInfo的声明 5 | 6 | // 建议是加一个命名空间,避免与其他插件同类名的情况 7 | namespace custom_structure_dimension { 8 | 9 | class CustomStructureDimension : public Dimension { 10 | public: 11 | // 建议固定这样写,DimensionFactoryInfo类里面提供了Dimension实例化的基本数据,name就是维度名,多维度是维度名区分不同维度 12 | CustomStructureDimension(std::string const& name, more_dimensions::DimensionFactoryInfo const& info); 13 | 14 | // 多维度需要的一个方法,参数是你需要处理的数据,比如种子,这里不没有这样的需要,后面说原因 15 | static CompoundTag generateNewData(); 16 | 17 | // 以下六个是必须重写的函数 18 | // 维度地形的生成器,是本教程主要更改的地方 19 | std::unique_ptr createGenerator(br::worldgen::StructureSetRegistry const&) override; 20 | 21 | // 与本教程无关,按照本教程写的就行,无需留意 22 | void upgradeLevelChunk(ChunkSource& chunkSource, LevelChunk& oldLc, LevelChunk& newLc) override; 23 | 24 | // 与本教程无关,按照本教程写的就行,无需留意 25 | void fixWallChunk(ChunkSource& cs, LevelChunk& lc) override; 26 | 27 | // 与本教程无关,按照本教程写的就行,无需留意 28 | bool levelChunkNeedsUpgrade(LevelChunk const& lc) const override; 29 | 30 | // 与本教程无关,按照本教程写的就行,无需留意 31 | void _upgradeOldLimboEntity(CompoundTag& tag, ::LimboEntitiesVersion vers) override; 32 | 33 | // 与本教程无关,按照本教程写的就行,无需留意 34 | std::unique_ptr 35 | _wrapStorageForVersionCompatibility(std::unique_ptr cs, ::StorageVersion ver) override; 36 | 37 | // 当你转到这个维度时,坐标怎么转换,比如主世界与地狱的 38 | Vec3 translatePosAcrossDimension(Vec3 const& pos, DimensionType did) const override; 39 | 40 | // 云高度,默认是y128,但多维度高度范围是在y-64~320,与主世界相同,重写它,放高些 41 | short getCloudHeight() const override; 42 | 43 | // 非必要。下雨时,可视范围的更改 44 | // bool hasPrecipitationFog() const override; 45 | }; 46 | 47 | } // namespace custom_structure_dimension -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/generator/CustomStructureGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include "CustomStructureGenerator.h" 2 | 3 | #include "test/mc/FixedBiomeSource.h" 4 | 5 | #include "mc/deps/core/math/Random.h" 6 | #include "mc/platform/threading/Mutex.h" 7 | #include "mc/util/ThreadOwner.h" 8 | #include "mc/world/level/BlockSource.h" 9 | #include "mc/world/level/ChunkPos.h" 10 | #include "mc/world/level/Level.h" 11 | #include "mc/world/level/biome/registry/BiomeRegistry.h" 12 | #include "mc/world/level/biome/registry/VanillaBiomeNames.h" 13 | #include "mc/world/level/chunk/ChunkViewSource.h" 14 | #include "mc/world/level/chunk/LevelChunk.h" 15 | #include "mc/world/level/chunk/PostprocessingManager.h" 16 | #include "mc/world/level/dimension/Dimension.h" 17 | #include "mc/world/level/levelgen/v1/ChunkLocalNoiseCache.h" 18 | 19 | 20 | namespace custom_structure_generator { 21 | 22 | CustomStructureGenerator::CustomStructureGenerator( 23 | Dimension& dimension, 24 | uint seed, 25 | Json::Value const& generationOptionsJSON 26 | ) 27 | : FlatWorldGenerator(dimension, seed, generationOptionsJSON) { 28 | // 值得注意的是,我们是继承的FlatWorldGenerator,后续也会使用其内部成员,所以我们需要调用FlatWorldGenerator的构造 29 | random.mRandom->mObject.mSeed = seed; 30 | mSeed = seed; 31 | 32 | mBiome = mLevel->getBiomeRegistry().lookupByHash(VanillaBiomeNames::Plains()); 33 | mBiomeSource = std::make_unique(*mBiome); 34 | } 35 | 36 | bool CustomStructureGenerator::postProcess(ChunkViewSource& neighborhood) { 37 | ChunkPos chunkPos; 38 | chunkPos.x = neighborhood.mArea->mBounds.mMin->x; 39 | chunkPos.z = neighborhood.mArea->mBounds.mMin->z; 40 | auto levelChunk = neighborhood.getExistingChunk(chunkPos); 41 | 42 | auto seed = mSeed; 43 | 44 | // 必须,需要给区块上锁 45 | auto lockChunk = 46 | levelChunk->mDimension.mPostProcessingManager->tryLock(levelChunk->mPosition, neighborhood); 47 | 48 | if (!lockChunk) { 49 | return false; 50 | } 51 | BlockSource blockSource(*mLevel, *neighborhood.mDimension, neighborhood, false, true, true); 52 | auto chunkPosL = levelChunk->mPosition; 53 | random.mRandom->mObject.mSeed = seed; 54 | auto one = 2 * (random.nextInt() / 2) + 1; 55 | auto two = 2 * (random.nextInt() / 2) + 1; 56 | random.mRandom->mObject.mSeed = seed ^ (chunkPosL->x * one + chunkPosL->z * two); 57 | // 放置结构体,如果包含有某个结构的区块,就会放置loadChunk准备的结构 58 | WorldGenerator::postProcessStructureFeatures(blockSource, random, chunkPosL->x, chunkPosL->z); 59 | // 处理其它单体结构,比如沉船,这里不是必须 60 | WorldGenerator::postProcessStructures(blockSource, random, chunkPosL->x, chunkPosL->z); 61 | levelChunk->finalizePostProcessing(); 62 | return true; 63 | } 64 | 65 | void CustomStructureGenerator::loadChunk(LevelChunk& levelchunk, bool forceImmediateReplacementDataLoad) { 66 | auto chunkPos = levelchunk.mPosition; 67 | 68 | auto blockPos = BlockPos(chunkPos, 0); 69 | DividedPos2d<4> dividedPos2D; 70 | dividedPos2D.x = (blockPos.x >> 31) - ((blockPos.x >> 31) - blockPos.x) / 4; 71 | dividedPos2D.z = (blockPos.z >> 31) - ((blockPos.z >> 31) - blockPos.z) / 4; 72 | 73 | // 处理其它单体结构,比如沉船,这里不是必须 74 | // WorldGenerator::preProcessStructures(getDimension(), chunkPos, getBiomeSource()); 75 | // 准备要放置的结构,如果是某个某个结构的区块,就会准备结构 76 | WorldGenerator::prepareStructureFeatureBlueprints(*mDimension, chunkPos, getBiomeSource(), *this); 77 | 78 | // 这里并没有放置结构,只有单纯基本地形 79 | levelchunk.setBlockVolume(mPrototype, 0); 80 | 81 | levelchunk.recomputeHeightMap(0); 82 | ChunkLocalNoiseCache chunkLocalNoiseCache(dividedPos2D, 8); 83 | mBiomeSource->fillBiomes(levelchunk, chunkLocalNoiseCache); 84 | levelchunk.setSaved(); 85 | auto loadState = ChunkState::Generating; 86 | levelchunk.mLoadState->compare_exchange_weak(loadState, ChunkState::Generated); 87 | } 88 | 89 | std::optional CustomStructureGenerator::getPreliminarySurfaceLevel(DividedPos2d<4> worldPos) const { 90 | // 超平坦的高度都是一样的,直接返回固定值即可 91 | return -61; 92 | } 93 | 94 | void CustomStructureGenerator::prepareAndComputeHeights( 95 | BlockVolume& box, 96 | ChunkPos const& chunkPos, 97 | std::vector& ZXheights, 98 | bool factorInBeardsAndShavers, 99 | int skipTopN 100 | ) { 101 | auto heightMap = mPrototype->computeHeightMap(); 102 | ZXheights.assign(heightMap->begin(), heightMap->end()); 103 | } 104 | 105 | void CustomStructureGenerator::prepareHeights( 106 | BlockVolume& box, 107 | ChunkPos const& chunkPos, 108 | bool factorInBeardsAndShavers 109 | ) { 110 | // 在其它类型世界里,这里是需要对box进行处理,生成地形,超平坦没有这个需要,所以直接赋值即可 111 | box = mPrototype; 112 | }; 113 | 114 | HashedString CustomStructureGenerator::findStructureFeatureTypeAt(BlockPos const& blockPos) { 115 | return WorldGenerator::findStructureFeatureTypeAt(blockPos); 116 | }; 117 | 118 | bool CustomStructureGenerator::isStructureFeatureTypeAt(const BlockPos& blockPos, ::HashedString type) const { 119 | return WorldGenerator::isStructureFeatureTypeAt(blockPos, type); 120 | } 121 | 122 | bool CustomStructureGenerator::findNearestStructureFeature( 123 | ::HashedString type, 124 | BlockPos const& blockPos, 125 | BlockPos& blockPos1, 126 | bool mustBeInNewChunks, 127 | std::optional hash 128 | ) { 129 | return WorldGenerator::findNearestStructureFeature(type, blockPos, blockPos1, mustBeInNewChunks, hash); 130 | }; 131 | 132 | void CustomStructureGenerator::garbageCollectBlueprints(buffer_span activeChunks) { 133 | return WorldGenerator::garbageCollectBlueprints(activeChunks); 134 | }; 135 | 136 | } // namespace custom_structure_generator 137 | -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/generator/CustomStructureGenerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/deps/core/string/HashedString.h" 4 | #include "mc/deps/core/utility/buffer_span.h" 5 | #include "mc/util/Random.h" 6 | #include "mc/world/level/BlockPos.h" 7 | #include "mc/world/level/DividedPos2d.h" 8 | #include "mc/world/level/block/BlockVolume.h" 9 | #include "mc/world/level/levelgen/flat/FlatWorldGenerator.h" 10 | 11 | 12 | #include 13 | 14 | class ChunkViewSource; 15 | class LevelChunk; 16 | class ChunkPos; 17 | 18 | // 依旧建议加一个命名空间避免冲突 19 | namespace custom_structure_generator { 20 | 21 | // 我们直接继承原版超平坦这个类来写会方便很多 22 | class CustomStructureGenerator : public FlatWorldGenerator { 23 | public: 24 | Random random; // 这个是BDS生成随机数有关的类 25 | uint mSeed; 26 | 27 | // 后面的generationOptionsJSON虽然用不上,但FlatWorldGenerator的实例化需要 28 | CustomStructureGenerator(Dimension& dimension, uint seed, Json::Value const& generationOptionsJSON); 29 | 30 | // 这里是处理结构放置相关的,包括地物,结构,地形 31 | bool postProcess(ChunkViewSource& neighborhood); 32 | 33 | // 这里是初始处理新的单区块的方块生成相关的,比如一些大量的方块(石头,泥土) 34 | void loadChunk(LevelChunk& levelchunk, bool forceImmediateReplacementDataLoad); 35 | 36 | // 判断某个点在哪个结构范围里 37 | HashedString findStructureFeatureTypeAt(BlockPos const&); 38 | 39 | // 判断某个点是否在某个结构范围里 40 | bool isStructureFeatureTypeAt(BlockPos const&, ::HashedString) const; 41 | 42 | // 这里是获取某个坐标的最高方块 43 | std::optional getPreliminarySurfaceLevel(DividedPos2d<4> worldPos) const; 44 | 45 | // 如意,以一个坐标,在一定范围内查找某个类型的结构 46 | bool 47 | findNearestStructureFeature(::HashedString, BlockPos const&, BlockPos&, bool, std::optional); 48 | 49 | // 无需在意,照写就行 50 | void garbageCollectBlueprints(buffer_span); 51 | 52 | // 处理地形 53 | void prepareHeights(BlockVolume& box, ChunkPos const& chunkPos, bool factorInBeardsAndShavers); 54 | 55 | // 与prepareHeights一样,不过与之不同的是,还会计算单区块内的高度 56 | void prepareAndComputeHeights( 57 | BlockVolume& box, 58 | ChunkPos const& chunkPos, 59 | std::vector& ZXheights, 60 | bool factorInBeardsAndShavers, 61 | int skipTopN 62 | ); 63 | 64 | // 可选,可以不写 65 | BlockPos findSpawnPosition() const { return {0, 16, 0}; }; 66 | }; 67 | 68 | } // namespace flat_village_generator -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure-files/README.md: -------------------------------------------------------------------------------- 1 | ## You need to copy this folder to this path: 2 | 3 | ``` 4 | behavior_packs\vanilla\structures\ 5 | ``` -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure-files/custom/21room.mcstructure: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiteLDev/MoreDimensions/03587dfe5b9bc820a4df43de99add99a5a9a35ba/src/test/generator/generator-custom-structure/structure-files/custom/21room.mcstructure -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure-files/custom/beds5x5int.mcstructure: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiteLDev/MoreDimensions/03587dfe5b9bc820a4df43de99add99a5a9a35ba/src/test/generator/generator-custom-structure/structure-files/custom/beds5x5int.mcstructure -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure-files/custom/chestcarpet5x5int.mcstructure: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiteLDev/MoreDimensions/03587dfe5b9bc820a4df43de99add99a5a9a35ba/src/test/generator/generator-custom-structure/structure-files/custom/chestcarpet5x5int.mcstructure -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure-files/custom/ewcap.mcstructure: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiteLDev/MoreDimensions/03587dfe5b9bc820a4df43de99add99a5a9a35ba/src/test/generator/generator-custom-structure/structure-files/custom/ewcap.mcstructure -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure-files/custom/ewhall.mcstructure: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiteLDev/MoreDimensions/03587dfe5b9bc820a4df43de99add99a5a9a35ba/src/test/generator/generator-custom-structure/structure-files/custom/ewhall.mcstructure -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure-files/custom/kitchen5x5int.mcstructure: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiteLDev/MoreDimensions/03587dfe5b9bc820a4df43de99add99a5a9a35ba/src/test/generator/generator-custom-structure/structure-files/custom/kitchen5x5int.mcstructure -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure-files/custom/nbt/back_bridge_bottom.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiteLDev/MoreDimensions/03587dfe5b9bc820a4df43de99add99a5a9a35ba/src/test/generator/generator-custom-structure/structure-files/custom/nbt/back_bridge_bottom.nbt -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure-files/custom/nbt/back_bridge_top.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiteLDev/MoreDimensions/03587dfe5b9bc820a4df43de99add99a5a9a35ba/src/test/generator/generator-custom-structure/structure-files/custom/nbt/back_bridge_top.nbt -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure-files/custom/nbt/bridge.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiteLDev/MoreDimensions/03587dfe5b9bc820a4df43de99add99a5a9a35ba/src/test/generator/generator-custom-structure/structure-files/custom/nbt/bridge.nbt -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure-files/custom/nscap.mcstructure: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiteLDev/MoreDimensions/03587dfe5b9bc820a4df43de99add99a5a9a35ba/src/test/generator/generator-custom-structure/structure-files/custom/nscap.mcstructure -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure-files/custom/nshall.mcstructure: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiteLDev/MoreDimensions/03587dfe5b9bc820a4df43de99add99a5a9a35ba/src/test/generator/generator-custom-structure/structure-files/custom/nshall.mcstructure -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure/CustomStructureFeature.cpp: -------------------------------------------------------------------------------- 1 | #include "CustomStructureFeature.h" 2 | 3 | #include "test/generator/generator-custom-structure/structure/CustomStructurePiece.h" 4 | #include "test/generator/generator-custom-structure/structure/CustomStructureStart.h" 5 | 6 | 7 | #include "mc/deps/core/math/Random.h" 8 | #include "mc/deps/core/string/HashedString.h" 9 | #include "mc/util/Random.h" 10 | #include "mc/world/level/ChunkPos.h" 11 | #include "mc/world/level/Level.h" 12 | #include "mc/world/level/biome/Biome.h" 13 | #include "mc/world/level/biome/source/BiomeSource.h" 14 | #include "mc/world/level/dimension/Dimension.h" 15 | #include "mc/world/level/levelgen/structure/BoundingBox.h" 16 | #include "mc/world/level/levelgen/structure/StructureStart.h" 17 | 18 | 19 | #include 20 | 21 | namespace custom_structure { 22 | bool CustomStructureFeature::getNearestGeneratedFeature( 23 | ::Dimension& dimension, 24 | ::BiomeSource const& biomeSource, 25 | ::BlockPos const& origin, 26 | ::BlockPos& pos, 27 | ::IPreliminarySurfaceProvider const& preliminarySurfaceLevel, 28 | bool mustBeInNewChunks, 29 | ::std::optional<::HashedString> const& biomeTag 30 | ) { 31 | return StructureFeature::findNearestFeaturePositionBySpacing(dimension, preliminarySurfaceLevel, *this, biomeTag, biomeSource, origin, pos, mMaxSpacing, mMinSpacing, 39281139, true, 0, mustBeInNewChunks); 32 | }; 33 | 34 | bool CustomStructureFeature:: 35 | isFeatureChunk(::BiomeSource const&, ::Random& random, ::ChunkPos const& cpos, uint, ::IPreliminarySurfaceProvider const&, ::Dimension const&) { 36 | int salt = 39281139; 37 | uint newSeed = mSeed + salt + 0xF1565BD5 * (cpos.z / mMaxSpacing) - 0x66C60AF8 * (cpos.x / mMaxSpacing); 38 | random.mRandom->mObject.mHaveNextNextGaussian = false; 39 | random.mRandom->mObject.mSeed = newSeed; 40 | random.mRandom->mObject.mNextNextGaussian = 0.0; 41 | random.mRandom->mObject.mNextNextGaussianDouble = 0.0; 42 | random.mRandom->mObject._mt[0] = newSeed; 43 | 44 | auto _mtLast = newSeed; 45 | for (int i = 1; i <= 397; i++) { 46 | random.mRandom->mObject._mt[i] = i + 0x6C078965 * (_mtLast ^ (_mtLast >> 30)); 47 | _mtLast = i + 0x6C078965 * (_mtLast ^ (_mtLast >> 30)); 48 | } 49 | random.mRandom->mObject._mti = 624; 50 | random.mRandom->mObject.mInitedIdx = 398; 51 | 52 | auto able_spacing = mMaxSpacing - mMinSpacing; 53 | 54 | auto random_int_x = (random.nextInt(able_spacing) + random.nextInt(able_spacing)) / 2; 55 | auto random_int_z = (random.nextInt(able_spacing) + random.nextInt(able_spacing)) / 2; 56 | 57 | ChunkPos target_cpos(able_spacing * (cpos.x / able_spacing) + random_int_x, able_spacing * (cpos.z / able_spacing) + random_int_z); 58 | if (cpos != target_cpos) return false; 59 | return true; 60 | }; 61 | 62 | std::unique_ptr<::StructureStart> CustomStructureFeature:: 63 | createStructureStart(::Dimension& dim, ::BiomeSource const& biomeSource, ::Random& random, ::ChunkPos const& cpos, ::IPreliminarySurfaceProvider const&) { 64 | auto start = std::make_unique(); 65 | CustomStructurePiece::addPieces( 66 | {cpos.x * 16, 0, cpos.z * 16}, 67 | start->pieces, 68 | random, 69 | dim.mLevel.getJigsawStructureRegistry(), 70 | biomeSource.getBiome(cpos.x * 16, 1, cpos.z * 16)->getBiomeType(), 71 | dim 72 | ); 73 | start->calculateBoundingBox(); 74 | return std::move(start); 75 | }; 76 | 77 | CustomStructureFeature::CustomStructureFeature(uint seed, uint minSpacing, uint maxSpacing) 78 | : StructureFeature(seed, HashedString("mike:basic_dungeon")), 79 | mSeed(seed), 80 | mMinSpacing(minSpacing), 81 | mMaxSpacing(maxSpacing) {} 82 | 83 | } // namespace custom_structure 84 | -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure/CustomStructureFeature.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/world/level/levelgen/structure/StructureFeature.h" 4 | 5 | namespace custom_structure { 6 | class CustomStructureFeature : public StructureFeature { 7 | uint mSeed; // 虚函数的参数传过来的都是默认的level种子,自定义就存一下 8 | int mMaxSpacing; // 最大间距 9 | int mMinSpacing; // 最小间距 10 | public: 11 | virtual bool getNearestGeneratedFeature( 12 | ::Dimension& dimension, 13 | ::BiomeSource const& biomeSource, 14 | ::BlockPos const& origin, 15 | ::BlockPos& pos, 16 | ::IPreliminarySurfaceProvider const& preliminarySurfaceLevel, 17 | bool mustBeInNewChunks, 18 | ::std::optional<::HashedString> const& biomeTag 19 | ); 20 | 21 | virtual bool 22 | isFeatureChunk(::BiomeSource const&, ::Random&, ::ChunkPos const&, uint, ::IPreliminarySurfaceProvider const&, ::Dimension const&); 23 | 24 | virtual ::std::unique_ptr<::StructureStart> 25 | createStructureStart(::Dimension&, ::BiomeSource const&, ::Random&, ::ChunkPos const&, ::IPreliminarySurfaceProvider const&); 26 | 27 | CustomStructureFeature(uint seed, uint minSpacing, uint maxSpacing); 28 | }; 29 | 30 | } // namespace custom_structure -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure/CustomStructurePiece.cpp: -------------------------------------------------------------------------------- 1 | #include "CustomStructurePiece.h" 2 | 3 | #include "mc/util/Random.h" 4 | #include "mc/world/level/BlockPos.h" 5 | #include "mc/world/level/block/VanillaBlockTypeIds.h" 6 | #include "mc/world/level/block/registry/BlockTypeRegistry.h" 7 | #include "mc/world/level/dimension/Dimension.h" 8 | #include "mc/world/level/levelgen/structure/BoundingBox.h" 9 | #include "test/mc/JigsawJunction.h" 10 | #include "test/mc/JigsawPlacement.h" 11 | #include "mc/world/level/levelgen/structure/registry/JigsawStructureRegistry.h" 12 | #include "mc/world/level/levelgen/structure/structurepools/StructurePoolElement.h" 13 | #include "test/mc/StructureTemplatePool.h" 14 | #include "test/mc/PoolAliasBinding.h" 15 | #include "mc/world/level/levelgen/v1/AdjustmentEffect.h" 16 | 17 | 18 | #include 19 | 20 | 21 | namespace custom_structure { 22 | 23 | int CustomStructurePiece:: 24 | generateHeightAtPosition(BlockPos const&, Dimension& dim, BlockVolume&, std::unordered_map>>&) 25 | const { 26 | return dim.mSeaLevel + 100; 27 | }; 28 | 29 | Block const* CustomStructurePiece::getSupportBlock(::BlockSource&, ::BlockPos const&, ::Block const&) const { 30 | return &BlockTypeRegistry::getDefaultBlockState(VanillaBlockTypeIds::GrassBlock()); 31 | }; 32 | 33 | Block const& CustomStructurePiece::getBeardStabilizeBlock(::Block const&) const { 34 | return BlockTypeRegistry::getDefaultBlockState(VanillaBlockTypeIds::GrassBlock()); 35 | }; 36 | 37 | AdjustmentEffect CustomStructurePiece::getTerrainAdjustmentEffect() const { return AdjustmentEffect::Beard; }; 38 | 39 | CustomStructurePiece::CustomStructurePiece( 40 | ::StructurePoolElement const& element, 41 | ::BlockPos position, 42 | ::Rotation rotation, 43 | int genDepth, 44 | ::JigsawJunction& junction, 45 | ::BoundingBox const& box, 46 | ::BlockPos refPos 47 | ) 48 | : PoolElementStructurePiece(element, position, rotation, genDepth, junction, box, refPos) {}; 49 | 50 | void CustomStructurePiece::addPieces( 51 | BlockPos position, 52 | std::vector>& pieces, 53 | Random& random, 54 | JigsawStructureRegistry& pools, 55 | VanillaBiomeTypes biomeType, 56 | Dimension& dimension 57 | ) { 58 | auto templates = pools.lookupByName("mike:ns7x4"); 59 | // templates.getRandomTemplate(random); 60 | 61 | auto lambda = [](StructurePoolElement const& element, 62 | ::BlockPos const& pos, 63 | ::Rotation const& rot, 64 | int unk, 65 | ::JigsawJunction& jigction, 66 | ::BoundingBox const& bb, 67 | ::BlockPos const& pos1) { 68 | return std::make_unique(element, pos, rot, unk, jigction, bb, pos1); 69 | }; 70 | JigsawPlacement place(15, 80, pieces, lambda, random, pools, dimension); 71 | 72 | auto index = random.nextInt(0, templates->mTemplates->size() - 1); 73 | place.addPieces( 74 | *templates->mTemplates->at(index), 75 | position, 76 | Rotation(random.nextInt(4)), 77 | "", 78 | {} 79 | ); 80 | } 81 | 82 | } // namespace custom_structure 83 | -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure/CustomStructurePiece.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/util/Rotation.h" 4 | #include "mc/world/level/biome/components/vanilla/VanillaBiomeTypes.h" 5 | #include "test/mc/PoolElementStructurePiece.h" 6 | 7 | 8 | 9 | class JigsawStructureRegistry; 10 | class StructurePoolElement; 11 | struct JigsawJunction; 12 | 13 | namespace custom_structure { 14 | 15 | class CustomStructurePiece : public PoolElementStructurePiece { 16 | public: 17 | virtual int 18 | generateHeightAtPosition(::BlockPos const&, ::Dimension&, ::BlockVolume&, ::std::unordered_map<::ChunkPos, ::std::unique_ptr<::std::vector>>&) 19 | const; 20 | 21 | virtual Block const* getSupportBlock(::BlockSource&, ::BlockPos const&, ::Block const&) const; 22 | 23 | virtual Block const& getBeardStabilizeBlock(::Block const&) const; 24 | 25 | virtual AdjustmentEffect getTerrainAdjustmentEffect() const; 26 | 27 | CustomStructurePiece( 28 | ::StructurePoolElement const& element, 29 | ::BlockPos position, 30 | ::Rotation rotation, 31 | int genDepth, 32 | ::JigsawJunction& junction, 33 | ::BoundingBox const& box, 34 | ::BlockPos refPos 35 | ); 36 | 37 | static void addPieces( 38 | BlockPos position, 39 | std::vector>& pieces, 40 | Random& random, 41 | JigsawStructureRegistry& pools, 42 | VanillaBiomeTypes biomeType, 43 | Dimension& dimension 44 | ); 45 | }; 46 | 47 | } // namespace custom_structure 48 | -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure/CustomStructureStart.cpp: -------------------------------------------------------------------------------- 1 | #include "CustomStructureStart.h" 2 | 3 | // CustomStructureStart::CustomStructureStart(int chunk_x, int chunk_z) { 4 | // chunkX = chunk_x; 5 | // chunkZ = chunk_z; 6 | // } -------------------------------------------------------------------------------- /src/test/generator/generator-custom-structure/structure/CustomStructureStart.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/world/level/levelgen/structure/StructureStart.h" 4 | 5 | 6 | class CustomStructureStart : public StructureStart { 7 | public: 8 | CustomStructureStart() = default; 9 | virtual std::string_view getStructureName() const { return "mike:basic_dungeon"; }; 10 | }; 11 | -------------------------------------------------------------------------------- /src/test/generator/generator-terrain/NxnBorderTerrainDimension.cpp: -------------------------------------------------------------------------------- 1 | #include "NxnBorderTerrainDimension.h" 2 | 3 | #include "test/generator/generator-terrain/NxnBorderTerrainGenerator.h" 4 | 5 | #include "mc/common/Brightness.h" 6 | #include "mc/common/BrightnessPair.h" 7 | #include "mc/deps/core/math/Vec3.h" 8 | #include "mc/world/level/BlockSource.h" 9 | #include "mc/world/level/DimensionConversionData.h" 10 | #include "mc/world/level/Level.h" 11 | #include "mc/world/level/chunk/vanilla_level_chunk_upgrade/VanillaLevelChunkUpgrade.h" 12 | #include "mc/world/level/dimension/DimensionBrightnessRamp.h" 13 | #include "mc/world/level/dimension/DimensionHeightRange.h" 14 | #include "mc/world/level/dimension/OverworldBrightnessRamp.h" 15 | #include "mc/world/level/dimension/VanillaDimensions.h" 16 | #include "mc/world/level/levelgen/flat/FlatWorldGenerator.h" 17 | #include "mc/world/level/levelgen/structure/StructureFeatureRegistry.h" 18 | #include "mc/world/level/levelgen/structure/VillageFeature.h" 19 | #include "mc/world/level/levelgen/v2/ChunkGeneratorStructureState.h" 20 | #include "mc/world/level/storage/LevelData.h" 21 | 22 | 23 | namespace nxn_border_terrain { 24 | 25 | NxnBorderTerrainDimension::NxnBorderTerrainDimension( 26 | std::string const& name, 27 | more_dimensions::DimensionFactoryInfo const& info 28 | ) 29 | : Dimension(info.level, info.dimId, {-64, 320}, info.scheduler, name) { 30 | // 这里说明下,在DimensionFactoryInfo里面more-dimensions会提供维度id,请不要使用固定维度id,避免id冲突导致维度注册出现异常 31 | mDefaultBrightness->sky = Brightness::MAX(); 32 | mSeaLevel = -61; 33 | mHasWeather = true; 34 | mDimensionBrightnessRamp = std::make_unique(); 35 | mDimensionBrightnessRamp->buildBrightnessRamp(); 36 | 37 | // 这个是边长的区块数,是将会传到生成器里面用的 38 | chunkLength = info.data["ChunkLength"]; 39 | } 40 | 41 | CompoundTag NxnBorderTerrainDimension::generateNewData(uint chunkLength) { 42 | CompoundTag result; 43 | result["ChunkLength"] = chunkLength; 44 | return result; 45 | } 46 | 47 | std::unique_ptr NxnBorderTerrainDimension::createGenerator(br::worldgen::StructureSetRegistry const&) { 48 | 49 | std::unique_ptr worldGenerator; 50 | auto seed = mLevel.getSeed(); 51 | auto& levelData = mLevel.getLevelData(); 52 | 53 | // 实例化一个FlatWorldGenerator类 54 | worldGenerator = 55 | std::make_unique(*this, seed, chunkLength, levelData.mFlatWorldOptions); 56 | // 此为必须,一些结构生成相关 57 | worldGenerator->mStructureFeatureRegistry->mGeneratorState = 58 | br::worldgen::ChunkGeneratorStructureState::createFlat(seed, worldGenerator->getBiomeSource(), {}); 59 | 60 | return std::move(worldGenerator); 61 | } 62 | 63 | void NxnBorderTerrainDimension::upgradeLevelChunk(ChunkSource& cs, LevelChunk& lc, LevelChunk& generatedChunk) { 64 | auto blockSource = BlockSource(static_cast(mLevel), *this, cs, false, true, false); 65 | VanillaLevelChunkUpgrade::_upgradeLevelChunkViaMetaData(lc, generatedChunk, blockSource); 66 | VanillaLevelChunkUpgrade::_upgradeLevelChunkLegacy(lc, blockSource); 67 | } 68 | 69 | void NxnBorderTerrainDimension::fixWallChunk(ChunkSource& cs, LevelChunk& lc) { 70 | auto blockSource = BlockSource(static_cast(mLevel), *this, cs, false, true, false); 71 | VanillaLevelChunkUpgrade::fixWallChunk(lc, blockSource); 72 | } 73 | 74 | bool NxnBorderTerrainDimension::levelChunkNeedsUpgrade(LevelChunk const& lc) const { 75 | return VanillaLevelChunkUpgrade::levelChunkNeedsUpgrade(lc); 76 | } 77 | void NxnBorderTerrainDimension::_upgradeOldLimboEntity(CompoundTag& tag, ::LimboEntitiesVersion vers) { 78 | auto isTemplate = mLevel.getLevelData().mIsFromLockedTemplate; 79 | return VanillaLevelChunkUpgrade::upgradeOldLimboEntity(tag, vers, isTemplate); 80 | } 81 | 82 | std::unique_ptr NxnBorderTerrainDimension:: 83 | _wrapStorageForVersionCompatibility(std::unique_ptr cs, ::StorageVersion /*ver*/) { 84 | return cs; 85 | } 86 | 87 | Vec3 NxnBorderTerrainDimension::translatePosAcrossDimension(Vec3 const& fromPos, DimensionType fromId) const { 88 | Vec3 topos; 89 | VanillaDimensions::convertPointBetweenDimensions(fromPos, topos, fromId, mId, mLevel.getDimensionConversionData()); 90 | constexpr auto clampVal = 32000000.0f - 128.0f; 91 | 92 | topos.x = std::clamp(topos.x, -clampVal, clampVal); 93 | topos.z = std::clamp(topos.z, -clampVal, clampVal); 94 | 95 | return topos; 96 | } 97 | 98 | short NxnBorderTerrainDimension::getCloudHeight() const { return 192; } 99 | 100 | // bool NxnBorderTerrainDimension::hasPrecipitationFog() const { return true; } 101 | 102 | } // namespace nxn_border_terrain -------------------------------------------------------------------------------- /src/test/generator/generator-terrain/NxnBorderTerrainDimension.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/world/level/dimension/Dimension.h" // 新维度类需要继承的类 4 | #include "more_dimensions/api/dimension/CustomDimensionManager.h" // 使用DimensionFactoryInfo的声明 5 | 6 | // 建议是加一个命名空间,避免与其他插件同类名的情况 7 | namespace nxn_border_terrain { 8 | 9 | class NxnBorderTerrainDimension : public Dimension { 10 | uint chunkLength; 11 | 12 | public: 13 | // 建议固定这样写,DimensionFactoryInfo类里面提供了Dimension实例化的基本数据,name就是维度名,多维度是维度名区分不同维度 14 | NxnBorderTerrainDimension(std::string const& name, more_dimensions::DimensionFactoryInfo const& info); 15 | 16 | // 多维度需要的一个方法,参数是你需要的一些额外的数据,比如种子 17 | static CompoundTag generateNewData(uint chunkLength = 4); 18 | 19 | // 以下六个是必须重写的函数 20 | // 维度地形的生成器,是本教程主要更改的地方 21 | std::unique_ptr createGenerator(br::worldgen::StructureSetRegistry const&) override; 22 | 23 | // 与本教程无关,按照本教程写的就行,无需留意 24 | void upgradeLevelChunk(ChunkSource& chunkSource, LevelChunk& oldLc, LevelChunk& newLc) override; 25 | 26 | // 与本教程无关,按照本教程写的就行,无需留意 27 | void fixWallChunk(ChunkSource& cs, LevelChunk& lc) override; 28 | 29 | // 与本教程无关,按照本教程写的就行,无需留意 30 | bool levelChunkNeedsUpgrade(LevelChunk const& lc) const override; 31 | 32 | // 与本教程无关,按照本教程写的就行,无需留意 33 | void _upgradeOldLimboEntity(CompoundTag& tag, ::LimboEntitiesVersion vers) override; 34 | 35 | // 与本教程无关,按照本教程写的就行,无需留意 36 | std::unique_ptr 37 | _wrapStorageForVersionCompatibility(std::unique_ptr cs, ::StorageVersion ver) override; 38 | 39 | // 当你转到这个维度时,坐标怎么转换,比如主世界与地狱的 40 | Vec3 translatePosAcrossDimension(Vec3 const& pos, DimensionType did) const override; 41 | 42 | // 云高度,默认是y128,但多维度高度范围是在y-64~320,与主世界相同,重写它,放高些 43 | short getCloudHeight() const override; 44 | 45 | // 非必要。下雨时,可视范围的更改 46 | // bool hasPrecipitationFog() const override; 47 | }; 48 | 49 | } // namespace nxn_border_terrain -------------------------------------------------------------------------------- /src/test/generator/generator-terrain/NxnBorderTerrainGenerator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by User on 2024/2/22. 3 | // 4 | 5 | #include "NxnBorderTerrainGenerator.h" 6 | 7 | #include "test/mc/FixedBiomeSource.h" 8 | 9 | #include "mc/world/level/ChunkPos.h" 10 | #include "mc/world/level/block/BedrockBlockNames.h" 11 | #include "mc/world/level/block/Block.h" 12 | #include "mc/world/level/block/BlockVolume.h" 13 | #include "mc/world/level/block/VanillaBlockTypeIds.h" 14 | #include "mc/world/level/block/registry/BlockTypeRegistry.h" 15 | #include "mc/world/level/chunk/LevelChunk.h" 16 | #include "mc/world/level/dimension/Dimension.h" 17 | #include "mc/world/level/levelgen/v1/ChunkLocalNoiseCache.h" 18 | 19 | #include "mc/world/level/block/Block.h" 20 | 21 | 22 | namespace nxn_border_terrain { 23 | 24 | NxnBorderTerrainGenerator::NxnBorderTerrainGenerator( 25 | Dimension& dimension, 26 | uint seed, 27 | uint chunkLength, 28 | Json::Value const& generationOptionsJSON 29 | ) 30 | : FlatWorldGenerator(dimension, seed, generationOptionsJSON) { 31 | chunk_n = chunkLength; 32 | auto height = mPrototype->mHeight; 33 | auto& roadBlock = BlockTypeRegistry::getDefaultBlockState(VanillaBlockTypeIds::GrassPath()); 34 | auto& borderBlock = BlockTypeRegistry::getDefaultBlockState(VanillaBlockTypeIds::SmoothStoneSlab()); 35 | 36 | east_side_b.mBlocks = {east_side.data(), east_side.data() + east_side.size()}; 37 | south_side_b.mBlocks = {south_side.data(), south_side.data() + south_side.size()}; 38 | west_side_b.mBlocks = {west_side.data(), west_side.data() + west_side.size()}; 39 | north_side_b.mBlocks = {north_side.data(), north_side.data() + north_side.size()}; 40 | n_e_angle_b.mBlocks = {n_e_angle.data(), n_e_angle.data() + n_e_angle.size()}; 41 | e_s_angle_b.mBlocks = {e_s_angle.data(), e_s_angle.data() + e_s_angle.size()}; 42 | s_w_angle_b.mBlocks = {s_w_angle.data(), s_w_angle.data() + s_w_angle.size()}; 43 | w_n_angle_b.mBlocks = {w_n_angle.data(), w_n_angle.data() + w_n_angle.size()}; 44 | 45 | for (int i = 0; i < 16; i++) { 46 | // 一般开始的是距离第一个方块的差值,然后是会乘 47 | // i的间隔方块,然后是与另外一条路或者半砖方块的间隔,最后面的是第几层 48 | // 南边 49 | e_s_angle[height * 15 + height * 16 * i + 3] = &roadBlock; 50 | 51 | s_w_angle[height * 15 + height * 16 * i + 3] = &roadBlock; 52 | 53 | south_side[height * 15 + height * 16 * i + 3] = &roadBlock; 54 | south_side[height * 14 + height * 16 * i + 4] = &borderBlock; 55 | // 东边 56 | e_s_angle[height * 16 * 15 + height * i + 3] = &roadBlock; 57 | 58 | n_e_angle[height * 16 * 15 + height * i + 3] = &roadBlock; 59 | 60 | east_side[height * 16 * 15 + height * i + 3] = &roadBlock; 61 | east_side[height * 16 * 14 + height * i + 4] = &borderBlock; 62 | // 西边 63 | s_w_angle[height * i + 3] = &roadBlock; 64 | 65 | w_n_angle[height * i + 3] = &roadBlock; 66 | 67 | west_side[height * i + 3] = &roadBlock; 68 | west_side[height * 16 + height * i + 4] = &borderBlock; 69 | // 北边 70 | n_e_angle[height * 16 * i + 3] = &roadBlock; 71 | 72 | w_n_angle[height * 16 * i + 3] = &roadBlock; 73 | 74 | north_side[height * 16 * i + 3] = &roadBlock; 75 | north_side[height + height * 16 * i + 4] = &borderBlock; 76 | 77 | // 半砖避免放到路上,最后一次循环 78 | if (i < 15) { 79 | // 南 80 | e_s_angle[height * 14 + height * 16 * i + 4] = &borderBlock; 81 | // 东 82 | e_s_angle[height * 16 * 14 + height * i + 4] = &borderBlock; 83 | // 西 84 | s_w_angle[height * 16 + height * i + 4] = &borderBlock; 85 | // 北 86 | n_e_angle[height + height * 16 * i + 4] = &borderBlock; 87 | } 88 | // 第一次循环 89 | if (i > 0) { 90 | // 西 91 | w_n_angle[height * 16 + height * i + 4] = &borderBlock; 92 | // 北 93 | w_n_angle[height + height * 16 * i + 4] = &borderBlock; 94 | // 南 95 | s_w_angle[height * 14 + height * 16 * i + 4] = &borderBlock; 96 | // 东 97 | n_e_angle[height * 16 * 14 + height * i + 4] = &borderBlock; 98 | } 99 | } 100 | } 101 | 102 | void NxnBorderTerrainGenerator::loadChunk(LevelChunk& levelchunk, bool forceImmediateReplacementDataLoad) { 103 | auto chunkPos = levelchunk.mPosition; 104 | 105 | int n = chunk_n; 106 | auto pos_x = (chunkPos->x % n + n) % n; 107 | auto pos_z = (chunkPos->z % n + n) % n; 108 | 109 | if (pos_x == 0) { 110 | if (pos_z == 0) { 111 | levelchunk.setBlockVolume(w_n_angle_b, 0); 112 | } else if (pos_z == (n - 1)) { 113 | levelchunk.setBlockVolume(s_w_angle_b, 0); 114 | } else { 115 | levelchunk.setBlockVolume(west_side_b, 0); 116 | } 117 | 118 | } else if (pos_x == (n - 1)) { 119 | if (pos_z == 0) { 120 | levelchunk.setBlockVolume(n_e_angle_b, 0); 121 | } else if (pos_z == (n - 1)) { 122 | levelchunk.setBlockVolume(e_s_angle_b, 0); 123 | } else { 124 | levelchunk.setBlockVolume(east_side_b, 0); 125 | } 126 | } else if (pos_z == 0) { 127 | levelchunk.setBlockVolume(north_side_b, 0); 128 | } else if (pos_z == (n - 1)) { 129 | levelchunk.setBlockVolume(south_side_b, 0); 130 | } else { 131 | levelchunk.setBlockVolume(mPrototype, 0); 132 | } 133 | 134 | levelchunk.recomputeHeightMap(false); 135 | mBiomeSource = std::make_unique(*mBiome); 136 | DividedPos2d<4> dividedPos2D; 137 | ChunkLocalNoiseCache chunkLocalNoiseCache(dividedPos2D, 8); 138 | mBiomeSource->fillBiomes(levelchunk, chunkLocalNoiseCache); 139 | levelchunk.setSaved(); 140 | auto loadState = ChunkState::Generating; 141 | levelchunk.mLoadState->compare_exchange_weak(loadState, ChunkState::Generated); 142 | } 143 | 144 | } // namespace nxn_border_terrain -------------------------------------------------------------------------------- /src/test/generator/generator-terrain/NxnBorderTerrainGenerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/world/level/block/BlockVolume.h" 4 | #include "mc/world/level/levelgen/flat/FlatWorldGenerator.h" 5 | 6 | #include 7 | 8 | namespace nxn_border_terrain { 9 | 10 | class NxnBorderTerrainGenerator : public FlatWorldGenerator { 11 | public: 12 | uint chunk_n = 4; // n * n的区块 13 | std::vector east_side = mPrototypeBlocks; 14 | std::vector south_side = mPrototypeBlocks; 15 | std::vector west_side = mPrototypeBlocks; 16 | std::vector north_side = mPrototypeBlocks; 17 | std::vector n_e_angle = mPrototypeBlocks; 18 | std::vector e_s_angle = mPrototypeBlocks; 19 | std::vector s_w_angle = mPrototypeBlocks; 20 | std::vector w_n_angle = mPrototypeBlocks; 21 | BlockVolume east_side_b = mPrototype; 22 | BlockVolume south_side_b = mPrototype; 23 | BlockVolume west_side_b = mPrototype; 24 | BlockVolume north_side_b = mPrototype; 25 | BlockVolume n_e_angle_b = mPrototype; 26 | BlockVolume e_s_angle_b = mPrototype; 27 | BlockVolume s_w_angle_b = mPrototype; 28 | BlockVolume w_n_angle_b = mPrototype; 29 | NxnBorderTerrainGenerator( 30 | Dimension& dimension, 31 | uint seed, 32 | uint chunkLength, 33 | Json::Value const& generationOptionsJSON 34 | ); 35 | void loadChunk(class LevelChunk& levelchunk, bool forceImmediateReplacementDataLoad); 36 | }; 37 | } // namespace nxn_border_terrain -------------------------------------------------------------------------------- /src/test/mc/FixedBiomeSource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/_HeaderOutputPredefine.h" 4 | 5 | // auto generated inclusion list 6 | #include "mc/world/level/biome/source/BiomeSource.h" 7 | 8 | // auto generated forward declare list 9 | // clang-format off 10 | class Biome; 11 | class BiomeArea; 12 | class BlockPos; 13 | class BoundingBox; 14 | class ChunkLocalNoiseCache; 15 | class LevelChunk; 16 | struct GetBiomeOptions; 17 | // clang-format on 18 | 19 | class FixedBiomeSource : public ::BiomeSource { 20 | public: 21 | // member variables 22 | // NOLINTBEGIN 23 | ::ll::TypedStorage<8, 8, ::Biome const&> mFixedBiome; 24 | // NOLINTEND 25 | 26 | public: 27 | // virtual functions 28 | // NOLINTBEGIN 29 | // vIndex: 1 30 | virtual void fillBiomes(::LevelChunk& levelChunk, ::ChunkLocalNoiseCache const& chunkLocalNoiseCache) const 31 | /*override*/; 32 | 33 | // vIndex: 4 34 | virtual bool containsOnly(int, int, int, int, ::gsl::span allowed) const /*override*/; 35 | 36 | // vIndex: 7 37 | virtual ::Biome const* getBiome(::BlockPos const& blockPos) const /*override*/; 38 | 39 | // vIndex: 6 40 | virtual ::Biome const* getBiome(::GetBiomeOptions const& getBiomeOptions) const /*override*/; 41 | 42 | // vIndex: 5 43 | virtual ::Biome const* getBiome(int blockX, int blockY, int blockZ) const /*override*/; 44 | 45 | // vIndex: 3 46 | virtual ::BiomeArea getBiomeArea(::BoundingBox const& area, uint scale) const /*override*/; 47 | 48 | // vIndex: 2 49 | virtual ::BiomeArea 50 | getBiomeArea(::BoundingBox const& area, uint scale, ::GetBiomeOptions const& getBiomeOptions) const /*override*/; 51 | 52 | // vIndex: 8 53 | virtual bool has(uint64 id) const /*override*/; 54 | 55 | // vIndex: 9 56 | virtual bool hasByHashId(uint64 id) const /*override*/; 57 | 58 | // vIndex: 10 59 | virtual ::BiomeSourceType const getType() const /*override*/; 60 | 61 | // vIndex: 0 62 | virtual ~FixedBiomeSource() /*override*/ = default; 63 | // NOLINTEND 64 | 65 | public: 66 | FixedBiomeSource(Biome const& biome) : mFixedBiome(biome){}; 67 | // destructor thunk 68 | // NOLINTBEGIN 69 | 70 | // NOLINTEND 71 | 72 | public: 73 | // virtual function thunks 74 | // NOLINTBEGIN 75 | MCAPI void $fillBiomes(::LevelChunk& levelChunk, ::ChunkLocalNoiseCache const& chunkLocalNoiseCache) const; 76 | 77 | MCAPI bool $containsOnly(int, int, int, int, ::gsl::span allowed) const; 78 | 79 | MCFOLD ::Biome const* $getBiome(::BlockPos const& blockPos) const; 80 | 81 | MCFOLD ::Biome const* $getBiome(::GetBiomeOptions const& getBiomeOptions) const; 82 | 83 | MCFOLD ::Biome const* $getBiome(int blockX, int blockY, int blockZ) const; 84 | 85 | MCAPI ::BiomeArea $getBiomeArea(::BoundingBox const& area, uint scale) const; 86 | 87 | MCAPI ::BiomeArea 88 | $getBiomeArea(::BoundingBox const& area, uint scale, ::GetBiomeOptions const& getBiomeOptions) const; 89 | 90 | MCAPI bool $has(uint64 id) const; 91 | 92 | MCAPI bool $hasByHashId(uint64 id) const; 93 | // NOLINTEND 94 | 95 | public: 96 | // vftables 97 | // NOLINTBEGIN 98 | MCAPI static void** $vftable(); 99 | // NOLINTEND 100 | }; 101 | -------------------------------------------------------------------------------- /src/test/mc/JigsawJunction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/_HeaderOutputPredefine.h" 4 | 5 | #include "mc/world/level/BlockPos.h" 6 | #include "mc/world/level/levelgen/structure/Projection.h" 7 | 8 | 9 | struct JigsawJunction { 10 | public: 11 | // member variables 12 | // NOLINTBEGIN 13 | ::ll::TypedStorage<4, 12, BlockPos> mSourceBlockPos; 14 | ::ll::TypedStorage<4, 4, int> mDeltaSourceY; 15 | ::ll::TypedStorage<4, 4, int> mDeltaTargetY; 16 | ::ll::TypedStorage<1, 1, Projection> mSourceProjection; 17 | ::ll::TypedStorage<1, 1, Projection> mTargetProjection; 18 | // NOLINTEND 19 | 20 | public: 21 | // prevent constructor by default 22 | }; 23 | -------------------------------------------------------------------------------- /src/test/mc/JigsawPlacement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/_HeaderOutputPredefine.h" 4 | 5 | // auto generated inclusion list 6 | #include "mc/util/Rotation.h" 7 | #include "test/mc/PoolAliasBinding.h" 8 | 9 | // auto generated forward declare list 10 | // clang-format off 11 | class BlockPos; 12 | class BoundingBox; 13 | class Dimension; 14 | class JigsawBlockInfo; 15 | class JigsawStructureRegistry; 16 | class PoolElementStructurePiece; 17 | class Random; 18 | class StructurePiece; 19 | class StructurePoolElement; 20 | class StructureTemplatePool; 21 | struct JigsawJunction; 22 | // clang-format on 23 | 24 | class JigsawPlacement { 25 | public: 26 | // member variables 27 | // NOLINTBEGIN 28 | ::ll::UntypedStorage<4, 4> mUnkcc2c4f; 29 | ::ll::UntypedStorage<4, 4> mUnk230fb5; 30 | ::ll::UntypedStorage<8, 64> mUnk40c5ee; 31 | ::ll::UntypedStorage<8, 8> mUnke0bb10; 32 | ::ll::UntypedStorage<8, 8> mUnk3c1434; 33 | ::ll::UntypedStorage<8, 8> mUnkfa3181; 34 | ::ll::UntypedStorage<8, 8> mUnk2bf1da; 35 | ::ll::UntypedStorage<8, 64> mUnk5862e9; 36 | ::ll::UntypedStorage<8, 40> mUnkdd8234; 37 | ::ll::UntypedStorage<8, 24> mUnkb1b40e; 38 | ::ll::UntypedStorage<8, 24> mUnka60e45; 39 | ::ll::UntypedStorage<8, 40> mUnk747941; 40 | // NOLINTEND 41 | 42 | public: 43 | // prevent constructor by default 44 | JigsawPlacement& operator=(JigsawPlacement const&); 45 | JigsawPlacement(JigsawPlacement const&); 46 | JigsawPlacement(); 47 | 48 | public: 49 | // member functions 50 | // NOLINTBEGIN 51 | MCAPI JigsawPlacement( 52 | uint64 maxDepth, 53 | uint64 globalContextSize, 54 | ::std::vector<::std::unique_ptr<::StructurePiece>>& pieceList, 55 | ::std::function<::std::unique_ptr< 56 | ::PoolElementStructurePiece>(::StructurePoolElement const&, ::BlockPos const&, ::Rotation const&, int, ::JigsawJunction&, ::BoundingBox const&, ::BlockPos const&)> 57 | factory, 58 | ::Random& random, 59 | ::JigsawStructureRegistry const& pools, 60 | ::Dimension& dimension 61 | ); 62 | 63 | MCAPI void _addPiece( 64 | ::PoolElementStructurePiece const& sourcePiece, 65 | ::BlockPos const& position, 66 | ::Rotation const& rotation, 67 | ::BlockPos const& refPos, 68 | uint64 contextDepth, 69 | ::PoolAliasBinding::PoolAliasLookup const& poolAliasLookup 70 | ); 71 | 72 | MCAPI ::BlockPos _findLocalAnchorOffset( 73 | ::StructurePoolElement const& initialElement, 74 | ::BlockPos const& pieceCornerPosition, 75 | ::Rotation const& rotation, 76 | ::std::string_view startAnchorName 77 | ) const; 78 | 79 | MCAPI bool _tryPlacingPiece( 80 | ::PoolElementStructurePiece const& sourcePiece, 81 | ::BoundingBox const& sourceBB, 82 | ::JigsawBlockInfo const& sourceJigsaw, 83 | ::BlockPos const& attachPos, 84 | ::StructureTemplatePool const* targetPool, 85 | ::BlockPos const& refPos, 86 | uint64 contextDepth, 87 | ::PoolAliasBinding::PoolAliasLookup const& poolAliasLookup 88 | ); 89 | 90 | MCAPI void addPieces( 91 | ::StructurePoolElement const& initialElement, 92 | ::BlockPos const& startPosition, 93 | ::Rotation const& rotation, 94 | ::std::string_view startAnchorName, 95 | ::PoolAliasBinding::PoolAliasLookup const& poolAliasLookup 96 | ); 97 | 98 | MCAPI ~JigsawPlacement(); 99 | // NOLINTEND 100 | 101 | public: 102 | // constructor thunks 103 | // NOLINTBEGIN 104 | MCAPI void* $ctor( 105 | uint64 maxDepth, 106 | uint64 globalContextSize, 107 | ::std::vector<::std::unique_ptr<::StructurePiece>>& pieceList, 108 | ::std::function<::std::unique_ptr< 109 | ::PoolElementStructurePiece>(::StructurePoolElement const&, ::BlockPos const&, ::Rotation const&, int, ::JigsawJunction&, ::BoundingBox const&, ::BlockPos const&)> 110 | factory, 111 | ::Random& random, 112 | ::JigsawStructureRegistry const& pools, 113 | ::Dimension& dimension 114 | ); 115 | // NOLINTEND 116 | 117 | public: 118 | // destructor thunk 119 | // NOLINTBEGIN 120 | MCAPI void $dtor(); 121 | // NOLINTEND 122 | }; 123 | -------------------------------------------------------------------------------- /src/test/mc/PoolAliasBinding.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/_HeaderOutputPredefine.h" 4 | 5 | // auto generated inclusion list 6 | #include "mc/deps/core/math/SimpleWeightedEntry.h" 7 | 8 | // auto generated forward declare list 9 | // clang-format off 10 | class BlockPos; 11 | class IRandom; 12 | // clang-format on 13 | 14 | class PoolAliasBinding { 15 | public: 16 | // PoolAliasBinding inner types declare 17 | // clang-format off 18 | class PoolAliasLookup; 19 | // clang-format on 20 | 21 | // PoolAliasBinding inner types define 22 | class PoolAliasLookup { 23 | public: 24 | // member variables 25 | // NOLINTBEGIN 26 | ::ll::TypedStorage<8, 24, std::vector>> mLookupTable; 27 | // NOLINTEND 28 | 29 | public: 30 | // prevent constructor by default 31 | 32 | public: 33 | // member functions 34 | // NOLINTBEGIN 35 | MCAPI ~PoolAliasLookup(); 36 | // NOLINTEND 37 | 38 | public: 39 | // destructor thunk 40 | // NOLINTBEGIN 41 | MCFOLD void $dtor(); 42 | // NOLINTEND 43 | }; 44 | 45 | public: 46 | // virtual functions 47 | // NOLINTBEGIN 48 | // vIndex: 0 49 | virtual void appendResolvedAliases(::IRandom&, ::PoolAliasBinding::PoolAliasLookup&) const = 0; 50 | 51 | // vIndex: 1 52 | virtual void forAllTargets(::std::function const&) const = 0; 53 | 54 | // vIndex: 2 55 | virtual ~PoolAliasBinding() = default; 56 | // NOLINTEND 57 | 58 | public: 59 | // static functions 60 | // NOLINTBEGIN 61 | MCAPI static ::std::shared_ptr<::PoolAliasBinding> direct(::std::string&& id, ::std::string&& target); 62 | 63 | MCAPI static ::std::shared_ptr<::PoolAliasBinding> 64 | random(::std::string&& id, ::std::vector<::Core::SimpleWeightedEntry<::std::string>>&& targets); 65 | 66 | MCAPI static ::PoolAliasBinding::PoolAliasLookup resolvePoolAliases( 67 | ::std::vector<::std::shared_ptr<::PoolAliasBinding>> const& aliases, 68 | ::BlockPos const& structureStartPosition, 69 | int64 levelSeed 70 | ); 71 | // NOLINTEND 72 | 73 | public: 74 | // destructor thunk 75 | // NOLINTBEGIN 76 | 77 | // NOLINTEND 78 | 79 | public: 80 | // virtual function thunks 81 | // NOLINTBEGIN 82 | 83 | // NOLINTEND 84 | 85 | public: 86 | // vftables 87 | // NOLINTBEGIN 88 | MCAPI static void** $vftable(); 89 | // NOLINTEND 90 | }; 91 | -------------------------------------------------------------------------------- /src/test/mc/PoolElementStructurePiece.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/_HeaderOutputPredefine.h" 4 | 5 | // auto generated inclusion list 6 | #include "mc/util/Rotation.h" 7 | #include "mc/world/actor/ActorDefinitionIdentifier.h" 8 | #include "mc/world/level/BlockPos.h" 9 | #include "mc/world/level/levelgen/structure/BoundingBox.h" 10 | #include "test/mc/JigsawJunction.h" 11 | #include "mc/world/level/levelgen/structure/structurepools/StructurePoolElement.h" 12 | #include "mc/world/level/levelgen/v1/AdjustmentEffect.h" 13 | #include "test/mc/StructurePiece.h" 14 | 15 | 16 | 17 | // auto generated forward declare list 18 | // clang-format off 19 | class Block; 20 | class BlockSource; 21 | class BlockVolume; 22 | class ChunkPos; 23 | class Dimension; 24 | class Random; 25 | // clang-format on 26 | 27 | class PoolElementStructurePiece : public ::StructurePiece { 28 | public: 29 | // member variables 30 | // NOLINTBEGIN 31 | ::ll::TypedStorage<4, 24, ::BoundingBox> mCachedPieceBounds; 32 | ::ll::TypedStorage<4, 4, int> mCachedPieceBaseY; 33 | ::ll::TypedStorage<4, 4, int> mCachedXCenter; 34 | ::ll::TypedStorage<4, 4, int> mCachedZCenter; 35 | ::ll::TypedStorage<4, 4, float> mCachedMaxRadius; 36 | ::ll::TypedStorage<8, 8, ::StructurePoolElement const&> mElement; 37 | ::ll::TypedStorage<4, 12, ::BlockPos> mPosition; 38 | ::ll::TypedStorage<1, 1, ::Rotation> mRotation; 39 | ::ll::TypedStorage<4, 24, ::JigsawJunction> mJigsawJunction; 40 | ::ll::TypedStorage<8, 64, ::std::unordered_map<::BlockPos, ::std::optional<::ActorDefinitionIdentifier>>> 41 | mEntitiesToPlace; 42 | ::ll::TypedStorage<4, 12, ::BlockPos> mRefPos; 43 | // NOLINTEND 44 | 45 | PoolElementStructurePiece( 46 | ::StructurePoolElement const& element, 47 | ::BlockPos position, 48 | ::Rotation rotation, 49 | int genDepth, 50 | ::JigsawJunction& junction, 51 | ::BoundingBox const& box, 52 | ::BlockPos refPos 53 | ) 54 | : mElement(element), 55 | mPosition(position), 56 | mRotation(rotation), 57 | mJigsawJunction(junction), 58 | mRefPos(refPos) { 59 | mBoundingBox = box; 60 | mGenDepth = genDepth; 61 | }; 62 | 63 | public: 64 | // virtual functions 65 | // NOLINTBEGIN 66 | // vIndex: 4 67 | virtual bool postProcess(::BlockSource& region, ::Random& random, ::BoundingBox const& chunkBB) /*override*/; 68 | 69 | // vIndex: 5 70 | virtual void postProcessMobsAt(::BlockSource& region, ::Random& random, ::BoundingBox const& chunkBB) /*override*/; 71 | 72 | // vIndex: 1 73 | virtual void moveBoundingBox(int dx, int dy, int dz) /*override*/; 74 | 75 | // vIndex: 13 76 | virtual int 77 | generateHeightAtPosition(::BlockPos const&, ::Dimension&, ::BlockVolume&, ::std::unordered_map<::ChunkPos, ::std::unique_ptr<::std::vector>>&) 78 | const = 0; 79 | 80 | // vIndex: 14 81 | virtual ::Block const* getSupportBlock(::BlockSource&, ::BlockPos const&, ::Block const&) const = 0; 82 | 83 | // vIndex: 15 84 | virtual ::Block const& getBeardStabilizeBlock(::Block const&) const = 0; 85 | 86 | // vIndex: 16 87 | virtual ::AdjustmentEffect getTerrainAdjustmentEffect() const = 0; 88 | 89 | // vIndex: 17 90 | virtual bool _needsPostProcessing(::BlockSource& region); 91 | 92 | // vIndex: 0 93 | virtual ~PoolElementStructurePiece() /*override*/ = default; 94 | // NOLINTEND 95 | 96 | public: 97 | // destructor thunk 98 | // NOLINTBEGIN 99 | 100 | // NOLINTEND 101 | 102 | public: 103 | // virtual function thunks 104 | // NOLINTBEGIN 105 | MCAPI bool $postProcess(::BlockSource& region, ::Random& random, ::BoundingBox const& chunkBB); 106 | 107 | MCAPI void $postProcessMobsAt(::BlockSource& region, ::Random& random, ::BoundingBox const& chunkBB); 108 | 109 | MCAPI void $moveBoundingBox(int dx, int dy, int dz); 110 | 111 | MCFOLD bool $_needsPostProcessing(::BlockSource& region); 112 | // NOLINTEND 113 | 114 | public: 115 | // vftables 116 | // NOLINTBEGIN 117 | MCAPI static void** $vftable(); 118 | // NOLINTEND 119 | }; 120 | -------------------------------------------------------------------------------- /src/test/mc/StructurePiece.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/_HeaderOutputPredefine.h" 4 | 5 | // auto generated inclusion list 6 | #include "mc/world/level/levelgen/structure/StructurePieceType.h" 7 | 8 | // auto generated forward declare list 9 | // clang-format off 10 | class Block; 11 | class BlockSelector; 12 | class BlockSource; 13 | class BoundingBox; 14 | class LevelChunk; 15 | class Random; 16 | // clang-format on 17 | 18 | class StructurePiece { 19 | public: 20 | // member variables 21 | // NOLINTBEGIN 22 | ::ll::TypedStorage<4, 24, BoundingBox> mBoundingBox; 23 | ::ll::TypedStorage<4, 4, int> mOrientation; 24 | ::ll::TypedStorage<4, 4, int> mGenDepth; 25 | ::ll::TypedStorage<8, 16, std::shared_ptr> mTerrainAdjustmentToken; 26 | // NOLINTEND 27 | 28 | public: 29 | // prevent constructor by default 30 | 31 | public: 32 | // virtual functions 33 | // NOLINTBEGIN 34 | // vIndex: 0 35 | virtual ~StructurePiece(); 36 | 37 | // vIndex: 1 38 | virtual void moveBoundingBox(int dx, int dy, int dz); 39 | 40 | // vIndex: 2 41 | virtual ::StructurePieceType getType() const; 42 | 43 | // vIndex: 3 44 | virtual void addChildren( 45 | ::StructurePiece& startPiece, 46 | ::std::vector<::std::unique_ptr<::StructurePiece>>& pieces, 47 | ::Random& random 48 | ); 49 | 50 | // vIndex: 4 51 | virtual bool postProcess(::BlockSource&, ::Random&, ::BoundingBox const&) = 0; 52 | 53 | // vIndex: 5 54 | virtual void postProcessMobsAt(::BlockSource& region, ::Random& random, ::BoundingBox const& chunkBB); 55 | 56 | // vIndex: 6 57 | virtual bool isInInvalidLocation(::BlockSource& region, ::BoundingBox const& chunkBB); 58 | 59 | // vIndex: 7 60 | virtual int getWorldX(int x, int z); 61 | 62 | // vIndex: 8 63 | virtual int getWorldZ(int x, int z); 64 | 65 | // vIndex: 9 66 | virtual void 67 | placeBlock(::BlockSource& region, ::Block const& block, int x, int y, int z, ::BoundingBox const& chunkBB); 68 | 69 | // vIndex: 10 70 | virtual bool canBeReplaced(::BlockSource&, int const, int const, int const, ::BoundingBox const&); 71 | 72 | // vIndex: 11 73 | virtual void generateBox( 74 | ::BlockSource& region, 75 | ::BoundingBox const& chunkBB, 76 | int x0, 77 | int y0, 78 | int z0, 79 | int x1, 80 | int y1, 81 | int z1, 82 | ::Block const& edgeBlock, 83 | ::Block const& fillBlock, 84 | bool skipAir 85 | ); 86 | 87 | // vIndex: 12 88 | virtual void addHardcodedSpawnAreas(::LevelChunk& chunk) const; 89 | // NOLINTEND 90 | 91 | public: 92 | // member functions 93 | // NOLINTBEGIN 94 | MCAPI void addTerrainAdjustmentToken(::std::shared_ptr token); 95 | 96 | MCAPI void generateBox( 97 | ::BlockSource& region, 98 | ::BoundingBox const& chunkBB, 99 | int x0, 100 | int y0, 101 | int z0, 102 | int x1, 103 | int y1, 104 | int z1, 105 | bool random, 106 | ::Random& selector, 107 | ::BlockSelector const& skipAir 108 | ); 109 | 110 | MCAPI void generateMaybeBox( 111 | ::BlockSource& region, 112 | ::BoundingBox const& chunkBB, 113 | ::Random& random, 114 | float probability, 115 | int x0, 116 | int y0, 117 | int z0, 118 | int x1, 119 | int y1, 120 | int z1, 121 | ::Block const& edgeBlock, 122 | ::Block const& fillBlock, 123 | bool excludeSky, 124 | bool skipAir 125 | ); 126 | 127 | MCAPI ::Block const& getBlock(::BlockSource& region, int x, int y, int z, ::BoundingBox const& chunkBB); 128 | 129 | MCAPI ushort getOrientationData(::Block const* block, ushort data); 130 | 131 | MCAPI int getWorldY(int y); 132 | 133 | MCAPI bool isAboveGround(int x0, int y1, int z, ::BlockSource& region); 134 | // NOLINTEND 135 | 136 | public: 137 | // destructor thunk 138 | // NOLINTBEGIN 139 | MCFOLD void $dtor(); 140 | // NOLINTEND 141 | 142 | public: 143 | // virtual function thunks 144 | // NOLINTBEGIN 145 | MCAPI void $moveBoundingBox(int dx, int dy, int dz); 146 | 147 | MCFOLD ::StructurePieceType $getType() const; 148 | 149 | MCFOLD void $addChildren( 150 | ::StructurePiece& startPiece, 151 | ::std::vector<::std::unique_ptr<::StructurePiece>>& pieces, 152 | ::Random& random 153 | ); 154 | 155 | MCFOLD void $postProcessMobsAt(::BlockSource& region, ::Random& random, ::BoundingBox const& chunkBB); 156 | 157 | MCAPI bool $isInInvalidLocation(::BlockSource& region, ::BoundingBox const& chunkBB); 158 | 159 | MCAPI int $getWorldX(int x, int z); 160 | 161 | MCAPI int $getWorldZ(int x, int z); 162 | 163 | MCAPI void 164 | $placeBlock(::BlockSource& region, ::Block const& block, int x, int y, int z, ::BoundingBox const& chunkBB); 165 | 166 | MCFOLD bool $canBeReplaced(::BlockSource&, int const, int const, int const, ::BoundingBox const&); 167 | 168 | MCAPI void $generateBox( 169 | ::BlockSource& region, 170 | ::BoundingBox const& chunkBB, 171 | int x0, 172 | int y0, 173 | int z0, 174 | int x1, 175 | int y1, 176 | int z1, 177 | ::Block const& edgeBlock, 178 | ::Block const& fillBlock, 179 | bool skipAir 180 | ); 181 | 182 | MCFOLD void $addHardcodedSpawnAreas(::LevelChunk& chunk) const; 183 | // NOLINTEND 184 | 185 | public: 186 | // vftables 187 | // NOLINTBEGIN 188 | MCAPI static void** $vftable(); 189 | // NOLINTEND 190 | }; 191 | -------------------------------------------------------------------------------- /src/test/mc/StructurePoolBlockPredicateBlockMatchRandom.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/_HeaderOutputPredefine.h" 4 | 5 | // auto generated inclusion list 6 | #include "mc/world/level/levelgen/structure/structurepools/IStructurePoolBlockPredicate.h" 7 | #include "mc/world/level/levelgen/structure/structurepools/StructurePoolBlockPredicateType.h" 8 | 9 | // auto generated forward declare list 10 | // clang-format off 11 | class Block; 12 | class BlockPos; 13 | class Randomize; 14 | namespace Util { class XXHash; } 15 | // clang-format on 16 | 17 | class StructurePoolBlockPredicateBlockMatchRandom : public ::IStructurePoolBlockPredicate { 18 | public: 19 | // member variables 20 | // NOLINTBEGIN 21 | ::ll::TypedStorage<8, 8, Block const*> mBlock; 22 | ::ll::TypedStorage<4, 4, float const> mProbability; 23 | // NOLINTEND 24 | 25 | StructurePoolBlockPredicateBlockMatchRandom(::Block const& block, float probability) 26 | : mBlock(&block), 27 | mProbability(probability){}; 28 | 29 | public: 30 | // prevent constructor by default 31 | 32 | public: 33 | // virtual functions 34 | // NOLINTBEGIN 35 | // vIndex: 2 36 | virtual bool test(::Block const& block, ::Randomize& randomize) const /*override*/; 37 | 38 | // vIndex: 1 39 | virtual bool test(::BlockPos const& worldPos, ::BlockPos const& refPos, ::Randomize& randomize) const /*override*/; 40 | 41 | // vIndex: 5 42 | virtual ::StructurePoolBlockPredicateType getType() const /*override*/; 43 | 44 | // vIndex: 6 45 | virtual void appendMetadataKey(::Util::XXHash& hash) const /*override*/; 46 | 47 | // vIndex: 0 48 | virtual ~StructurePoolBlockPredicateBlockMatchRandom() /*override*/ = default; 49 | // NOLINTEND 50 | 51 | public: 52 | // destructor thunk 53 | // NOLINTBEGIN 54 | 55 | // NOLINTEND 56 | 57 | public: 58 | // virtual function thunks 59 | // NOLINTBEGIN 60 | MCAPI bool $test(::Block const& block, ::Randomize& randomize) const; 61 | 62 | MCFOLD bool $test(::BlockPos const& worldPos, ::BlockPos const& refPos, ::Randomize& randomize) const; 63 | 64 | MCFOLD ::StructurePoolBlockPredicateType $getType() const; 65 | 66 | MCAPI void $appendMetadataKey(::Util::XXHash& hash) const; 67 | // NOLINTEND 68 | 69 | public: 70 | // vftables 71 | // NOLINTBEGIN 72 | MCAPI static void** $vftable(); 73 | // NOLINTEND 74 | }; 75 | -------------------------------------------------------------------------------- /src/test/mc/StructurePoolBlockRule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/_HeaderOutputPredefine.h" 4 | #include "mc/world/level/levelgen/structure/structurepools/IStructurePoolBlockPredicate.h" 5 | 6 | // auto generated forward declare list 7 | // clang-format off 8 | class Block; 9 | class BlockPos; 10 | class Random; 11 | // clang-format on 12 | 13 | class StructurePoolBlockRule { 14 | public: 15 | // member variables 16 | // NOLINTBEGIN 17 | ::ll::TypedStorage<8, 8, std::unique_ptr const> mSourcePredicate; 18 | ::ll::TypedStorage<8, 8, std::unique_ptr const> mTargetPredicate; 19 | ::ll::TypedStorage<8, 8, std::unique_ptr const> mPositionPredicate; 20 | ::ll::TypedStorage<8, 8, Block const*> mResultBlock; 21 | // NOLINTEND 22 | 23 | StructurePoolBlockRule( 24 | ::std::unique_ptr<::IStructurePoolBlockPredicate>&& sourceBlockPredicate, 25 | ::std::unique_ptr<::IStructurePoolBlockPredicate>&& targetBlockPredicate, 26 | ::Block const* resultBlock 27 | ) 28 | : mSourcePredicate(std::move(sourceBlockPredicate)), 29 | mTargetPredicate(std::move(targetBlockPredicate)), 30 | mResultBlock(resultBlock){}; 31 | 32 | public: 33 | // prevent constructor by default 34 | 35 | 36 | public: 37 | // member functions 38 | // NOLINTBEGIN 39 | MCAPI bool processRule( 40 | ::Block const& sourceBlock, 41 | ::Block const& targetBlock, 42 | ::Random& random, 43 | ::Block const*& outputBlock, 44 | ::BlockPos const& worldPos, 45 | ::BlockPos const& refPos 46 | ) const; 47 | // NOLINTEND 48 | }; 49 | -------------------------------------------------------------------------------- /src/test/mc/StructureTemplatePool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/_HeaderOutputPredefine.h" 4 | 5 | // auto generated inclusion list 6 | #include "mc/world/level/levelgen/structure/Projection.h" 7 | 8 | // auto generated forward declare list 9 | // clang-format off 10 | class Random; 11 | class StructurePoolElement; 12 | struct StructureTemplateRegistrationContext; 13 | struct WeightedStructureTemplateRegistration; 14 | // clang-format on 15 | 16 | class StructureTemplatePool { 17 | public: 18 | // member variables 19 | // NOLINTBEGIN 20 | ::ll::TypedStorage<8, 32, std::string> mName; 21 | ::ll::TypedStorage<8, 24, std::vector> mTemplates; 22 | ::ll::TypedStorage<8, 32, std::string> mFallback; 23 | // NOLINTEND 24 | 25 | public: 26 | // prevent constructor by default 27 | 28 | public: 29 | // member functions 30 | // NOLINTBEGIN 31 | MCAPI StructureTemplatePool( 32 | ::std::string name, 33 | ::std::string fallback, 34 | ::std::vector<::std::pair<::StructurePoolElement const*, int>> const& templates 35 | ); 36 | 37 | MCAPI StructureTemplatePool( 38 | ::StructureTemplateRegistrationContext context, 39 | ::std::string_view name, 40 | ::std::string_view fallback, 41 | ::Projection projection, 42 | ::std::initializer_list<::WeightedStructureTemplateRegistration> pieces 43 | ); 44 | 45 | MCAPI ::std::vector getShuffledTemplateIndexes(::Random& random) const; 46 | 47 | MCAPI ~StructureTemplatePool(); 48 | // NOLINTEND 49 | 50 | public: 51 | // static functions 52 | // NOLINTBEGIN 53 | MCAPI static ::std::unique_ptr<::StructureTemplatePool> create( 54 | ::StructureTemplateRegistrationContext context, 55 | ::std::string_view name, 56 | ::std::string_view fallback, 57 | ::std::initializer_list<::WeightedStructureTemplateRegistration> pieces, 58 | ::Projection projection 59 | ); 60 | // NOLINTEND 61 | 62 | public: 63 | // constructor thunks 64 | // NOLINTBEGIN 65 | MCAPI void* $ctor( 66 | ::std::string name, 67 | ::std::string fallback, 68 | ::std::vector<::std::pair<::StructurePoolElement const*, int>> const& templates 69 | ); 70 | 71 | MCAPI void* $ctor( 72 | ::StructureTemplateRegistrationContext context, 73 | ::std::string_view name, 74 | ::std::string_view fallback, 75 | ::Projection projection, 76 | ::std::initializer_list<::WeightedStructureTemplateRegistration> pieces 77 | ); 78 | // NOLINTEND 79 | 80 | public: 81 | // destructor thunk 82 | // NOLINTBEGIN 83 | MCAPI void $dtor(); 84 | // NOLINTEND 85 | }; 86 | -------------------------------------------------------------------------------- /src/test/mc/StructureTemplateRegistrationContext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/_HeaderOutputPredefine.h" 4 | 5 | // auto generated inclusion list 6 | #include "mc/deps/core/utility/NonOwnerPointer.h" 7 | #include "mc/resources/BaseGameVersion.h" 8 | 9 | // auto generated forward declare list 10 | // clang-format off 11 | class Experiments; 12 | class FeatureRegistry; 13 | class JigsawStructureElementRegistry; 14 | class StructureManager; 15 | // clang-format on 16 | 17 | struct StructureTemplateRegistrationContext { 18 | public: 19 | // member variables 20 | // NOLINTBEGIN 21 | ::ll::TypedStorage<8, 24, ::Bedrock::NotNullNonOwnerPtr<::StructureManager>> mManager; 22 | ::ll::TypedStorage<8, 8, ::JigsawStructureElementRegistry&> mStructureRegistry; 23 | ::ll::TypedStorage<8, 8, ::FeatureRegistry&> mFeatureRegistry; 24 | ::ll::TypedStorage<8, 32, ::BaseGameVersion> mBaseGameVersion; 25 | ::ll::TypedStorage<8, 8, ::Experiments const&> mExperiments; 26 | // NOLINTEND 27 | 28 | StructureTemplateRegistrationContext( 29 | Bedrock::NotNullNonOwnerPtr<::StructureManager> manager, 30 | JigsawStructureElementRegistry& structureRegistry, 31 | FeatureRegistry& featureRegistry, 32 | BaseGameVersion baseGameVersion, 33 | Experiments const& experiments 34 | ) 35 | : mManager(manager), 36 | mStructureRegistry(structureRegistry), 37 | mFeatureRegistry(featureRegistry), 38 | mBaseGameVersion(baseGameVersion), 39 | mExperiments(experiments){}; 40 | 41 | public: 42 | // prevent constructor by default 43 | StructureTemplateRegistrationContext& operator=(StructureTemplateRegistrationContext const&); 44 | StructureTemplateRegistrationContext(); 45 | 46 | public: 47 | // member functions 48 | // NOLINTBEGIN 49 | MCNAPI StructureTemplateRegistrationContext(::StructureTemplateRegistrationContext const&); 50 | 51 | MCNAPI StructureTemplateRegistrationContext(::StructureTemplateRegistrationContext&&); 52 | 53 | MCNAPI ~StructureTemplateRegistrationContext(); 54 | // NOLINTEND 55 | 56 | public: 57 | // constructor thunks 58 | // NOLINTBEGIN 59 | MCNAPI void* $ctor(::StructureTemplateRegistrationContext const&); 60 | 61 | MCNAPI void* $ctor(::StructureTemplateRegistrationContext&&); 62 | // NOLINTEND 63 | 64 | public: 65 | // destructor thunk 66 | // NOLINTBEGIN 67 | MCNAPI void $dtor(); 68 | // NOLINTEND 69 | }; 70 | -------------------------------------------------------------------------------- /src/test/mc/WeightedStructureTemplateRegistration.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mc/_HeaderOutputPredefine.h" 4 | 5 | // auto generated inclusion list 6 | #include "mc/world/level/levelgen/structure/Projection.h" 7 | 8 | // auto generated forward declare list 9 | // clang-format off 10 | class StructurePoolElement; 11 | struct StructureTemplateRegistrationContext; 12 | // clang-format on 13 | 14 | struct WeightedStructureTemplateRegistration { 15 | public: 16 | // member variables 17 | // NOLINTBEGIN 18 | std::function<::StructurePoolElement const&(::StructureTemplateRegistrationContext, ::Projection)> mElementFactory; 19 | int mWeight; 20 | // NOLINTEND 21 | }; 22 | -------------------------------------------------------------------------------- /tooth.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": 3, 3 | "format_uuid": "289f771f-2c9a-4d73-9f3f-8492495a924d", 4 | "tooth": "github.com/LiteLDev/MoreDimensions", 5 | "version": "0.7.0", 6 | "info": { 7 | "name": "MoreDimensions", 8 | "description": "More than three dimensions on BDS!", 9 | "tags": [ 10 | "platform:levilamina", 11 | "library", 12 | "type:mod" 13 | ], 14 | "avatar_url": "" 15 | }, 16 | "variants": [ 17 | { 18 | "platform": "win-x64", 19 | "assets": [ 20 | { 21 | "type": "zip", 22 | "urls": [ 23 | "https://{{tooth}}/releases/download/v{{version}}/more-dimensions-windows-x64-v{{version}}.zip" 24 | ], 25 | "dependencies": { 26 | "github.com/LiteLDev/LeviLamina": "1.2.*" 27 | }, 28 | "placements": [ 29 | { 30 | "type": "dir", 31 | "src": "more-dimensions/", 32 | "dest": "plugins/more-dimensions/" 33 | } 34 | ] 35 | } 36 | ] 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /xmake.lua: -------------------------------------------------------------------------------- 1 | add_rules("mode.debug", "mode.release") 2 | 3 | add_repositories("liteldev-repo https://github.com/LiteLDev/xmake-repo.git") 4 | 5 | if is_config("target_type", "server") then 6 | add_requires("levilamina ef5b1d2541205b8eb806729237e0e5f30e0b7c90", {configs = {target_type = "server"}}) 7 | else 8 | add_requires("levilamina 1.2.0", {configs = {target_type = "client"}}) 9 | end 10 | 11 | add_requires("levibuildscript") 12 | add_requires("snappy 1.2.1") 13 | add_requires("preloader 1.15.3") 14 | 15 | if not has_config("vs_runtime") then 16 | set_runtimes("MD") 17 | end 18 | 19 | option("tests") 20 | set_default(false) 21 | set_showmenu(true) 22 | set_description("Enable tests") 23 | 24 | option("target_type") 25 | set_default("server") 26 | set_showmenu(true) 27 | set_values("server", "client") 28 | option_end() 29 | 30 | target("more-dimensions") 31 | add_rules("@levibuildscript/linkrule") 32 | add_rules("@levibuildscript/modpacker") 33 | add_cxflags( "/EHa", "/utf-8", "/W4", "/w44265", "/w44289", "/w44296", "/w45263", "/w44738", "/w45204") 34 | add_defines("NOMINMAX", "UNICODE", "MORE_DIMENSIONS_EXPORTS") 35 | add_packages("levilamina", "snappy", "preloader") 36 | set_exceptions("none") 37 | set_kind("shared") 38 | set_languages("c++20") 39 | set_symbols("debug") 40 | add_files( 41 | "src/more_dimensions/**.cpp" 42 | ) 43 | add_includedirs( 44 | "src" 45 | ) 46 | add_headerfiles( 47 | "src/(more_dimensions/api/**.h)", 48 | "src/(more_dimensions/core/Macros.h)" 49 | ) 50 | if has_config("tests") then 51 | add_files("src/test/TestCustomDimension.cpp", 52 | "src/test/generator/flat-gen-village/**.cpp", 53 | "src/test/generator/generator-terrain/**.cpp", 54 | "src/test/generator/generator-custom-structure/**.cpp" 55 | ) 56 | end --------------------------------------------------------------------------------