[Guide][1.12.2] Генерация структур и заполнение сундуков с помощью loot_table.

[Guide][1.12.2] Генерация структур и заполнение сундуков с помощью loot_table.

Версия(и) Minecraft
1.12.2
Не нашёл в ру сегменте полноценной информации об этой теме и решил написать полноценный гайд.

Генерация структур
Для начала настроим главный класс мода:
Main:
@Mod(modid = Reference.MODID, version = Reference.VERSION)
public class Main
{
    @Instance
    public static TemplesMod instance;
  
    @SidedProxy(clientSide = Reference.CLIENT, serverSide = Reference.SERVER)
    public static CommonProxy proxy;
  
    @EventHandler
    public void preInit(FMLPreInitializationEvent event)
    {
        proxy.preInit(event);
    }
  
    @EventHandler
    public void init(FMLInitializationEvent event)
    {
        proxy.init(event);
    }
  
    @EventHandler
    public void postInit(FMLPostInitializationEvent event)
    {
        proxy.postInit(event);
    }
}
Далее создадим рядом класс Reference который будет хранить наш MODID, MODNAME, VERSION, а также ссылки на ClientProxy и CommonProxy:
Reference:
public class Reference
{
    public static final String MODID = "templesmod";
    public static final String MODNAME = "Temples Mod";
    public static final String VERSION = "1.0";
  
    public static final String CLIENT = "daola.templesmod.proxy.ClientProxy";
    public static final String SERVER = "daola.templesmod.proxy.CommonProxy";
}
И само собой создаём директорию templesmod.proxy, в которой создаём ClientProxy и CommonProxy:
ClientProxy:
public class ClientProxy extends CommonProxy {

    @Override
    public void preInit(FMLPreInitializationEvent event)
    {
        super.preInit(event);
    }

    @Override
    public void init(FMLInitializationEvent event)
    {
        super.init(event);
    }

    @Override
    public void postInit(FMLPostInitializationEvent event)
    {
        super.postInit(event);
    }
}
CommonProxy:
public class CommonProxy
{
    public void preInit(FMLPreInitializationEvent event)
    {
        RegistryHandler.preInitRegistries();
    }

    public void init(FMLInitializationEvent event)
    {
      
    }

    public void postInit(FMLPostInitializationEvent event)
    {

    }
}
Далее в temples.util.handlers создадим класс для регистрации RegisterHandler, который будет в преинициализации регистрировать наш генератор структур:
RegisterHandler:
@EventBusSubscriber
public class RegistryHandler
{
    public static void preInitRegistries()
    {
        GameRegistry.registerWorldGenerator(new WorldGenCustomStructures(), 0);
    }
}
Также для генератора в templesmod.util.interfaces заранее создадим интерфейс IStructure, который будет задавать параметры расположения структуры:
IStructure:
public interface IStructure
{
    public static final WorldServer worldServer = FMLCommonHandler.instance().getMinecraftServerInstance().getWorld(0);
  
    public static final PlacementSettings settings = (new PlacementSettings()).setChunk(null)
            .setIgnoreEntities(false)
            .setIgnoreStructureBlock(false)
            .setMirror(Mirror.NONE)
            .setRotation(Rotation.NONE);
}
И вот дошли до самого генератора. Создаём директорию templesmod.generation и в ней создаём класс WorldGenCustomStructures, в котором будет прописываться запуск генератора для измерений, а также высчитываться позиция для генерации структуры:
WorldGenCustomStructures:
public class WorldGenCustomStructures implements IWorldGenerator
{
    public static final WorldGenStructure YODA_HOME = new WorldGenStructure("yoda_home");
  
    @Override
    public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider)
    {
        switch(world.provider.getDimension())
        {
        //case 2: если есть своё измерение
        //    break;
        case 1: //край
            break;
        case 0: //обычный мир
            generateStructure(YODA_HOME, world, random, chunkX, chunkZ, 10, Blocks.SAND, BiomeMesa.class); //структура объявленная выше, мир, рандом, чанкХ, чанкZ, частота спавна (меньше чаще), на каком блоке будет спавниться, биом
            break;
        case -1: //ад
            break;
        }
    }
  
    private void generateStructure(WorldGenerator generator,
            World world, Random random, int chunkX, int chunkZ, int chance, Block topBlock, Class<?>...classes)
    {
        ArrayList<Class<?>> classesList = new ArrayList<Class<?>>(Arrays.asList(classes));
      
        int x = (chunkX * 16) + random.nextInt(15);
        int z = (chunkZ * 16) + random.nextInt(15);
        int y = calculateGenerationHeight(world, x, z, topBlock);
        BlockPos pos = new BlockPos(x,y,z);
      
        Class<?> biome = world.provider.getBiomeForCoords(pos).getClass();
      
        if(world.getWorldType() != WorldType.FLAT)
        {
            if(classesList.contains(biome))
            {
                if(random.nextInt(chance) == 0)
                {
                    generator.generate(world, random, pos);
                }
            }
        }
    }
  
    private static int calculateGenerationHeight(World world, int x, int z, Block topBlock) //высчитывание высоты (y)
    {
        int y = world.getHeight(); //получаем высоту мира (256)
        boolean foundGround = false;
      
        while(!foundGround && y-- >= 0) //если земля не найдена и значение уменьшения высоты больше или равно 0
        {
            Block block = world.getBlockState(new BlockPos(x,y,z)).getBlock();
            foundGround = block == topBlock; //если найденный block равен topBlock, то foundGround = true
        }
        return y; //возвращаем высоту (если постройка уходит вниз под землю, то убавляем тут количество блоков от нужного "пола" постройки, чтобы она генерировалась ниже)
    }
}
Далее создаём в директории templesmod.generation.generators сам генератор WorldGenStructure:
WorldGenStructure:
public class WorldGenStructure extends WorldGenerator implements IStructure
{
    public static String structureName;
  
    public WorldGenStructure (String name)
    {
        this.structureName = name; //передаём название структуры в переменную name
    }
  
    @Override
    public boolean generate(World worldIn, Random rand, BlockPos position)
    {
        this.generateStructure(worldIn, position, rand);
        return true;
    }
  
    public static void generateStructure(World world, BlockPos pos, Random rand)
    {
        MinecraftServer mcServer = world.getMinecraftServer();
        TemplateManager manager = worldServer.getStructureTemplateManager();
        ResourceLocation location = new ResourceLocation(Reference.MODID, structureName);
        Template template = manager.get(mcServer, location);
      
        if(template != null)
        {
            IBlockState state = world.getBlockState(pos);
            world.notifyBlockUpdate(pos, state, state, 3);
            template.addBlocksToWorldChunk(world, pos, settings);
        }
    }
}
Далее начинается более интересная часть - создаём директорию в ресурсах assets.templesmod.structures и пока оставляем её. Далее заходим в минекрафт и в плоском мире (кому как удобно) начинаем строить нашу структуру.
После того как построили наш шедевр необходимо выдать себе блок для разметки структуры командой
/give @a minecraft:structure_block
и расположить его в углу постройки следующим образом:
Screenshot_2.png
После чего настроить размеры конструкции в настройках блока (после ПКМ нажать "данные", название такое же как и в коде)
Screenshot_1.png
И финальным штрихом нажать "запись", после чего перейти в saves/[название мира]/structures и скопировать [название постройки].nbt в ранее нами созданную директорию assets.templesmod.structures
После чего заходим в игру и видим наши структуры:
Screenshot_3.png
Чтобы убрать пустое пространство при генерации необходимо перед сохранением постройки заполнить это пустое пространство нужными блоками (область постройки включает в себя в том числе блок воздуха и вырезает под него место)

Генерация лута в сундуках
Для генерации лута из списка loot_table необходимо добавить несколько строк в класс WorldGenStructure:
WorldGenStructure:
if(template != null)
        {
            IBlockState state = world.getBlockState(pos);
            world.notifyBlockUpdate(pos, state, state, 3);
            template.addBlocksToWorldChunk(world, pos, settings);
          
            for(int x = 0; x <= template.getSize().getX(); x++) {
              
                for(int y = 0; y <= template.getSize().getY(); y++) {
                  
                    for(int z = 0; z <= template.getSize().getZ(); z++){
                      
                        BlockPos tmp = new BlockPos(pos.getX() + x, pos.getY() + y, pos.getZ() + z);
                          
                        if(world.getTileEntity(tmp) != null){
                          
                            if(world.getTileEntity(tmp) instanceof TileEntityChest){
                              
                                TileEntityChest chest = (TileEntityChest) world.getTileEntity(tmp);
                                ((TileEntityChest)chest).setLootTable(new ResourceLocation(Reference.MODID + ":chests/" + structureName), rand.nextLong());
                            }
                        }
                    }
                }
            }
Данный цикл просчитывает структуру и ищет блок типа TileEntityChest и если он найден, то загружает в него ваш loot_table.
Также необходимо создать саму таблицу в директории assets.templesmod.loot_tables.chests с названием вашей структуры (к примеру yoda_home.json) и сгенерировать необходимую таблицу с помощью инструмента от Amaury Carrade. ВАЖНО после того как вставите сгенерированную разметку необходимо перед "rolls" указать "name" к примеру "name": "yoda_homeMain".
yoda_home:
{
    "pools": [
        {
            "name": "yoda_homeMain",
            "rolls": {
                "min": 4,
                "max": 7
            },
            "bonus_rolls": {
                "min": 2,
                "max": 5
            },
            "entries": [
                {
                    "type": "item",
                    "weight": 1,
                    "name": "minecraft:stone"
                },
                {
                    "type": "item",
                    "weight": 1,
                    "name": "minecraft:book",
                    "functions": [
                        {
                            "function": "enchant_randomly"
                        }
                    ]
                },
                {
                    "type": "item",
                    "weight": 1,
                    "name": "minecraft:rotten_flesh",
                    "functions": [
                        {
                            "function": "set_count",
                            "count": {
                                "min": 3,
                                "max": 7
                            }
                        }
                    ]
                },
                {
                    "type": "item",
                    "weight": 1,
                    "name": "minecraft:bone",
                    "functions": [
                        {
                            "function": "set_count",
                            "count": {
                                "min": 4,
                                "max": 10
                            }
                        }
                    ]
                }
            ]
        },
        {
            "name": "yoda_homeLuck",
            "rolls": {
                "min": 5,
                "max": 8
            },
            "bonus_rolls": {
                "min": 1,
                "max": 3
            },
            "entries": [
                {
                    "type": "item",
                    "weight": 1,
                    "name": "minecraft:diamond",
                    "functions": [
                        {
                            "function": "set_count",
                            "count": 1
                        }
                    ]
                },
                {
                    "type": "item",
                    "weight": 1,
                    "name": "minecraft:emerald",
                    "functions": [
                        {
                            "function": "set_count",
                            "count": {
                                "min": 1,
                                "max": 3
                            }
                        }
                    ]
                }
            ]
        }
    ]
}
Screenshot_4.png

Благодарю за внимание и прошу строго не судить за мой первый гайд :alien:
  • Like
Реакции: Artur114 и ItemStack
Автор
daola
Просмотры
2,436
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху