Minecraft 1.18.1、1.18.2模组开发 15.自定义生成建筑(structure)

我们今天在1.18的模组中实现一个建筑的生成。

往期教程:

1.12.2自定义建筑生成

1.16.5自定义建筑生成

1.首先我们按照往常要制作一个建筑的并保存为nbt文件。B站教程

2.在Java包中新建一个world包 -> world包中新建一个 structure包 -> structure包中新建一个建筑类ChurchStructure

ChurchStructure.java

package com.joy187.re8joymod.world.structure;

import java.util.Optional;

import org.apache.logging.log4j.Level;

import com.joy187.re8joymod.Main;

import net.minecraft.core.BlockPos;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import net.minecraft.world.level.levelgen.feature.configurations.JigsawConfiguration;
import net.minecraft.world.level.levelgen.structure.BuiltinStructureSets;
import net.minecraft.world.level.levelgen.structure.PoolElementStructurePiece;
import net.minecraft.world.level.levelgen.structure.PostPlacementProcessor;
import net.minecraft.world.level.levelgen.structure.pieces.PieceGenerator;
import net.minecraft.world.level.levelgen.structure.pieces.PieceGeneratorSupplier;
import net.minecraft.world.level.levelgen.structure.pools.JigsawPlacement;

public class ChurchStructure extends StructureFeature<JigsawConfiguration>{
    public ChurchStructure() {
        // Create the pieces layout of the structure and give it to the game
        super(JigsawConfiguration.CODEC, ChurchStructure::createPiecesGenerator, PostPlacementProcessor.NONE);
    }
    
    @Override
    public GenerationStep.Decoration step() {
        return GenerationStep.Decoration.SURFACE_STRUCTURES;
    }


    private static boolean isFeatureChunk(PieceGeneratorSupplier.Context<JigsawConfiguration> context) {
        // Grabs the chunk position we are at
        ChunkPos chunkpos = context.chunkPos();

        // Checks to make sure our structure does not spawn within 10 chunks of an Ocean Monument
        // to demonstrate how this method is good for checking extra conditions for spawning
        return !context.chunkGenerator().hasFeatureChunkInRange(BuiltinStructureSets.VILLAGES, context.seed(), chunkpos.x, chunkpos.z, 10);
    }
    
    public static Optional<PieceGenerator<JigsawConfiguration>> createPiecesGenerator(PieceGeneratorSupplier.Context<JigsawConfiguration> context) {

        // Check if the spot is valid for our structure. This is just as another method for cleanness.
        // Returning an empty optional tells the game to skip this spot as it will not generate the structure.
        if (!ChurchStructure.isFeatureChunk(context)) {
            return Optional.empty();
        }

        // Turns the chunk coordinates into actual coordinates we can use. (Gets center of that chunk)
        BlockPos blockpos = context.chunkPos().getMiddleBlockPosition(0);

        // Find the top Y value of the land and then offset our structure to 60 blocks above that.
        // WORLD_SURFACE_WG will stop at top water so we don't accidentally put our structure into the ocean if it is a super deep ocean.
        int topLandY = context.chunkGenerator().getFirstFreeHeight(blockpos.getX(), blockpos.getZ(), Heightmap.Types.WORLD_SURFACE_WG, context.heightAccessor());
        
        //方块开始建造的位置,如果你改成 topLandY+40 的话就可以生成天空岛
        blockpos = blockpos.above(topLandY);

        Optional<PieceGenerator<JigsawConfiguration>> structurePiecesGenerator =
        		JigsawPlacement.addPieces(
                        context, // Used for JigsawPlacement to get all the proper behaviors done.
                        PoolElementStructurePiece::new, // Needed in order to create a list of jigsaw pieces when making the structure's layout.
                        blockpos, // Position of the structure. Y value is ignored if last parameter is set to true.
                        false,  // Special boundary adjustments for villages. It's... hard to explain. Keep this false and make your pieces not be partially intersecting.
                        // Either not intersecting or fully contained will make children pieces spawn just fine. It's easier that way.
                        false // Place at heightmap (top land). Set this to false for structure to be place at the passed in blockpos's Y value instead.
                        // Definitely keep this false when placing structures in the nether as otherwise, heightmap placing will put the structure on the Bedrock roof.
                );

        if(structurePiecesGenerator.isPresent()) {
            // 方便我们进入游戏后找到建筑.
            Main.LOGGER.log(Level.DEBUG, "Church Structrue is at {}", blockpos);
        }

        return structurePiecesGenerator;
    }
    
    
}

3.在structure包中新建一个ModStructures类对我们所有的建筑进行注册:

ModStructures.java

package com.joy187.re8joymod.world.structure;

import com.joy187.re8joymod.Main;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;

public class ModStructures {

    public static final DeferredRegister<StructureFeature<?>> DEFERRED_REGISTRY_STRUCTURE =
            DeferredRegister.create(ForgeRegistries.STRUCTURE_FEATURES, Main.MOD_ID);

    //我们刚刚的建筑类
    public static final RegistryObject<StructureFeature<?>> CHURCH_STRUCTURE =
            DEFERRED_REGISTRY_STRUCTURE.register("church_structure", ChurchStructure::new);
    
    //public static final RegistryObject<StructureFeature<?>> Tank_STRUCTURE =
    //        DEFERRED_REGISTRY_STRUCTURE.register("tank_structure", TankStructure::new);
    
    public static void register(IEventBus eventBus) {
        DEFERRED_REGISTRY_STRUCTURE.register(eventBus);
    }
    
}
在我们的项目主类的主函数中对所有建筑进行注册事件
	public Main() {
		IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();

		ItemInit.ITEMS.register(bus);
		BlockInit.BLOCKS.register(bus);
		EntityInit.ENTITY_TYPES.register(bus);
		EffectInit.EFFECTS.register(bus);
		PotionInit.POTIONS.register(bus);
		SoundInit.SOUNDS.register(bus);
		
		//添加这个
        ModStructures.register(bus);


		MinecraftForge.EVENT_BUS.register(this);
	}

4.代码部分结束,来到资源包制作环节:

数据包文件树

cr1.png

1.在resources\data\你的modid中新建structures包并将第一步的nbt建筑放进入其中
2.新建一个tags包 -> 包中新建worldgen包 -> 新建biome包 -> biome包中新建has_structure包 -> 新建我们的建筑文件用来指明建筑在哪些地形生成

church.json

{
  "replace": false,

  "_comment": " This biome tag can specify the biome directly. Or specify another biome tag by starting with # ",
  "values": [
    "#minecraft:is_jungle",
    "#minecraft:is_forest",
    "#minecraft:is_taiga",
    "minecraft:desert",
    "minecraft:plains",
    "minecraft:savanna",
    "minecraft:savanna_plateau"
  ]
}
3.新建一个worldgen包 -> 包中新建configured_structure_feature包 -> 包中新建一个建筑文件来

church.json

{
  // 第三步我们ModStructure.java中定义的建筑类
  "type": "re8joymod:church_structure",

  "config": {
    // 指明我们的建筑生成文件
    "start_pool": "re8joymod:church/start_pool",

    // This is how many pieces away from the starting piece a piece of the structure can spawn
    // Think of it like the length of the branch of the structure
    "size": 2
  },

  // 上一步我们的地形生成文件
  "biomes": "#re8joymod:has_structure/church",

  // If true, land will be add around the bottom of the structure. (Based on the starting piece's y value)
  "adapt_noise": true,

  //建筑中可以生成什么生物
  "spawn_overrides": {
    "creature": {
      "bounding_box": "piece",
      "spawns": [
        {
          "type": "minecraft:bat",
          //生成权重
          "weight": 1,
          //最少生成几个
          "minCount": 1,
          //最多几个
          "maxCount": 2
        }
      ]
    }
  }
}
4.在worldgen包中新建一个structure_set包 -> 包中新建一个建筑文件说明这个建筑内生成的所有建筑:

church.json

{
  // What structures to pick to try and spawn if a spot passes the placement check.
  // If two or more structures in this list can spawn in a biome at a spot, a random one based on weight is chosen to spawn
  "structures": [
    {
    //这个建筑是我们的nbt文件名称
      "structure": "re8joymod:church",
      "weight": 1
    }
  ],
  "placement": {
    // 这个数介于int范围之内,请设置一个独一无二的大小
    "salt": 2036674,

    // The average distance apart in chunks for spawn attempts
    "spacing": 20,

    // Minimum distance apart in chunks for spawn attempts
    // MUST ALWAYS BE SMALLER THAN spacing ABOVE
    "separation": 6,

    // The kind of placement to use. The other kind is ring based like strongholds use.
    "type": "minecraft:random_spread"
  }
}
5.worldgen包中新建一个template_pool包 -> 包中新建我们的建筑包church -> 包中新建start_pool.json文件说明我们建筑从哪里开始生成。

start_pool.json

{
//我们建筑的开始生成的文件
  "name": "re8joymod:church/start_pool",
  "fallback": "minecraft:empty",
  "elements": [
    {
      "weight": 1,
      "element": {
        "location": "re8joymod:church",
        "processors": "minecraft:empty",
        "projection": "rigid",
        "element_type": "minecraft:single_pool_element"
      }
    }
  ]
}

5.保存所有文件 -> 进入游戏

我们新建一个世界进行测试:

按T键进入命令行输入指令找到我们的建筑

/locate re8joymod:church

cr3.png

之后传送到建筑的位置

str.png

我们成功找到了生成的建筑!

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jay_fearless

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值