Удаление сущностей в непрогруженных чанках

Версия Minecraft
1.20.1
API
Forge
Всем привет. Мне нужно с помощью команды удалять сущностей в определённой области, находящейся на большом расстоянии от игроков, чанки в этой области непрогружены. Как на время удаления сущностей прогрузить нужные чанки, а затем их отгрузить?
 
Как на время удаления сущностей прогрузить нужные чанки, а затем их отгрузить?
Простой и медленный способ: Просто синхронно обращаешься к чанку - он загрузится, и делай что хочешь, потом когда он перестанет использоваться он автоматом выгрузится (по крайне мере должен)

Быстрый способ: Изучи место где идет сохранение чанка в NBT и на диск, считай данные чанков как NBT, и удали от туда тег с сущностями и сохрани обратно
 
Вариант с указанием координат для создания "области"

Java:
    // код для удаления entity в определённой области(/removeEntityArea 10 10 10 20 20 20)/
    // координаты указаны рандомные!
    @Override
    public void execute(ICommandSender sender, String[] args) {
        if (args.length != 6) {
            throw new CommandException("Недопустимое количество аргументов");
        }

        // Переобразуем аргументы в координаты
        int x1 = parseInt(args[0]);
        int y1 = parseInt(args[1]);
        int z1 = parseInt(args[2]);
        int x2 = parseInt(args[3]);
        int y2 = parseInt(args[4]);
        int z2 = parseInt(args[5]);

        World world = sender.getEntityWorld();
        
        // Список чанков для отгрузки
        List<Chunk> loadedChunks = new ArrayList<>();

        // Прогружаем чанки в заданной области
        for (int x = Math.min(x1, x2) >> 4; x <= Math.max(x1, x2) >> 4; x++) {
            for (int z = Math.min(z1, z2) >> 4; z <= Math.max(z1, z2) >> 4; z++) {
                Chunk chunk = world.getChunk(x, z);
                loadedChunks.add(chunk);
            }
        }

        // Удаление сущностей в области
        for (Entity entity : world.loadedEntityList) {
            if (entity.posX >= Math.min(x1, x2) && entity.posX <= Math.max(x1, x2) && entity.posY >= Math.min(y1, y2) && entity.posY <= Math.max(y1, y2) && entity.posZ >= Math.min(z1, z2) && entity.posZ <= Math.max(z1, z2)) {
                entity.setDead();
            }
        }

        // Отгрузка чанков
        for (Chunk chunk : loadedChunks) {
            world.unloadChunk(chunk);
        }

        sender.sendMessage(new TextComponentString("Объекты удалены в указанной области"));
    }

Вариант второй, когда за основу берутся координаты игрока.

Java:
    // вариант с использованием радиуса от игрока.
    // за основу беруться координаты игрока и во все стороны на N-ое колл-во блоков происходит действие
    // /removeEntityArea 100
    @Override
    public void execute(ICommandSender sender, String[] args) {
        if (args.length != 1) {
            throw new CommandException("Недопустимое количество аргументов");
        }

        // Передаём аргумент
        int radius = parseInt(args[0]);

        EntityPlayer player = getCommandSenderAsPlayer(sender);
        World world = player.getEntityWorld();
        BlockPos playerPos = player.getPosition();

        // Список чанков для отгрузки
        List<Chunk> loadedChunks = new ArrayList<>();

        // Прогружаем чанки в радиусе
        int startX = playerPos.getX() - radius;
        int startZ = playerPos.getZ() - radius;
        int endX = playerPos.getX() + radius;
        int endZ = playerPos.getZ() + radius;

        for (int x = startX >> 4; x <= endX >> 4; x++) {
            for (int z = startZ >> 4; z <= endZ >> 4; z++) {
                Chunk chunk = world.getChunk(x, z);
                loadedChunks.add(chunk);
            }
        }

        // Удаление сущностей в радиусе
        for (Entity entity : world.loadedEntityList) {
            if (entity.getDistanceSq(playerPos) <= radius * radius) {
                entity.setDead();
            }
        }

        // Отгрузка чанков
        for (Chunk chunk : loadedChunks) {
            world.unloadChunk(chunk);
        }

        sender.sendMessage(new TextComponentString("Объекты удалены в радиусе " + radius + " блоков"));
    }
 
Вариант с указанием координат для создания "области"

Java:
    // код для удаления entity в определённой области(/removeEntityArea 10 10 10 20 20 20)/
    // координаты указаны рандомные!
    @Override
    public void execute(ICommandSender sender, String[] args) {
        if (args.length != 6) {
            throw new CommandException("Недопустимое количество аргументов");
        }

        // Переобразуем аргументы в координаты
        int x1 = parseInt(args[0]);
        int y1 = parseInt(args[1]);
        int z1 = parseInt(args[2]);
        int x2 = parseInt(args[3]);
        int y2 = parseInt(args[4]);
        int z2 = parseInt(args[5]);

        World world = sender.getEntityWorld();
       
        // Список чанков для отгрузки
        List<Chunk> loadedChunks = new ArrayList<>();

        // Прогружаем чанки в заданной области
        for (int x = Math.min(x1, x2) >> 4; x <= Math.max(x1, x2) >> 4; x++) {
            for (int z = Math.min(z1, z2) >> 4; z <= Math.max(z1, z2) >> 4; z++) {
                Chunk chunk = world.getChunk(x, z);
                loadedChunks.add(chunk);
            }
        }

        // Удаление сущностей в области
        for (Entity entity : world.loadedEntityList) {
            if (entity.posX >= Math.min(x1, x2) && entity.posX <= Math.max(x1, x2) && entity.posY >= Math.min(y1, y2) && entity.posY <= Math.max(y1, y2) && entity.posZ >= Math.min(z1, z2) && entity.posZ <= Math.max(z1, z2)) {
                entity.setDead();
            }
        }

        // Отгрузка чанков
        for (Chunk chunk : loadedChunks) {
            world.unloadChunk(chunk);
        }

        sender.sendMessage(new TextComponentString("Объекты удалены в указанной области"));
    }

Вариант второй, когда за основу берутся координаты игрока.

Java:
    // вариант с использованием радиуса от игрока.
    // за основу беруться координаты игрока и во все стороны на N-ое колл-во блоков происходит действие
    // /removeEntityArea 100
    @Override
    public void execute(ICommandSender sender, String[] args) {
        if (args.length != 1) {
            throw new CommandException("Недопустимое количество аргументов");
        }

        // Передаём аргумент
        int radius = parseInt(args[0]);

        EntityPlayer player = getCommandSenderAsPlayer(sender);
        World world = player.getEntityWorld();
        BlockPos playerPos = player.getPosition();

        // Список чанков для отгрузки
        List<Chunk> loadedChunks = new ArrayList<>();

        // Прогружаем чанки в радиусе
        int startX = playerPos.getX() - radius;
        int startZ = playerPos.getZ() - radius;
        int endX = playerPos.getX() + radius;
        int endZ = playerPos.getZ() + radius;

        for (int x = startX >> 4; x <= endX >> 4; x++) {
            for (int z = startZ >> 4; z <= endZ >> 4; z++) {
                Chunk chunk = world.getChunk(x, z);
                loadedChunks.add(chunk);
            }
        }

        // Удаление сущностей в радиусе
        for (Entity entity : world.loadedEntityList) {
            if (entity.getDistanceSq(playerPos) <= radius * radius) {
                entity.setDead();
            }
        }

        // Отгрузка чанков
        for (Chunk chunk : loadedChunks) {
            world.unloadChunk(chunk);
        }

        sender.sendMessage(new TextComponentString("Объекты удалены в радиусе " + radius + " блоков"));
    }
Данный код не будет работать на новых версиях. Да и загрузка чанков там асинхронная, что добавит только геморроя в удалении мобов.

Просто синхронно обращаешься к чанку - он загрузится, и делай что хочешь, потом когда он перестанет использоваться он автоматом выгрузится (по крайне мере должен)
Лучше вручную его выгрузить, а точнее отправить на выгрузку. Также можно использовать систему тикетов с помощью которой можно загрузить выгруженный чанк. Хотя вообще всё это сомнительно, так как может произойти race-condition и мобы либо не удалятся, либо чанк откатится, как и с редактированием чанков через файлы.
 
Назад
Сверху