├── .github └── workflows │ ├── build.yml │ └── release.yml ├── .gitignore ├── LICENSE ├── README.en.md ├── README.md ├── VERSION.md ├── build.gradle ├── datapack ├── data │ ├── minecraft │ │ ├── loot_tables │ │ │ └── gameplay │ │ │ │ ├── hero_of_the_village │ │ │ │ ├── farmer_gift.json │ │ │ │ ├── leatherworker_gift.json │ │ │ │ └── toolsmith_gift.json │ │ │ │ └── piglin_bartering.json │ │ └── recipes │ │ │ ├── blast_furnace.json │ │ │ └── pointed_dripstone.json │ └── skyland │ │ └── recipes │ │ ├── glow_ink_sac_4_ink_sac.json │ │ └── netherrack_from_blasting.json ├── pack.mcmeta └── pack.png ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src └── main ├── generated └── data │ └── skyland │ └── advancements │ ├── ancient_debris.json │ ├── bedrock_layer.json │ ├── better_wood.json │ ├── blast_furnace.json │ ├── breed_villagers.json │ ├── bulk_lava.json │ ├── composter.json │ ├── coral_fan.json │ ├── elytra.json │ ├── gold_ingot.json │ ├── ice.json │ ├── kill_wrong.json │ ├── kill_zombified_piglin.json │ ├── lava_bucket.json │ ├── netherrack.json │ ├── respawn.json │ ├── root.json │ ├── save_villager.json │ ├── shulker_box.json │ ├── slime.json │ ├── the_end.json │ ├── village_hero.json │ ├── water.json │ ├── weakness.json │ └── wood.json ├── java └── dev │ └── dubhe │ └── skyland │ ├── ComposterCoolDown.java │ ├── SkyLandChunkGenerator.java │ ├── SkyLandGamerules.java │ ├── SkyLandMod.java │ ├── SkyLandStructures.java │ ├── SkyLandTrades.java │ ├── data │ ├── AdvancementProvider.java │ └── SkyLandDataGenerator.java │ ├── mixin │ ├── BoneMealItemMixin.java │ ├── CauldronBlockMixin.java │ ├── ChunkGeneratorsMixin.java │ ├── EnderDragonFightMixin.java │ ├── FallingBlockEntityMixin.java │ ├── FluidBlockMixin.java │ ├── IntegratedServerLoaderMixin.java │ ├── LeveledCauldronBlockMixin.java │ ├── MinecraftServerMixin.java │ ├── PatrolSpawnerMixin.java │ ├── PlayerInventoryMixin.java │ ├── SellItemFactoryAccessor.java │ ├── ServerPlayerEntityMixin.java │ ├── ServerWorldMixin.java │ ├── SlimeEntityMixin.java │ ├── SnowGolemEntityMixin.java │ ├── SpawnHelperMixin.java │ ├── TheEndBiomeCreatorMixin.java │ ├── TheNetherBiomeCreatorMixin.java │ ├── WanderingTraderManagerMixin.java │ ├── WaterCreatureEntityMixin.java │ ├── WorldPresetsRegistrarMixin.java │ └── ZombieEntityMixin.java │ └── plugin │ ├── ComposterCoolDownProvider.java │ └── ComposterPlugin.java └── resources ├── assets └── skyland │ └── lang │ ├── en_us.json │ ├── zh_cn.json │ ├── zh_hk.json │ └── zh_tw.json ├── data ├── minecraft │ ├── loot_tables │ │ └── blocks │ │ │ └── powder_snow.json │ ├── tags │ │ ├── mineable │ │ │ └── shovel.json │ │ └── worldgen │ │ │ └── world_preset │ │ │ └── normal.json │ └── worldgen │ │ └── structure │ │ └── bastion_remnant.json └── skyland │ └── structures │ ├── spawn_platform.nbt │ └── the_end_portal.nbt ├── fabric.mod.json ├── pack.png ├── skyland.accesswidener └── skyland.mixins.json /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: 3 | push: 4 | branches: 5 | - "1.19" 6 | - "1.18.2" 7 | paths: 8 | - "*.gradle" 9 | - "gradle.properties" 10 | - "src/**" 11 | - ".github/**" 12 | - "datapack/**" 13 | pull_request: 14 | 15 | jobs: 16 | build: 17 | strategy: 18 | matrix: 19 | java: [ 17 ] 20 | os: [ ubuntu-latest ] 21 | runs-on: ${{ matrix.os }} 22 | steps: 23 | - uses: actions/checkout@v3 24 | 25 | - name: validate gradle wrapper 26 | uses: gradle/wrapper-validation-action@v1 27 | 28 | - name: setup jdk ${{ matrix.java }} 29 | uses: actions/setup-java@v3 30 | with: 31 | distribution: 'temurin' 32 | java-version: ${{ matrix.java }} 33 | 34 | - name: Cache gradle files 35 | uses: actions/cache@v2 36 | with: 37 | path: | 38 | ~/.gradle/caches 39 | ~/.gradle/wrapper 40 | ./.gradle/loom-cache 41 | key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle', 'gradle.properties', '**/*.accesswidener') }} 42 | restore-keys: | 43 | ${{ runner.os }}-gradle- 44 | 45 | - name: make gradle wrapper executable 46 | if: ${{ runner.os != 'Windows' }} 47 | run: chmod +x ./gradlew 48 | 49 | - name: Build with Gradle 50 | run: ./gradlew build --no-daemon --stacktrace 51 | 52 | - uses: actions/upload-artifact@v3 53 | with: 54 | name: build-artifact 55 | path: build/libs/** 56 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created 2 | # For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle 3 | 4 | name: Publish Release 5 | 6 | on: 7 | release: 8 | types: [published] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: validate gradle wrapper 17 | uses: gradle/wrapper-validation-action@v1 18 | 19 | - name: setup jdk ${{ matrix.java }} 20 | uses: actions/setup-java@v3 21 | with: 22 | distribution: 'temurin' 23 | java-version: ${{ matrix.java }} 24 | 25 | - name: Cache gradle files 26 | uses: actions/cache@v2 27 | with: 28 | path: | 29 | ~/.gradle/caches 30 | ~/.gradle/wrapper 31 | ./.gradle/loom-cache 32 | key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle', 'gradle.properties', '**/*.accesswidener') }} 33 | restore-keys: | 34 | ${{ runner.os }}-gradle- 35 | 36 | - name: make gradle wrapper executable 37 | if: ${{ runner.os != 'Windows' }} 38 | run: chmod +x ./gradlew 39 | 40 | - name: Build with Gradle 41 | run: ./gradlew build --no-daemon --stacktrace 42 | 43 | - name: Get jar 44 | id: getjar 45 | run: | 46 | output="$(find build/libs/ ! -name "*-dev.jar" ! -name "*.zip" ! -name "*-sources.jar" -type f -printf "%f\n")" 47 | echo "::set-output name=jarname::$output" 48 | 49 | - name: Get zip 50 | id: getzip 51 | run: | 52 | output="$(find build/libs/ ! -name "*.jar" -type f -printf "%f\n")" 53 | echo "::set-output name=zipname::$output" 54 | 55 | - uses: actions/upload-artifact@v3 56 | with: 57 | name: build-artifact 58 | path: build/libs/** 59 | 60 | - name: Upload mod to Github 61 | uses: actions/upload-release-asset@v1 62 | env: 63 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} 64 | with: 65 | upload_url: ${{ github.event.release.upload_url }} 66 | asset_path: build/libs/${{ steps.getjar.outputs.jarname }} 67 | asset_name: ${{ steps.getjar.outputs.jarname }} 68 | asset_content_type: application/java-archive 69 | 70 | - name: Upload datapack to Github 71 | uses: actions/upload-release-asset@v1 72 | env: 73 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} 74 | with: 75 | upload_url: ${{ github.event.release.upload_url }} 76 | asset_path: build/libs/${{ steps.getzip.outputs.zipname }} 77 | asset_name: ${{ steps.getzip.outputs.zipname }} 78 | asset_content_type: application/java-archive -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | .gradle/ 4 | build/ 5 | out/ 6 | classes/ 7 | 8 | # eclipse 9 | 10 | *.launch 11 | 12 | # idea 13 | 14 | .idea/ 15 | *.iml 16 | *.ipr 17 | *.iws 18 | 19 | # vscode 20 | 21 | .settings/ 22 | .vscode/ 23 | bin/ 24 | .classpath 25 | .project 26 | 27 | # macos 28 | 29 | *.DS_Store 30 | 31 | # fabric 32 | 33 | run/ 34 | /src/main/generated/.cache/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 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.en.md: -------------------------------------------------------------------------------- 1 | # 下界空岛 | Nether Sky Block 2 | 3 | [![Minecraft](https://img.shields.io/badge/Minecraft-1.19-66ccff)](https://www.minecraft.net/) 4 | [![Fabric](https://img.shields.io/badge/Fabric-0.14.8-fcd217)](https://fabricmc.net/use/installer/) 5 | [![Fabric API](https://img.shields.io/badge/FabricAPI-0.57.0+1.19-b2cf87)](https://modrinth.com/mod/fabric-api) 6 | [![Version](https://img.shields.io/badge/Version-1.1.0-9787c5)](https://github.com/Nether-Power/Nether-Sky-Block/releases/latest) 7 | [![Discord](https://img.shields.io/badge/Discord-nEt5QTRYTN-c6574b)](https://discord.gg/nEt5QTRYTN) 8 | 9 | [![Build Mod](https://github.com/Nether-Power/Nether-Sky-Block/actions/workflows/build.yml/badge.svg)](https://github.com/Nether-Power/Nether-Sky-Block/actions/workflows/build.yml/badge.svg) 10 | [![license](https://img.shields.io/github/license/Nether-Power/Nether-Sky-Block)](https://github.com/Nether-Power/Nether-Sky-Block/blob/main/LICENSE) 11 | [![pull request](https://img.shields.io/github/issues-pr/Nether-Power/Nether-Sky-Block)](https://github.com/Nether-Power/Nether-Sky-Block/pulls) 12 | [![fork](https://img.shields.io/github/forks/Nether-Power/Nether-Sky-Block)](https://github.com/Nether-Power/Nether-Sky-Block/network/members) 13 | [![star](https://img.shields.io/github/stars/Nether-Power/Nether-Sky-Block)](https://github.com/Nether-Power/Nether-Sky-Block/stargazers) 14 | [![issue](https://img.shields.io/github/issues/Nether-Power/Nether-Sky-Block)](https://github.com/Nether-Power/Nether-Sky-Block/issues) 15 | [![Java](https://img.shields.io/badge/Java-17-yellow)](https://docs.microsoft.com/java/openjdk/download) 16 | 17 | ## [中文](README.md) | English 18 | 19 | ## Install 20 | 21 | ### Client 22 | 23 | * Download and install `Minecraft 1.19` , install `Fabric 0.14.8` . 24 | * From [Release](https://github.com/Nether-Power/Nether-Sky-Block/releases/latest) download the last release `mod` 25 | and `datapack` , then put the `mod` to `mods` directory. 26 | * Download `Fabric API 0.57.0+1.19`, then put it to `mods` directory. 27 | * When you create new world, Set `World Type` to `SkyLand` in `More World Options` , and add the DataPack. 28 | * After entering the world, type `/skyland gamerule true` command to enable Nether-Sky-Block settings. 29 | 30 | ### Server 31 | 32 | * Download and install `Minecraft Server 1.19` , install `Fabric 0.14.8` . 33 | * From [Release](https://github.com/Nether-Power/Nether-Sky-Block/releases/latest) download the last release `mod` 34 | and `datapack` , then put the `mod` to `mods` directory and put the `datapack` to `world/datapacks` directory. 35 | * Download `Fabric API 0.57.0+1.19`, then put it to `mods` directory. 36 | * Set `level-type` to `skyland:skyland` in `server.properties` . 37 | * After starting the server, type `/skyland gamerule true` command in console to enable Nether-Sky-Block settings. 38 | 39 | ## Features 40 | 41 | ### MOD 42 | 43 | - Set three dimensions to void 44 | - Replace overworld with nether 45 | - Removed the experimental world warning 46 | - All features of one key switch 47 | - `/skyland gamerule ` 48 | - Ignore the influence of LC value on monster spawn efficiency 49 | - `/gamerule qnmdLC true` 50 | - Increase the spawning probability of Wandering Trader merchants by 10 times 51 | - `/gamerule chieftainMode true` 52 | - When creating a map, an initial platform will be created on the y-axis 64(A crimson nylium, a warped nylium, crimson 53 | fungus is planted above the crimson nylium, and an apple in item frame is hung above the warped nylium) 54 | - When the first player first entered the world, he was given 32 bone meal 55 | - Zombie villager is generated when zombified piglin and zombie trigger zombie reinforcements 56 | - `/gamerule villagerReinforcements true` 57 | - The nether will generate patrol 58 | - `/gamerule netherPatrol true` 59 | - Soul Sand Valley spawn Witch (extremely low probability) 60 | - Bastion Remnant spawn Pillager 61 | - Basalt Deltas spawn Slime 62 | - The lava beside the Water Cauldron (full of water) is converted into obsidian and consumes all the water in the Water 63 | Cauldron 64 | - `/gamerule waterCauldron true` 65 | - Enable the nether biome to spawn Wandering Trader riding Strider(When the highest point of a player's 40 blocks radius 66 | is lava, there is a 10% probability of spawn every 20min. When the first spawn fails, the probability of subsequent 67 | spawn increases to 30%) 68 | - `/gamerule netherTrader true` 69 | - Delete the Emerald for Pumpkin Pie transaction when the Farmer Villager apprentice level is removed 70 | - The water above the coral blocks will spawn squid 71 | - When you kill the resurrected Ender Dragon, you will refresh the Shulker above the Exit portal 72 | - `/gamerule killDragonSpawnShulker true` 73 | - When you kill the Ender Dragon, you will drop an Elytra with the remaining 1% durability 74 | - `/gamerule killDragonDropElytra true` 75 | - Generate the End Portal in the nether 76 | - The world will generate `8` End Portal frames with a radius of `1024` centered on `spawnpoint` 77 | - Anvil Handle 78 | - `/gamerule anvilHandle true` 79 | - Press a Moss Block and a Dirt into a Grass Block 80 | - The Raid can be triggered in the nether 81 | - Items no longer scatter when you death 82 | - Use bone meal on the side of the coral block to make it grow a coral fan, and use bone meal on the top to grow coral 83 | - Dig powder snow to get snowballs 84 | - The Snow Golem standing on the water will turn the water into ice 85 | - `/gamerule iceGolem true` 86 | - Sneak in composer can produce bone meal 87 | - `/gamerule ComposterBoneMeal true` 88 | - The following animals will be spawn on the Grass Block of the Nether Waste 89 | - Cow 90 | - Sheep 91 | - Llama 92 | - Wolf 93 | - Horse 94 | - Donkey 95 | - The FoodLevel before death will be remembered after death 96 | - `/gamerule memoryFoodLevel true` 97 | - Minimum FoodLevel after death and resurrection (effective after the rule `memoryFoodLevel` is turned on, the default is `4`) 98 | - `/gamerule respawnMinFoodLevel 4` 99 | - The Wandering Trader deals in additional items 100 | - You can containing powder snow in Basalt Deltas 101 | 102 | | **Item** | **Count** | **Price** | **Transactions Count** | 103 | |-------------|-----------|-----------|------------------------| 104 | | Turtle Egg | 1 | 16 | 4 | 105 | | Tall Flower | 1 | 8 | 8 | 106 | | Cocoa Bean | 1 | 16 | 8 | 107 | | Bamboo | 1 | 16 | 8 | 108 | | Nether Wart | 1 | 32 | 4 | 109 | 110 | ### DATAPACK 111 | 112 | - recipes 113 | - Blast furnace recipe of replacing Smooth Stone with Obsidian 114 | - Burn the Nether Wart Block in the blast furnace to obtain the Nether Wart Block 115 | - Use the stone cutter to cut the dripstone block to obtain dripstone 116 | - Glow ink sac synthesized by glowstone powder and ink sac 117 | - Modify piglin transaction 118 | - Delete Fire Resistance Potion trading 119 | - Increase Blackstone trading probability 120 | - Reduce Water Bottle trading probability 121 | - Added Glowstone Dust trading 122 | - Delete Ender Pearl trading 123 | - When owning a Hero of the Village Status Effect 124 | - the Mason Villager has a probability to throw Lava Bucket (weight 3) 125 | - the Toolsmith Villager has a probability to throw Netherite Scrap (weight 3) 126 | - Farmers have a chance to throw pumpkins (weight 3) 127 | 128 | ## Contributor 129 | 130 | * Planner 131 | * [朽白](https://space.bilibili.com/178682437) 132 | * Programmer 133 | * [古镇天Gugle](https://space.bilibili.com/19822751) 134 | * [Cjsah](https://space.bilibili.com/19170004) 135 | * [DancingSnow](https://space.bilibili.com/302121711) 136 | * [Huaji_MUR233](https://space.bilibili.com/434118309) 137 | 138 | ## Powered by 139 | 140 | * [AnvilCraft-SkyLandMod](https://github.com/Dubhe-Studio/AnvilCraft-SkyLandMod) 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 下界空岛 | Nether Sky Block 2 | 3 | [![Minecraft](https://img.shields.io/badge/Minecraft-1.19-66ccff)](https://www.minecraft.net/) 4 | [![Fabric](https://img.shields.io/badge/Fabric-0.14.8-fcd217)](https://fabricmc.net/use/installer/) 5 | [![Fabric API](https://img.shields.io/badge/FabricAPI-0.57.0+1.19-b2cf87)](https://modrinth.com/mod/fabric-api) 6 | [![Version](https://img.shields.io/badge/Version-1.1.0-9787c5)](https://github.com/Nether-Power/Nether-Sky-Block/releases/latest) 7 | [![KOOK](https://img.shields.io/badge/KOOK-eZ59fk-c6574b)](https://kook.top/eZ59fk) 8 | 9 | 10 | [![Build Mod](https://github.com/Nether-Power/Nether-Sky-Block/actions/workflows/build.yml/badge.svg)](https://github.com/Nether-Power/Nether-Sky-Block/actions/workflows/build.yml/badge.svg) 11 | [![license](https://img.shields.io/github/license/Nether-Power/Nether-Sky-Block)](https://github.com/Nether-Power/Nether-Sky-Block/blob/main/LICENSE) 12 | [![pull request](https://img.shields.io/github/issues-pr/Nether-Power/Nether-Sky-Block)](https://github.com/Nether-Power/Nether-Sky-Block/pulls) 13 | [![fork](https://img.shields.io/github/forks/Nether-Power/Nether-Sky-Block)](https://github.com/Nether-Power/Nether-Sky-Block/network/members) 14 | [![star](https://img.shields.io/github/stars/Nether-Power/Nether-Sky-Block)](https://github.com/Nether-Power/Nether-Sky-Block/stargazers) 15 | [![issue](https://img.shields.io/github/issues/Nether-Power/Nether-Sky-Block)](https://github.com/Nether-Power/Nether-Sky-Block/issues) 16 | [![Java](https://img.shields.io/badge/Java-17-yellow)](https://docs.microsoft.com/java/openjdk/download) 17 | 18 | ## 中文 | [English](README.en.md) 19 | 20 | ## Install 21 | 22 | ### Client 23 | 24 | * 下载安装 `Minecraft 1.19`, 安装 `Fabric 0.14.8` 25 | * 从 [Release](https://github.com/Nether-Power/Nether-Sky-Block/releases/latest) 下载最新发行版 `mod` 和 `datapack`, 并将 `mod` 放入 `mods` 文件夹 26 | * 下载 `Fabric API 0.57.0+1.19`, 并放入 `mods` 文件夹 27 | * 创建世界时, 在 `更多选项` 中将 `世界类型` 调为 `空岛` 并添加数据包 28 | * 进入进入世界后,输入 `/skyland gamerule true` 命令打开地狱空岛的所需规则 29 | 30 | ### Server 31 | 32 | * 下载安装 `Minecraft Server 1.19`, 安装 `Fabric 0.14.8` 33 | * 从 [Release](https://github.com/Nether-Power/Nether-Sky-Block/releases/latest) 下载最新发行版 `mod` 和 `datapack`, 并分别放入 `mods` 与 `world/datapacks` 文件夹 34 | * 下载 `Fabric API 0.57.0+1.19`, 并放入 `mods` 文件夹 35 | * 创建世界时, 在 `server.properties` 中将 `level-type` 调为 `skyland:skyland` 36 | * 开启服务器后,在控制台输入 `/skyland gamerule true` 命令打开地狱空岛的所需规则 37 | 38 | ## Features 39 | 40 | ### 模组 41 | 42 | - 将三个维度设置为虚空 43 | - 将主世界生成替换为下界 44 | - 去除了实验性世界警告 45 | - 一键开关所有特性 46 | - `/skyland gamerule ` 47 | - 忽略LC值对刷怪效率的影响 48 | - `/gamerule qnmdLC true` 49 | - 使流浪商人的刷新概率提升10倍 50 | - `/gamerule chieftainMode true` 51 | - 创建地图时会在Y轴64创建一个初始平台(一个绯红菌岩、一个诡异菌岩、绯红菌岩上方种植绯红菌、诡异菌岩上方挂着放着苹果的展示框) 52 | - 第一个玩家第一次进入世界时给予32个骨粉 53 | - 僵尸猪灵和僵尸触发僵尸增援时生成僵尸村民 54 | - `/gamerule villagerReinforcements true` 55 | - 下界会生成灾厄巡逻队 56 | - `/gamerule netherPatrol true` 57 | - 灵魂沙峡谷刷新女巫(概率极低) 58 | - 堡垒遗迹刷新劫掠者 59 | - 玄武岩三角洲刷新史莱姆 60 | - 储水炼药锅(满水)旁的熔岩转化为黑曜石并消耗储水炼药锅内的全部水 61 | - `/gamerule waterCauldron true` 62 | - 使下界群系可以生成骑着赤足兽的游商(玩家40格半径最高点为熔岩时,每20min有10%概率生成,当第一次生成失败时后续生成概率提高至30%) 63 | - `/gamerule netherTrader true` 64 | - 删除农民学徒等级时的绿宝石换南瓜派交易 65 | - 珊瑚块上方的水会生成鱿鱼 66 | - 击杀复活的末影龙时会在祭坛上方刷新潜影贝 67 | - `/gamerule killDragonSpawnShulker true` 68 | - 击杀末影龙时会掉落一个剩余1%耐久的鞘翅 69 | - `/gamerule killDragonDropElytra true` 70 | - 下界内生成末地传送门 71 | - 世界内会以 `出生点` 为中心, 半径 `1024` 生成 `8` 个末地门框架 72 | - 铁砧处理 73 | - `/gamerule anvilHandle true` 74 | - 将一个苔藓块与一个泥土压合成草方块 75 | - 在下界里可以触发袭击 76 | - 死亡时物品不再散开 77 | - 对着珊瑚块侧面使用骨粉使之生长出珊瑚扇,对其顶面使用骨粉生长出珊瑚 78 | - 挖掘细雪获取雪球 79 | - 雪傀儡站在水上面会将水变为冰 80 | - `/gamerule iceGolem true` 81 | - 站在堆肥桶中下蹲,可以产生骨粉 82 | - `/gamerule composterBoneMeal true` 83 | - 下界荒地的草方块上会生成以下动物 84 | - 牛 85 | - 马 86 | - 羊 87 | - 驴 88 | - 羊驼 89 | - 狼 90 | - 死亡后会记忆死亡前的饱食度 91 | - `/gamerule memoryFoodLevel true` 92 | - 死亡复活后最低饱食度(在规则 `memoryFoodLevel` 开启后有效, 默认为 `4`) 93 | - `/gamerule respawnMinFoodLevel 4` 94 | - 玄武岩三角洲接细雪 95 | - 游商会交易除基础物品外的额外物品 96 | 97 | | **物品** | **数量** | **价格** | **交易次数** | 98 | |--------|--------|--------|----------| 99 | | 海龟蛋 | 1 | 16 | 4 | 100 | | 高花 | 1 | 8 | 8 | 101 | | 可可豆 | 1 | 16 | 8 | 102 | | 竹子 | 1 | 16 | 8 | 103 | | 地狱疣 | 1 | 32 | 4 | 104 | 105 | ### 数据包 106 | 107 | - 配方 108 | - 用黑曜石替换平滑石的高炉合成 109 | - 高炉里烧下界疣块以获取下界岩 110 | - 使用切石机切割滴水石块获取滴水石锥 111 | - 萤石粉和墨囊合成荧光墨囊 112 | - 修改猪灵交易 113 | - 删除抗火药水 114 | - 增加黑石交易概率 115 | - 降低水瓶交易概率 116 | - 增加萤石粉交易 117 | - 删除末影珍珠交易 118 | - 拥有村庄英雄时 119 | - 皮匠会有概率丢岩浆桶(权重3) 120 | - 工具匠会有概率丢下界合金碎片(权重3) 121 | - 农民有概率丢南瓜(权重3) 122 | 123 | ## Contributor 124 | 125 | * 策划 126 | * [朽白](https://space.bilibili.com/178682437) 127 | * 代码 128 | * [古镇天Gugle](https://space.bilibili.com/19822751) 129 | * [Cjsah](https://space.bilibili.com/19170004) 130 | * [DancingSnow](https://space.bilibili.com/302121711) 131 | * [Huaji_MUR233](https://space.bilibili.com/434118309) 132 | 133 | ## Powered by 134 | 135 | * [AnvilCraft-SkyLandMod](https://github.com/Dubhe-Studio/AnvilCraft-SkyLandMod) 136 | -------------------------------------------------------------------------------- /VERSION.md: -------------------------------------------------------------------------------- 1 | ## 2022/07/23 1.1.0 2 | * Added 3 | * 在满水的储水炼药锅内消耗全部水将玄武岩洗涤为滴水石块 4 | * 使用切石机切割滴水石块获取滴水石锥 5 | * 玄武岩三角洲接细雪 6 | * 细雪挖掘可以获得雪球 7 | * 对着珊瑚块侧面使用骨粉使之生长出珊瑚扇,对其顶面右键生长出珊瑚 8 | * 死亡时物品不再散开 9 | * 下界荒地的草方块上会生成以下动物 10 | * 牛 11 | * 马 12 | * 羊 13 | * 驴 14 | * 羊驼 15 | * 狼 16 | * Remove 17 | * 删除灵魂土配方 18 | * 农民不再有概率丢小麦种子 19 | * 游商会出售雪球、珊瑚扇 20 | * 用铁砧砸一下滴水石块将其变为滴水石锥 21 | * 珊瑚扇在有水炼药锅里用铁砧砸一下会消耗一层水并增加多一个珊瑚扇 22 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'fabric-loom' version '0.12-SNAPSHOT' 3 | id 'io.github.juuxel.loom-quiltflower' version '1.7.3' 4 | id 'maven-publish' 5 | } 6 | 7 | version = project.mod_version 8 | group = project.maven_group 9 | 10 | sourceCompatibility = JavaVersion.VERSION_17 11 | targetCompatibility = JavaVersion.VERSION_17 12 | 13 | println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) 14 | 15 | sourceSets { 16 | main { 17 | resources { 18 | srcDirs += [ 19 | "src/main/generated" 20 | ] 21 | } 22 | } 23 | } 24 | 25 | loom { 26 | accessWidenerPath = file("src/main/resources/skyland.accesswidener") 27 | 28 | runs { 29 | datagen { 30 | server() 31 | 32 | name "Minecraft Data" 33 | 34 | vmArg "-Dfabric-api.datagen" 35 | vmArg "-Dfabric-api.datagen.output-dir=${file("src/main/generated")}" 36 | 37 | runDir "build/datagen" 38 | } 39 | } 40 | } 41 | assemble.dependsOn runDatagen 42 | 43 | repositories { 44 | maven { 45 | url "https://cursemaven.com" 46 | content { 47 | includeGroup "curse.maven" 48 | } 49 | } 50 | } 51 | dependencies { 52 | minecraft "com.mojang:minecraft:${project.mc_version}" 53 | mappings "net.fabricmc:yarn:${project.yarn_version}:v2" 54 | modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" 55 | 56 | // Fabric API. This is technically optional, but you probably want it anyway. 57 | modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" 58 | 59 | // Nullable 60 | compileOnly "com.google.code.findbugs:jsr305:3.0.2" 61 | 62 | // Add other mod. 63 | modImplementation "curse.maven:jade-324717:${jade_file}" 64 | 65 | } 66 | 67 | processResources { 68 | inputs.property "version", project.version 69 | 70 | filesMatching("fabric.mod.json") { 71 | expand "version": project.version 72 | } 73 | } 74 | 75 | tasks.withType(JavaCompile).configureEach { 76 | it.options.release = 17 77 | } 78 | 79 | java { 80 | // withSourcesJar() 81 | } 82 | 83 | jar { 84 | from("LICENSE") { 85 | rename { "${it}_${project.name}" } 86 | } 87 | } 88 | 89 | publishing { 90 | publications { 91 | mavenJava(MavenPublication) { 92 | artifact(remapJar) { 93 | builtBy remapJar 94 | } 95 | // artifact(sourcesJar) { 96 | // builtBy remapSourcesJar 97 | // } 98 | } 99 | } 100 | 101 | def ENV = System.getenv() 102 | if (ENV.MAVEN_URL) { 103 | repositories.maven { 104 | url ENV.MAVEN_URL 105 | credentials { 106 | username ENV.MAVEN_USERNAME 107 | password ENV.MAVEN_PASSWORD 108 | } 109 | } 110 | } 111 | } 112 | 113 | task build_datapack(type: Zip) { 114 | archiveName "${project.name}-datapack-${project.version}.zip" 115 | 116 | destinationDir file('build/libs') 117 | 118 | from 'datapack' 119 | from("LICENSE") { 120 | rename { "${it}_${project.name}" } 121 | } 122 | } 123 | 124 | build.dependsOn build_datapack 125 | -------------------------------------------------------------------------------- /datapack/data/minecraft/loot_tables/gameplay/hero_of_the_village/farmer_gift.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:gift", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "name": "minecraft:bread", 10 | "weight": 30 11 | }, 12 | { 13 | "type": "minecraft:item", 14 | "name": "minecraft:pumpkin_pie", 15 | "weight": 30 16 | }, 17 | { 18 | "type": "minecraft:item", 19 | "name": "minecraft:cookie", 20 | "weight": 30 21 | }, 22 | { 23 | "type": "minecraft:item", 24 | "name": "minecraft:pumpkin", 25 | "weight": 1 26 | } 27 | ], 28 | "rolls": 1.0 29 | } 30 | ] 31 | } -------------------------------------------------------------------------------- /datapack/data/minecraft/loot_tables/gameplay/hero_of_the_village/leatherworker_gift.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:gift", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "name": "minecraft:leather", 10 | "weight": 40 11 | }, 12 | { 13 | "type": "minecraft:item", 14 | "name": "minecraft:lava_bucket", 15 | "weight": 3 16 | } 17 | ], 18 | "rolls": 1.0 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /datapack/data/minecraft/loot_tables/gameplay/hero_of_the_village/toolsmith_gift.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:gift", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "name": "minecraft:stone_pickaxe", 10 | "weight": 40 11 | }, 12 | { 13 | "type": "minecraft:item", 14 | "name": "minecraft:stone_axe", 15 | "weight": 40 16 | }, 17 | { 18 | "type": "minecraft:item", 19 | "name": "minecraft:stone_hoe", 20 | "weight": 40 21 | }, 22 | { 23 | "type": "minecraft:item", 24 | "name": "minecraft:stone_shovel", 25 | "weight": 40 26 | }, 27 | { 28 | "type": "minecraft:item", 29 | "name": "minecraft:ancient_debris", 30 | "weight": 3 31 | } 32 | ], 33 | "rolls": 1.0 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /datapack/data/minecraft/loot_tables/gameplay/piglin_bartering.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:barter", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "enchantments": [ 12 | "minecraft:soul_speed" 13 | ], 14 | "function": "minecraft:enchant_randomly" 15 | } 16 | ], 17 | "name": "minecraft:book", 18 | "weight": 5 19 | }, 20 | { 21 | "type": "minecraft:item", 22 | "functions": [ 23 | { 24 | "function": "minecraft:set_potion", 25 | "id": "minecraft:water" 26 | } 27 | ], 28 | "name": "minecraft:potion", 29 | "weight": 10 30 | }, 31 | { 32 | "type": "minecraft:item", 33 | "functions": [ 34 | { 35 | "add": false, 36 | "count": { 37 | "type": "minecraft:uniform", 38 | "max": 46.0, 39 | "min": 20.0 40 | }, 41 | "function": "minecraft:set_count" 42 | } 43 | ], 44 | "name": "minecraft:iron_nugget", 45 | "weight": 15 46 | }, 47 | { 48 | "type": "minecraft:item", 49 | "functions": [ 50 | { 51 | "add": false, 52 | "count": { 53 | "type": "minecraft:uniform", 54 | "max": 9.0, 55 | "min": 3.0 56 | }, 57 | "function": "minecraft:set_count" 58 | } 59 | ], 60 | "name": "minecraft:string", 61 | "weight": 20 62 | }, 63 | { 64 | "type": "minecraft:item", 65 | "functions": [ 66 | { 67 | "add": false, 68 | "count": { 69 | "type": "minecraft:uniform", 70 | "max": 12.0, 71 | "min": 5.0 72 | }, 73 | "function": "minecraft:set_count" 74 | } 75 | ], 76 | "name": "minecraft:quartz", 77 | "weight": 20 78 | }, 79 | { 80 | "type": "minecraft:item", 81 | "name": "minecraft:obsidian", 82 | "weight": 40 83 | }, 84 | { 85 | "type": "minecraft:item", 86 | "functions": [ 87 | { 88 | "add": false, 89 | "count": { 90 | "type": "minecraft:uniform", 91 | "max": 3.0, 92 | "min": 1.0 93 | }, 94 | "function": "minecraft:set_count" 95 | } 96 | ], 97 | "name": "minecraft:crying_obsidian", 98 | "weight": 40 99 | }, 100 | { 101 | "type": "minecraft:item", 102 | "name": "minecraft:fire_charge", 103 | "weight": 40 104 | }, 105 | { 106 | "type": "minecraft:item", 107 | "functions": [ 108 | { 109 | "add": false, 110 | "count": { 111 | "type": "minecraft:uniform", 112 | "max": 4.0, 113 | "min": 2.0 114 | }, 115 | "function": "minecraft:set_count" 116 | } 117 | ], 118 | "name": "minecraft:leather", 119 | "weight": 40 120 | }, 121 | { 122 | "type": "minecraft:item", 123 | "functions": [ 124 | { 125 | "add": false, 126 | "count": { 127 | "type": "minecraft:uniform", 128 | "max": 8.0, 129 | "min": 2.0 130 | }, 131 | "function": "minecraft:set_count" 132 | } 133 | ], 134 | "name": "minecraft:soul_sand", 135 | "weight": 40 136 | }, 137 | { 138 | "type": "minecraft:item", 139 | "functions": [ 140 | { 141 | "add": false, 142 | "count": { 143 | "type": "minecraft:uniform", 144 | "max": 8.0, 145 | "min": 2.0 146 | }, 147 | "function": "minecraft:set_count" 148 | } 149 | ], 150 | "name": "minecraft:nether_brick", 151 | "weight": 40 152 | }, 153 | { 154 | "type": "minecraft:item", 155 | "functions": [ 156 | { 157 | "add": false, 158 | "count": { 159 | "type": "minecraft:uniform", 160 | "max": 12.0, 161 | "min": 6.0 162 | }, 163 | "function": "minecraft:set_count" 164 | } 165 | ], 166 | "name": "minecraft:spectral_arrow", 167 | "weight": 40 168 | }, 169 | { 170 | "type": "minecraft:item", 171 | "functions": [ 172 | { 173 | "add": false, 174 | "count": { 175 | "type": "minecraft:uniform", 176 | "max": 16.0, 177 | "min": 8.0 178 | }, 179 | "function": "minecraft:set_count" 180 | } 181 | ], 182 | "name": "minecraft:gravel", 183 | "weight": 30 184 | }, 185 | { 186 | "type": "minecraft:item", 187 | "functions": [ 188 | { 189 | "add": false, 190 | "count": { 191 | "type": "minecraft:uniform", 192 | "max": 24.0, 193 | "min": 16.0 194 | }, 195 | "function": "minecraft:set_count" 196 | } 197 | ], 198 | "name": "minecraft:blackstone", 199 | "weight": 60 200 | }, 201 | { 202 | "type": "minecraft:item", 203 | "name": "minecraft:glowstone_dust", 204 | "weight": 40 205 | } 206 | ], 207 | "rolls": 1.0 208 | } 209 | ] 210 | } -------------------------------------------------------------------------------- /datapack/data/minecraft/recipes/blast_furnace.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "key": { 4 | "#": { 5 | "item": "minecraft:obsidian" 6 | }, 7 | "I": { 8 | "item": "minecraft:iron_ingot" 9 | }, 10 | "X": { 11 | "item": "minecraft:furnace" 12 | } 13 | }, 14 | "pattern": [ 15 | "III", 16 | "IXI", 17 | "###" 18 | ], 19 | "result": { 20 | "item": "minecraft:blast_furnace" 21 | } 22 | } -------------------------------------------------------------------------------- /datapack/data/minecraft/recipes/pointed_dripstone.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:stonecutting", 3 | "ingredient": { 4 | "item": "minecraft:dripstone_block" 5 | }, 6 | "result": "minecraft:pointed_dripstone", 7 | "count": 1 8 | } -------------------------------------------------------------------------------- /datapack/data/skyland/recipes/glow_ink_sac_4_ink_sac.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shapeless", 3 | "ingredients": [ 4 | { 5 | "item": "minecraft:ink_sac" 6 | }, 7 | { 8 | "item": "minecraft:glowstone_dust" 9 | } 10 | ], 11 | "result": { 12 | "item": "minecraft:glow_ink_sac" 13 | } 14 | } -------------------------------------------------------------------------------- /datapack/data/skyland/recipes/netherrack_from_blasting.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:blasting", 3 | "ingredient": { 4 | "item": "minecraft:nether_wart_block" 5 | }, 6 | "result": "minecraft:netherrack", 7 | "experience": 0.1, 8 | "cookingtime": 100 9 | } 10 | -------------------------------------------------------------------------------- /datapack/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "Nether_Sky_Block datapack", 4 | "pack_format": 10 5 | } 6 | } -------------------------------------------------------------------------------- /datapack/pack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nether-Power/Nether-Sky-Block/d155f0f4b3898cd11a1a218cf6d359662c9c8c92/datapack/pack.png -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1G 2 | 3 | mc_version=1.19.2 4 | yarn_version=1.19.2+build.4 5 | loader_version=0.14.9 6 | 7 | mod_version=1.1.0 8 | maven_group=dev.dubhe 9 | 10 | fabric_version=0.60.0+1.19.2 11 | 12 | jade_file=3836188 13 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nether-Power/Nether-Sky-Block/d155f0f4b3898cd11a1a218cf6d359662c9c8c92/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/ancient_debris.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:village_hero", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:ancient_debris" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.ancient_debris.desc" 22 | }, 23 | "frame": "challenge", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:ancient_debris" 27 | }, 28 | "show_toast": true, 29 | "title": { 30 | "translate": "advancement.skyland.ancient_debris.title" 31 | } 32 | }, 33 | "requirements": [ 34 | [ 35 | "0" 36 | ] 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/bedrock_layer.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:root", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "player": [ 7 | { 8 | "condition": "minecraft:entity_properties", 9 | "entity": "this", 10 | "predicate": { 11 | "location": { 12 | "position": { 13 | "y": { 14 | "max": 1.0 15 | } 16 | } 17 | } 18 | } 19 | } 20 | ] 21 | }, 22 | "trigger": "minecraft:location" 23 | } 24 | }, 25 | "display": { 26 | "announce_to_chat": true, 27 | "background": "minecraft:textures/block/crimson_planks.png", 28 | "description": { 29 | "translate": "advancement.skyland.bedrock_layer.desc" 30 | }, 31 | "frame": "goal", 32 | "hidden": false, 33 | "icon": { 34 | "item": "minecraft:bedrock" 35 | }, 36 | "show_toast": true, 37 | "title": { 38 | "translate": "advancement.skyland.bedrock_layer.title" 39 | } 40 | }, 41 | "requirements": [ 42 | [ 43 | "0" 44 | ] 45 | ] 46 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/better_wood.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:lava_bucket", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:spruce_sapling" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | }, 16 | "1": { 17 | "conditions": { 18 | "items": [ 19 | { 20 | "items": [ 21 | "minecraft:acacia_sapling" 22 | ] 23 | } 24 | ] 25 | }, 26 | "trigger": "minecraft:inventory_changed" 27 | }, 28 | "2": { 29 | "conditions": { 30 | "items": [ 31 | { 32 | "items": [ 33 | "minecraft:birch_sapling" 34 | ] 35 | } 36 | ] 37 | }, 38 | "trigger": "minecraft:inventory_changed" 39 | }, 40 | "3": { 41 | "conditions": { 42 | "items": [ 43 | { 44 | "items": [ 45 | "minecraft:dark_oak_sapling" 46 | ] 47 | } 48 | ] 49 | }, 50 | "trigger": "minecraft:inventory_changed" 51 | }, 52 | "4": { 53 | "conditions": { 54 | "items": [ 55 | { 56 | "items": [ 57 | "minecraft:jungle_sapling" 58 | ] 59 | } 60 | ] 61 | }, 62 | "trigger": "minecraft:inventory_changed" 63 | }, 64 | "5": { 65 | "conditions": { 66 | "items": [ 67 | { 68 | "items": [ 69 | "minecraft:oak_sapling" 70 | ] 71 | } 72 | ] 73 | }, 74 | "trigger": "minecraft:inventory_changed" 75 | }, 76 | "6": { 77 | "conditions": { 78 | "items": [ 79 | { 80 | "items": [ 81 | "minecraft:mangrove_propagule" 82 | ] 83 | } 84 | ] 85 | }, 86 | "trigger": "minecraft:inventory_changed" 87 | } 88 | }, 89 | "display": { 90 | "announce_to_chat": true, 91 | "background": "minecraft:textures/block/crimson_planks.png", 92 | "description": { 93 | "translate": "advancement.skyland.better_wood.desc" 94 | }, 95 | "frame": "task", 96 | "hidden": false, 97 | "icon": { 98 | "item": "minecraft:oak_wood" 99 | }, 100 | "show_toast": true, 101 | "title": { 102 | "translate": "advancement.skyland.better_wood.title" 103 | } 104 | }, 105 | "requirements": [ 106 | [ 107 | "0", 108 | "1", 109 | "2", 110 | "3", 111 | "4", 112 | "5", 113 | "6" 114 | ] 115 | ] 116 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/blast_furnace.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:gold_ingot", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:blast_furnace" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.blast_furnace.desc" 22 | }, 23 | "frame": "task", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:blast_furnace" 27 | }, 28 | "show_toast": true, 29 | "title": { 30 | "translate": "advancement.skyland.blast_furnace.title" 31 | } 32 | }, 33 | "requirements": [ 34 | [ 35 | "0" 36 | ] 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/breed_villagers.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:village_hero", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:bread" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.breed_villagers.desc" 22 | }, 23 | "frame": "task", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:bread" 27 | }, 28 | "show_toast": true, 29 | "title": { 30 | "translate": "advancement.skyland.breed_villagers.title" 31 | } 32 | }, 33 | "requirements": [ 34 | [ 35 | "0" 36 | ] 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/bulk_lava.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:ice", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:pointed_dripstone" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.bulk_lava.desc" 22 | }, 23 | "frame": "goal", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:pointed_dripstone" 27 | }, 28 | "show_toast": true, 29 | "title": { 30 | "translate": "advancement.skyland.bulk_lava.title" 31 | } 32 | }, 33 | "requirements": [ 34 | [ 35 | "0" 36 | ] 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/composter.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:wood", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:composter" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.composter.desc" 22 | }, 23 | "frame": "task", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:composter" 27 | }, 28 | "show_toast": true, 29 | "title": { 30 | "translate": "advancement.skyland.composter.title" 31 | } 32 | }, 33 | "requirements": [ 34 | [ 35 | "0" 36 | ] 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/coral_fan.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:lava_bucket", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:brain_coral_fan" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | }, 16 | "1": { 17 | "conditions": { 18 | "items": [ 19 | { 20 | "items": [ 21 | "minecraft:tube_coral_fan" 22 | ] 23 | } 24 | ] 25 | }, 26 | "trigger": "minecraft:inventory_changed" 27 | }, 28 | "2": { 29 | "conditions": { 30 | "items": [ 31 | { 32 | "items": [ 33 | "minecraft:bubble_coral_fan" 34 | ] 35 | } 36 | ] 37 | }, 38 | "trigger": "minecraft:inventory_changed" 39 | }, 40 | "3": { 41 | "conditions": { 42 | "items": [ 43 | { 44 | "items": [ 45 | "minecraft:fire_coral_fan" 46 | ] 47 | } 48 | ] 49 | }, 50 | "trigger": "minecraft:inventory_changed" 51 | }, 52 | "4": { 53 | "conditions": { 54 | "items": [ 55 | { 56 | "items": [ 57 | "minecraft:horn_coral_fan" 58 | ] 59 | } 60 | ] 61 | }, 62 | "trigger": "minecraft:inventory_changed" 63 | } 64 | }, 65 | "display": { 66 | "announce_to_chat": true, 67 | "background": "minecraft:textures/block/crimson_planks.png", 68 | "description": { 69 | "translate": "advancement.skyland.coral_fan.desc" 70 | }, 71 | "frame": "goal", 72 | "hidden": false, 73 | "icon": { 74 | "item": "minecraft:fire_coral_fan" 75 | }, 76 | "show_toast": true, 77 | "title": { 78 | "translate": "advancement.skyland.coral_fan.title" 79 | } 80 | }, 81 | "requirements": [ 82 | [ 83 | "0", 84 | "1", 85 | "2", 86 | "3", 87 | "4" 88 | ] 89 | ] 90 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/elytra.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:the_end", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:elytra" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.elytra.desc" 22 | }, 23 | "frame": "challenge", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:elytra", 27 | "nbt": "{Damage:0}" 28 | }, 29 | "show_toast": true, 30 | "title": { 31 | "translate": "advancement.skyland.elytra.title" 32 | } 33 | }, 34 | "requirements": [ 35 | [ 36 | "0" 37 | ] 38 | ] 39 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/gold_ingot.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:kill_zombified_piglin", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:gold_ingot" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.gold_ingot.desc" 22 | }, 23 | "frame": "task", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:gold_ingot" 27 | }, 28 | "show_toast": true, 29 | "title": { 30 | "translate": "advancement.skyland.gold_ingot.title" 31 | } 32 | }, 33 | "requirements": [ 34 | [ 35 | "0" 36 | ] 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/ice.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:water", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:ice" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.ice.desc" 22 | }, 23 | "frame": "task", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:ice" 27 | }, 28 | "show_toast": true, 29 | "title": { 30 | "translate": "advancement.skyland.ice.title" 31 | } 32 | }, 33 | "requirements": [ 34 | [ 35 | "0" 36 | ] 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/kill_wrong.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:kill_zombified_piglin", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "entity": [ 7 | { 8 | "condition": "minecraft:entity_properties", 9 | "entity": "this", 10 | "predicate": { 11 | "type": "minecraft:zombie_villager" 12 | } 13 | } 14 | ] 15 | }, 16 | "trigger": "minecraft:player_killed_entity" 17 | } 18 | }, 19 | "display": { 20 | "announce_to_chat": true, 21 | "background": "minecraft:textures/block/crimson_planks.png", 22 | "description": { 23 | "translate": "advancement.skyland.kill_wrong.desc" 24 | }, 25 | "frame": "task", 26 | "hidden": false, 27 | "icon": { 28 | "item": "minecraft:wooden_sword", 29 | "nbt": "{Damage:0}" 30 | }, 31 | "show_toast": true, 32 | "title": { 33 | "translate": "advancement.skyland.kill_wrong.title" 34 | } 35 | }, 36 | "requirements": [ 37 | [ 38 | "0" 39 | ] 40 | ] 41 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/kill_zombified_piglin.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:wood", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "entity": [ 7 | { 8 | "condition": "minecraft:entity_properties", 9 | "entity": "this", 10 | "predicate": { 11 | "type": "minecraft:zombified_piglin" 12 | } 13 | } 14 | ] 15 | }, 16 | "trigger": "minecraft:player_killed_entity" 17 | } 18 | }, 19 | "display": { 20 | "announce_to_chat": true, 21 | "background": "minecraft:textures/block/crimson_planks.png", 22 | "description": { 23 | "translate": "advancement.skyland.kill_zombified_piglin.desc" 24 | }, 25 | "frame": "task", 26 | "hidden": false, 27 | "icon": { 28 | "item": "minecraft:diamond_sword", 29 | "nbt": "{Damage:0}" 30 | }, 31 | "show_toast": true, 32 | "title": { 33 | "translate": "advancement.skyland.kill_zombified_piglin.title" 34 | } 35 | }, 36 | "requirements": [ 37 | [ 38 | "0" 39 | ] 40 | ] 41 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/lava_bucket.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:village_hero", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:lava_bucket" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.lava_bucket.desc" 22 | }, 23 | "frame": "goal", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:lava_bucket" 27 | }, 28 | "show_toast": true, 29 | "title": { 30 | "translate": "advancement.skyland.lava_bucket.title" 31 | } 32 | }, 33 | "requirements": [ 34 | [ 35 | "0" 36 | ] 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/netherrack.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:blast_furnace", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:netherrack" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.netherrack.desc" 22 | }, 23 | "frame": "task", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:netherrack" 27 | }, 28 | "show_toast": true, 29 | "title": { 30 | "translate": "advancement.skyland.netherrack.title" 31 | } 32 | }, 33 | "requirements": [ 34 | [ 35 | "0" 36 | ] 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/respawn.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:kill_zombified_piglin", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:respawn_anchor" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.respawn.desc" 22 | }, 23 | "frame": "goal", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:respawn_anchor" 27 | }, 28 | "show_toast": true, 29 | "title": { 30 | "translate": "advancement.skyland.respawn.title" 31 | } 32 | }, 33 | "requirements": [ 34 | [ 35 | "0" 36 | ] 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/root.json: -------------------------------------------------------------------------------- 1 | { 2 | "criteria": { 3 | "0": { 4 | "conditions": {}, 5 | "trigger": "minecraft:inventory_changed" 6 | } 7 | }, 8 | "display": { 9 | "announce_to_chat": false, 10 | "background": "minecraft:textures/block/crimson_planks.png", 11 | "description": { 12 | "translate": "advancement.skyland.root.desc" 13 | }, 14 | "frame": "task", 15 | "hidden": false, 16 | "icon": { 17 | "item": "minecraft:crimson_fungus" 18 | }, 19 | "show_toast": false, 20 | "title": { 21 | "translate": "advancement.skyland.root.title" 22 | } 23 | }, 24 | "requirements": [ 25 | [ 26 | "0" 27 | ] 28 | ] 29 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/save_villager.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:weakness", 3 | "criteria": { 4 | "0": { 5 | "conditions": {}, 6 | "trigger": "minecraft:cured_zombie_villager" 7 | } 8 | }, 9 | "display": { 10 | "announce_to_chat": true, 11 | "background": "minecraft:textures/block/crimson_planks.png", 12 | "description": { 13 | "translate": "advancement.skyland.save_villager.desc" 14 | }, 15 | "frame": "goal", 16 | "hidden": false, 17 | "icon": { 18 | "item": "minecraft:golden_apple" 19 | }, 20 | "show_toast": true, 21 | "title": { 22 | "translate": "advancement.skyland.save_villager.title" 23 | } 24 | }, 25 | "requirements": [ 26 | [ 27 | "0" 28 | ] 29 | ] 30 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/shulker_box.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:elytra", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:shulker_shell" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.shulker_box.desc" 22 | }, 23 | "frame": "challenge", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:shulker_shell" 27 | }, 28 | "show_toast": true, 29 | "title": { 30 | "translate": "advancement.skyland.shulker_box.title" 31 | } 32 | }, 33 | "requirements": [ 34 | [ 35 | "0" 36 | ] 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/slime.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:bedrock_layer", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:slime_ball" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.slime.desc" 22 | }, 23 | "frame": "task", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:slime_ball" 27 | }, 28 | "show_toast": true, 29 | "title": { 30 | "translate": "advancement.skyland.slime.title" 31 | } 32 | }, 33 | "requirements": [ 34 | [ 35 | "0" 36 | ] 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/the_end.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:root", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:ender_eye" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.the_end.desc" 22 | }, 23 | "frame": "task", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:end_portal_frame" 27 | }, 28 | "show_toast": true, 29 | "title": { 30 | "translate": "advancement.skyland.the_end.title" 31 | } 32 | }, 33 | "requirements": [ 34 | [ 35 | "0" 36 | ] 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/village_hero.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:save_villager", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "effects": { 7 | "minecraft:bad_omen": {} 8 | } 9 | }, 10 | "trigger": "minecraft:effects_changed" 11 | }, 12 | "1": { 13 | "conditions": { 14 | "effects": { 15 | "minecraft:hero_of_the_village": {} 16 | } 17 | }, 18 | "trigger": "minecraft:effects_changed" 19 | } 20 | }, 21 | "display": { 22 | "announce_to_chat": true, 23 | "background": "minecraft:textures/block/crimson_planks.png", 24 | "description": { 25 | "translate": "advancement.skyland.village_hero.desc" 26 | }, 27 | "frame": "challenge", 28 | "hidden": false, 29 | "icon": { 30 | "item": "minecraft:emerald" 31 | }, 32 | "show_toast": true, 33 | "title": { 34 | "translate": "advancement.skyland.village_hero.title" 35 | } 36 | }, 37 | "requirements": [ 38 | [ 39 | "0" 40 | ], 41 | [ 42 | "1" 43 | ] 44 | ] 45 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/water.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:the_end", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "item": { 7 | "items": [ 8 | "minecraft:water_bucket" 9 | ] 10 | } 11 | }, 12 | "trigger": "minecraft:filled_bucket" 13 | } 14 | }, 15 | "display": { 16 | "announce_to_chat": true, 17 | "background": "minecraft:textures/block/crimson_planks.png", 18 | "description": { 19 | "translate": "advancement.skyland.water.desc" 20 | }, 21 | "frame": "goal", 22 | "hidden": false, 23 | "icon": { 24 | "item": "minecraft:water_bucket" 25 | }, 26 | "show_toast": true, 27 | "title": { 28 | "translate": "advancement.skyland.water.title" 29 | } 30 | }, 31 | "requirements": [ 32 | [ 33 | "0" 34 | ] 35 | ] 36 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/weakness.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:composter", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "effects": { 7 | "minecraft:weakness": {} 8 | } 9 | }, 10 | "trigger": "minecraft:effects_changed" 11 | } 12 | }, 13 | "display": { 14 | "announce_to_chat": true, 15 | "background": "minecraft:textures/block/crimson_planks.png", 16 | "description": { 17 | "translate": "advancement.skyland.weakness.desc" 18 | }, 19 | "frame": "task", 20 | "hidden": false, 21 | "icon": { 22 | "item": "minecraft:splash_potion" 23 | }, 24 | "show_toast": true, 25 | "title": { 26 | "translate": "advancement.skyland.weakness.title" 27 | } 28 | }, 29 | "requirements": [ 30 | [ 31 | "0" 32 | ] 33 | ] 34 | } -------------------------------------------------------------------------------- /src/main/generated/data/skyland/advancements/wood.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "skyland:root", 3 | "criteria": { 4 | "0": { 5 | "conditions": { 6 | "items": [ 7 | { 8 | "items": [ 9 | "minecraft:crimson_stem" 10 | ] 11 | } 12 | ] 13 | }, 14 | "trigger": "minecraft:inventory_changed" 15 | } 16 | }, 17 | "display": { 18 | "announce_to_chat": true, 19 | "background": "minecraft:textures/block/crimson_planks.png", 20 | "description": { 21 | "translate": "advancement.skyland.wood.desc" 22 | }, 23 | "frame": "task", 24 | "hidden": false, 25 | "icon": { 26 | "item": "minecraft:crimson_stem" 27 | }, 28 | "show_toast": true, 29 | "title": { 30 | "translate": "advancement.skyland.wood.title" 31 | } 32 | }, 33 | "requirements": [ 34 | [ 35 | "0" 36 | ] 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/ComposterCoolDown.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland; 2 | 3 | public class ComposterCoolDown { 4 | 5 | public static boolean last_is_sneaking = false; 6 | public static int cool_down = 0; 7 | public static final int MAX_COOL_DOWN = 40; 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/SkyLandChunkGenerator.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland; 2 | 3 | import com.mojang.serialization.Codec; 4 | import com.mojang.serialization.codecs.RecordCodecBuilder; 5 | import net.minecraft.block.BlockState; 6 | import net.minecraft.structure.StructurePiece; 7 | import net.minecraft.structure.StructurePieceType; 8 | import net.minecraft.structure.StructureSet; 9 | import net.minecraft.util.Identifier; 10 | import net.minecraft.util.dynamic.RegistryOps; 11 | import net.minecraft.util.math.BlockPos; 12 | import net.minecraft.util.math.ChunkPos; 13 | import net.minecraft.util.math.ChunkSectionPos; 14 | import net.minecraft.util.math.noise.DoublePerlinNoiseSampler; 15 | import net.minecraft.util.math.random.ChunkRandom; 16 | import net.minecraft.util.math.random.RandomSeed; 17 | import net.minecraft.util.math.random.Xoroshiro128PlusPlusRandom; 18 | import net.minecraft.util.registry.Registry; 19 | import net.minecraft.util.registry.RegistryEntry; 20 | import net.minecraft.world.ChunkRegion; 21 | import net.minecraft.world.HeightLimitView; 22 | import net.minecraft.world.StructureWorldAccess; 23 | import net.minecraft.world.biome.source.BiomeAccess; 24 | import net.minecraft.world.biome.source.BiomeSource; 25 | import net.minecraft.world.chunk.Chunk; 26 | import net.minecraft.world.gen.GenerationStep; 27 | import net.minecraft.world.gen.StructureAccessor; 28 | import net.minecraft.world.gen.chunk.Blender; 29 | import net.minecraft.world.gen.chunk.ChunkGenerator; 30 | import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; 31 | import net.minecraft.world.gen.chunk.NoiseChunkGenerator; 32 | import net.minecraft.world.gen.chunk.VerticalBlockSample; 33 | import net.minecraft.world.gen.noise.NoiseConfig; 34 | 35 | import java.util.concurrent.CompletableFuture; 36 | import java.util.concurrent.Executor; 37 | 38 | public class SkyLandChunkGenerator extends NoiseChunkGenerator { 39 | 40 | private final Registry structuresRegistry; 41 | 42 | public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( 43 | RegistryOps.createRegistryCodec(Registry.STRUCTURE_SET_KEY) 44 | .forGetter(generator -> generator.structureSetRegistry), 45 | RegistryOps.createRegistryCodec(Registry.NOISE_KEY).forGetter(generator -> generator.structuresRegistry), 46 | BiomeSource.CODEC.fieldOf("biome_source").forGetter(generator -> generator.biomeSource), 47 | ChunkGeneratorSettings.REGISTRY_CODEC.fieldOf("settings").forGetter(generator -> generator.settings)) 48 | .apply(instance, instance.stable(SkyLandChunkGenerator::new))); 49 | 50 | public SkyLandChunkGenerator(Registry noiseRegistry, 51 | Registry structuresRegistry, BiomeSource biomeSource, 52 | RegistryEntry settings) { 53 | super(noiseRegistry, structuresRegistry, biomeSource, settings); 54 | this.structuresRegistry = structuresRegistry; 55 | } 56 | 57 | @Override 58 | protected Codec getCodec() { 59 | return CODEC; 60 | } 61 | 62 | @Override 63 | public VerticalBlockSample getColumnSample(int x, int z, HeightLimitView world, NoiseConfig noiseConfig) { 64 | return new VerticalBlockSample(world.getBottomY(), new BlockState[0]); 65 | } 66 | 67 | @Override 68 | public CompletableFuture populateNoise(Executor executor, Blender blender, NoiseConfig noiseConfig, 69 | StructureAccessor structureAccessor, Chunk chunk) { 70 | return CompletableFuture.completedFuture(chunk); 71 | } 72 | 73 | @Override 74 | public void generateFeatures(StructureWorldAccess world, Chunk chunk, StructureAccessor structureAccessor) { 75 | ChunkPos chunkPos = chunk.getPos(); 76 | BlockPos pos = new BlockPos(chunkPos.getStartX(), chunk.getBottomY(), chunkPos.getStartZ()); 77 | 78 | structureAccessor.getStructureStarts(ChunkSectionPos.from(pos), 79 | world.getRegistryManager().get(Registry.STRUCTURE_KEY).get(new Identifier("minecraft:stronghold"))) 80 | .forEach(structureStart -> { 81 | for (StructurePiece piece : structureStart.getChildren()) { 82 | if (piece.getType() == StructurePieceType.STRONGHOLD_PORTAL_ROOM) { 83 | if (piece.intersectsChunk(chunkPos, 0)) { 84 | ChunkRandom random = new ChunkRandom( 85 | new Xoroshiro128PlusPlusRandom(RandomSeed.getSeed())); 86 | random.setCarverSeed(world.getSeed(), chunkPos.x, chunkPos.z); 87 | } 88 | } 89 | } 90 | }); 91 | } 92 | 93 | @Override 94 | public void buildSurface(ChunkRegion region, StructureAccessor structures, NoiseConfig noiseConfig, Chunk chunk) { 95 | } 96 | 97 | @Override 98 | public void populateEntities(ChunkRegion region) { 99 | } 100 | 101 | @Override 102 | public void carve(ChunkRegion chunkRegion, long seed, NoiseConfig noiseConfig, BiomeAccess biomeAccess, 103 | StructureAccessor structureAccessor, Chunk chunk, GenerationStep.Carver generationStep) { 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/SkyLandGamerules.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland; 2 | 3 | import net.fabricmc.fabric.api.gamerule.v1.GameRuleFactory; 4 | import net.fabricmc.fabric.api.gamerule.v1.GameRuleRegistry; 5 | import net.minecraft.world.GameRules.BooleanRule; 6 | import net.minecraft.world.GameRules.Category; 7 | import net.minecraft.world.GameRules.IntRule; 8 | import net.minecraft.world.GameRules.Key; 9 | 10 | public class SkyLandGamerules { 11 | 12 | public static void registry() { 13 | 14 | } 15 | 16 | public static final Key LC = GameRuleRegistry.register("qnmdLC", Category.MOBS, 17 | GameRuleFactory.createBooleanRule(false)); 18 | public static final Key CHIEFTAIN = GameRuleRegistry.register("chieftainMode", Category.MISC, 19 | GameRuleFactory.createBooleanRule(false)); 20 | public static final Key WATER_CAULDRON = GameRuleRegistry.register("waterCauldron", Category.MISC, 21 | GameRuleFactory.createBooleanRule(false)); 22 | public static final Key NETHER_TRADER = GameRuleRegistry.register("netherTrader", Category.SPAWNING, 23 | GameRuleFactory.createBooleanRule(false)); 24 | public static final Key ICE_GOLEM = GameRuleRegistry.register("iceGolem", Category.MISC, 25 | GameRuleFactory.createBooleanRule(false)); 26 | public static final Key ANVIL_HANDLE = GameRuleRegistry.register("anvilHandle", Category.MISC, 27 | GameRuleFactory.createBooleanRule(false)); 28 | public static final Key NETHER_PATROL = GameRuleRegistry.register("netherPatrol", Category.SPAWNING, 29 | GameRuleFactory.createBooleanRule(false)); 30 | public static final Key VILLAGER_REINFORCEMENTS = GameRuleRegistry.register("villagerReinforcements", 31 | Category.SPAWNING, GameRuleFactory.createBooleanRule(false)); 32 | public static final Key KILL_DRAGON_SPAWN_SHULKER = GameRuleRegistry.register("killDragonSpawnShulker", 33 | Category.MOBS, GameRuleFactory.createBooleanRule(false)); 34 | public static final Key KILL_DRAGON_DROP_ELYTRA = GameRuleRegistry.register("killDragonDropElytra", 35 | Category.DROPS, GameRuleFactory.createBooleanRule(false)); 36 | public static final Key COMPOSTER_BONE_MEAL = GameRuleRegistry.register("composterBoneMeal", 37 | Category.MISC, GameRuleFactory.createBooleanRule(false)); 38 | public static final Key MEMORY_FOOD_LEVEL = GameRuleRegistry.register("memoryFoodLevel", 39 | Category.PLAYER, GameRuleFactory.createBooleanRule(false)); 40 | public static final Key RESPAWN_MIN_FOOD_LEVEL = GameRuleRegistry.register("respawnMinFoodLevel", 41 | Category.PLAYER, GameRuleFactory.createIntRule(4)); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/SkyLandMod.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland; 2 | 3 | import com.mojang.brigadier.arguments.BoolArgumentType; 4 | import net.fabricmc.api.ModInitializer; 5 | import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; 6 | import net.fabricmc.fabric.api.entity.event.v1.ServerEntityCombatEvents; 7 | import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents; 8 | import net.minecraft.entity.EntityType; 9 | import net.minecraft.entity.ItemEntity; 10 | import net.minecraft.entity.boss.dragon.EnderDragonEntity; 11 | import net.minecraft.item.ItemStack; 12 | import net.minecraft.item.Items; 13 | import net.minecraft.nbt.NbtCompound; 14 | import net.minecraft.server.command.CommandManager; 15 | import net.minecraft.server.command.ServerCommandSource; 16 | import net.minecraft.server.world.ServerWorld; 17 | import net.minecraft.text.Text; 18 | import net.minecraft.util.Identifier; 19 | import net.minecraft.util.math.Vec3d; 20 | import net.minecraft.util.registry.Registry; 21 | import net.minecraft.util.registry.RegistryKey; 22 | import net.minecraft.world.GameRules; 23 | import net.minecraft.world.gen.WorldPreset; 24 | 25 | public class SkyLandMod implements ModInitializer { 26 | 27 | public static final String MOD_ID = "skyland"; 28 | public static final Identifier ID = new Identifier(SkyLandMod.MOD_ID, "skyland"); 29 | 30 | public static final RegistryKey SKYLAND = RegistryKey.of(Registry.WORLD_PRESET_KEY, ID); 31 | 32 | @Override 33 | public void onInitialize() { 34 | 35 | SkyLandGamerules.registry(); 36 | 37 | SkyLandTrades.mergeWanderingTraderOffers(SkyLandTrades.getSkyLandWanderingTraderOffersTier2()); 38 | SkyLandTrades.removeFarmerTrades(); 39 | 40 | ServerEntityCombatEvents.AFTER_KILLED_OTHER_ENTITY.register((world, entity, killedEntity) -> { 41 | if (world.getGameRules().getBoolean(SkyLandGamerules.KILL_DRAGON_DROP_ELYTRA) 42 | && killedEntity instanceof EnderDragonEntity enderDragonEntity) { 43 | ItemEntity itemEntity = EntityType.ITEM.create(world); 44 | assert itemEntity != null; 45 | 46 | NbtCompound nbtCompound = new NbtCompound(); 47 | nbtCompound.putInt("Damage", 426); 48 | 49 | ItemStack itemStack = new ItemStack(Items.ELYTRA, 1); 50 | itemStack.setNbt(nbtCompound); 51 | itemEntity.setStack(itemStack); 52 | Vec3d pos = enderDragonEntity.getPos(); 53 | itemEntity.setPosition(pos); 54 | world.spawnEntityAndPassengers(itemEntity); 55 | } 56 | }); 57 | 58 | ServerPlayerEvents.AFTER_RESPAWN.register((oldPlayer, newPlayer, alive) -> { 59 | ServerWorld world = newPlayer.getWorld(); 60 | if (world.getGameRules().getBoolean(SkyLandGamerules.MEMORY_FOOD_LEVEL)) { 61 | int old_food_level = oldPlayer.getHungerManager().getFoodLevel(); 62 | int new_food_level = Math.max(old_food_level, 63 | world.getGameRules().getInt(SkyLandGamerules.RESPAWN_MIN_FOOD_LEVEL)); 64 | float old_saturation_level = oldPlayer.getHungerManager().getSaturationLevel(); 65 | newPlayer.getHungerManager().setFoodLevel(new_food_level); 66 | newPlayer.getHungerManager().setSaturationLevel(old_saturation_level); 67 | } 68 | }); 69 | 70 | CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register( 71 | CommandManager.literal("skyland").then(CommandManager.literal("gamerule") 72 | .then(CommandManager.argument("boolean", BoolArgumentType.bool()).executes(context -> { 73 | ServerCommandSource serverCommandSource = context.getSource(); 74 | boolean bool = BoolArgumentType.getBool(context, "boolean"); 75 | serverCommandSource.getServer().getGameRules().get(SkyLandGamerules.WATER_CAULDRON) 76 | .set(bool, serverCommandSource.getServer()); 77 | serverCommandSource.getServer().getGameRules().get(SkyLandGamerules.ICE_GOLEM) 78 | .set(bool, serverCommandSource.getServer()); 79 | serverCommandSource.getServer().getGameRules().get(SkyLandGamerules.NETHER_TRADER) 80 | .set(bool, serverCommandSource.getServer()); 81 | serverCommandSource.getServer().getGameRules().get(SkyLandGamerules.ANVIL_HANDLE) 82 | .set(bool, serverCommandSource.getServer()); 83 | serverCommandSource.getServer().getGameRules().get(SkyLandGamerules.NETHER_PATROL) 84 | .set(bool, serverCommandSource.getServer()); 85 | serverCommandSource.getServer().getGameRules().get(SkyLandGamerules.VILLAGER_REINFORCEMENTS) 86 | .set(bool, serverCommandSource.getServer()); 87 | serverCommandSource.getServer().getGameRules() 88 | .get(SkyLandGamerules.KILL_DRAGON_SPAWN_SHULKER) 89 | .set(bool, serverCommandSource.getServer()); 90 | serverCommandSource.getServer().getGameRules().get(SkyLandGamerules.KILL_DRAGON_DROP_ELYTRA) 91 | .set(bool, serverCommandSource.getServer()); 92 | serverCommandSource.getServer().getGameRules().get(GameRules.DO_INSOMNIA) 93 | .set(!bool, serverCommandSource.getServer()); 94 | serverCommandSource.sendFeedback( 95 | Text.translatable("skyland.command.gamerule_set_succeed", String.valueOf(bool)), 96 | true); 97 | return 1; 98 | }))))); 99 | 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/SkyLandStructures.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland; 2 | 3 | import net.minecraft.block.Block; 4 | import net.minecraft.structure.StructurePlacementData; 5 | import net.minecraft.structure.StructureTemplate; 6 | import net.minecraft.util.Identifier; 7 | import net.minecraft.util.math.BlockPos; 8 | import net.minecraft.util.math.random.Random; 9 | import net.minecraft.world.ServerWorldAccess; 10 | 11 | import java.util.Objects; 12 | 13 | public class SkyLandStructures { 14 | 15 | public record SpawnPlatform(BlockPos worldSpawn) { 16 | 17 | public void generate(ServerWorldAccess world, Random random) { 18 | StructureTemplate structure = Objects.requireNonNull(world.getServer()).getStructureTemplateManager() 19 | .getTemplate(new Identifier(SkyLandMod.MOD_ID, "spawn_platform")).orElseThrow(); 20 | BlockPos structureOrigin = worldSpawn.subtract(new BlockPos(0, 1, 0)); 21 | structure.place(world, structureOrigin, worldSpawn, new StructurePlacementData(), random, 22 | Block.NOTIFY_LISTENERS); 23 | } 24 | } 25 | 26 | public record TheEndPortal(BlockPos worldSpawn) { 27 | 28 | public void generate(ServerWorldAccess world, Random random, BlockPos fixPos) { 29 | StructureTemplate structure = Objects.requireNonNull(world.getServer()).getStructureTemplateManager() 30 | .getTemplate(new Identifier(SkyLandMod.MOD_ID, "the_end_portal")).orElseThrow(); 31 | BlockPos structureOrigin = worldSpawn.subtract(fixPos); 32 | structure.place(world, structureOrigin, worldSpawn, new StructurePlacementData(), random, 33 | Block.NOTIFY_LISTENERS); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/SkyLandTrades.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import dev.dubhe.skyland.mixin.SellItemFactoryAccessor; 5 | import it.unimi.dsi.fastutil.ints.Int2ObjectMap; 6 | import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; 7 | import net.fabricmc.fabric.api.object.builder.v1.trade.TradeOfferHelper; 8 | import net.minecraft.item.Item; 9 | import net.minecraft.item.Items; 10 | import net.minecraft.village.TradeOffers; 11 | import net.minecraft.village.TradeOffers.Factory; 12 | import net.minecraft.village.TradeOffers.SellItemFactory; 13 | import net.minecraft.village.VillagerProfession; 14 | 15 | import java.util.List; 16 | 17 | public class SkyLandTrades { 18 | 19 | public static void mergeWanderingTraderOffers(Int2ObjectMap custom) { 20 | TradeOffers.Factory[] customTier1 = custom.get(1); 21 | TradeOffers.Factory[] customTier2 = custom.get(2); 22 | 23 | TradeOfferHelper.registerWanderingTraderOffers(1, factories -> { 24 | if (customTier1 != null) { 25 | factories.addAll(List.of(customTier1)); 26 | } 27 | }); 28 | 29 | TradeOfferHelper.registerWanderingTraderOffers(2, factories -> { 30 | if (customTier2 != null) { 31 | factories.addAll(List.of(customTier2)); 32 | } 33 | }); 34 | 35 | } 36 | 37 | private static TradeOffers.Factory sell(Item item, int price, int maxUses) { 38 | return new TradeOffers.SellItemFactory(item, price, 1, maxUses, 1); 39 | } 40 | 41 | public static Int2ObjectMap getSkyLandWanderingTraderOffersTier2() { 42 | return new Int2ObjectOpenHashMap<>(ImmutableMap.of(2, 43 | new TradeOffers.Factory[] { 44 | sell(Items.NETHER_WART, 32, 4), 45 | sell(Items.BAMBOO, 16, 8), 46 | sell(Items.SEA_PICKLE, 16, 8), 47 | sell(Items.COCOA_BEANS, 16, 8), 48 | sell(Items.SUNFLOWER, 8, 8), 49 | sell(Items.LILAC, 8, 8), 50 | sell(Items.ROSE_BUSH, 8, 8), 51 | sell(Items.PEONY, 8, 8), 52 | sell(Items.TURTLE_EGG, 16, 4) 53 | })); 54 | } 55 | 56 | public static void removeFarmerTrades() { 57 | 58 | Factory[] farm_trades = TradeOffers.PROFESSION_TO_LEVELED_TRADE.get(VillagerProfession.FARMER).get(2); 59 | Factory[] new_farm_trades = new Factory[2]; 60 | 61 | int counter = 0; 62 | for (Factory factory : farm_trades) { 63 | if (factory instanceof SellItemFactory sellItemFactory) { 64 | if (((SellItemFactoryAccessor) sellItemFactory).getSell().getItem() != Items.PUMPKIN_PIE) { 65 | new_farm_trades[counter] = factory; 66 | counter += 1; 67 | } 68 | } else { 69 | new_farm_trades[counter] = factory; 70 | counter += 1; 71 | } 72 | } 73 | TradeOffers.PROFESSION_TO_LEVELED_TRADE.get(VillagerProfession.FARMER).put(2, new_farm_trades); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/data/AdvancementProvider.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.data; 2 | 3 | import dev.dubhe.skyland.SkyLandMod; 4 | import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; 5 | import net.fabricmc.fabric.api.datagen.v1.provider.FabricAdvancementProvider; 6 | import net.minecraft.advancement.Advancement; 7 | import net.minecraft.advancement.AdvancementFrame; 8 | import net.minecraft.advancement.CriterionMerger; 9 | import net.minecraft.advancement.criterion.ChangedDimensionCriterion; 10 | import net.minecraft.advancement.criterion.CriterionConditions; 11 | import net.minecraft.advancement.criterion.CuredZombieVillagerCriterion; 12 | import net.minecraft.advancement.criterion.EffectsChangedCriterion; 13 | import net.minecraft.advancement.criterion.FilledBucketCriterion; 14 | import net.minecraft.advancement.criterion.InventoryChangedCriterion; 15 | import net.minecraft.advancement.criterion.OnKilledCriterion; 16 | import net.minecraft.advancement.criterion.TickCriterion; 17 | import net.minecraft.entity.EntityType; 18 | import net.minecraft.entity.effect.StatusEffects; 19 | import net.minecraft.item.Item; 20 | import net.minecraft.item.Items; 21 | import net.minecraft.predicate.NumberRange.FloatRange; 22 | import net.minecraft.predicate.entity.EntityEffectPredicate; 23 | import net.minecraft.predicate.entity.EntityPredicate; 24 | import net.minecraft.predicate.entity.LocationPredicate; 25 | import net.minecraft.predicate.item.ItemPredicate; 26 | import net.minecraft.text.Text; 27 | import net.minecraft.util.Identifier; 28 | import net.minecraft.world.World; 29 | 30 | import java.util.function.Consumer; 31 | 32 | public class AdvancementProvider extends FabricAdvancementProvider { 33 | 34 | public static String LANG = "advancement." + SkyLandMod.MOD_ID + "."; 35 | public static final Identifier BACK_GROUND = new Identifier("textures/block/crimson_planks.png"); 36 | 37 | protected AdvancementProvider(FabricDataGenerator dataGenerator) { 38 | super(dataGenerator); 39 | } 40 | 41 | @SuppressWarnings("unused") 42 | @Override 43 | public void generateAdvancement(Consumer consumer) { 44 | Advancement ROOT = newAdvancement("root", Items.CRIMSON_FUNGUS, TaskType.ROOT, 45 | new Criterion("0", InventoryChangedCriterion.Conditions.items(new ItemPredicate[]{})), consumer); 46 | Advancement WOOD = newAdvancement("wood", Items.CRIMSON_STEM, TaskType.MILESTONE, ROOT, 47 | new Criterion("0", InventoryChangedCriterion.Conditions.items(Items.CRIMSON_STEM)), consumer); 48 | Advancement COMPOSTER = newAdvancement("composter", Items.COMPOSTER, TaskType.MILESTONE, WOOD, 49 | new Criterion("0", InventoryChangedCriterion.Conditions.items(Items.COMPOSTER)), consumer); 50 | Advancement KILL_ZOMBIFIED_PIGLIN = newAdvancement("kill_zombified_piglin", Items.DIAMOND_SWORD, 51 | TaskType.MILESTONE, WOOD, new Criterion("0", OnKilledCriterion.Conditions.createPlayerKilledEntity( 52 | EntityPredicate.Builder.create().type(EntityType.ZOMBIFIED_PIGLIN))), consumer); 53 | Advancement KILL_WRONG = newAdvancement("kill_wrong", Items.WOODEN_SWORD, TaskType.MILESTONE, 54 | KILL_ZOMBIFIED_PIGLIN, new Criterion("0", OnKilledCriterion.Conditions.createPlayerKilledEntity( 55 | EntityPredicate.Builder.create().type(EntityType.ZOMBIE_VILLAGER))), consumer); 56 | Advancement GOLD_INGOT = newAdvancement("gold_ingot", Items.GOLD_INGOT, TaskType.MILESTONE, 57 | KILL_ZOMBIFIED_PIGLIN, new Criterion("0", InventoryChangedCriterion.Conditions.items(Items.GOLD_INGOT)), 58 | consumer); 59 | Advancement BLAST_FURNACE = newAdvancement("blast_furnace", Items.BLAST_FURNACE, TaskType.MILESTONE, GOLD_INGOT, 60 | new Criterion("0", InventoryChangedCriterion.Conditions.items(Items.BLAST_FURNACE)), consumer); 61 | Advancement NETHERRACK = newAdvancement("netherrack", Items.NETHERRACK, TaskType.MILESTONE, BLAST_FURNACE, 62 | new Criterion("0", InventoryChangedCriterion.Conditions.items(Items.NETHERRACK)), consumer); 63 | Advancement WEAKNESS = newAdvancement("weakness", Items.SPLASH_POTION, TaskType.MILESTONE, COMPOSTER, 64 | new Criterion("0", EffectsChangedCriterion.Conditions.create( 65 | EntityEffectPredicate.create().withEffect(StatusEffects.WEAKNESS))), consumer); 66 | Advancement SAVE_VILLAGER = newAdvancement("save_villager", Items.GOLDEN_APPLE, TaskType.GOAL, WEAKNESS, 67 | new Criterion("0", CuredZombieVillagerCriterion.Conditions.any()), consumer); 68 | Advancement VILLAGE_HERO = Advancement.Builder.create().parent(SAVE_VILLAGER) 69 | .display(Items.EMERALD, getTranslatableTitle("village_hero"), getTranslatableDesc("village_hero"), 70 | BACK_GROUND, AdvancementFrame.CHALLENGE, true, true, false).criterion("0", 71 | EffectsChangedCriterion.Conditions.create( 72 | EntityEffectPredicate.create().withEffect(StatusEffects.BAD_OMEN))).criterion("1", 73 | EffectsChangedCriterion.Conditions.create( 74 | EntityEffectPredicate.create().withEffect(StatusEffects.HERO_OF_THE_VILLAGE))) 75 | .build(consumer, SkyLandMod.MOD_ID + ":village_hero"); 76 | Advancement BREED_VILLAGERS = newAdvancement("breed_villagers", Items.BREAD, TaskType.MILESTONE, VILLAGE_HERO, 77 | new Criterion("0", InventoryChangedCriterion.Conditions.items(Items.BREAD)), consumer); 78 | Advancement LAVA_BUCKET = newAdvancement("lava_bucket", Items.LAVA_BUCKET, TaskType.GOAL, VILLAGE_HERO, 79 | new Criterion("0", InventoryChangedCriterion.Conditions.items(Items.LAVA_BUCKET)), consumer); 80 | Advancement BETTER_WOOD = Advancement.Builder.create().parent(LAVA_BUCKET) 81 | .display(Items.OAK_WOOD, getTranslatableTitle("better_wood"), getTranslatableDesc("better_wood"), 82 | BACK_GROUND, AdvancementFrame.TASK, true, true, false).criteriaMerger(CriterionMerger.OR) 83 | .criterion("0", InventoryChangedCriterion.Conditions.items(Items.SPRUCE_SAPLING)) 84 | .criterion("1", InventoryChangedCriterion.Conditions.items(Items.ACACIA_SAPLING)) 85 | .criterion("2", InventoryChangedCriterion.Conditions.items(Items.BIRCH_SAPLING)) 86 | .criterion("3", InventoryChangedCriterion.Conditions.items(Items.DARK_OAK_SAPLING)) 87 | .criterion("4", InventoryChangedCriterion.Conditions.items(Items.JUNGLE_SAPLING)) 88 | .criterion("5", InventoryChangedCriterion.Conditions.items(Items.OAK_SAPLING)) 89 | .criterion("6", InventoryChangedCriterion.Conditions.items(Items.MANGROVE_PROPAGULE)) 90 | .build(consumer, SkyLandMod.MOD_ID + ":better_wood"); 91 | Advancement ANCIENT_DEBRIS = newAdvancement("ancient_debris", Items.ANCIENT_DEBRIS, TaskType.CHALLENGE, 92 | VILLAGE_HERO, new Criterion("0", InventoryChangedCriterion.Conditions.items(Items.ANCIENT_DEBRIS)), 93 | consumer); 94 | Advancement BEDROCK_LAYER = newAdvancement("bedrock_layer", Items.BEDROCK, TaskType.GOAL, ROOT, 95 | new Criterion("0", TickCriterion.Conditions.createLocation(LocationPredicate.y(FloatRange.atMost(1)))), 96 | consumer); 97 | Advancement SLIME = newAdvancement("slime", Items.SLIME_BALL, TaskType.MILESTONE, BEDROCK_LAYER, 98 | new Criterion("0", InventoryChangedCriterion.Conditions.items(Items.SLIME_BALL)), consumer); 99 | Advancement THE_END = newAdvancement("the_end", Items.END_PORTAL_FRAME, TaskType.MILESTONE, ROOT, 100 | new Criterion("0", ChangedDimensionCriterion.Conditions.to(World.END)), consumer); 101 | Advancement WATER = newAdvancement("water", Items.WATER_BUCKET, TaskType.GOAL, THE_END, new Criterion("0", 102 | FilledBucketCriterion.Conditions.create( 103 | ItemPredicate.Builder.create().items(Items.WATER_BUCKET).build())), consumer); 104 | Advancement ICE = newAdvancement("ice", Items.ICE, TaskType.MILESTONE, WATER, 105 | new Criterion("0", InventoryChangedCriterion.Conditions.items(Items.ICE)), consumer); 106 | Advancement CORAL_FAN = Advancement.Builder.create().parent(LAVA_BUCKET) 107 | .display(Items.FIRE_CORAL_FAN, getTranslatableTitle("coral_fan"), getTranslatableDesc("coral_fan"), 108 | BACK_GROUND, AdvancementFrame.GOAL, true, true, false).criteriaMerger(CriterionMerger.OR) 109 | .criterion("0", InventoryChangedCriterion.Conditions.items(Items.BRAIN_CORAL_BLOCK)) 110 | .criterion("1", InventoryChangedCriterion.Conditions.items(Items.TUBE_CORAL_BLOCK)) 111 | .criterion("2", InventoryChangedCriterion.Conditions.items(Items.BUBBLE_CORAL_BLOCK)) 112 | .criterion("3", InventoryChangedCriterion.Conditions.items(Items.FIRE_CORAL_BLOCK)) 113 | .criterion("4", InventoryChangedCriterion.Conditions.items(Items.HORN_CORAL_BLOCK)) 114 | .build(consumer, SkyLandMod.MOD_ID + ":coral_fan"); 115 | Advancement ELYTRA = newAdvancement("elytra", Items.ELYTRA, TaskType.CHALLENGE, THE_END, 116 | new Criterion("0", InventoryChangedCriterion.Conditions.items(Items.ELYTRA)), consumer); 117 | Advancement SHULKER_BOX = newAdvancement("shulker_box", Items.SHULKER_SHELL, TaskType.CHALLENGE, ELYTRA, 118 | new Criterion("0", InventoryChangedCriterion.Conditions.items(Items.SHULKER_SHELL)), consumer); 119 | Advancement BULK_LAVA = newAdvancement("bulk_lava", Items.POINTED_DRIPSTONE, TaskType.GOAL, ICE, 120 | new Criterion("0", InventoryChangedCriterion.Conditions.items(Items.POINTED_DRIPSTONE)), consumer); 121 | Advancement RESPAWN = newAdvancement("respawn", Items.RESPAWN_ANCHOR, TaskType.GOAL, KILL_ZOMBIFIED_PIGLIN, 122 | new Criterion("0", InventoryChangedCriterion.Conditions.items(Items.RESPAWN_ANCHOR)), consumer); 123 | } 124 | 125 | public static Text getTranslatableTitle(String title) { 126 | return Text.translatable(LANG + title + ".title"); 127 | } 128 | 129 | public static Text getTranslatableDesc(String desc) { 130 | return Text.translatable(LANG + desc + ".desc"); 131 | } 132 | 133 | public static Advancement newAdvancement(String id, Item icon, TaskType type, Advancement parent, 134 | Criterion criterion, Consumer consumer) { 135 | return Advancement.Builder.create().parent(parent) 136 | .display(icon, getTranslatableTitle(id), getTranslatableDesc(id), BACK_GROUND, type.frame, type.toast, 137 | type.announce, type.hide).criterion(criterion.name, criterion.conditions) 138 | .build(consumer, SkyLandMod.MOD_ID + ":" + id); 139 | } 140 | 141 | public static Advancement newAdvancement(String id, Item icon, TaskType type, Criterion criterion, 142 | Consumer consumer) { 143 | return Advancement.Builder.create() 144 | .display(icon, getTranslatableTitle(id), getTranslatableDesc(id), BACK_GROUND, type.frame, type.toast, 145 | type.announce, type.hide).criterion(criterion.name, criterion.conditions) 146 | .build(consumer, SkyLandMod.MOD_ID + ":" + id); 147 | } 148 | 149 | enum TaskType { 150 | ROOT(AdvancementFrame.TASK, false, false, false), MILESTONE(AdvancementFrame.TASK, true, true, false), GOAL( 151 | AdvancementFrame.GOAL, true, true, false), SECRET(AdvancementFrame.GOAL, true, true, true), SILENT_GATE( 152 | AdvancementFrame.CHALLENGE, false, false, false), CHALLENGE(AdvancementFrame.CHALLENGE, true, true, 153 | false), 154 | 155 | ; 156 | 157 | private final AdvancementFrame frame; 158 | private final boolean toast; 159 | private final boolean announce; 160 | private final boolean hide; 161 | 162 | TaskType(AdvancementFrame frame, boolean toast, boolean announce, boolean hide) { 163 | this.frame = frame; 164 | this.toast = toast; 165 | this.announce = announce; 166 | this.hide = hide; 167 | } 168 | } 169 | 170 | public record Criterion(String name, CriterionConditions conditions) { 171 | 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/data/SkyLandDataGenerator.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.data; 2 | 3 | import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint; 4 | import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; 5 | 6 | public class SkyLandDataGenerator implements DataGeneratorEntrypoint { 7 | 8 | @Override 9 | public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) { 10 | fabricDataGenerator.addProvider(new AdvancementProvider(fabricDataGenerator)); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/BoneMealItemMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.block.Blocks; 6 | import net.minecraft.block.CoralWallFanBlock; 7 | import net.minecraft.item.BoneMealItem; 8 | import net.minecraft.item.ItemStack; 9 | import net.minecraft.item.ItemUsageContext; 10 | import net.minecraft.util.ActionResult; 11 | import net.minecraft.util.math.BlockPos; 12 | import net.minecraft.util.math.Direction; 13 | import net.minecraft.world.World; 14 | import net.minecraft.world.WorldEvents; 15 | import org.jetbrains.annotations.Nullable; 16 | import org.spongepowered.asm.mixin.Mixin; 17 | import org.spongepowered.asm.mixin.injection.At; 18 | import org.spongepowered.asm.mixin.injection.Inject; 19 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 20 | 21 | @Mixin(BoneMealItem.class) 22 | public class BoneMealItemMixin { 23 | 24 | @Inject(method = "useOnBlock", at = @At("HEAD"), cancellable = true) 25 | private void useOnBlock(ItemUsageContext context, CallbackInfoReturnable cir){ 26 | World world = context.getWorld(); 27 | BlockPos blockPos = context.getBlockPos(); 28 | BlockPos blockPos2 = blockPos.offset(context.getSide()); 29 | BlockState blockState = world.getBlockState(blockPos); 30 | boolean bl = blockState.isSideSolidFullSquare(world, blockPos, context.getSide()); 31 | if (bl && useOnGround(context.getStack(), world, blockPos2, blockState, context.getSide())) { 32 | if (!world.isClient) { 33 | world.syncWorldEvent(WorldEvents.BONE_MEAL_USED, blockPos2, 0); 34 | } 35 | cir.setReturnValue(ActionResult.success(world.isClient)); 36 | } 37 | } 38 | 39 | private static boolean useOnGround(ItemStack stack, World world, BlockPos blockPos, BlockState blockState, @Nullable Direction facing) { 40 | BlockState blockState2 = world.getBlockState(blockPos); 41 | if (facing == Direction.DOWN || !blockState2.getFluidState().isStill()) { 42 | return false; 43 | } 44 | if (facing == Direction.UP){ 45 | if (blockState.getBlock() == Blocks.BUBBLE_CORAL_BLOCK){ 46 | world.setBlockState(blockPos, Blocks.BUBBLE_CORAL.getDefaultState()); 47 | } else if (blockState.getBlock() == Blocks.BRAIN_CORAL_BLOCK){ 48 | world.setBlockState(blockPos, Blocks.BRAIN_CORAL.getDefaultState()); 49 | } else if (blockState.getBlock() == Blocks.FIRE_CORAL_BLOCK){ 50 | world.setBlockState(blockPos, Blocks.FIRE_CORAL.getDefaultState()); 51 | } else if (blockState.getBlock() == Blocks.HORN_CORAL_BLOCK){ 52 | world.setBlockState(blockPos, Blocks.HORN_CORAL.getDefaultState()); 53 | } else if (blockState.getBlock() == Blocks.TUBE_CORAL_BLOCK){ 54 | world.setBlockState(blockPos, Blocks.TUBE_CORAL.getDefaultState()); 55 | } 56 | } else { 57 | if (blockState.getBlock() == Blocks.BUBBLE_CORAL_BLOCK){ 58 | world.setBlockState(blockPos, Blocks.BUBBLE_CORAL_WALL_FAN.getDefaultState().with(CoralWallFanBlock.FACING, facing)); 59 | } else if (blockState.getBlock() == Blocks.BRAIN_CORAL_BLOCK){ 60 | world.setBlockState(blockPos, Blocks.BRAIN_CORAL_WALL_FAN.getDefaultState().with(CoralWallFanBlock.FACING, facing)); 61 | } else if (blockState.getBlock() == Blocks.FIRE_CORAL_BLOCK){ 62 | world.setBlockState(blockPos, Blocks.FIRE_CORAL_WALL_FAN.getDefaultState().with(CoralWallFanBlock.FACING, facing)); 63 | } else if (blockState.getBlock() == Blocks.HORN_CORAL_BLOCK){ 64 | world.setBlockState(blockPos, Blocks.HORN_CORAL_WALL_FAN.getDefaultState().with(CoralWallFanBlock.FACING, facing)); 65 | } else if (blockState.getBlock() == Blocks.TUBE_CORAL_BLOCK){ 66 | world.setBlockState(blockPos, Blocks.TUBE_CORAL_WALL_FAN.getDefaultState().with(CoralWallFanBlock.FACING, facing)); 67 | } 68 | } 69 | stack.decrement(1); 70 | return true; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/CauldronBlockMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import net.minecraft.block.BlockState; 4 | import net.minecraft.block.Blocks; 5 | import net.minecraft.block.CauldronBlock; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.world.World; 8 | import net.minecraft.world.biome.Biome.Precipitation; 9 | import net.minecraft.world.biome.BiomeKeys; 10 | import net.minecraft.world.event.GameEvent; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | 16 | @Mixin(CauldronBlock.class) 17 | public class CauldronBlockMixin { 18 | 19 | @Inject(method = "precipitationTick", at = @At("HEAD")) 20 | private void precipitationTick(BlockState state, World world, BlockPos pos, Precipitation precipitation, 21 | CallbackInfo ci){ 22 | if (world.getBiome(pos).matchesId(BiomeKeys.BASALT_DELTAS.getValue())){ 23 | world.setBlockState(pos, Blocks.POWDER_SNOW_CAULDRON.getDefaultState()); 24 | world.emitGameEvent(null, GameEvent.BLOCK_CHANGE, pos); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/ChunkGeneratorsMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import com.mojang.serialization.Codec; 4 | import dev.dubhe.skyland.SkyLandMod; 5 | import dev.dubhe.skyland.SkyLandChunkGenerator; 6 | import net.minecraft.util.registry.Registry; 7 | import net.minecraft.world.gen.chunk.ChunkGenerator; 8 | import net.minecraft.world.gen.chunk.ChunkGenerators; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 13 | 14 | @Mixin(ChunkGenerators.class) 15 | public class ChunkGeneratorsMixin { 16 | 17 | @Inject(method = "registerAndGetDefault", at = @At("RETURN")) 18 | private static void register(Registry> registry, 19 | CallbackInfoReturnable> cir) { 20 | Registry.register(registry, SkyLandMod.ID, SkyLandChunkGenerator.CODEC); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/EnderDragonFightMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import dev.dubhe.skyland.SkyLandChunkGenerator; 4 | import dev.dubhe.skyland.SkyLandGamerules; 5 | import net.minecraft.entity.EntityType; 6 | import net.minecraft.entity.boss.dragon.EnderDragonEntity; 7 | import net.minecraft.entity.boss.dragon.EnderDragonFight; 8 | import net.minecraft.entity.mob.ShulkerEntity; 9 | import net.minecraft.nbt.NbtCompound; 10 | import net.minecraft.server.world.ServerWorld; 11 | import net.minecraft.util.math.BlockPos; 12 | import net.minecraft.world.Heightmap; 13 | import net.minecraft.world.gen.feature.EndPortalFeature; 14 | import org.spongepowered.asm.mixin.Final; 15 | import org.spongepowered.asm.mixin.Mixin; 16 | import org.spongepowered.asm.mixin.Shadow; 17 | import org.spongepowered.asm.mixin.injection.At; 18 | import org.spongepowered.asm.mixin.injection.At.Shift; 19 | import org.spongepowered.asm.mixin.injection.Inject; 20 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 21 | 22 | @Mixin(EnderDragonFight.class) 23 | public class EnderDragonFightMixin { 24 | 25 | @Final 26 | @Shadow 27 | private ServerWorld world; 28 | 29 | @Shadow 30 | private BlockPos exitPortalLocation; 31 | 32 | @Shadow 33 | private boolean previouslyKilled; 34 | 35 | @Inject(method = "", at = @At("TAIL")) 36 | private void setPortal(ServerWorld world, long gatewaysSeed, NbtCompound nbt, CallbackInfo ci) { 37 | if (this.world.getChunkManager().getChunkGenerator() instanceof SkyLandChunkGenerator 38 | && this.exitPortalLocation == null) { 39 | this.exitPortalLocation = new BlockPos(0, 60, 0); 40 | } 41 | } 42 | 43 | @Inject(method = "dragonKilled(Lnet/minecraft/entity/boss/dragon/EnderDragonEntity;)V", 44 | at = @At( 45 | value = "INVOKE", 46 | target = "Lnet/minecraft/entity/boss/dragon/EnderDragonFight;generateNewEndGateway()V", 47 | shift = Shift.AFTER 48 | ) 49 | ) 50 | private void spawnShulker(EnderDragonEntity dragon, CallbackInfo ci) { 51 | if (world.getGameRules().getBoolean(SkyLandGamerules.KILL_DRAGON_SPAWN_SHULKER)) { 52 | ShulkerEntity shulker = EntityType.SHULKER.create(world); 53 | if (!previouslyKilled || shulker == null) { 54 | return; 55 | } 56 | BlockPos pos = this.world.getTopPosition(Heightmap.Type.MOTION_BLOCKING, EndPortalFeature.ORIGIN); 57 | shulker.setPos(pos.getX(), pos.getY() + 1, pos.getZ()); 58 | 59 | world.spawnEntityAndPassengers(shulker); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/FallingBlockEntityMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import dev.dubhe.skyland.SkyLandGamerules; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.block.Blocks; 6 | import net.minecraft.entity.Entity; 7 | import net.minecraft.entity.EntityType; 8 | import net.minecraft.entity.FallingBlockEntity; 9 | import net.minecraft.entity.ItemEntity; 10 | import net.minecraft.item.Item; 11 | import net.minecraft.item.ItemStack; 12 | import net.minecraft.item.Items; 13 | import net.minecraft.server.world.ServerWorld; 14 | import net.minecraft.tag.BlockTags; 15 | import net.minecraft.util.math.BlockPos; 16 | import net.minecraft.util.math.Box; 17 | import net.minecraft.world.World; 18 | import org.spongepowered.asm.mixin.Mixin; 19 | import org.spongepowered.asm.mixin.Shadow; 20 | import org.spongepowered.asm.mixin.injection.At; 21 | import org.spongepowered.asm.mixin.injection.Inject; 22 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 23 | 24 | import java.util.List; 25 | 26 | @Mixin(FallingBlockEntity.class) 27 | public abstract class FallingBlockEntityMixin extends Entity { 28 | @Shadow 29 | public abstract BlockState getBlockState(); 30 | 31 | public FallingBlockEntityMixin(EntityType type, World world) { 32 | super(type, world); 33 | } 34 | 35 | @Inject( 36 | method = "tick", 37 | at = @At( 38 | value = "INVOKE", 39 | target = "Lnet/minecraft/block/FallingBlock;canFallThrough(Lnet/minecraft/block/BlockState;)Z", 40 | shift = At.Shift.AFTER 41 | ) 42 | ) 43 | private void onTick(CallbackInfo ci) { 44 | if (world.getGameRules().getBoolean(SkyLandGamerules.ANVIL_HANDLE) && getBlockState().isIn( 45 | BlockTags.ANVIL)) { 46 | BlockState downBlockState = this.world.getBlockState( 47 | new BlockPos(this.getX(), this.getY() - 0.06, this.getZ())); 48 | BlockState downDownBlockState = this.world.getBlockState( 49 | new BlockPos(this.getX(), this.getY() - 1.12, this.getZ())); 50 | // 压合 51 | if (downBlockState.getBlock() == Blocks.MOSS_BLOCK && downDownBlockState.getBlock() == Blocks.DIRT) { 52 | world.setBlockState(new BlockPos(this.getX(), this.getY() - 1.06, this.getZ()), Blocks.GRASS_BLOCK.getDefaultState()); 53 | world.setBlockState(new BlockPos(this.getX(), this.getY() - 0.06, this.getZ()), Blocks.AIR.getDefaultState()); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/FluidBlockMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import dev.dubhe.skyland.SkyLandGamerules; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.block.Blocks; 6 | import net.minecraft.block.FluidBlock; 7 | import net.minecraft.block.LeveledCauldronBlock; 8 | import net.minecraft.util.math.BlockPos; 9 | import net.minecraft.util.math.Direction; 10 | import net.minecraft.world.World; 11 | import net.minecraft.world.WorldEvents; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 16 | 17 | @Mixin(FluidBlock.class) 18 | public class FluidBlockMixin { 19 | 20 | @Inject(method = "receiveNeighborFluids", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockState;isOf(Lnet/minecraft/block/Block;)Z", shift = At.Shift.AFTER)) 21 | private void cauldronObsidian(World world, BlockPos pos, BlockState state, CallbackInfoReturnable cir) { 22 | if (world.getGameRules().getBoolean(SkyLandGamerules.WATER_CAULDRON)) { 23 | for (Direction direction : FluidBlock.FLOW_DIRECTIONS) { 24 | BlockPos blockPos = pos.offset(direction.getOpposite()); 25 | BlockState blockState = world.getBlockState(blockPos); 26 | if (blockState.isOf(Blocks.WATER_CAULDRON) && ((LeveledCauldronBlock) blockState.getBlock()).isFull( 27 | blockState)) { 28 | if (world.getFluidState(pos).isStill()) { 29 | world.setBlockState(pos, Blocks.OBSIDIAN.getDefaultState()); 30 | world.setBlockState(blockPos, Blocks.CAULDRON.getDefaultState()); 31 | world.syncWorldEvent(WorldEvents.LAVA_EXTINGUISHED, pos, 0); 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/IntegratedServerLoaderMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | 4 | import com.mojang.serialization.Lifecycle; 5 | import net.minecraft.client.MinecraftClient; 6 | import net.minecraft.client.gui.screen.world.CreateWorldScreen; 7 | import net.minecraft.server.integrated.IntegratedServerLoader; 8 | import net.minecraft.world.SaveProperties; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.Redirect; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 14 | 15 | @Mixin(IntegratedServerLoader.class) 16 | public class IntegratedServerLoaderMixin { 17 | 18 | @Redirect(method = "start(Lnet/minecraft/client/gui/screen/Screen;Ljava/lang/String;ZZ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/SaveProperties;getLifecycle()Lcom/mojang/serialization/Lifecycle;"), require = 1) 19 | private Lifecycle removeAdviceOnLoad(SaveProperties properties) { 20 | Lifecycle original = properties.getLifecycle(); 21 | if (original == Lifecycle.stable() || original == Lifecycle.experimental()) { 22 | return Lifecycle.stable(); 23 | } else { 24 | return original; 25 | } 26 | } 27 | 28 | @Inject(method = "tryLoad(Lnet/minecraft/client/MinecraftClient;Lnet/minecraft/client/gui/screen/world/CreateWorldScreen;Lcom/mojang/serialization/Lifecycle;Ljava/lang/Runnable;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;setScreen(Lnet/minecraft/client/gui/screen/Screen;)V", ordinal = 0), cancellable = true) 29 | private static void removeAdviceOnCreation(MinecraftClient client, CreateWorldScreen parent, Lifecycle lifecycle, 30 | Runnable loader, CallbackInfo ci) { 31 | loader.run(); 32 | ci.cancel(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/LeveledCauldronBlockMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import net.minecraft.block.BlockState; 4 | import net.minecraft.block.Blocks; 5 | import net.minecraft.block.LeveledCauldronBlock; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.world.World; 8 | import net.minecraft.world.biome.Biome.Precipitation; 9 | import net.minecraft.world.biome.BiomeKeys; 10 | import net.minecraft.world.event.GameEvent; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | 16 | @Mixin(LeveledCauldronBlock.class) 17 | public class LeveledCauldronBlockMixin { 18 | 19 | @Inject(method = "precipitationTick", at = @At("HEAD")) 20 | public void precipitationTick(BlockState state, World world, BlockPos pos, Precipitation precipitation, 21 | CallbackInfo ci) { 22 | if (world.getBiome(pos).matchesKey(BiomeKeys.BASALT_DELTAS) 23 | && state.getBlock() == Blocks.POWDER_SNOW_CAULDRON) { 24 | BlockState blockState = state.cycle(LeveledCauldronBlock.LEVEL); 25 | world.setBlockState(pos, blockState); 26 | world.emitGameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Emitter.of(blockState)); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/MinecraftServerMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import dev.dubhe.skyland.SkyLandChunkGenerator; 4 | import dev.dubhe.skyland.SkyLandStructures; 5 | import net.minecraft.server.MinecraftServer; 6 | import net.minecraft.server.world.ServerChunkManager; 7 | import net.minecraft.server.world.ServerWorld; 8 | import net.minecraft.util.math.BlockPos; 9 | import net.minecraft.util.math.ChunkPos; 10 | import net.minecraft.world.gen.chunk.ChunkGenerator; 11 | import net.minecraft.world.level.ServerWorldProperties; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 16 | import org.spongepowered.asm.mixin.injection.callback.LocalCapture; 17 | 18 | @Mixin(MinecraftServer.class) 19 | public class MinecraftServerMixin { 20 | 21 | @Inject(method = "setupSpawn", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "HEAD"), cancellable = true) 22 | private static void generateSpawnPlatform(ServerWorld world, ServerWorldProperties worldProperties, 23 | boolean bonusChest, boolean debugWorld, CallbackInfo ci) { 24 | ServerChunkManager chunkManager = world.getChunkManager(); 25 | ChunkGenerator chunkGenerator = chunkManager.getChunkGenerator(); 26 | if (!(chunkGenerator instanceof SkyLandChunkGenerator)) { 27 | return; 28 | } 29 | 30 | ChunkPos chunkPos = new ChunkPos(chunkManager.getNoiseConfig().getMultiNoiseSampler().findBestSpawnPosition()); 31 | int spawnHeight = chunkGenerator.getSpawnHeight(world); 32 | BlockPos worldSpawn = chunkPos.getStartPos().add(8, spawnHeight, 8); 33 | worldProperties.setSpawnPos(worldSpawn, 0.0f); 34 | 35 | new SkyLandStructures.SpawnPlatform(worldSpawn).generate(world, world.random); 36 | 37 | new SkyLandStructures.TheEndPortal(worldSpawn).generate(world, world.random, new BlockPos(1024, 0, 0)); 38 | new SkyLandStructures.TheEndPortal(worldSpawn).generate(world, world.random, new BlockPos(-1024, 0, 0)); 39 | new SkyLandStructures.TheEndPortal(worldSpawn).generate(world, world.random, new BlockPos(0, 0, 1024)); 40 | new SkyLandStructures.TheEndPortal(worldSpawn).generate(world, world.random, new BlockPos(0, 0, -1024)); 41 | new SkyLandStructures.TheEndPortal(worldSpawn).generate(world, world.random, new BlockPos(724, 0, 724)); 42 | new SkyLandStructures.TheEndPortal(worldSpawn).generate(world, world.random, new BlockPos(724, 0, -724)); 43 | new SkyLandStructures.TheEndPortal(worldSpawn).generate(world, world.random, new BlockPos(-724, 0, 724)); 44 | new SkyLandStructures.TheEndPortal(worldSpawn).generate(world, world.random, new BlockPos(-724, 0, -724)); 45 | 46 | ci.cancel(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/PatrolSpawnerMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import dev.dubhe.skyland.SkyLandGamerules; 4 | import net.minecraft.entity.player.PlayerEntity; 5 | import net.minecraft.server.world.ServerWorld; 6 | import net.minecraft.tag.BiomeTags; 7 | import net.minecraft.util.math.BlockPos; 8 | import net.minecraft.util.math.random.Random; 9 | import net.minecraft.util.registry.RegistryEntry; 10 | import net.minecraft.world.Heightmap; 11 | import net.minecraft.world.biome.Biome; 12 | import net.minecraft.world.spawner.PatrolSpawner; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.Shadow; 15 | import org.spongepowered.asm.mixin.injection.At; 16 | import org.spongepowered.asm.mixin.injection.Inject; 17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 18 | 19 | @Mixin(PatrolSpawner.class) 20 | public abstract class PatrolSpawnerMixin { 21 | 22 | @Inject(method = "spawn", 23 | at = @At( 24 | value = "INVOKE", 25 | target = "Lnet/minecraft/server/world/ServerWorld;getBiome(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/util/registry/RegistryEntry;", 26 | shift = At.Shift.AFTER 27 | ), 28 | cancellable = true 29 | ) 30 | private void atSpawn(ServerWorld world, boolean spawnMonsters, boolean spawnAnimals, 31 | CallbackInfoReturnable cir) { 32 | if (world.getGameRules().getBoolean(SkyLandGamerules.NETHER_PATROL)) { 33 | Random random = world.random; 34 | int i = world.getPlayers().size(); 35 | PlayerEntity playerEntity = world.getPlayers().get(random.nextInt(i)); 36 | int j = (24 + random.nextInt(24)) * (random.nextBoolean() ? -1 : 1); 37 | int k = (24 + random.nextInt(24)) * (random.nextBoolean() ? -1 : 1); 38 | BlockPos.Mutable mutable = playerEntity.getBlockPos().mutableCopy().move(j, 0, k); 39 | RegistryEntry registryEntry = world.getBiome(mutable); 40 | if (registryEntry.isIn(BiomeTags.IS_NETHER)) { 41 | int n = 0; 42 | int o = (int) Math.ceil(world.getLocalDifficulty(mutable).getLocalDifficulty()) + 1; 43 | for (int p = 0; p < o; ++p) { 44 | ++n; 45 | mutable.setY(world.getTopPosition(Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, mutable).getY()); 46 | if (p == 0) { 47 | if (!this.spawnPillager(world, mutable, random, true)) { 48 | break; 49 | } 50 | } else { 51 | this.spawnPillager(world, mutable, random, false); 52 | } 53 | mutable.setX(mutable.getX() + random.nextInt(5) - random.nextInt(5)); 54 | mutable.setZ(mutable.getZ() + random.nextInt(5) - random.nextInt(5)); 55 | } 56 | cir.setReturnValue(n); 57 | } 58 | } 59 | } 60 | 61 | @Shadow 62 | protected abstract boolean spawnPillager(ServerWorld world, BlockPos pos, Random random, boolean captain); 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/PlayerInventoryMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import net.minecraft.entity.player.PlayerInventory; 4 | import net.minecraft.item.ItemStack; 5 | import net.minecraft.util.collection.DefaultedList; 6 | import org.spongepowered.asm.mixin.Final; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | import java.util.List; 14 | 15 | @Mixin(PlayerInventory.class) 16 | public class PlayerInventoryMixin { 17 | 18 | @Shadow @Final private List> combinedInventory; 19 | 20 | @Inject(method = "dropAll", at = @At("HEAD")) 21 | private void drop(CallbackInfo ci){ 22 | for (List list : this.combinedInventory) { 23 | for (int i = 0; i < list.size(); ++i) { 24 | ItemStack itemStack = (ItemStack)list.get(i); 25 | if (itemStack.isEmpty()) continue; 26 | ((PlayerInventory)(Object)this).player.dropItem(itemStack, false, false); 27 | list.set(i, ItemStack.EMPTY); 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/SellItemFactoryAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import net.minecraft.item.ItemStack; 4 | import net.minecraft.village.TradeOffers; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(TradeOffers.SellItemFactory.class) 9 | public interface SellItemFactoryAccessor { 10 | 11 | @Accessor 12 | ItemStack getSell(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/ServerPlayerEntityMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import dev.dubhe.skyland.ComposterCoolDown; 4 | import dev.dubhe.skyland.SkyLandGamerules; 5 | import net.minecraft.block.BlockState; 6 | import net.minecraft.block.Blocks; 7 | import net.minecraft.block.ComposterBlock; 8 | import net.minecraft.item.ItemStack; 9 | import net.minecraft.item.Items; 10 | import net.minecraft.server.MinecraftServer; 11 | import net.minecraft.server.network.ServerPlayerEntity; 12 | import net.minecraft.server.world.ServerWorld; 13 | import net.minecraft.util.WorldSavePath; 14 | import net.minecraft.util.math.BlockPos; 15 | import org.spongepowered.asm.mixin.Final; 16 | import org.spongepowered.asm.mixin.Mixin; 17 | import org.spongepowered.asm.mixin.Shadow; 18 | import org.spongepowered.asm.mixin.injection.At; 19 | import org.spongepowered.asm.mixin.injection.Inject; 20 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 21 | 22 | import java.io.File; 23 | import java.io.IOException; 24 | 25 | @Mixin(ServerPlayerEntity.class) 26 | public abstract class ServerPlayerEntityMixin { 27 | 28 | 29 | @Shadow 30 | @Final 31 | public MinecraftServer server; 32 | 33 | @Inject(method = "onSpawn", at = @At("HEAD")) 34 | private void spawn(CallbackInfo ci) { 35 | File ojng = server.getSavePath(WorldSavePath.ROOT).resolve("skyland.ojng").toFile(); 36 | if (!ojng.isFile()) { 37 | ((ServerPlayerEntity) (Object) this).giveItemStack(new ItemStack(Items.BONE_MEAL, 32)); 38 | try { 39 | ojng.createNewFile(); 40 | } catch (IOException e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | } 45 | 46 | @Inject(method = "tick()V", at = @At("RETURN")) 47 | private void tick(CallbackInfo ci) { 48 | 49 | ServerPlayerEntity player = (ServerPlayerEntity) (Object) this; 50 | ServerWorld world = player.getWorld(); 51 | 52 | if (!world.getGameRules().getBoolean(SkyLandGamerules.COMPOSTER_BONE_MEAL)) { 53 | return; 54 | } 55 | 56 | if ((ComposterCoolDown.cool_down == 0)) { 57 | if (player.isSneaking()) { 58 | if (!ComposterCoolDown.last_is_sneaking) { 59 | ComposterCoolDown.last_is_sneaking = true; 60 | 61 | BlockPos pos = player.getBlockPos(); 62 | 63 | BlockState state = world.getBlockState(pos); 64 | 65 | if (state.getBlock() == Blocks.COMPOSTER) { 66 | int level = state.get(ComposterBlock.LEVEL); 67 | if (level < 7) { 68 | int new_level = level + 1; 69 | BlockState blockState = state.with(ComposterBlock.LEVEL, new_level); 70 | world.setBlockState(pos, blockState); 71 | if (player.getRandom().nextFloat() < 0.3) { 72 | player.getHungerManager().add(-1, -1); 73 | } 74 | if (new_level == 7) { 75 | world.createAndScheduleBlockTick(pos, blockState.getBlock(), 20); 76 | } 77 | ComposterCoolDown.cool_down = ComposterCoolDown.MAX_COOL_DOWN; 78 | } 79 | } 80 | } 81 | } else { 82 | ComposterCoolDown.last_is_sneaking = false; 83 | } 84 | } 85 | if (ComposterCoolDown.cool_down > 0) { 86 | ComposterCoolDown.cool_down = ComposterCoolDown.cool_down - 1; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/ServerWorldMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import net.minecraft.block.BlockState; 4 | import net.minecraft.block.Blocks; 5 | import net.minecraft.server.world.ServerWorld; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.util.math.ChunkPos; 8 | import net.minecraft.util.registry.RegistryEntry; 9 | import net.minecraft.world.Heightmap; 10 | import net.minecraft.world.biome.Biome; 11 | import net.minecraft.world.biome.BiomeKeys; 12 | import net.minecraft.world.chunk.WorldChunk; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | import org.spongepowered.asm.mixin.injection.Inject; 16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 17 | 18 | @Mixin(ServerWorld.class) 19 | public class ServerWorldMixin { 20 | 21 | @Inject(method = "tickChunk", at = @At("HEAD")) 22 | private void tickChunk(WorldChunk chunk, int randomTickSpeed, CallbackInfo ci) { 23 | BlockPos blockPos; 24 | ChunkPos chunkPos = chunk.getPos(); 25 | int i = chunkPos.getStartX(); 26 | int j = chunkPos.getStartZ(); 27 | if (((ServerWorld) (Object) this).random.nextInt(64) == 0) { 28 | blockPos = ((ServerWorld) (Object) this).getTopPosition(Heightmap.Type.MOTION_BLOCKING, 29 | ((ServerWorld) (Object) this).getRandomPosInChunk(i, 0, j, 15)); 30 | BlockPos blockPos2 = blockPos.down(); 31 | RegistryEntry biome = ((ServerWorld) (Object) this).getBiome(blockPos); 32 | if (biome.matchesId(BiomeKeys.BASALT_DELTAS.getValue())) { 33 | BlockState blockState = ((ServerWorld) (Object) this).getBlockState(blockPos2); 34 | if(blockState.getBlock() == Blocks.CAULDRON || blockState.getBlock() == Blocks.POWDER_SNOW_CAULDRON){ 35 | Biome.Precipitation precipitation = biome.value().getPrecipitation(); 36 | blockState.getBlock() 37 | .precipitationTick(blockState, ((ServerWorld) (Object) this), blockPos2, precipitation); 38 | } 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/SlimeEntityMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import net.minecraft.entity.EntityType; 4 | import net.minecraft.entity.SpawnReason; 5 | import net.minecraft.entity.mob.SlimeEntity; 6 | import net.minecraft.util.Identifier; 7 | import net.minecraft.util.math.BlockPos; 8 | import net.minecraft.util.math.random.Random; 9 | import net.minecraft.world.Difficulty; 10 | import net.minecraft.world.WorldAccess; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 15 | 16 | @Mixin(SlimeEntity.class) 17 | public class SlimeEntityMixin { 18 | 19 | private static final Identifier BASALT_DELTAS = new Identifier("basalt_deltas"); 20 | 21 | @Inject(method = "canSpawn(Lnet/minecraft/entity/EntityType;Lnet/minecraft/world/WorldAccess;Lnet/minecraft/entity/SpawnReason;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/random/Random;)Z", at = @At("RETURN"), cancellable = true) 22 | private static void canSpawnMixin(EntityType type, WorldAccess world, SpawnReason spawnReason, 23 | BlockPos pos, Random random, CallbackInfoReturnable cir) { 24 | if (cir.getReturnValue()) { 25 | return; 26 | } 27 | if (world.getDifficulty() != Difficulty.PEACEFUL) { 28 | if (world.getBiome(pos).matchesId(SlimeEntityMixin.BASALT_DELTAS)) { 29 | cir.setReturnValue(true); 30 | } 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/SnowGolemEntityMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | 4 | import dev.dubhe.skyland.SkyLandGamerules; 5 | import net.minecraft.block.BlockState; 6 | import net.minecraft.block.Blocks; 7 | import net.minecraft.entity.passive.SnowGolemEntity; 8 | import net.minecraft.util.math.BlockPos; 9 | import net.minecraft.util.math.MathHelper; 10 | import net.minecraft.world.World; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | 16 | @Mixin(SnowGolemEntity.class) 17 | public class SnowGolemEntityMixin { 18 | 19 | @Inject(method = "tickMovement()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;getDefaultState()Lnet/minecraft/block/BlockState;")) 20 | private void setIce(CallbackInfo ci) { 21 | World world = ((SnowGolemEntity) (Object) this).world; 22 | BlockState iceState = Blocks.ICE.getDefaultState(); 23 | if (world.getGameRules().getBoolean(SkyLandGamerules.ICE_GOLEM)) { 24 | for (int l = 0; l < 4; ++l) { 25 | int i = MathHelper.floor( 26 | ((SnowGolemEntity) (Object) this).getX() + (double) ((float) (l % 2 * 2 - 1) * 0.25F)); 27 | int j = MathHelper.floor(((SnowGolemEntity) (Object) this).getY()); 28 | int k = MathHelper.floor( 29 | ((SnowGolemEntity) (Object) this).getZ() + (double) ((float) (l / 2 % 2 * 2 - 1) * 0.25F)); 30 | BlockPos icePos = new BlockPos(i, j - 1, k); 31 | BlockState state = world.getBlockState(icePos); 32 | if (state.isOf(Blocks.WATER) && state.getFluidState().isStill() && iceState.canPlaceAt(world, icePos)) { 33 | world.setBlockState(icePos, iceState); 34 | } 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/SpawnHelperMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import dev.dubhe.skyland.SkyLandGamerules; 4 | import net.minecraft.entity.SpawnGroup; 5 | import net.minecraft.server.world.ServerWorld; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.util.math.ChunkPos; 8 | import net.minecraft.world.SpawnHelper; 9 | import net.minecraft.world.World; 10 | import net.minecraft.world.chunk.Chunk; 11 | import net.minecraft.world.chunk.ChunkSection; 12 | import net.minecraft.world.chunk.WorldChunk; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.Shadow; 15 | import org.spongepowered.asm.mixin.injection.At; 16 | import org.spongepowered.asm.mixin.injection.Inject; 17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 18 | 19 | @Mixin(SpawnHelper.class) 20 | public class SpawnHelperMixin { 21 | 22 | @Shadow 23 | public static void spawnEntitiesInChunk(SpawnGroup group, ServerWorld world, Chunk chunk, BlockPos pos, 24 | SpawnHelper.Checker checker, SpawnHelper.Runner runner) { 25 | } 26 | 27 | @Inject(method = "spawnEntitiesInChunk(Lnet/minecraft/entity/SpawnGroup;Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/world/chunk/WorldChunk;Lnet/minecraft/world/SpawnHelper$Checker;Lnet/minecraft/world/SpawnHelper$Runner;)V", at = @At("HEAD"), cancellable = true) 28 | private static void spawnEntities(SpawnGroup group, ServerWorld world, WorldChunk chunk, 29 | SpawnHelper.Checker checker, SpawnHelper.Runner runner, CallbackInfo ci) { 30 | if (world.getGameRules().getBoolean(SkyLandGamerules.LC)) { 31 | for (int i = chunk.getBottomY(); i < chunk.getTopY(); i += 16) { 32 | ChunkSection chunkSection = chunk.getSectionArray()[chunk.getSectionIndex(i)]; 33 | if (chunkSection != null && !chunkSection.isEmpty()) { 34 | BlockPos blockPos = getRandomPosInChunk(world, chunk).add(0, i, 0); 35 | spawnEntitiesInChunk(group, world, chunk, blockPos, checker, runner); 36 | } 37 | } 38 | ci.cancel(); 39 | } 40 | } 41 | 42 | private static BlockPos getRandomPosInChunk(World world, WorldChunk chunk) { 43 | ChunkPos chunkPos = chunk.getPos(); 44 | int x = chunkPos.getStartX() + world.random.nextInt(16); 45 | int z = chunkPos.getStartZ() + world.random.nextInt(16); 46 | int y = world.random.nextInt(16) + 1; 47 | return new BlockPos(x, y, z); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/TheEndBiomeCreatorMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import net.minecraft.entity.EntityType; 4 | import net.minecraft.entity.SpawnGroup; 5 | import net.minecraft.sound.BiomeMoodSound; 6 | import net.minecraft.world.biome.Biome; 7 | import net.minecraft.world.biome.BiomeEffects; 8 | import net.minecraft.world.biome.GenerationSettings.Builder; 9 | import net.minecraft.world.biome.SpawnSettings; 10 | import net.minecraft.world.biome.TheEndBiomeCreator; 11 | import net.minecraft.world.gen.feature.DefaultBiomeFeatures; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 16 | 17 | @Mixin(TheEndBiomeCreator.class) 18 | public class TheEndBiomeCreatorMixin { 19 | 20 | @Inject(method = "createEndBiome", at = @At("HEAD"), cancellable = true) 21 | private static void createEndBiome(Builder builder, CallbackInfoReturnable cir) { 22 | SpawnSettings.Builder builder2 = new SpawnSettings.Builder(); 23 | builder2.spawn( 24 | SpawnGroup.WATER_CREATURE, 25 | new SpawnSettings.SpawnEntry(EntityType.SQUID, 2, 1, 4) 26 | ); 27 | DefaultBiomeFeatures.addEndMobs(builder2); 28 | Biome biome = new Biome.Builder() 29 | .precipitation(Biome.Precipitation.NONE) 30 | .temperature(0.5f) 31 | .downfall(0.5f) 32 | .effects( 33 | new BiomeEffects.Builder() 34 | .waterColor(4159204) 35 | .waterFogColor(329011) 36 | .fogColor(0xA080A0) 37 | .skyColor(0) 38 | .moodSound(BiomeMoodSound.CAVE) 39 | .build() 40 | ) 41 | .spawnSettings(builder2.build()) 42 | .generationSettings(builder.build()).build(); 43 | cir.setReturnValue(biome); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/TheNetherBiomeCreatorMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import net.minecraft.client.sound.MusicType; 4 | import net.minecraft.entity.EntityType; 5 | import net.minecraft.entity.SpawnGroup; 6 | import net.minecraft.particle.ParticleTypes; 7 | import net.minecraft.sound.BiomeAdditionsSound; 8 | import net.minecraft.sound.BiomeMoodSound; 9 | import net.minecraft.sound.SoundEvents; 10 | import net.minecraft.util.math.MathHelper; 11 | import net.minecraft.world.biome.Biome; 12 | import net.minecraft.world.biome.BiomeEffects; 13 | import net.minecraft.world.biome.BiomeParticleConfig; 14 | import net.minecraft.world.biome.GenerationSettings; 15 | import net.minecraft.world.biome.SpawnSettings; 16 | import net.minecraft.world.biome.TheNetherBiomeCreator; 17 | import net.minecraft.world.gen.GenerationStep; 18 | import net.minecraft.world.gen.carver.ConfiguredCarvers; 19 | import net.minecraft.world.gen.feature.DefaultBiomeFeatures; 20 | import net.minecraft.world.gen.feature.MiscPlacedFeatures; 21 | import net.minecraft.world.gen.feature.NetherPlacedFeatures; 22 | import net.minecraft.world.gen.feature.OrePlacedFeatures; 23 | import net.minecraft.world.gen.feature.VegetationPlacedFeatures; 24 | import org.spongepowered.asm.mixin.Mixin; 25 | import org.spongepowered.asm.mixin.injection.At; 26 | import org.spongepowered.asm.mixin.injection.Inject; 27 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 28 | 29 | @Mixin(TheNetherBiomeCreator.class) 30 | public class TheNetherBiomeCreatorMixin { 31 | 32 | @Inject(method = "createSoulSandValley", at = @At("HEAD"), cancellable = true) 33 | private static void createSoulSandValley(CallbackInfoReturnable cir) { 34 | SpawnSettings spawnSettings = new SpawnSettings.Builder() 35 | .spawn(SpawnGroup.MONSTER, new SpawnSettings.SpawnEntry(EntityType.SKELETON, 20, 5, 5)) 36 | .spawn(SpawnGroup.MONSTER, new SpawnSettings.SpawnEntry(EntityType.GHAST, 50, 4, 4)) 37 | .spawn(SpawnGroup.MONSTER, new SpawnSettings.SpawnEntry(EntityType.ENDERMAN, 1, 4, 4)) 38 | .spawn(SpawnGroup.CREATURE, new SpawnSettings.SpawnEntry(EntityType.STRIDER, 60, 1, 2)) 39 | .spawn(SpawnGroup.MONSTER, new SpawnSettings.SpawnEntry(EntityType.WITCH, 1, 1, 1)) 40 | .spawnCost(EntityType.SKELETON, 0.7, 0.15) 41 | .spawnCost(EntityType.GHAST, 0.7, 0.15) 42 | .spawnCost(EntityType.ENDERMAN, 0.7, 0.15) 43 | .spawnCost(EntityType.STRIDER, 0.7, 0.15) 44 | .spawnCost(EntityType.WITCH, 0.7, 0.15) 45 | .build(); 46 | GenerationSettings.Builder builder = new GenerationSettings.Builder() 47 | .carver(GenerationStep.Carver.AIR, ConfiguredCarvers.NETHER_CAVE) 48 | .feature(GenerationStep.Feature.VEGETAL_DECORATION, MiscPlacedFeatures.SPRING_LAVA) 49 | .feature(GenerationStep.Feature.LOCAL_MODIFICATIONS, NetherPlacedFeatures.BASALT_PILLAR) 50 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.SPRING_OPEN) 51 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.PATCH_FIRE) 52 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.PATCH_SOUL_FIRE) 53 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.GLOWSTONE_EXTRA) 54 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.GLOWSTONE) 55 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.PATCH_CRIMSON_ROOTS) 56 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, OrePlacedFeatures.ORE_MAGMA) 57 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.SPRING_CLOSED) 58 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, OrePlacedFeatures.ORE_SOUL_SAND); 59 | DefaultBiomeFeatures.addNetherMineables(builder); 60 | cir.setReturnValue( 61 | new Biome.Builder() 62 | .precipitation(Biome.Precipitation.NONE) 63 | .temperature(2.0f).downfall(0.0f) 64 | .effects(new BiomeEffects.Builder() 65 | .waterColor(4159204) 66 | .waterFogColor(329011) 67 | .fogColor(1787717) 68 | .skyColor(getSkyColor()) 69 | .particleConfig(new BiomeParticleConfig(ParticleTypes.ASH, 0.00625f)) 70 | .loopSound(SoundEvents.AMBIENT_SOUL_SAND_VALLEY_LOOP) 71 | .moodSound(new BiomeMoodSound(SoundEvents.AMBIENT_SOUL_SAND_VALLEY_MOOD, 6000, 8, 2.0)) 72 | .additionsSound(new BiomeAdditionsSound(SoundEvents.AMBIENT_SOUL_SAND_VALLEY_ADDITIONS, 0.0111)) 73 | .music(MusicType.createIngameMusic(SoundEvents.MUSIC_NETHER_SOUL_SAND_VALLEY)) 74 | .build()) 75 | .spawnSettings(spawnSettings) 76 | .generationSettings(builder.build()) 77 | .build() 78 | ); 79 | 80 | } 81 | 82 | @Inject(method = "createBasaltDeltas", at = @At("HEAD"), cancellable = true) 83 | private static void createBasaltDeltas(CallbackInfoReturnable cir) { 84 | SpawnSettings spawnSettings = new SpawnSettings.Builder() 85 | .spawn(SpawnGroup.MONSTER, new SpawnSettings.SpawnEntry(EntityType.GHAST, 40, 1, 1)) 86 | .spawn(SpawnGroup.MONSTER, new SpawnSettings.SpawnEntry(EntityType.MAGMA_CUBE, 100, 2, 5)) 87 | .spawn(SpawnGroup.CREATURE, new SpawnSettings.SpawnEntry(EntityType.STRIDER, 60, 1, 2)) 88 | .spawn(SpawnGroup.MONSTER, new SpawnSettings.SpawnEntry(EntityType.SLIME, 10, 2, 5)) 89 | .build(); 90 | GenerationSettings.Builder builder = new GenerationSettings.Builder() 91 | .carver(GenerationStep.Carver.AIR, ConfiguredCarvers.NETHER_CAVE) 92 | .feature(GenerationStep.Feature.SURFACE_STRUCTURES, NetherPlacedFeatures.DELTA) 93 | .feature(GenerationStep.Feature.SURFACE_STRUCTURES, NetherPlacedFeatures.SMALL_BASALT_COLUMNS) 94 | .feature(GenerationStep.Feature.SURFACE_STRUCTURES, NetherPlacedFeatures.LARGE_BASALT_COLUMNS) 95 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.BASALT_BLOBS) 96 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.BLACKSTONE_BLOBS) 97 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.SPRING_DELTA) 98 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.PATCH_FIRE) 99 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.PATCH_SOUL_FIRE) 100 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.GLOWSTONE_EXTRA) 101 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.GLOWSTONE) 102 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, VegetationPlacedFeatures.BROWN_MUSHROOM_NETHER) 103 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, VegetationPlacedFeatures.RED_MUSHROOM_NETHER) 104 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, OrePlacedFeatures.ORE_MAGMA) 105 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.SPRING_CLOSED_DOUBLE) 106 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, OrePlacedFeatures.ORE_GOLD_DELTAS) 107 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, OrePlacedFeatures.ORE_QUARTZ_DELTAS); 108 | DefaultBiomeFeatures.addAncientDebris(builder); 109 | cir.setReturnValue( 110 | new Biome.Builder() 111 | .precipitation(Biome.Precipitation.NONE) 112 | .temperature(2.0f) 113 | .downfall(0.0f) 114 | .effects(new BiomeEffects.Builder() 115 | .waterColor(4159204) 116 | .waterFogColor(329011) 117 | .fogColor(6840176) 118 | .skyColor(getSkyColor()) 119 | .particleConfig(new BiomeParticleConfig(ParticleTypes.WHITE_ASH, 0.118093334f)) 120 | .loopSound(SoundEvents.AMBIENT_BASALT_DELTAS_LOOP) 121 | .moodSound(new BiomeMoodSound(SoundEvents.AMBIENT_BASALT_DELTAS_MOOD, 6000, 8, 2.0)) 122 | .additionsSound(new BiomeAdditionsSound(SoundEvents.AMBIENT_BASALT_DELTAS_ADDITIONS, 0.0111)) 123 | .music(MusicType.createIngameMusic(SoundEvents.MUSIC_NETHER_BASALT_DELTAS)).build()) 124 | .spawnSettings(spawnSettings) 125 | .generationSettings(builder.build()) 126 | .build() 127 | ); 128 | } 129 | 130 | @Inject(method = "createNetherWastes", at = @At("HEAD"), cancellable = true) 131 | private static void createNetherWastes(CallbackInfoReturnable cir){ 132 | SpawnSettings spawnSettings = new SpawnSettings.Builder() 133 | .spawn(SpawnGroup.MONSTER, new SpawnSettings.SpawnEntry(EntityType.GHAST, 50, 4, 4)) 134 | .spawn(SpawnGroup.MONSTER, new SpawnSettings.SpawnEntry(EntityType.ZOMBIFIED_PIGLIN, 100, 4, 4)) 135 | .spawn(SpawnGroup.MONSTER, new SpawnSettings.SpawnEntry(EntityType.MAGMA_CUBE, 2, 4, 4)) 136 | .spawn(SpawnGroup.MONSTER, new SpawnSettings.SpawnEntry(EntityType.ENDERMAN, 1, 4, 4)) 137 | .spawn(SpawnGroup.MONSTER, new SpawnSettings.SpawnEntry(EntityType.PIGLIN, 15, 4, 4)) 138 | .spawn(SpawnGroup.CREATURE, new SpawnSettings.SpawnEntry(EntityType.STRIDER, 60, 1, 2)) 139 | 140 | .spawn(SpawnGroup.CREATURE, new SpawnSettings.SpawnEntry(EntityType.WOLF, 20, 4, 4)) 141 | .spawn(SpawnGroup.CREATURE, new SpawnSettings.SpawnEntry(EntityType.COW, 20, 2, 4)) 142 | .spawn(SpawnGroup.CREATURE, new SpawnSettings.SpawnEntry(EntityType.SHEEP, 20, 2, 4)) 143 | .spawn(SpawnGroup.CREATURE, new SpawnSettings.SpawnEntry(EntityType.LLAMA, 20, 4, 6)) 144 | .spawn(SpawnGroup.CREATURE, new SpawnSettings.SpawnEntry(EntityType.HORSE, 20, 2, 6)) 145 | .spawn(SpawnGroup.CREATURE, new SpawnSettings.SpawnEntry(EntityType.DONKEY, 20, 1, 2)) 146 | 147 | .build(); 148 | GenerationSettings.Builder builder = new GenerationSettings.Builder() 149 | .carver(GenerationStep.Carver.AIR, ConfiguredCarvers.NETHER_CAVE) 150 | .feature(GenerationStep.Feature.VEGETAL_DECORATION, MiscPlacedFeatures.SPRING_LAVA); 151 | DefaultBiomeFeatures.addDefaultMushrooms(builder); 152 | builder 153 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.SPRING_OPEN) 154 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.PATCH_FIRE) 155 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.PATCH_SOUL_FIRE) 156 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.GLOWSTONE_EXTRA) 157 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.GLOWSTONE) 158 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, VegetationPlacedFeatures.BROWN_MUSHROOM_NETHER) 159 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, VegetationPlacedFeatures.RED_MUSHROOM_NETHER) 160 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, OrePlacedFeatures.ORE_MAGMA) 161 | .feature(GenerationStep.Feature.UNDERGROUND_DECORATION, NetherPlacedFeatures.SPRING_CLOSED); 162 | DefaultBiomeFeatures.addNetherMineables(builder); 163 | cir.setReturnValue( 164 | new Biome.Builder() 165 | .precipitation(Biome.Precipitation.NONE) 166 | .temperature(2.0f) 167 | .downfall(0.0f) 168 | .effects(new BiomeEffects.Builder() 169 | .waterColor(4159204) 170 | .waterFogColor(329011) 171 | .fogColor(0x330808) 172 | .skyColor(getSkyColor()) 173 | .loopSound(SoundEvents.AMBIENT_NETHER_WASTES_LOOP) 174 | .moodSound(new BiomeMoodSound(SoundEvents.AMBIENT_NETHER_WASTES_MOOD, 6000, 8, 2.0)) 175 | .additionsSound(new BiomeAdditionsSound(SoundEvents.AMBIENT_NETHER_WASTES_ADDITIONS, 0.0111)) 176 | .music(MusicType.createIngameMusic(SoundEvents.MUSIC_NETHER_NETHER_WASTES)).build()) 177 | .spawnSettings(spawnSettings) 178 | .generationSettings(builder.build()) 179 | .build() 180 | ); 181 | } 182 | 183 | private static int getSkyColor() { 184 | float temperature = MathHelper.clamp(2.0f / 3.0f, -1.0f, 1.0f); 185 | return MathHelper.hsvToRgb(0.62222224f - temperature * 0.05f, 0.5f + temperature * 0.1f, 1.0f); 186 | } 187 | 188 | } 189 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/WanderingTraderManagerMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import dev.dubhe.skyland.SkyLandGamerules; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.entity.EntityType; 6 | import net.minecraft.entity.SpawnReason; 7 | import net.minecraft.entity.passive.StriderEntity; 8 | import net.minecraft.entity.passive.WanderingTraderEntity; 9 | import net.minecraft.fluid.Fluids; 10 | import net.minecraft.server.network.ServerPlayerEntity; 11 | import net.minecraft.server.world.ServerWorld; 12 | import net.minecraft.tag.BiomeTags; 13 | import net.minecraft.util.math.BlockPos; 14 | import net.minecraft.util.math.random.Random; 15 | import net.minecraft.world.BlockView; 16 | import net.minecraft.world.Heightmap.Type; 17 | import net.minecraft.world.WanderingTraderManager; 18 | import net.minecraft.world.level.ServerWorldProperties; 19 | import net.minecraft.world.poi.PointOfInterestStorage; 20 | import net.minecraft.world.poi.PointOfInterestTypes; 21 | import org.jetbrains.annotations.Nullable; 22 | import org.spongepowered.asm.mixin.Final; 23 | import org.spongepowered.asm.mixin.Mixin; 24 | import org.spongepowered.asm.mixin.Shadow; 25 | import org.spongepowered.asm.mixin.injection.At; 26 | import org.spongepowered.asm.mixin.injection.Inject; 27 | import org.spongepowered.asm.mixin.injection.Redirect; 28 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 29 | 30 | import java.util.Optional; 31 | 32 | @Mixin(WanderingTraderManager.class) 33 | public abstract class WanderingTraderManagerMixin { 34 | 35 | @Shadow 36 | @Final 37 | private Random random; 38 | 39 | @Shadow 40 | @Final 41 | private ServerWorldProperties properties; 42 | 43 | @Redirect(method = "trySpawn", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/math/random/Random;nextInt(I)I")) 44 | private int spawnX10(Random random, int value, ServerWorld world) { 45 | return world.getGameRules().getBoolean(SkyLandGamerules.CHIEFTAIN) ? 0 : random.nextInt(value); 46 | } 47 | 48 | @Inject(method = "trySpawn", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerWorld;getRandomAlivePlayer()Lnet/minecraft/server/network/ServerPlayerEntity;", shift = At.Shift.AFTER), cancellable = true) 49 | private void spawn(ServerWorld world, CallbackInfoReturnable cir) { 50 | if (world.getGameRules().getBoolean(SkyLandGamerules.NETHER_TRADER)) { 51 | ServerPlayerEntity playerEntity = world.getRandomAlivePlayer(); 52 | if (!world.getGameRules().getBoolean(SkyLandGamerules.CHIEFTAIN) && this.random.nextFloat() >= 0.1) { 53 | cir.setReturnValue(false); 54 | } 55 | if (playerEntity != null) { 56 | BlockPos blockPos = playerEntity.getBlockPos(); 57 | PointOfInterestStorage pointOfInterestStorage = world.getPointOfInterestStorage(); 58 | Optional optional = pointOfInterestStorage.getPosition( 59 | registryEntry -> registryEntry.matchesKey(PointOfInterestTypes.MEETING), pos -> true, blockPos, 60 | 48, PointOfInterestStorage.OccupationStatus.ANY); 61 | BlockPos blockPos2 = optional.orElse(blockPos); 62 | BlockPos blockPos3 = this.getNearbySpawnPos(world, blockPos2); 63 | if (blockPos3 != null && this.doesNotSuffocateAt(world, blockPos3)) { 64 | if (world.getBiome(blockPos3).isIn(BiomeTags.IS_NETHER)) { 65 | StriderEntity striderEntity = EntityType.STRIDER.spawn(world, null, null, null, blockPos3, 66 | SpawnReason.EVENT, false, false); 67 | WanderingTraderEntity wanderingTraderEntity = EntityType.WANDERING_TRADER.spawn(world, null, 68 | null, null, blockPos3, SpawnReason.EVENT, false, false); 69 | if (wanderingTraderEntity != null) { 70 | if (striderEntity != null) { 71 | striderEntity.saddle(null); 72 | wanderingTraderEntity.startRiding(striderEntity, true); 73 | } 74 | properties.setWanderingTraderId(wanderingTraderEntity.getUuid()); 75 | wanderingTraderEntity.setDespawnDelay(48000); 76 | wanderingTraderEntity.setWanderTarget(blockPos2); 77 | wanderingTraderEntity.setPositionTarget(blockPos2, 16); 78 | cir.setReturnValue(true); 79 | } 80 | } 81 | } 82 | } 83 | } 84 | } 85 | 86 | @Nullable 87 | private BlockPos getNearbySpawnPos(ServerWorld world, BlockPos pos) { 88 | BlockPos blockPos = null; 89 | 90 | for (int i = 0; i < 10; ++i) { 91 | int j = pos.getX() + this.random.nextInt(48 * 2) - 48; 92 | int k = pos.getZ() + this.random.nextInt(48 * 2) - 48; 93 | int l = world.getTopY(Type.WORLD_SURFACE, j, k); 94 | BlockPos blockPos2 = new BlockPos(j, l, k); 95 | BlockPos blockPos3 = new BlockPos(j, l - 1, k); 96 | BlockState blockState = world.getBlockState(blockPos3); 97 | if (blockState.getFluidState().isOf(Fluids.LAVA) && blockState.getFluidState().isStill()) { 98 | blockPos = blockPos2; 99 | break; 100 | } 101 | } 102 | 103 | return blockPos; 104 | } 105 | 106 | @Shadow 107 | protected abstract boolean doesNotSuffocateAt(BlockView world, BlockPos pos); 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/WaterCreatureEntityMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import net.minecraft.block.Blocks; 4 | import net.minecraft.entity.EntityType; 5 | import net.minecraft.entity.SpawnReason; 6 | import net.minecraft.entity.mob.WaterCreatureEntity; 7 | import net.minecraft.tag.FluidTags; 8 | import net.minecraft.util.math.BlockPos; 9 | import net.minecraft.util.math.random.Random; 10 | import net.minecraft.world.WorldAccess; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 15 | 16 | @Mixin(WaterCreatureEntity.class) 17 | public class WaterCreatureEntityMixin { 18 | 19 | @Inject(method = "canSpawn(Lnet/minecraft/entity/EntityType;Lnet/minecraft/world/WorldAccess;Lnet/minecraft/entity/SpawnReason;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/random/Random;)Z", at = @At("RETURN"), cancellable = true) 20 | private static void canSpawn(EntityType type, WorldAccess world, SpawnReason reason, 21 | BlockPos pos, Random random, CallbackInfoReturnable cir){ 22 | boolean bl = world.getFluidState(pos).isIn(FluidTags.WATER); 23 | while (world.getFluidState(pos).isIn(FluidTags.WATER)){ 24 | pos = pos.down(); 25 | } 26 | boolean bl2 = world.getBlockState(pos).isOf(Blocks.BRAIN_CORAL_BLOCK) || 27 | world.getBlockState(pos).isOf(Blocks.BUBBLE_CORAL_BLOCK) || 28 | world.getBlockState(pos).isOf(Blocks.FIRE_CORAL_BLOCK) || 29 | world.getBlockState(pos).isOf(Blocks.BUBBLE_CORAL_BLOCK) || 30 | world.getBlockState(pos).isOf(Blocks.TUBE_CORAL_BLOCK); 31 | cir.setReturnValue(bl && bl2); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/WorldPresetsRegistrarMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import dev.dubhe.skyland.SkyLandMod; 4 | import dev.dubhe.skyland.SkyLandChunkGenerator; 5 | import net.minecraft.structure.StructureSet; 6 | import net.minecraft.tag.BlockTags; 7 | import net.minecraft.util.Identifier; 8 | import net.minecraft.util.math.intprovider.ConstantIntProvider; 9 | import net.minecraft.util.math.noise.DoublePerlinNoiseSampler; 10 | import net.minecraft.util.registry.BuiltinRegistries; 11 | import net.minecraft.util.registry.Registry; 12 | import net.minecraft.util.registry.RegistryEntry; 13 | import net.minecraft.util.registry.RegistryKey; 14 | import net.minecraft.world.biome.Biome; 15 | import net.minecraft.world.biome.source.BiomeSource; 16 | import net.minecraft.world.biome.source.MultiNoiseBiomeSource; 17 | import net.minecraft.world.biome.source.TheEndBiomeSource; 18 | import net.minecraft.world.dimension.DimensionOptions; 19 | import net.minecraft.world.dimension.DimensionType; 20 | import net.minecraft.world.gen.WorldPreset; 21 | import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; 22 | import org.spongepowered.asm.mixin.Final; 23 | import org.spongepowered.asm.mixin.Mixin; 24 | import org.spongepowered.asm.mixin.Shadow; 25 | import org.spongepowered.asm.mixin.injection.At; 26 | import org.spongepowered.asm.mixin.injection.Inject; 27 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 28 | 29 | import java.util.Map; 30 | import java.util.OptionalLong; 31 | 32 | @Mixin(targets = "net.minecraft.world.gen.WorldPresets$Registrar") 33 | public class WorldPresetsRegistrarMixin { 34 | 35 | @Final 36 | @Shadow 37 | private Registry worldPresetRegistry; 38 | @Final 39 | @Shadow 40 | private Registry biomeRegistry; 41 | @Final 42 | @Shadow 43 | private Registry structureSetRegistry; 44 | @Final 45 | @Shadow 46 | private Registry chunkGeneratorSettingsRegistry; 47 | @Final 48 | @Shadow 49 | private Registry noiseParametersRegistry; 50 | @Final 51 | @Shadow 52 | private RegistryEntry theNetherDimensionType; 53 | @Final 54 | @Shadow 55 | private Registry dimensionTypeRegistry; 56 | @Final 57 | @Shadow 58 | private RegistryEntry theEndDimensionType; 59 | 60 | private static final DimensionType overNether = new DimensionType(OptionalLong.of(18000L), false, true, true, false, 61 | 1.0, false, true, 0, 256, 128, BlockTags.INFINIBURN_NETHER, 62 | net.minecraft.world.dimension.DimensionTypes.THE_NETHER_ID, 0.1F, 63 | new DimensionType.MonsterSettings(true, true, ConstantIntProvider.create(11), 15)); 64 | 65 | private static final RegistryKey OVER_NETHER = RegistryKey.of(Registry.DIMENSION_TYPE_KEY, 66 | new Identifier("over_nether")); 67 | 68 | @Inject(method = "initAndGetDefault", at = @At("RETURN")) 69 | private void register(CallbackInfoReturnable> cir) { 70 | BuiltinRegistries.add(dimensionTypeRegistry, OVER_NETHER, overNether); 71 | DimensionOptions overworld = this.createSkyDimensionOptions( 72 | this.dimensionTypeRegistry.getOrCreateEntry(OVER_NETHER), 73 | MultiNoiseBiomeSource.Preset.NETHER.getBiomeSource(this.biomeRegistry), ChunkGeneratorSettings.NETHER); 74 | DimensionOptions nether = this.createSkyDimensionOptions(this.theNetherDimensionType, 75 | MultiNoiseBiomeSource.Preset.NETHER.getBiomeSource(this.biomeRegistry), ChunkGeneratorSettings.NETHER); 76 | DimensionOptions end = this.createSkyDimensionOptions(this.theEndDimensionType, 77 | new TheEndBiomeSource(this.biomeRegistry), ChunkGeneratorSettings.END); 78 | BuiltinRegistries.add(this.worldPresetRegistry, SkyLandMod.SKYLAND, new WorldPreset( 79 | Map.of(DimensionOptions.OVERWORLD, overworld, DimensionOptions.NETHER, nether, DimensionOptions.END, 80 | end))); 81 | } 82 | 83 | private DimensionOptions createSkyDimensionOptions(RegistryEntry type, BiomeSource biomes, 84 | RegistryKey key) { 85 | return new DimensionOptions(type, 86 | new SkyLandChunkGenerator(this.structureSetRegistry, this.noiseParametersRegistry, biomes, 87 | this.chunkGeneratorSettingsRegistry.getOrCreateEntry(key))); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/mixin/ZombieEntityMixin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.mixin; 2 | 3 | import dev.dubhe.skyland.SkyLandGamerules; 4 | import net.minecraft.entity.EntityType; 5 | import net.minecraft.entity.LivingEntity; 6 | import net.minecraft.entity.SpawnReason; 7 | import net.minecraft.entity.SpawnRestriction; 8 | import net.minecraft.entity.attribute.EntityAttributeModifier; 9 | import net.minecraft.entity.attribute.EntityAttributes; 10 | import net.minecraft.entity.damage.DamageSource; 11 | import net.minecraft.entity.mob.ZombieEntity; 12 | import net.minecraft.entity.mob.ZombieVillagerEntity; 13 | import net.minecraft.server.world.ServerWorld; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraft.util.math.MathHelper; 16 | import net.minecraft.util.math.random.Random; 17 | import net.minecraft.world.Difficulty; 18 | import net.minecraft.world.GameRules; 19 | import net.minecraft.world.SpawnHelper; 20 | import net.minecraft.world.World; 21 | import org.spongepowered.asm.mixin.Mixin; 22 | import org.spongepowered.asm.mixin.injection.At; 23 | import org.spongepowered.asm.mixin.injection.Inject; 24 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 25 | 26 | import java.util.Objects; 27 | 28 | @Mixin(ZombieEntity.class) 29 | public class ZombieEntityMixin { 30 | 31 | protected final Random random = Random.create(); 32 | 33 | @Inject(method = "damage", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/mob/ZombieEntity;getTarget()Lnet/minecraft/entity/LivingEntity;", shift = At.Shift.AFTER), cancellable = true) 34 | private void zombieVillager(DamageSource source, float amount, CallbackInfoReturnable cir) { 35 | ZombieEntity zombie = (ZombieEntity) (Object) this; 36 | World world = zombie.world; 37 | if (world.getGameRules().getBoolean(SkyLandGamerules.VILLAGER_REINFORCEMENTS)) { 38 | LivingEntity livingEntity = zombie.getTarget(); 39 | if (livingEntity == null && source.getAttacker() instanceof LivingEntity) { 40 | livingEntity = (LivingEntity) source.getAttacker(); 41 | } 42 | if (livingEntity != null && world.getDifficulty() == Difficulty.HARD && (double) this.random.nextFloat() < ( 43 | zombie.getAttributeValue(EntityAttributes.ZOMBIE_SPAWN_REINFORCEMENTS) * 2.0) 44 | && world.getGameRules().getBoolean(GameRules.DO_MOB_SPAWNING) 45 | && world instanceof ServerWorld serverWorld) { 46 | int i = MathHelper.floor(zombie.getX()); 47 | int j = MathHelper.floor(zombie.getY()); 48 | int k = MathHelper.floor(zombie.getZ()); 49 | ZombieVillagerEntity zombieVillager = new ZombieVillagerEntity(EntityType.ZOMBIE_VILLAGER, serverWorld); 50 | for (int l = 0; l < 50; ++l) { 51 | int m = i + MathHelper.nextInt(random, 7, 40) * MathHelper.nextInt(this.random, -1, 1); 52 | int n = j + MathHelper.nextInt(random, 7, 40) * MathHelper.nextInt(this.random, -1, 1); 53 | int o = k + MathHelper.nextInt(random, 7, 40) * MathHelper.nextInt(this.random, -1, 1); 54 | BlockPos blockPos = new BlockPos(m, n, o); 55 | EntityType entityType = zombieVillager.getType(); 56 | SpawnRestriction.Location location = SpawnRestriction.getLocation(entityType); 57 | if (!SpawnHelper.canSpawn(location, world, blockPos, entityType) || !SpawnRestriction.canSpawn( 58 | entityType, serverWorld, SpawnReason.REINFORCEMENT, blockPos, world.random)) { 59 | continue; 60 | } 61 | zombieVillager.setPosition(m, n, o); 62 | if (world.isPlayerInRange(m, n, o, 7.0) || !world.doesNotIntersectEntities(zombieVillager) 63 | || !world.isSpaceEmpty(zombieVillager) || world.containsFluid( 64 | zombieVillager.getBoundingBox())) { 65 | continue; 66 | } 67 | zombieVillager.setTarget(livingEntity); 68 | zombieVillager.initialize(serverWorld, world.getLocalDifficulty(zombieVillager.getBlockPos()), 69 | SpawnReason.REINFORCEMENT, null, null); 70 | serverWorld.spawnEntityAndPassengers(zombieVillager); 71 | Objects.requireNonNull(zombie.getAttributeInstance(EntityAttributes.ZOMBIE_SPAWN_REINFORCEMENTS)) 72 | .addPersistentModifier( 73 | new EntityAttributeModifier("Zombie reinforcement caller charge", -0.05f, 74 | EntityAttributeModifier.Operation.ADDITION)); 75 | Objects.requireNonNull( 76 | zombieVillager.getAttributeInstance(EntityAttributes.ZOMBIE_SPAWN_REINFORCEMENTS)) 77 | .addPersistentModifier( 78 | new EntityAttributeModifier("Zombie reinforcement callee charge", -0.05f, 79 | EntityAttributeModifier.Operation.ADDITION)); 80 | break; 81 | } 82 | } 83 | } 84 | cir.setReturnValue(true); 85 | } 86 | } -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/plugin/ComposterCoolDownProvider.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.plugin; 2 | 3 | import dev.dubhe.skyland.ComposterCoolDown; 4 | import dev.dubhe.skyland.SkyLandMod; 5 | import net.minecraft.block.Blocks; 6 | import net.minecraft.text.Text; 7 | import net.minecraft.util.Identifier; 8 | import snownee.jade.api.BlockAccessor; 9 | import snownee.jade.api.IBlockComponentProvider; 10 | import snownee.jade.api.ITooltip; 11 | import snownee.jade.api.config.IPluginConfig; 12 | 13 | public enum ComposterCoolDownProvider implements IBlockComponentProvider { 14 | INSTANCE; 15 | 16 | @Override 17 | public void appendTooltip(ITooltip iTooltip, BlockAccessor blockAccessor, IPluginConfig iPluginConfig) { 18 | if (blockAccessor.getBlock() == Blocks.COMPOSTER) { 19 | if (ComposterCoolDown.cool_down > 0) { 20 | iTooltip.add(Text.translatable("skyland.tooltip.cool_down", ComposterCoolDown.cool_down)); 21 | } else { 22 | iTooltip.add(Text.translatable("skyland.tooltip.ready")); 23 | } 24 | } 25 | } 26 | 27 | @Override 28 | public Identifier getUid() { 29 | return new Identifier(SkyLandMod.MOD_ID, "composter_cool_down"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/dev/dubhe/skyland/plugin/ComposterPlugin.java: -------------------------------------------------------------------------------- 1 | package dev.dubhe.skyland.plugin; 2 | 3 | import net.minecraft.block.ComposterBlock; 4 | import snownee.jade.api.IWailaClientRegistration; 5 | import snownee.jade.api.IWailaCommonRegistration; 6 | import snownee.jade.api.IWailaPlugin; 7 | 8 | public class ComposterPlugin implements IWailaPlugin { 9 | 10 | @Override 11 | public void register(IWailaCommonRegistration registration) { 12 | IWailaPlugin.super.register(registration); 13 | } 14 | 15 | @Override 16 | public void registerClient(IWailaClientRegistration registration) { 17 | IWailaPlugin.super.registerClient(registration); 18 | registration.registerBlockComponent(ComposterCoolDownProvider.INSTANCE, ComposterBlock.class); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/assets/skyland/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator.skyland.skyland": "SkyLand", 3 | "gamerule.qnmdLC": "qnmdLC", 4 | "gamerule.chieftainMode": "Chieftain Mode", 5 | "gamerule.waterCauldron": "Water Cauldron Turn lava into Obsidian", 6 | "gamerule.netherTrader": "Nether Trader", 7 | "gamerule.iceGolem": "Snow golem can turn water into ice", 8 | "gamerule.anvilHandle": "Anvil Handle", 9 | "gamerule.netherPatrol": "Nether Patrol", 10 | "gamerule.villagerReinforcements": "Villager Reinforcements", 11 | "gamerule.killDragonSpawnShulker": "Kill Dragon Spawn Shulker", 12 | "gamerule.killDragonDropElytra": "Kill Dragon Drop Elytra", 13 | "gamerule.composterBoneMeal": "Squat down in a composter to get bone meal", 14 | "gamerule.memoryFoodLevel": "Memories of satiety before death", 15 | "gamerule.respawnMinFoodLevel": "Minimum satiety after respawn", 16 | 17 | "skyland.command.gamerule_set_succeed": "SkyLand gamerules set to %s succeed", 18 | 19 | "advancement.skyland.ancient_debris.title": "Netherite ingot", 20 | "advancement.skyland.ancient_debris.desc": "When have Hero Of The Village effect, the toolsmith will have a chance to throw Ancient Debris to the player", 21 | "advancement.skyland.bedrock_layer.title": "Bedrock layer", 22 | "advancement.skyland.bedrock_layer.desc": "Increased chance of spawning monsters on low Y platforms", 23 | "advancement.skyland.better_wood.title": "Better wood", 24 | "advancement.skyland.better_wood.desc": "The wandering Trader will ride a strider to have a chance to generate on the lava (the generation mechanism is the same as the vanilla, but requires lava)", 25 | "advancement.skyland.blast_furnace.title": "Blast furnace", 26 | "advancement.skyland.blast_furnace.desc": "Trade from piglins to get what you need to craft a blast furnace", 27 | "advancement.skyland.breed_villagers.title": "Breed villagers", 28 | "advancement.skyland.breed_villagers.desc": "Emeralds obtained from raids buy bread and apples from villagers to breed villagers", 29 | "advancement.skyland.bulk_lava.title": "Lava batching", 30 | "advancement.skyland.bulk_lava.desc": "Basalt can be washed in a cauldron to obtain Dripstone Block, which will drop Pointed Dripstone cones when smashed by an anvil.", 31 | "advancement.skyland.composter.title": "Composter!", 32 | "advancement.skyland.composter.desc": "Compost in a composter to get Bone Meal", 33 | "advancement.skyland.coral_fan.title": "Coral", 34 | "advancement.skyland.coral_fan.desc": "Use bone meal on the side of the coral block to make it grow a coral fan, and use bone meal on the top to grow coral", 35 | "advancement.skyland.elytra.title": "Damaged elytra", 36 | "advancement.skyland.elytra.desc": "When killing an ender dragon, elytra will drop at the location where the dragon died", 37 | "advancement.skyland.gold_ingot.title": "Gold_ingot!", 38 | "advancement.skyland.gold_ingot.desc": "Killing zombified piglin has a chance to get gold nuggets and gold ingots", 39 | "advancement.skyland.ice.title": "Artificial Ice", 40 | "advancement.skyland.ice.desc": "Snow golems standing on water will turn the water under their feet into ice", 41 | "advancement.skyland.kill_wrong.title": "Kill wrong(っ °Д °;)っ", 42 | "advancement.skyland.kill_wrong.desc": "Zombie reinforcements from zombified piglins will spawn zombie villagers", 43 | "advancement.skyland.kill_zombified_piglin.title": "Kill Zombified piglin", 44 | "advancement.skyland.kill_zombified_piglin.desc": "Build a spawning platform to kill Zombified piglin", 45 | "advancement.skyland.lava_bucket.title": "Lava Bucket", 46 | "advancement.skyland.lava_bucket.desc": "When have Hero Of The Village effect, the leatherworker will have a chance to throw Lava Bucket to the player", 47 | "advancement.skyland.netherrack.title": "Netherrack", 48 | "advancement.skyland.netherrack.desc": "Netherrack can be obtained by firing nether wart blocks in a blast furnace", 49 | "advancement.skyland.respawn.title": "Respawn", 50 | "advancement.skyland.respawn.desc": "There is no bed in the nether, can use the respawn anchor to revive", 51 | "advancement.skyland.root.title": "Nether Skyblock", 52 | "advancement.skyland.root.desc": "Start your Nether Skyblock journey\nUse the §b/skyland gamerule true§a command to open the desired rule before starting", 53 | "advancement.skyland.save_villager.title": "Save the villagers", 54 | "advancement.skyland.save_villager.desc": "There is only one apple to save the villagers (be careful to back up the world to avoid saving foolish villagers)", 55 | "advancement.skyland.shulker_box.title": "Shulker Box", 56 | "advancement.skyland.shulker_box.desc": "After killing the resurrected ender dragon, shulkers will spawn above the altar", 57 | "advancement.skyland.slime.title": "Slime", 58 | "advancement.skyland.slime.desc": "Slimes and magma cubes spawn together in the Basalt Delta biome", 59 | "advancement.skyland.the_end.title": "The End?", 60 | "advancement.skyland.the_end.desc": "With the initial platform as the center and a radius of 1024, 8 end portal frames will be generated.", 61 | "advancement.skyland.village_hero.title": "Village hero", 62 | "advancement.skyland.village_hero.desc": "Gain Bad Omen and Hero Of The Village.\nLooting squads spawn inside Blackrock fortress structures", 63 | "advancement.skyland.water.title": "Water source", 64 | "advancement.skyland.water.desc": "Water can be placed in the end", 65 | "advancement.skyland.weakness.title": "Weakness", 66 | "advancement.skyland.weakness.desc": "There is a very low chance for witches to spawn in Soul Sand Valley", 67 | "advancement.skyland.wood.title": "Wood!", 68 | "advancement.skyland.wood.desc": "Use bone meal to ripen Crimson Fungus to obtain wood", 69 | 70 | "skyland.tooltip.cool_down": "Cool down: %d", 71 | "skyland.tooltip.ready": "Ready", 72 | "config.jade.plugin_skyland.composter_cool_down": "Composter cool down" 73 | } -------------------------------------------------------------------------------- /src/main/resources/assets/skyland/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator.skyland.skyland": "空岛", 3 | "gamerule.qnmdLC": "忽略LC值影响", 4 | "gamerule.chieftainMode": "非酋模式", 5 | "gamerule.waterCauldron": "储水炼药锅将熔岩变为黑曜石", 6 | "gamerule.netherTrader": "下界游商", 7 | "gamerule.iceGolem": "雪傀儡可以将水变为冰", 8 | "gamerule.anvilHandle": "铁砧处理", 9 | "gamerule.netherPatrol": "下界灾厄巡逻队", 10 | "gamerule.villagerReinforcements": "村民增援", 11 | "gamerule.killDragonSpawnShulker": "龙亡贝诞", 12 | "gamerule.killDragonDropElytra": "战龙夺翅", 13 | "gamerule.composterBoneMeal": "在堆肥桶下蹲获得骨粉", 14 | "gamerule.memoryFoodLevel": "记忆死亡前的饱食度", 15 | "gamerule.respawnMinFoodLevel": "重生后的最低饱食度", 16 | 17 | "skyland.command.gamerule_set_succeed": "SkyLand 规则设置到 %s 成功", 18 | 19 | "advancement.skyland.ancient_debris.title": "下界合金", 20 | "advancement.skyland.ancient_debris.desc": "拥有村庄英雄状态效果时,工具匠会有概率丢远古残骸给玩家", 21 | "advancement.skyland.bedrock_layer.title": "基岩层", 22 | "advancement.skyland.bedrock_layer.desc": "在低Y的平台生成怪物的概率提升", 23 | "advancement.skyland.better_wood.title": "更好的木头", 24 | "advancement.skyland.better_wood.desc": "游商会骑着炽足兽在熔岩上生成概率生成(生成机制原版一样,不过需要熔岩)", 25 | "advancement.skyland.blast_furnace.title": "高炉", 26 | "advancement.skyland.blast_furnace.desc": "向猪灵交易获得所需的东西来合成高炉", 27 | "advancement.skyland.breed_villagers.title": "繁殖村民", 28 | "advancement.skyland.breed_villagers.desc": "袭击获得的绿宝石向村民购买面包与苹果来繁殖村民", 29 | "advancement.skyland.bulk_lava.title": "熔岩批量化", 30 | "advancement.skyland.bulk_lava.desc": "玄武岩在炼药锅里洗涤能获得滴水石块,滴水石块被铁砧砸会掉落滴水石锥", 31 | "advancement.skyland.composter.title": "堆肥桶!", 32 | "advancement.skyland.composter.desc": "在堆肥桶中堆肥可以获得骨粉", 33 | "advancement.skyland.coral_fan.title": "珊瑚", 34 | "advancement.skyland.coral_fan.desc": "对着珊瑚块侧面使用骨粉使之生长出珊瑚扇,对其顶面使用骨粉生长出珊瑚", 35 | "advancement.skyland.elytra.title": "损坏的翅膀", 36 | "advancement.skyland.elytra.desc": "击杀末影龙时,鞘翅会在龙死亡的位置掉落", 37 | "advancement.skyland.gold_ingot.title": "金锭!", 38 | "advancement.skyland.gold_ingot.desc": "击杀僵尸猪灵会有概率获得金粒和金锭", 39 | "advancement.skyland.ice.title": "人工冰", 40 | "advancement.skyland.ice.desc": "雪傀儡站在水上会将脚下的水变为冰", 41 | "advancement.skyland.kill_wrong.title": "杀错了(っ °Д °;)っ", 42 | "advancement.skyland.kill_wrong.desc": "僵尸猪灵触发的僵尸增援会生成僵尸村民", 43 | "advancement.skyland.kill_zombified_piglin.title": "击杀僵尸猪灵", 44 | "advancement.skyland.kill_zombified_piglin.desc": "搭建刷怪平台杀死僵尸猪灵", 45 | "advancement.skyland.lava_bucket.title": "熔岩桶", 46 | "advancement.skyland.lava_bucket.desc": "拥有村庄英雄状态效果时,皮匠会有概率丢熔岩桶给玩家", 47 | "advancement.skyland.netherrack.title": "下界岩", 48 | "advancement.skyland.netherrack.desc": "在高炉里烧制下界疣块可以获得下界岩", 49 | "advancement.skyland.respawn.title": "重生", 50 | "advancement.skyland.respawn.desc": "虽然下界不能使用床但是能使用重生锚来重生", 51 | "advancement.skyland.root.title": "Nether Skyblock", 52 | "advancement.skyland.root.desc": "开始你的 Nether Skyblock 之旅\n在开始之前使用 §b/skyland gamerule true§a 命令打开需要的规则", 53 | "advancement.skyland.save_villager.title": "拯救村民", 54 | "advancement.skyland.save_villager.desc": "只有一个苹果来救村民(注意备份存档免救到傻子村民)", 55 | "advancement.skyland.shulker_box.title": "潜影盒", 56 | "advancement.skyland.shulker_box.desc": "击杀复活后的末影龙后,潜影贝会生成在返回传送门上方", 57 | "advancement.skyland.slime.title": "史莱姆", 58 | "advancement.skyland.slime.desc": "在玄武岩三角洲群系史莱姆和岩浆怪会一同生成", 59 | "advancement.skyland.the_end.title": "末地?", 60 | "advancement.skyland.the_end.desc": "在以初始平台为圆心,半径1024,会固定生成8个末地传送门框架", 61 | "advancement.skyland.village_hero.title": "村庄英雄", 62 | "advancement.skyland.village_hero.desc": "获得不祥之兆和村庄英雄。\n在堡垒遗迹结构内会生成劫掠者", 63 | "advancement.skyland.water.title": "水源", 64 | "advancement.skyland.water.desc": "在末地可以放置水出来", 65 | "advancement.skyland.weakness.title": "虚弱", 66 | "advancement.skyland.weakness.desc": "在灵魂沙峡谷会有很低的概率生成女巫", 67 | "advancement.skyland.wood.title": "木头!", 68 | "advancement.skyland.wood.desc": "用骨粉催熟绯红菌获得木头", 69 | 70 | "skyland.tooltip.cool_down": "冷却: %d", 71 | "skyland.tooltip.ready": "就绪", 72 | "config.jade.plugin_skyland.composter_cool_down": "堆肥桶冷却" 73 | } -------------------------------------------------------------------------------- /src/main/resources/assets/skyland/lang/zh_hk.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator.skyland.skyland": "空島", 3 | "gamerule.qnmdLC": "忽略LC值影響", 4 | "gamerule.chieftainMode": "非酋模式", 5 | "gamerule.waterCauldron": "儲水煉藥鍋將熔岩變爲黑曜石", 6 | "gamerule.netherTrader": "地獄游商", 7 | "gamerule.iceGolem": "雪傀儡可以將水變為冰", 8 | "gamerule.anvilHandle": "鐵砧處理", 9 | "gamerule.netherPatrol": "地獄掠奪者巡邏隊", 10 | "gamerule.villagerReinforcements": "村民增援", 11 | "gamerule.killDragonSpawnShulker": "龍亡貝誕", 12 | "gamerule.killDragonDropElytra": "戰龍奪翅", 13 | "gamerule.composterBoneMeal": "在堆肥桶下蹲獲得骨粉", 14 | "gamerule.memoryFoodLevel": "記憶死亡前的飽食度", 15 | "gamerule.respawnMinFoodLevel": "重生後的最低飽食度", 16 | 17 | "skyland.command.gamerule_set_succeed": "SkyLand 規則設置到 %s 成功", 18 | 19 | 20 | "advancement.skyland.ancient_debris.title": "獄髓", 21 | "advancement.skyland.ancient_debris.desc": "擁有村莊英雄狀態效果時,工具匠會有概率給予玩家遠古遺骸", 22 | "advancement.skyland.bedrock_layer.title": "基岩層", 23 | "advancement.skyland.bedrock_layer.desc": "在低Y的平臺生成怪物的概率提升", 24 | "advancement.skyland.better_wood.title": "更好的木頭", 25 | "advancement.skyland.better_wood.desc": "流浪商人會騎著熾足獸在熔岩上生成(生成機制于原版相同,但是需要熔岩)", 26 | "advancement.skyland.blast_furnace.title": "高爐", 27 | "advancement.skyland.blast_furnace.desc": "于豬布林交易以獲取合成高爐的材料", 28 | "advancement.skyland.breed_villagers.title": "繁殖村民", 29 | "advancement.skyland.breed_villagers.desc": "用突襲事件中獲取的綠寶石向村民購買麵包于蘋果來繁殖村民", 30 | "advancement.skyland.bulk_lava.title": "熔岩批量化", 31 | "advancement.skyland.bulk_lava.desc": "玄武岩在鍋釜中洗滌能獲取鐘乳石方塊,鐘乳石方塊被鐵砧砸能獲取鐘乳石簇", 32 | "advancement.skyland.composter.title": "堆肥桶!", 33 | "advancement.skyland.composter.desc": "在堆肥桶中堆肥可以獲得骨粉", 34 | "advancement.skyland.coral_fan.title": "珊瑚", 35 | "advancement.skyland.coral_fan.desc": "對著珊瑚塊側面使用骨粉使之生長出珊瑚扇,對其頂面使用骨粉生長出珊瑚", 36 | "advancement.skyland.elytra.title": "損壞的翅膀", 37 | "advancement.skyland.elytra.desc": "擊殺終界龍时,鞘翅會在龍死亡的位置掉落", 38 | "advancement.skyland.gold_ingot.title": "金錠!", 39 | "advancement.skyland.gold_ingot.desc": "擊殺殭屍化豬布林會有概率獲得金粒和金錠", 40 | "advancement.skyland.ice.title": "人工冰", 41 | "advancement.skyland.ice.desc": "雪人站在水上會將脚下的水變成冰", 42 | "advancement.skyland.kill_wrong.title": "殺錯了(っ °Д °;)っ", 43 | "advancement.skyland.kill_wrong.desc": "僵屍化豬布林觸發的僵屍增援會生成殭屍村民", 44 | "advancement.skyland.kill_zombified_piglin.title": "擊殺僵屍化豬布林", 45 | "advancement.skyland.kill_zombified_piglin.desc": "搭建刷怪平臺殺死僵屍化豬布林", 46 | "advancement.skyland.lava_bucket.title": "熔岩桶", 47 | "advancement.skyland.lava_bucket.desc": "擁有村莊英雄狀態效果時,皮匠有概率丟熔岩桶給玩家", 48 | "advancement.skyland.netherrack.title": "地獄岩", 49 | "advancement.skyland.netherrack.desc": "在高爐裏燒製地獄疙瘩塊可以獲得地獄岩", 50 | "advancement.skyland.respawn.title": "重生", 51 | "advancement.skyland.respawn.desc": "雖然地獄無法使用床,但你可以使用重生錨來重生", 52 | "advancement.skyland.root.title": "Nether Skyblock", 53 | "advancement.skyland.root.desc": "開始你的 Nether Skyblock 之旅\n在此之前 §b/skyland gamerule true§a 命令打開需要的游戲規則", 54 | "advancement.skyland.save_villager.title": "拯救村民", 55 | "advancement.skyland.save_villager.desc": "只有一個蘋果可以用來救村民(記得備份存檔以免救到傻子)", 56 | "advancement.skyland.shulker_box.title": "界伏盒", 57 | "advancement.skyland.shulker_box.desc": "擊殺復活后的終界龍后,界伏蚌会生成在終界池的上方", 58 | "advancement.skyland.slime.title": "史萊姆", 59 | "advancement.skyland.slime.desc": "在玄武岩三角洲史萊姆會和岩漿怪一同生成", 60 | "advancement.skyland.the_end.title": "終界?", 61 | "advancement.skyland.the_end.desc": "在以初始平臺為圓心,1024為半徑的位置上,會固定生成8個終界傳送門框架", 62 | "advancement.skyland.village_hero.title": "村莊英雄", 63 | "advancement.skyland.village_hero.desc": "獲得获得不祥之兆和村莊英雄。\n在堡壘遺跡結構内會生成掠奪者", 64 | "advancement.skyland.water.title": "水源", 65 | "advancement.skyland.water.desc": "在終界可以放置水出来", 66 | "advancement.skyland.weakness.title": "虛弱", 67 | "advancement.skyland.weakness.desc": "在靈魂沙峽谷會有很低的概率生成女巫", 68 | "advancement.skyland.wood.title": "木頭!", 69 | "advancement.skyland.wood.desc": "用骨粉催熟緋紅蕈菇獲得木頭", 70 | 71 | "skyland.tooltip.cool_down": "冷卻: %d", 72 | "skyland.tooltip.ready": "就緒", 73 | "config.jade.plugin_skyland.composter_cool_down": "堆肥桶冷卻" 74 | } -------------------------------------------------------------------------------- /src/main/resources/assets/skyland/lang/zh_tw.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator.skyland.skyland": "空島", 3 | "gamerule.qnmdLC": "忽略LC值影響", 4 | "gamerule.chieftainMode": "非酋模式", 5 | "gamerule.waterCauldron": "儲水煉藥鍋將熔岩變爲黑曜石", 6 | "gamerule.netherTrader": "地獄游商", 7 | "gamerule.iceGolem": "雪傀儡可以將水變為冰", 8 | "gamerule.anvilHandle": "鐵砧處理", 9 | "gamerule.netherPatrol": "地獄掠奪者巡邏隊", 10 | "gamerule.villagerReinforcements": "村民增援", 11 | "gamerule.killDragonSpawnShulker": "龍亡貝誕", 12 | "gamerule.killDragonDropElytra": "戰龍奪翅", 13 | "gamerule.composterBoneMeal": "在堆肥桶下蹲獲得骨粉", 14 | "gamerule.memoryFoodLevel": "記憶死亡前的飽食度", 15 | "gamerule.respawnMinFoodLevel": "重生後的最低飽食度", 16 | 17 | "skyland.command.gamerule_set_succeed": "SkyLand 規則設置到 %s 成功", 18 | 19 | 20 | "advancement.skyland.ancient_debris.title": "獄髓", 21 | "advancement.skyland.ancient_debris.desc": "擁有村莊英雄狀態效果時,工具匠會有概率給予玩家遠古遺骸", 22 | "advancement.skyland.bedrock_layer.title": "基岩層", 23 | "advancement.skyland.bedrock_layer.desc": "在低Y的平臺生成怪物的概率提升", 24 | "advancement.skyland.better_wood.title": "更好的木頭", 25 | "advancement.skyland.better_wood.desc": "流浪商人會騎著熾足獸在熔岩上生成(生成機制于原版相同,但是需要熔岩)", 26 | "advancement.skyland.blast_furnace.title": "高爐", 27 | "advancement.skyland.blast_furnace.desc": "于豬布林交易以獲取合成高爐的材料", 28 | "advancement.skyland.breed_villagers.title": "繁殖村民", 29 | "advancement.skyland.breed_villagers.desc": "用突襲事件中獲取的綠寶石向村民購買麵包于蘋果來繁殖村民", 30 | "advancement.skyland.bulk_lava.title": "熔岩批量化", 31 | "advancement.skyland.bulk_lava.desc": "玄武岩在鍋釜中洗滌能獲取鐘乳石方塊,鐘乳石方塊被鐵砧砸能獲取鐘乳石簇", 32 | "advancement.skyland.composter.title": "堆肥桶!", 33 | "advancement.skyland.composter.desc": "在堆肥桶中堆肥可以獲得骨粉", 34 | "advancement.skyland.coral_fan.title": "珊瑚", 35 | "advancement.skyland.coral_fan.desc": "對著珊瑚塊側面使用骨粉使之生長出珊瑚扇,對其頂面使用骨粉生長出珊瑚", 36 | "advancement.skyland.elytra.title": "損壞的翅膀", 37 | "advancement.skyland.elytra.desc": "擊殺終界龍时,鞘翅會在龍死亡的位置掉落", 38 | "advancement.skyland.gold_ingot.title": "金錠!", 39 | "advancement.skyland.gold_ingot.desc": "擊殺殭屍化豬布林會有概率獲得金粒和金錠", 40 | "advancement.skyland.ice.title": "人工冰", 41 | "advancement.skyland.ice.desc": "雪人站在水上會將脚下的水變成冰", 42 | "advancement.skyland.kill_wrong.title": "殺錯了(っ °Д °;)っ", 43 | "advancement.skyland.kill_wrong.desc": "僵屍化豬布林觸發的僵屍增援會生成殭屍村民", 44 | "advancement.skyland.kill_zombified_piglin.title": "擊殺僵屍化豬布林", 45 | "advancement.skyland.kill_zombified_piglin.desc": "搭建刷怪平臺殺死僵屍化豬布林", 46 | "advancement.skyland.lava_bucket.title": "熔岩桶", 47 | "advancement.skyland.lava_bucket.desc": "擁有村莊英雄狀態效果時,皮匠有概率丟熔岩桶給玩家", 48 | "advancement.skyland.netherrack.title": "地獄岩", 49 | "advancement.skyland.netherrack.desc": "在高爐裏燒製地獄疙瘩塊可以獲得地獄岩", 50 | "advancement.skyland.respawn.title": "重生", 51 | "advancement.skyland.respawn.desc": "雖然地獄無法使用床,但你可以使用重生錨來重生", 52 | "advancement.skyland.root.title": "Nether Skyblock", 53 | "advancement.skyland.root.desc": "開始你的 Nether Skyblock 之旅\n在此之前 §b/skyland gamerule true§a 命令打開需要的游戲規則", 54 | "advancement.skyland.save_villager.title": "拯救村民", 55 | "advancement.skyland.save_villager.desc": "只有一個蘋果可以用來救村民(記得備份存檔以免救到傻子)", 56 | "advancement.skyland.shulker_box.title": "界伏盒", 57 | "advancement.skyland.shulker_box.desc": "擊殺復活后的終界龍后,界伏蚌会生成在終界池的上方", 58 | "advancement.skyland.slime.title": "史萊姆", 59 | "advancement.skyland.slime.desc": "在玄武岩三角洲史萊姆會和岩漿怪一同生成", 60 | "advancement.skyland.the_end.title": "終界?", 61 | "advancement.skyland.the_end.desc": "在以初始平臺為圓心,1024為半徑的位置上,會固定生成8個終界傳送門框架", 62 | "advancement.skyland.village_hero.title": "村莊英雄", 63 | "advancement.skyland.village_hero.desc": "獲得获得不祥之兆和村莊英雄。\n在堡壘遺跡結構内會生成掠奪者", 64 | "advancement.skyland.water.title": "水源", 65 | "advancement.skyland.water.desc": "在終界可以放置水出来", 66 | "advancement.skyland.weakness.title": "虛弱", 67 | "advancement.skyland.weakness.desc": "在靈魂沙峽谷會有很低的概率生成女巫", 68 | "advancement.skyland.wood.title": "木頭!", 69 | "advancement.skyland.wood.desc": "用骨粉催熟緋紅蕈菇獲得木頭", 70 | 71 | "skyland.tooltip.cool_down": "冷卻: %d", 72 | "skyland.tooltip.ready": "就緒", 73 | "config.jade.plugin_skyland.composter_cool_down": "堆肥桶冷卻" 74 | } -------------------------------------------------------------------------------- /src/main/resources/data/minecraft/loot_tables/blocks/powder_snow.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:block", 3 | "pools": [ 4 | { 5 | "rolls": 1.0, 6 | "bonus_rolls": 0.0, 7 | "entries": [ 8 | { 9 | "type": "minecraft:item", 10 | "name": "minecraft:snowball" 11 | } 12 | ], 13 | "conditions": [ 14 | { 15 | "condition": "minecraft:survives_explosion" 16 | } 17 | ] 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /src/main/resources/data/minecraft/tags/mineable/shovel.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "values": [ 4 | "minecraft:clay", 5 | "minecraft:dirt", 6 | "minecraft:coarse_dirt", 7 | "minecraft:podzol", 8 | "minecraft:farmland", 9 | "minecraft:grass_block", 10 | "minecraft:gravel", 11 | "minecraft:mycelium", 12 | "minecraft:sand", 13 | "minecraft:red_sand", 14 | "minecraft:snow_block", 15 | "minecraft:snow", 16 | "minecraft:soul_sand", 17 | "minecraft:dirt_path", 18 | "minecraft:white_concrete_powder", 19 | "minecraft:orange_concrete_powder", 20 | "minecraft:magenta_concrete_powder", 21 | "minecraft:light_blue_concrete_powder", 22 | "minecraft:yellow_concrete_powder", 23 | "minecraft:lime_concrete_powder", 24 | "minecraft:pink_concrete_powder", 25 | "minecraft:gray_concrete_powder", 26 | "minecraft:light_gray_concrete_powder", 27 | "minecraft:cyan_concrete_powder", 28 | "minecraft:purple_concrete_powder", 29 | "minecraft:blue_concrete_powder", 30 | "minecraft:brown_concrete_powder", 31 | "minecraft:green_concrete_powder", 32 | "minecraft:red_concrete_powder", 33 | "minecraft:black_concrete_powder", 34 | "minecraft:soul_soil", 35 | "minecraft:rooted_dirt", 36 | "minecraft:powder_snow" 37 | ] 38 | } -------------------------------------------------------------------------------- /src/main/resources/data/minecraft/tags/worldgen/world_preset/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": [ 3 | "minecraft:normal", 4 | "minecraft:flat", 5 | "minecraft:large_biomes", 6 | "minecraft:amplified", 7 | "minecraft:single_biome_surface", 8 | "skyland:skyland" 9 | ] 10 | } -------------------------------------------------------------------------------- /src/main/resources/data/minecraft/worldgen/structure/bastion_remnant.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:jigsaw", 3 | "biomes": "#minecraft:has_structure/bastion_remnant", 4 | "max_distance_from_center": 80, 5 | "size": 6, 6 | "spawn_overrides": { 7 | "monster": { 8 | "bounding_box": "full", 9 | "spawns": [ 10 | { 11 | "type": "minecraft:pillager", 12 | "maxCount": 1, 13 | "minCount": 1, 14 | "weight": 1 15 | }, 16 | { 17 | "type": "minecraft:piglin", 18 | "maxCount": 5, 19 | "minCount": 2, 20 | "weight": 20 21 | }, 22 | { 23 | "type": "minecraft:zombified_piglin", 24 | "maxCount": 4, 25 | "minCount": 2, 26 | "weight": 10 27 | } 28 | ] 29 | } 30 | }, 31 | "start_height": { 32 | "absolute": 33 33 | }, 34 | "start_pool": "minecraft:bastion/starts", 35 | "step": "surface_structures", 36 | "use_expansion_hack": false 37 | } -------------------------------------------------------------------------------- /src/main/resources/data/skyland/structures/spawn_platform.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nether-Power/Nether-Sky-Block/d155f0f4b3898cd11a1a218cf6d359662c9c8c92/src/main/resources/data/skyland/structures/spawn_platform.nbt -------------------------------------------------------------------------------- /src/main/resources/data/skyland/structures/the_end_portal.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nether-Power/Nether-Sky-Block/d155f0f4b3898cd11a1a218cf6d359662c9c8c92/src/main/resources/data/skyland/structures/the_end_portal.nbt -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "skyland", 4 | "version": "${version}", 5 | "name": "NetherSkyBlock", 6 | "description": "A Mod for Minecraft Nether SkyBlock", 7 | "authors": [ 8 | "Nether-Power" 9 | ], 10 | "contact": { 11 | "sources": "https://github.com/XXiuBai/Nether_Sky_Block", 12 | "issues": "https://github.com/XXiuBai/Nether_Sky_Block/issues" 13 | }, 14 | "license": "LGPL-3.0-or-later", 15 | "icon": "pack.png", 16 | "environment": "*", 17 | "entrypoints": { 18 | "main": [ 19 | "dev.dubhe.skyland.SkyLandMod" 20 | ], 21 | "fabric-datagen": [ 22 | "dev.dubhe.skyland.data.SkyLandDataGenerator" 23 | ], 24 | "jade": [ 25 | "dev.dubhe.skyland.plugin.ComposterPlugin" 26 | ] 27 | }, 28 | "mixins": [ 29 | "skyland.mixins.json" 30 | ], 31 | "accessWidener": "skyland.accesswidener", 32 | "depends": { 33 | "minecraft": ">=1.19", 34 | "fabricloader": "*", 35 | "fabric": "*" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/resources/pack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nether-Power/Nether-Sky-Block/d155f0f4b3898cd11a1a218cf6d359662c9c8c92/src/main/resources/pack.png -------------------------------------------------------------------------------- /src/main/resources/skyland.accesswidener: -------------------------------------------------------------------------------- 1 | accessWidener v1 named 2 | extendable class net/minecraft/world/gen/chunk/NoiseChunkGenerator 3 | 4 | accessible class net/minecraft/village/TradeOffers$SellItemFactory 5 | -------------------------------------------------------------------------------- /src/main/resources/skyland.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "dev.dubhe.skyland.mixin", 4 | "compatibilityLevel": "JAVA_17", 5 | "mixins": [ 6 | "BoneMealItemMixin", 7 | "CauldronBlockMixin", 8 | "ChunkGeneratorsMixin", 9 | "EnderDragonFightMixin", 10 | "FallingBlockEntityMixin", 11 | "FluidBlockMixin", 12 | "LeveledCauldronBlockMixin", 13 | "MinecraftServerMixin", 14 | "PatrolSpawnerMixin", 15 | "PlayerInventoryMixin", 16 | "SellItemFactoryAccessor", 17 | "ServerPlayerEntityMixin", 18 | "ServerWorldMixin", 19 | "SlimeEntityMixin", 20 | "SnowGolemEntityMixin", 21 | "SpawnHelperMixin", 22 | "TheEndBiomeCreatorMixin", 23 | "TheNetherBiomeCreatorMixin", 24 | "WanderingTraderManagerMixin", 25 | "WaterCreatureEntityMixin", 26 | "WorldPresetsRegistrarMixin", 27 | "ZombieEntityMixin" 28 | ], 29 | "client": [ 30 | "IntegratedServerLoaderMixin" 31 | ], 32 | "injectors": { 33 | "defaultRequire": 1 34 | } 35 | } 36 | --------------------------------------------------------------------------------