Minecraft 1.16.5模组开发(三十一) 自定义建筑生成(structure) (新)

如果你学习过我们之前在1.12.2的建筑生成教程,那么对本次的教程的理解可能会相对轻松。

往期回顾

Minecraft 1.12.2模组开发(十四) 建筑生成 (structure generation)
Minecraft 1.12.2模组开发(二十二) 多种建筑生成

我们本次将在1.16.5版本中实现建筑的自动生成。

1.首先我们需要生成一个建筑的.nbt文件

创建一个新世界

通过命令让我们获得一个建筑方块:

/give @s minecraft:structure_block

cr0.png

之后我们建造一个建筑

cr1.png

通过对建筑操作的坐标变换,将我们这个建筑完全包裹在区域内:

cr2.png

点击’Save’,建筑成功保存下来

cr3.png

保存的建筑会生成一个.nbt文件,我们需要将这个文件找到,路径为
开发包\run\saves\1_8version_test(你的存档名称)\generated\minecraft\structures

2.在data包中新建structures文件夹,将生成的.nbt文件放入其中。

cr4.png

3.在worldgen文件夹中新建template_pool(建筑模板库)文件夹 -> 新建一个与我们建筑名称对应的文件夹(以tank1为例) -> 在tank1中新建一个start_pool.json文件

在start_pool.json中编写:
{
  "name": "re8joymod:tank1/start_pool", //格式:模组名:建筑名称/start_pool的文件路径
  "fallback": "minecraft:empty",
  "elements": [
    {
      "weight": 1,
      "element": {
        "location": "re8joymod:tank1",  //格式:模组名:建筑名称
        "processors": "minecraft:empty",
        "projection": "rigid",
        "element_type": "minecraft:single_pool_element"
      }
    }
  ]
}

4.在common文件夹下新建 world文件夹 -> world文件夹中新建structure文件夹 -> structure文件夹中新建 structures文件夹 -> structures中新建一个建筑物类(以Tank1Structure.java为例)

cr5.png

在Tank1Structure.java中编写:
package com.joy187.re8joymod.common.world.structure.structures;

import com.google.common.collect.ImmutableList;
import com.mojang.serialization.Codec;
import net.minecraft.entity.EntityType;
import net.minecraft.util.SharedSeedRandom;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.MutableBoundingBox;
import net.minecraft.util.math.vector.Vector3i;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.MobSpawnInfo;
import net.minecraft.world.biome.provider.BiomeProvider;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraft.world.gen.GenerationStage;
import net.minecraft.world.gen.Heightmap;
import net.minecraft.world.gen.feature.NoFeatureConfig;
import net.minecraft.world.gen.feature.jigsaw.JigsawManager;
import net.minecraft.world.gen.feature.structure.*;
import net.minecraft.util.registry.DynamicRegistries;
import net.minecraft.world.gen.feature.template.TemplateManager;
import net.minecraft.block.BlockState;
import net.minecraft.util.ResourceLocation;
import com.joy187.re8joymod.Utils;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;

import java.util.List;

public class Tank1Structure extends Structure<NoFeatureConfig> {

    public Tank1Structure(Codec<NoFeatureConfig> codec) {
        super(codec);
    }

    @Override
    public IStartFactory<NoFeatureConfig> getStartFactory() {
        return Tank1Structure.Start::new;
    }

    @Override
    public GenerationStage.Decoration step() {
        return GenerationStage.Decoration.SURFACE_STRUCTURES;
    }

    private static final List<MobSpawnInfo.Spawners> STRUCTURE_MONSTERS = ImmutableList.of(
            new MobSpawnInfo.Spawners(EntityType.ILLUSIONER, 10, 1, 4),
            new MobSpawnInfo.Spawners(EntityType.VINDICATOR, 10, 1, 4)
    );

    private static final List<MobSpawnInfo.Spawners> STRUCTURE_CREATURES = ImmutableList.of(
            new MobSpawnInfo.Spawners(EntityType.SHEEP, 10, 1, 5),
            new MobSpawnInfo.Spawners(EntityType.RABBIT, 10, 1, 4)
    );

    @Override
    public List<MobSpawnInfo.Spawners> getDefaultSpawnList() {
        return STRUCTURE_MONSTERS;
    }

    @Override
    public List<MobSpawnInfo.Spawners> getDefaultCreatureSpawnList() {
        return STRUCTURE_CREATURES;
    }


    @Override
    protected boolean isFeatureChunk(ChunkGenerator chunkGenerator, BiomeProvider biomeSource,
                                     long seed, SharedSeedRandom chunkRandom, int chunkX, int chunkZ,
                                     Biome biome, ChunkPos chunkPos, NoFeatureConfig featureConfig) {
        BlockPos centerOfChunk = new BlockPos((chunkX << 4) + 7, 0, (chunkZ << 4) + 7);
        int landHeight = chunkGenerator.getBaseHeight(centerOfChunk.getX(), centerOfChunk.getZ(), Heightmap.Type.WORLD_SURFACE_WG);

        IBlockReader columnOfBlocks = chunkGenerator.getBaseColumn(centerOfChunk.getX(), centerOfChunk.getZ());
        BlockState topBlock = columnOfBlocks.getBlockState(centerOfChunk.above(landHeight));

        return topBlock.getFluidState().isEmpty();
    }


    @Override
    public boolean getDefaultRestrictsSpawnsToInside() {
        return true;
    }

    public static class Start extends StructureStart<NoFeatureConfig>  {
        public Start(Structure<NoFeatureConfig> structureIn, int chunkX, int chunkZ, MutableBoundingBox mutableBoundingBox, int referenceIn, long seedIn) {
            super(structureIn, chunkX, chunkZ, mutableBoundingBox, referenceIn, seedIn);
        }

        @Override
        public void generatePieces(DynamicRegistries dynamicRegistryManager, ChunkGenerator chunkGenerator, TemplateManager templateManagerIn, int chunkX, int chunkZ, Biome biomeIn, NoFeatureConfig config) {

            // Turns the chunk coordinates into actual coordinates we can use
            int x = chunkX * 16 + 7;
            int z = chunkZ * 16 + 7;

            /*
             * We pass this into addPieces to tell it where to generate the structure.
             * If addPieces's last parameter is true, blockpos's Y value is ignored and the
             * structure will spawn at terrain height instead. Set that parameter to false to
             * force the structure to spawn at blockpos's Y value instead. You got options here!
             */
            BlockPos centerPos = new BlockPos(x, 0, z);

            /*
             * If you are doing Nether structures, you'll probably want to spawn your structure on top of ledges.
             * Best way to do that is to use getBaseColumn to grab a column of blocks at the structure's x/z position.
             * Then loop through it and look for land with air above it and set blockpos's Y value to it.
             * Make sure to set the final boolean in JigsawManager.addPieces to false so
             * that the structure spawns at blockpos's y value instead of placing the structure on the Bedrock roof!
             */
            //IBlockReader blockReader = chunkGenerator.getBaseColumn(blockpos.getX(), blockpos.getZ());

            // All a structure has to do is call this method to turn it into a jigsaw based structure!
            JigsawManager.addPieces(
                    dynamicRegistryManager,
                    new VillageConfig(() -> dynamicRegistryManager.registryOrThrow(Registry.TEMPLATE_POOL_REGISTRY)
                            // The path to the starting Template Pool JSON file to read.
                            //
                            // Note, this is "structure_tutorial:run_down_house/start_pool" which means
                            // the game will automatically look into the following path for the template pool:
                            // "resources/data/structure_tutorial/worldgen/template_pool/run_down_house/start_pool.json"
                            // This is why your pool files must be in "data/<modid>/worldgen/template_pool/<the path to the pool here>"
                            // because the game automatically will check in worldgen/template_pool for the pools.
                            .get(new ResourceLocation(Utils.MOD_ID, "tank1/start_pool")),

                            // How many pieces outward from center can a recursive jigsaw structure spawn.
                            // Our structure is only 1 piece outward and isn't recursive so any value of 1 or more doesn't change anything.
                            // However, I recommend you keep this a decent value like 10 so people can use datapacks to add additional pieces to your structure easily.
                            // But don't make it too large for recursive structures like villages or you'll crash server due to hundreds of pieces attempting to generate!
                            10),
                    AbstractVillagePiece::new,
                    chunkGenerator,
                    templateManagerIn,
                    centerPos, // Position of the structure. Y value is ignored if last parameter is set to true.
                    this.pieces, // The list that will be populated with the jigsaw pieces after this method.
                    this.random,
                    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.
                    true);  // 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.


            // **THE FOLLOWING TWO LINES ARE OPTIONAL**
            //
            // Right here, you can do interesting stuff with the pieces in this.pieces such as offset the
            // center piece by 50 blocks up for no reason, remove repeats of a piece or add a new piece so
            // only 1 of that piece exists, etc. But you do not have access to the piece's blocks as this list
            // holds just the piece's size and positions. Blocks will be placed later in JigsawManager.
            //
            // In this case, we do `piece.offset` to raise pieces up by 1 block so that the house is not right on
            // the surface of water or sunken into land a bit.
            //
            // Then we extend the bounding box down by 1 by doing `piece.getBoundingBox().minY` which will cause the
            // land formed around the structure to be lowered and not cover the doorstep. You can raise the bounding
            // box to force the structure to be buried as well. This bounding box stuff with land is only for structures
            // that you added to Structure.NOISE_AFFECTING_FEATURES field handles adding land around the base of structures.
            //
            // By lifting the house up by 1 and lowering the bounding box, the land at bottom of house will now be
            // flush with the surrounding terrain without blocking off the doorstep.
            this.pieces.forEach(piece -> piece.move(0, 1, 0));
            this.pieces.forEach(piece -> piece.getBoundingBox().y0 -= 1);

            // Since by default, the start piece of a structure spawns with it's corner at centerPos
            // and will randomly rotate around that corner, we will center the piece on centerPos instead.
            // This is so that our structure's start piece is now centered on the water check done in isFeatureChunk.
            // Whatever the offset done to center the start piece, that offset is applied to all other pieces
            // so the entire structure is shifted properly to the new spot.
            Vector3i structureCenter = this.pieces.get(0).getBoundingBox().getCenter();
            int xOffset = centerPos.getX() - structureCenter.getX();
            int zOffset = centerPos.getZ() - structureCenter.getZ();
            for(StructurePiece structurePiece : this.pieces){
                structurePiece.move(xOffset, 0, zOffset);
            }

            this.calculateBoundingBox();

            //用作Debug,查看建筑生成的位置
            LogManager.getLogger().log(Level.DEBUG, "Rundown House at " +
                    this.pieces.get(0).getBoundingBox().x0 + " " +
                    this.pieces.get(0).getBoundingBox().y0 + " " +
                    this.pieces.get(0).getBoundingBox().z0);
        }
    }

}

5.在刚刚新建的 structure文件夹中新建 ModStructure.java

在ModStructure.java中编写:
package com.joy187.re8joymod.common.world.structure;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.joy187.re8joymod.Utils;
import com.joy187.re8joymod.common.world.structure.structures.Tank1Structure;
import net.minecraft.util.registry.WorldGenRegistries;
import net.minecraft.world.gen.feature.NoFeatureConfig;
import net.minecraft.world.gen.feature.structure.Structure;
import net.minecraft.world.gen.settings.DimensionStructuresSettings;
import net.minecraft.world.gen.settings.StructureSeparationSettings;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;

import java.util.HashMap;
import java.util.Map;

public class ModStructures {
    //  STStructures.java

    public static final DeferredRegister<Structure<?>> STRUCTURES =
            DeferredRegister.create(ForgeRegistries.STRUCTURE_FEATURES, Utils.MOD_ID);

//    public static final RegistryObject<Structure<NoFeatureConfig>> TANK1 = STRUCTURES.register("tank1", Tank1Structure::new);
    public static final RegistryObject<Structure<NoFeatureConfig>> TANK1 =
            STRUCTURES.register("tank1", () -> (new Tank1Structure(NoFeatureConfig.CODEC)));

    /* average distance apart in chunks between spawn attempts */
    /* minimum distance apart in chunks between spawn attempts. MUST BE LESS THAN ABOVE VALUE*/
    /* this modifies the seed of the structure so no two structures always spawn over each-other.
    Make this large and unique. */
    public static void setupStructures() {
        setupMapSpacingAndLand(TANK1.get(),new StructureSeparationSettings(100,50, 1234567897), true);

    }

    public static <F extends Structure<?>> void setupMapSpacingAndLand(
            F structure,
            StructureSeparationSettings structureSeparationSettings,
            boolean transformSurroundingLand)
    {
        /*
         * We need to add our structures into the map in Structure class
         * alongside vanilla structures or else it will cause errors.
         *
         * If the registration is setup properly for the structure,
         * getRegistryName() should never return null.
         */
        Structure.STRUCTURES_REGISTRY.put(structure.getRegistryName().toString(), structure);

        /*
         * Whether surrounding land will be modified automatically to conform to the bottom of the structure.
         * Basically, it adds land at the base of the structure like it does for Villages and Outposts.
         * Doesn't work well on structure that have pieces stacked vertically or change in heights.
         *
         * Note: The air space this method will create will be filled with water if the structure is below sealevel.
         * This means this is best for structure above sealevel so keep that in mind.
         *
         * NOISE_AFFECTING_FEATURES requires AccessTransformer  (See resources/META-INF/accesstransformer.cfg)
         */
        if(transformSurroundingLand){
            Structure.NOISE_AFFECTING_FEATURES = ImmutableList.<Structure<?>>builder()
                            .addAll(Structure.NOISE_AFFECTING_FEATURES)
                            .add(structure)
                            .build();
        }

        /*
         * This is the map that holds the default spacing of all structures.
         * Always add your structure to here so that other mods can utilize it if needed.
         *
         * However, while it does propagate the spacing to some correct dimensions from this map,
         * it seems it doesn't always work for code made dimensions as they read from this list beforehand.
         *
         * Instead, we will use the WorldEvent.Load event in StructureTutorialMain to add the structure
         * spacing from this list into that dimension or to do dimension blacklisting properly.
         * We also use our entry in DimensionStructuresSettings.DEFAULTS in WorldEvent.Load as well.
         *
         * DEFAULTS requires AccessTransformer  (See resources/META-INF/accesstransformer.cfg)
         */
        DimensionStructuresSettings.DEFAULTS =
                ImmutableMap.<Structure<?>, StructureSeparationSettings>builder()
                        .putAll(DimensionStructuresSettings.DEFAULTS)
                        .put(structure, structureSeparationSettings)
                        .build();


        /*
         * There are very few mods that relies on seeing your structure in the noise settings registry before the world is made.
         *
         * You may see some mods add their spacings to DimensionSettings.BUILTIN_OVERWORLD instead of the NOISE_GENERATOR_SETTINGS loop below but
         * that field only applies for the default overworld and won't add to other worldtypes or dimensions (like amplified or Nether).
         * So yeah, don't do DimensionSettings.BUILTIN_OVERWORLD. Use the NOISE_GENERATOR_SETTINGS loop below instead if you must.
         */
        WorldGenRegistries.NOISE_GENERATOR_SETTINGS.entrySet().forEach(settings -> {
            Map<Structure<?>, StructureSeparationSettings> structureMap = settings.getValue().structureSettings().structureConfig();

            /*
             * Pre-caution in case a mod makes the structure map immutable like datapacks do.
             * I take no chances myself. You never know what another mods does...
             *
             * structureConfig requires AccessTransformer  (See resources/META-INF/accesstransformer.cfg)
             */
            if(structureMap instanceof ImmutableMap){
                Map<Structure<?>, StructureSeparationSettings> tempMap = new HashMap<>(structureMap);
                tempMap.put(structure, structureSeparationSettings);
                settings.getValue().structureSettings().structureConfig = tempMap;

            }
            else{
                structureMap.put(structure, structureSeparationSettings);
            }
        });
    }

    public static void register(IEventBus eventBus) {
        STRUCTURES.register(eventBus);
    }
}
如果你出现了诸如这样的问题:

cr6.png
这说明你还没有配置accesstransformer.cfg文件(路径:**resources/META-INF/**accesstransformer.cfg)
在该路径下新建一个accesstransformer.cfg文件,将如下的代码copy进去:

public-f net.minecraft.world.gen.feature.structure.Structure field_236384_t_ #LAND_TRANSFORMING_STRUCTURES
public-f net.minecraft.world.gen.settings.DimensionStructuresSettings field_236191_b_ #DEFAULT_STRUCTURE_CONFIGS
public-f net.minecraft.world.gen.FlatGenerationSettings field_202247_j #STRUCTURES
public-f net.minecraft.world.gen.settings.DimensionStructuresSettings field_236193_d_ #structures
之后对我们的build.gradle进行修改:
在’mappings channel’下方另起一行添加如下语句:
 accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') 

cr7.png

Gradle修改之后需要进行一次重新加载(过程略慢,请耐心等待)

cr8.png

之后报错的字段应该就自然消除了。

6.接下来我们需要在world/gen文件夹中新建一个所有的建筑的配置文件:ModConfiguredStructures.java

在ModConfiguredStructures中编写
package com.joy187.re8joymod.common.world.gen;

import com.joy187.re8joymod.Utils;
import com.joy187.re8joymod.common.world.structure.ModStructures;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.WorldGenRegistries;
import net.minecraft.world.gen.FlatGenerationSettings;
import net.minecraft.world.gen.feature.IFeatureConfig;
import net.minecraft.world.gen.feature.StructureFeature;

public class ModConfiguredStructures {
    /**
     * Static instance of our structure so we can reference it and add it to biomes easily.
     */
     //你可以添加多个
    public static StructureFeature<?, ?> CONFIGURED_TANK1_HOUSE = ModStructures.TANK1.get().configured(IFeatureConfig.NONE);

    /**
     * Registers the configured structure which is what gets added to the biomes.
     * Noticed we are not using a forge registry because there is none for configured structures.
     *
     * We can register configured structures at any time before a world is clicked on and made.
     * But the best time to register configured features by code is honestly to do it in FMLCommonSetupEvent.
     */
    public static void registerConfiguredStructures() {
        Registry<StructureFeature<?, ?>> registry = WorldGenRegistries.CONFIGURED_STRUCTURE_FEATURE;
        
        //可以继续添加多个
        Registry.register(registry, new ResourceLocation(Utils.MOD_ID, "configured_tank1_house"), CONFIGURED_TANK1_HOUSE);
        
         /*
         * Requires AccessTransformer ( see resources/META-INF/accesstransformer.cfg )
         */
         //将上方的你的所有的建筑都加进来(put函数)
        FlatGenerationSettings.STRUCTURE_FEATURES.put(ModStructures.TANK1.get(), CONFIGURED_TANK1_HOUSE);
    }
}

7.在world/gen文件夹中新建一个ModStructureGeneration.java 用于编写建筑在世界生成的相关规则:

在ModStructureGeneration.java中编写:
package com.joy187.re8joymod.common.world.gen;

import com.joy187.re8joymod.common.init.BiomeInit;
import com.joy187.re8joymod.common.world.structure.ModStructures;
import net.minecraft.util.RegistryKey;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.feature.IFeatureConfig;
import net.minecraft.world.gen.feature.StructureFeature;
import net.minecraftforge.common.BiomeDictionary;
import net.minecraftforge.event.world.BiomeLoadingEvent;

import java.util.List;
import java.util.Set;
import java.util.function.Supplier;

public class ModStructureGeneration {
    public static void generateStructures(final BiomeLoadingEvent event) {
        RegistryKey<Biome> key = RegistryKey.create(Registry.BIOME_REGISTRY, event.getName());
        Set<BiomeDictionary.Type> types = BiomeDictionary.getTypes(key);

        //这里是MC中的地形,你可以让你的建筑生成在想要的地形中
        //例如生成在平原:types.contains(BiomeDictionary.Type.PLAINS)
        if(types.contains(BiomeInit.RE8_BIOME)) {
            //你可以添加多个自己想要生成的建筑
            event.getGeneration().getStructures().add(() -> ModConfiguredStructures.CONFIGURED_TANK1_HOUSE);
        }
        //else if... 可以添加多个想要生成的地形中的建筑
    }
}

8.在ModWorldEvents.java中(没有则在world文件夹中新建)添加一个函数addDimensionalSpacing():

package com.joy187.re8joymod.common.world;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.joy187.re8joymod.Utils;
import com.joy187.re8joymod.common.world.gen.ModFlowerGeneration;
import com.joy187.re8joymod.common.world.gen.ModStructureGeneration;
import com.joy187.re8joymod.common.world.structure.ModStructures;
import com.joy187.re8joymod.common.world.structure.structures.Tank1Structure;
import com.mojang.serialization.Codec;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.WorldGenRegistries;
import net.minecraft.world.World;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraft.world.gen.FlatChunkGenerator;
import net.minecraft.world.gen.feature.structure.Structure;
import net.minecraft.world.gen.settings.DimensionStructuresSettings;
import net.minecraft.world.gen.settings.StructureSeparationSettings;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.event.world.BiomeLoadingEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import org.apache.logging.log4j.LogManager;

import javax.swing.plaf.synth.SynthTreeUI;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@Mod.EventBusSubscriber(modid = Utils.MOD_ID)
public class ModWorldEvents {

      //StructureTutorialMain.java

    @SubscribeEvent
    public static void biomeLoadingEvent(final BiomeLoadingEvent event) {
        //加入建筑的生成事件的声明
        ModStructureGeneration.generateStructures(event);

//        ModOreGeneration.generateOres(event);
//        ModFlowerGeneration.generateFlowers(event);
//        ModTreeGeneration.generateTrees(event);
    }

    //加入空间生成的相关设置
    @SubscribeEvent
    public static void addDimensionalSpacing(final WorldEvent.Load event) {
        if(event.getWorld() instanceof ServerWorld) {
            ServerWorld serverWorld = (ServerWorld) event.getWorld();
            
            //建筑生成异常就会抛出相应错误
            try {
                Method GETCODEC_METHOD =
                        ObfuscationReflectionHelper.findMethod(ChunkGenerator.class, "func_230347_a_");
                ResourceLocation cgRL = Registry.CHUNK_GENERATOR.getKey(
                        (Codec<? extends ChunkGenerator>)GETCODEC_METHOD.invoke(serverWorld.getChunkSource().generator));

                if (cgRL != null && cgRL.getNamespace().equals("terraforged")) {
                    return;
                }
            } catch (Exception e) {
                LogManager.getLogger().error("Was unable to check if " + serverWorld.getLevel()
                        + " is using Terraforged's ChunkGenerator.");
            }
            
            
            // 放止建筑在超平坦世界生成
            if (serverWorld.getChunkSource().generator instanceof FlatChunkGenerator &&
                    serverWorld.getLevel().equals(World.OVERWORLD)) {
                return;
            }

            // 将我们的建筑添加到建筑生成地图中
            Map<Structure<?>, StructureSeparationSettings> tempMap =
                    new HashMap<>(serverWorld.getChunkSource().generator.getSettings().structureConfig());
            tempMap.putIfAbsent(ModStructures.TANK1.get(),
                    DimensionStructuresSettings.DEFAULTS.get(ModStructures.TANK1.get()));
            serverWorld.getChunkSource().generator.getSettings().structureConfig = tempMap;
        }
    }

}

9.在Main.java进行修改(添加建筑的相关注册与初始化语句):

在setup()中添加:
        event.enqueueWork(() -> {
            ModStructures.setupStructures();
            ModConfiguredStructures.registerConfiguredStructures();

        });

cr9.png

在Main()中添加:
        ModStructures.register(bus);
        SurfaceBuilderInit.SURFACE_BUILDERS.register(bus);

cr10.png

10.代码的部分结束了,之后进入游戏进行测试:

新建一个世界 -> 进入后输入查找我们的建筑的指令:
/locate re8joymod:tank1

cr11.png

之后我们会得到建筑的具体坐标

输入tp指令进行坐标传送:

tp @s 具体坐标

cr12.png

我们成功发现了我们自然生成的建筑!

cr13.png

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: 可以使用Java或者Modloader来进行Minecraft 1.16.5模组开发。需要使用Java作为开发语言,建议使用Eclipse或者IntelliJ IDEA作为开发工具。同时,需要了解Minecraft游戏内部的数据和机制,比如方块、控制器和生态系统等。然后就可以编写相关的代码,实现自己的想法,添加的物品、生物和方块等等。最后,通过测试和发布,让更多的玩家可以使用自己的模组。 ### 回答2: Minecraft是一款风靡全球的沙盒游戏,在游戏中我们可以建造自己的世界,发挥想象力创建各种不同的内容。而Minecraft模组开发则是玩家可以通过自己编写代码来加强游戏功能,并且实现更加丰富的游戏玩法,模组开发是游戏远景的一个重要方向,这篇文章主要探讨Minecraft 1.16.5的模组开发。 首先,我们需要了解一些Java语言的基础知识,因为Minecraft游戏是由Java编写的,而模组开发也需要使用Java编程语言。学习Java语言需要掌握变量、运算符、控制语句、数组、对象和方法等基础知识。 其次,要开始模组开发,需要先安装好Minecraft mod制作工具,可选择使用Eclipse、IntelliJ IDEA等开发工具,这些工具都可较好的支持Minecraft模组开发。 接下来就是模组开发的实践,请开发者根据自己想要实现的功能,在工具中建立对应的相关文件夹和类文件,定义变量和方法等,编写代码实现想要的效果。需要注意的是,模组开发需要深入学习Java知识,并注重代码的优化和规范,避免代码的冗长和重复。 最后,需要将编写好的模组进行编译和打包,生成对应的模组文件,并将其放置在游戏的mods文件夹中,重启动游戏即可在游戏中体验到添加的功能。如果有不懂得地方,可多查看官方文档、论坛、群组等相关内容获取更多帮助。 总之,Minecraft 1.16.5的模组开发需要具备一定的Java编程能力,掌握精通一门编程语言是一个漫长的过程,建议开发者可以在此基础上不断进行实践和深入学习。同时,模组开发需要注重规范,在开发模组时应尽可能使用Minecraft API和其他工具类库,进一步提高代码的优化,从而获得更好的游戏体验。 ### 回答3: Minecraft是一款老少皆宜的游戏,在这个游戏中,玩家可以用自己的想象力和创造力建造各种建筑物,探索丰富的世界。而模组的出现给Minecraft带来了无穷的可能性,让游戏过程更加有趣、多样化。在本文中,我们将重点介绍Minecraft 1.16.5模组开发的一些基本知识。 首先,为了开发Minecraft 1.16.5模组,我们需要使用Java编程语言,因为Minecraft游戏的模组是使用Java编写的。为了方便开发,我们可以使用一些流行的IDE(集成开发环境)如Eclipse或IntelliJ IDEA来进行编程工作。 其次,我们需要了解Minecraft的API(应用程序接口),这个API提供了在游戏中创建和操作各种物品、方块、实体等的方法,并且还提供了对游戏事件的处理方式,如方块、实体的生成和移动事件等。 最重要的是,我们需要学习如何使用Forge,这是一个非常流行的Minecraft模组开发平台。使用Forge可以方便地创建的方块、物品和实体,并添加的功能。但是,使用Forge开发模组需要一定的编程经验以及对Minecraft游戏的深入了解。 除了Forge之外,还有一些其他的模组开发平台,如Fabric和Spigot。这些平台也提供了类似于Forge的功能,而且使用它们可能会比使用Forge更便捷。 在开发模组的时候,我们需要牢记一些准则:比如模组的兼容性、可维护性和质量。我们还需要花时间测试我们的游戏,以确保模组的正常运作,并且要注意遵守著作权法和版权法。 总之,Minecraft 1.16.5模组开发需要编程知识、Minecraft游戏的深入了解和一定的调试经验。同时,还需要对游戏的兼容性、可维护性和质量进行考虑。如果您想要从事这个领域的开发工作,那么以上的基本知识会对您极有帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jay_fearless

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

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

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

打赏作者

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

抵扣说明:

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

余额充值