.

Статус
Закрыто для дальнейших ответов.
Если я получу папку с файлами регионов (в главном мире (обгаженном игроками)) я получу все чанки которые когда-либо были загружены, по их имени я получу их координаты, а дальше уже дело техники (координаты чанка в одном мире, те же координаты чанка в другом мире, и переносить блоки)
разве каждый файл, это свой чанк?
 
разве каждый файл, это свой чанк?
Ыыы... Если нет, то.. Мне нужен другой способ, как получить все чанки..
Хотя да, че мне кажется нафейлил я жоСССка..
И это реально не чанки а что-то другое((
 
В папке с миром хранятся файлы регионов, а в них хранятся данные о чанках. Вся информация хранится в сжатом виде в формате NBT.
 
В папке с миром хранятся файлы регионов, а в них хранятся данные о чанках. Вся информация хранится в сжатом виде в формате NBT.
Ыыы... Спасибо, а можно продолжение?)
Ну типо как все это прочитать?
По крайней мере просто вынуть коорды всех чанков...
 
Можно просто предположить, что если есть файл региона, то в нём есть все соответствующие чанки.
В файле региона содержится 32×32 чанка, регионы тоже имеют свои целочисленные знаковые номера в имени файла.
 
Можно просто предположить, что если есть файл региона, то в нём есть все соответствующие чанки.
В файле региона содержится 32×32 чанка, регионы тоже имеют свои целочисленные знаковые номера в имени файла.
Ыыы.. Ну окей, предположили.. А вынуть эти коорды чанков то как?(
 
Охринеть вы изверги
 
А вынуть эти коорды чанков то как?(
Вынимать через сложную формулу, которую не всем рассказывают в школе: умножение.

chunkAbsoluteX = regionX * 32 + chunkInRegionX;
blockAbsoluteX = chunkAbsoluteX * 16 + blockInChunkX,
где chunkInRegionX от 0 до 31, blockInChunkX от 0 до 15, regionX берется из названия файла.
 
Товарищи, которые не могут для Z сделать по аналогии, вообще желательны к покиданию данного раздела.
 
Ладно, сегодня уже мозг не варит, завтра утром свежим взглядом гляну - авось пойму чего :D
 
Что то ТС совсем фигнёй занимается.
Имеем регион. Регион есть две точки в 3D пространстве - A и B. Имея эти две точки, мы можем получить чанки C и D. К примеру, C = 31,-16; а D = 29,-20. Элементарным двойным циклом проходим по этим двум точкам (предварительно узнав максимальные и минимальные значения - чтобы не разъехалось) и заносим координаты в лист для регена. После либо через шедулер, либо другим макаром, "регеним" чанк - из чистого мира забираем чанк по нашим координатам (если нужно, а оно нужно, загружаем чанк в память) и ставим блоки из чистого чанка в старый. Как закончили - выгружаем чанк из памяти. И так проходим весь лист пока он не станет пустым.
Теперь вопрос. Зачем пытаться загружать мир ручками (привет, не меренные траты памяти) костыльными методами, когда можно нагрузить этой работой сам сервер?
 
Я в общем решил просто протестировать не крашнется ли сервер от такого...
И он все-таки крашнулся с сообщением типо "Сервер перестал отвечать на запросы"...
Как правильно перегенерировать все? Чанки и т.д. у меня уже есть, осталось только понять как это все сделать без краша сервера..
Код:
    @EventHandler
    public void test(AsyncPlayerChatEvent event) {
        if (event.getMessage().equalsIgnoreCase("START")) {
            List<String> chunks = chunkConfig.getStringList("CHUNKS");
            World world1 = Bukkit.getWorld("world1");
            World world2 = Bukkit.getWorld("world2");
            for (String ch : chunks) {
                int x = Integer.valueOf(ch.split("\\|")[0]);
                int z = Integer.valueOf(ch.split("\\|")[1]);
                Bukkit.getScheduler().runTask(GWMServerPlugin.plugin, () -> {
                    Chunk chunk1 = world1.getChunkAt(x, z);
                    if (chunk1.isLoaded()) chunk1.load();
                    Chunk chunk2 = world2.getChunkAt(x, z);
                    if (chunk2.isLoaded()) chunk2.load();
                    for (int xLoc = 0; xLoc < 16; xLoc++) {
                        for (int zLoc = 0; zLoc < 16; zLoc++) {
                            for (int yLoc = 0; yLoc < 256; yLoc++) {
                                Block block1 = chunk1.getBlock(xLoc, yLoc, zLoc);
                                Block block2 = chunk2.getBlock(xLoc, yLoc, zLoc);
                                block1.setTypeIdAndData(block2.getTypeId(), block2.getData(), true);
                            }
                        }
                    }
                });
            }
        }
    }

(Когда регенил один чанк (в котором стоит игрок) ничего страшного не было..)
Хотя я лучше решил регенить по блоку (я ж все-равно для себя пишу, нафиг я парюсь..).
Код:
    public void startRegeneration() {
        Bukkit.getScheduler().runTask(GWMServerPlugin.plugin, () -> {
            for (Player p : Bukkit.getOnlinePlayers()) p.kickPlayer(ChatColor.translateAlternateColorCodes('&',
                    GWMServerPlugin.plugin.languageConfig.getString("REGENERATING_WORLD")));
            regenerating = true;
            int x = minX;
            int x2 = maxX;
            int z = minZ;
            int z2 = maxZ;
            for (; x <= x2; x++) {
                for (; z <= z2; z++) {
                    for (int y = 0; y < 256; y++) {
                        Block block1 = world1.getBlockAt(x, y, z);
                        Block block2 = world2.getBlockAt(x, y, z);
                        if (!block1.getChunk().isLoaded()) block1.getChunk().load();
                        if (!block2.getChunk().isLoaded()) block2.getChunk().load();
                        block1.setTypeIdAndData(block2.getTypeId(), block2.getData(), false);
                        if (block1.getChunk().isLoaded()) block1.getChunk().unload();
                        if (block2.getChunk().isLoaded()) block2.getChunk().unload();
                    }
                }
            }
            regenerating = false;
        });
    }
Но проблема все та-же, надо это делать как-то поочередено, ибо сервер залагивает и посылает на..
А вот как это делать поочередно, я не пойму...
 
  1. Регенерацию нужно раскидывать во времени по серверным тикам. Нельзя просто так взять и регенерировать всю карту за один тик.
  2. Нельзя это делать вне основного серверного потока. Вне его можно только планировать действия на будущие такты.
  3. Регенерация одного чанка (где стоит игрок) — в целом, терпимая разовая задача, и от неё сервер повиснуть как следует не сможет.
План действий такой:
  1. Составить для себя список всех чанков, которые нужно в ближайшее время проверить/регенерировать.
    Зная фактические размеры своей карты (+/- x, +/- z) можно взять и заполнить список всеми возможными координатами чанков.
  2. По тактам регенерировать отдельные чанки из списка, возможно даже кусками. Например по 1/2 или 1/4 чанка. Под регеном я подразумеваю копипасту блоков из одного мира в другой.
 
  1. Составить для себя список всех чанков, которые нужно в ближайшее время проверить/регенерировать.
    Зная фактические размеры своей карты (+/- x, +/- z) можно взять и заполнить список всеми возможными координатами чанков.
1. Вот мне интересно как его составить... Точные размеры моей карты это int minX, maxX, minZ, MaxZ, и как мне из этого сделать список чанков?(
 
Поясню примером.

Рассматриваем мир в 2D, без учёта высоты y.
Допустим, карта имеет координаты min (x = -4789, z = -2050); max (x = 3765, z = 1023).
Плоскость мира делится на чанки блоков, размером по 16×16 блоков.
Блок с координатой (0; 0) находится в чанке с координатой (0; 0) и имеет координату внутри этого чанка (0; 0).
Блок с координатой (16; 15) находится в чанке с координатой (1; 0) и имеет координату внутри чанка (0; 15).
Имея только координаты блока bx и bz мы можем найти координаты чанка cx и cz и координаты блока внутри чанка bcx и bcz (я буду писать формулы только для x, т.к. для z они отличаются только буквой z):
cx = bx / 16 (целочисленное деление), bcx = bx % 16 (остаток от целочисленного деления).
Обратно, если мы знаем координату чанка и координату блока внутри чанка, мы можем найти абсолютное положение блока в мире: bx = cx * 16 + bcx.
Интереснее с отрицательной стороны координаты: если по формуле выше получается bcx < 0, то нужно сделать { bcx += 16; cx -= 1; }, чтобы привести координату блока в чанке в допустимые пределы [0; 15].

Найдём границы условного мира в чанках. Сперва для отрицательного угла:
cx1 = -4789 / 16 = -299; bcx = -4789 % 16 = -5.
Применим фикс: cx1 = -300, bcx = 11.
Аналогично находим для координаты z: cz1 = -129; bcz1 = 14.
Для положительного угла: cx2 = 235; cz2 = 63. Я опускаю координаты блоков, так как они дальше никуда не сдались.
Помним, что сервер не умеет работать с неполными чанками.
Наш мир в чанках имеет следующие размеры: min (-300; -129); max (235; 63) — это то, что мы искали.
Если интересна, то вот площадь мира в чанках: (235 - (-300) + 1) × (63 - (-129) + 1) = 103 448 чанка.

Java:
// Исходные данные: координаты угловых блоков мира
void aaa(long minX, long minZ, long maxX, long maxZ) {
    // Вычисление границ мира в чанках
    long minCX = minX / 16;
    long minCZ = minZ / 16;
    long maxCX = maxX / 16;
    long maxCZ = maxZ / 16;
    if(minX % 16 < 0)
        minCX -= 1;
    if(minZ % 16 < 0)
        minCZ -= 1;
    // Дальше можно итерировать по ним
    for(long CZ = minCZ; CZ <= maxCZ; CZ++)
        for(long CX = minCX; CX <= maxCX; CX++)
        {
            // CX и CZ -- координата очередного чанка, принадлежащего имеющейся карте.
            // Надо их все запомнить куда-то для последующей обработки.
        }
}
 
Последнее редактирование:
Статус
Закрыто для дальнейших ответов.
Назад
Верх