Разработка плагина на регенерацию мира с сохранением приватов

Статус
Закрыто для дальнейших ответов.

amorphine

Новичок
Баллы
16
Всем привет, недавно увлекся серверостроением майнкрафта и столкнулся с проблемой, что очень хочется повторить функционал плагина на проекте Mconly.
У них раз в месяц проводится очистка территории - полная регенерация всего, за исключением приватов - они остаются нетронутыми. Я сейчас вырабатываю стратегию, пишу первый код, однако столкнулся с философской дилеммой.
Наиболее простой способ сохранить приваты - экспорт их в БД в виде блоба(schematic). Однако проблемно получить сам блоб.
Казалось бы, можно использовать worldedit - да, но для работы с экспортом регионов ему требуется Player/
Есть ли возможность экспортировать регион, зная лишь его координаты? Спасибо.
 
Смотри AutoSaveWorld от Шевчика. В схематики сохранения там были вроде бы в 15 году.
 
Лучше удалять чанки где нет регионов, это будет в разы быстрее. Потом они сами отрегенятся при загрузке.
 
Накидал за часик:
SchematicMaster.ajav
Java:
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.LinkedList;

import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;

import ru.fallus.modifire.lib.ByteUtils;

public class SchematicMaster
{
    private Schemaster plugin;

    private File schematicFolder;

    public SchematicMaster(final Schemaster plugin)
    {
        this.plugin = plugin;

        schematicFolder = plugin.getDataFolder();
    }

    public void saveSchematic(Location loc1, Location loc2, String name) throws IOException
    {
        int minX = Math.min(loc1.getBlockX(), loc2.getBlockX());
        int maxX = Math.max(loc1.getBlockX(), loc2.getBlockX());

        int minY = Math.min(loc1.getBlockY(), loc2.getBlockY());
        int maxY = Math.max(loc1.getBlockY(), loc2.getBlockY());

        int minZ = Math.min(loc1.getBlockZ(), loc2.getBlockZ());
        int maxZ = Math.max(loc1.getBlockZ(), loc2.getBlockZ());

        File file = new File(schematicFolder, name + ".sch");

        if(!file.exists())
        {
            plugin.getDataFolder().mkdirs();
   
            file.createNewFile();
        }

        FileOutputStream os = new FileOutputStream(file);

        for(int x = minX; x < maxX; x++)
        {
            for(int y = minY; y < maxY; y++)
            {
                for(int z = minZ; z < maxZ; z++)
                {
                    Block block = loc1.getWorld().getBlockAt(x, y, z);
           
                    if(block.getType() == Material.AIR)
                        continue;
           
                    //использаем числа в диапазоне 0 - 65535
                    short localX = (short) (x - minX);
                    short localY = (short) (y - minY);
                    short localZ = (short) (z - minZ);
           
                    short id = (short) block.getTypeId();
           
                    byte data = block.getData();
           
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
           
                    //writing 9 bytes(in total) per block
                    bos.write(ByteUtils.makeBytes(localX));
                    bos.write(ByteUtils.makeBytes(localY));
                    bos.write(ByteUtils.makeBytes(localZ));
                    bos.write(ByteUtils.makeBytes(id));
                    bos.write(new byte[]{ data });
           
                    os.write(bos.toByteArray());
                }
            }
        }

        os.close();
    }

    public LinkedList<SchematicBlock> loadSchematic(String name) throws IOException
    {
        File file = new File(schematicFolder, name + ".sch");

        if(!file.exists())
            return null;

        //файл поврежден или данные записаны неверно
        if(file.length() % 9 != 0)
            return null;

        FileInputStream is = new FileInputStream(file);

        //для хранения большого кол-ва элементов
        LinkedList<SchematicBlock> blocks = new LinkedList<SchematicBlock>();

        //количество блоков, записанных в файле
        long blockCount = (long) (file.length() / 9);

        for(long i = 0; i < blockCount; i++)
        {
            byte[] bytes = new byte[9];
   
            if(is.read(bytes) == 9)
            {
                SchematicBlock b = new SchematicBlock();
       
                b.localX     = ByteUtils.makeShort(bytes, 0);
                b.localY     = ByteUtils.makeShort(bytes, 2);
                b.localZ     = ByteUtils.makeShort(bytes, 4);
                b.id         = ByteUtils.makeShort(bytes, 6);
                b.data        = bytes[8];
       
                blocks.add(b);
            }
        }

        is.close();

        return blocks;
    }
}

SchematicBlock.jvaa
Java:
import org.bukkit.Location;
import org.bukkit.Material;

public class SchematicBlock
{
    public short localX = 0;
    public short localY = 0;
    public short localZ = 0;

    public short id = 0;

    public byte data = 0x00;

    public void apply(Location origin)
    {
        Location loc = new Location(origin.getWorld(), origin.getBlockX() + localX, origin.getBlockY() + localY, origin.getBlockZ() + localZ);

        loc.getBlock().setType(Material.getMaterial(id));
        loc.getBlock().setData(data);
    }
}

Загрузка schematic:
Java:
public boolean loadAndApplySchematic(Location origin, String name)
{
    LinkedList<SchematicBlock> blocks;

    try
    {
        blocks = sm.loadSchematic(name);
 
        Iterator<SchematicBlock> i = blocks.iterator();
 
        //если выполняете анинхронно
        Bukkit.getScheduler().runTask(this, () -> {
            while(i.hasNext())
            {
                SchematicBlock b = i.next();
     
                b.apply(origin);
          }});
    }
    catch (IOException e)
    {
        e.printStackTrace();
 
        return false;
    }

    return true;
}

Надеюсь, как работать с байтами Вы знаете. Если нет, могу скинуть свой ByteUtils.java
 
Последнее редактирование:
Лучше удалять чанки где нет регионов, это будет в разы быстрее. Потом они сами отрегенятся при загрузке.
Всё зависит от того сколько весит мир, и сколько на нём регионов. Но удалять чанки тупо надёжнее, не надо потом мудохаться с правильной вставкой схематиков обратно.
 
Спасибо за код, очень лаконичный и понятный. Если не возражаете, я вам в ЛС отпишусь. Так же обещаю, что не буду использовать в коммерческих целях или выкладывать в общий доступ без разрешения)

Лучше удалять чанки где нет регионов, это будет в разы быстрее. Потом они сами отрегенятся при загрузке.
Всё зависит от того сколько весит мир, и сколько на нём регионов. Но удалять чанки тупо надёжнее, не надо потом мудохаться с правильной вставкой схематиков обратно.
Согласен, однако можно использовать этот подход для выполнения основной грубой работы, а для тонкой, с чанками с приватами - от fall.us. Теоретически, это позволит добиться того, что нужно. Спасибо за ответы.
 
Так же обещаю, что не буду использовать в коммерческих целях или выкладывать в общий доступ без разрешения)
Если бы я не хотел, чтобы мой код кто-то использовал, я бы его нигде не выкладывал))
Делайте что хотите.
 
Регенерация от шевчика, как-то криво работает, по крайней мере у меня.
 
Регенерация от шевчика, как-то криво работает, по крайней мере у меня.
Потому лучше и быстрее не проводить регенерацию, а просто обрезать чанки где нет регионов. Лучше пусть останется чанк рядом с регионом, чем реген отсетает содержимое сунтуков с края региона.
 
Потому лучше и быстрее не проводить регенерацию, а просто обрезать чанки где нет регионов. Лучше пусть останется чанк рядом с регионом, чем реген отсетает содержимое сунтуков с края региона.
Согласен, но чем можно это сделать?
 
Мой сервер регенерирует чанки со скоростью чуть больше 100 чанков/сек. Имея мир с максимальным размером в 30 млн. блоков, получаю 1.875.000 * 1.875.000 чанков. Итого получаю 1000+ лет регенерации*. В планетарных масштабах может и быстро))...
(* - при регенерации от x=z=-1875000,до x1=z1=1875000).

А если серьезно, то я могу помочь товарищу @amorphine написать такой плагин(если тот попросит).
 
Последнее редактирование:
Ну что могу сказать. Пытайтесь. На самом деле я думаю, что этот плагин будет не совместим с модами (екстарбиомс, биомопленти, сум. лес) По крайней мере стандартный WorldEdit не работает с ними)
 
Ну что могу сказать. Пытайтесь. На самом деле я думаю, что этот плагин будет не совместим с модами (екстарбиомс, биомопленти, сум. лес) По крайней мере стандартный WorldEdit не работает с ними)
Удаляя чанки с карты мы ломаем совместимость с Forge? Куда смеяться?
 
Удаляя чанки с карты мы ломаем совместимость с Forge? Куда смеяться?
Ты не понял. Я привёл в пример известный плагин WE. В его функционале есть команда //regen но при её использовании он использует плагин просто игнорирует наличие генерации других модов. А регенерирует мир чисто по seed
 
Ты не понял. Я привёл в пример известный плагин WE. В его функционале есть команда //regen но при её использовании он использует плагин просто игнорирует наличие генерации других модов. А регенерирует мир чисто по seed
Так то он так же использует баккитовский метод регенерации (использовал?). Ну и как пишут создатели модов - работоспособность модов на ядре с bukkit api не гарантируется.
 
Ты не понял. Я привёл в пример известный плагин WE. В его функционале есть команда //regen но при её использовании он использует плагин просто игнорирует наличие генерации других модов. А регенерирует мир чисто по seed
Реген и удаление чанков не одно и то же.
 
Статус
Закрыто для дальнейших ответов.
Назад
Верх