Nano Hash - криптовалюты, майнинг, программирование

Как правильно сжимать и конвертировать данные TiledMap с помощью Java?

Поэтому сейчас я создаю расширение библиотеки Slick2d под названием TiledMapPlus. Он направлен на предоставление большей поддержки людям, использующим Tiled, а также более быстрый доступ к данным и т. д.

Одной из целей библиотеки было обеспечить динамическое редактирование карт, следовательно, возможность записи новой карты в поток. Я реализовал это сегодня и вчера, и теперь мне нужна ваша помощь. Что-то не так с моим кодом.

Таким образом, основная проблема заключается в том, что данные слоя XML искажены и не могут быть прочитаны синтаксическим анализатором/редактором TiledMap. Я просмотрел множество руководств, пытаясь сжать данные в сжатый GZIP формат BASE64. Наконец, я прибегнул к использованию this с параметром сжатия GZIP. Однако каждый раз, когда я сжимаю данные и т. Д., Он всегда выводит больше, чем редактор Tiled2d, и выводит поврежденные данные. Почему это?

Ссылки на файлы:

Мозаичная карта, автоматически созданная редактором TiledMap

Мозаичная карта, сгенерированная из указанной выше TiledMap с использованием моей библиотеки

Неработающий фрагмент кода из моей библиотеки

В качестве альтернативы вы можете просмотреть их все в отформатированном виде здесь

27.10.2011

  • Не мог уследить за всем этим, но я знаю, что использование base64 для чего-то, что вы хотите сжать, - довольно плохая идея. Но опять же, любой приличный компрессор уловит тот факт, что каждый 7-й и 8-й бит в байте всегда равен 0, и сожмет соответственно... 27.10.2011
  • Если это какая-то путаница, я сжимаю данные с помощью GZIP, а затем конвертирую их в Base64. Это стандарт TiledMap, я не определял его, лол. 27.10.2011

Ответы:


1

Спасибо, Лиам, я на самом деле следил за всеми возможными вещами, которые я мог найти, что вы написали, и именно ваш код в TiledMapPlus наконец решил это для меня.

Вот правильно работающее решение, взятое из кода Лиама:

            Element layer = doc.createElement("layer");
        layer.setAttribute("name", "layer");
        layer.setAttribute("width", width);
        layer.setAttribute("height", height);



            Element data = doc.createElement("data");

            ByteArrayOutputStream os = new ByteArrayOutputStream();                
            for(int tileY = 0;tileY<layerHeight;tileY++){
                for(int tileX = 0;tileX<layerWidth;tileX++){
                    int tileGID = this.data[tileX][tileY];
                    os.write(tileGID);
                    os.write(tileGID << 8);
                    os.write(tileGID << 16);
                    os.write(tileGID << 24);
                }
            }
            os.flush();
            String compressedData = Base64.encodeBytes(os.toByteArray(),Base64.DONT_BREAK_LINES|Base64.GZIP|Base64.ENCODE);
            data.appendChild(doc.createTextNode(compressedData));               
            data.setAttribute("encoding", "base64");
            data.setAttribute("compression","gzip");

            layer.appendChild(data);

        mapElement.appendChild(layer);

Я использую те же методы генерации данных и передаю любой идентификационный номер, который хочу, и он отлично принимает и кодирует его!

26.02.2012

2

Метод, который вы используете, заключается в настройке конвейера выходных потоков следующим образом:

ObjectOutputStream -> GZIPOutputStream -> Base64OutputStream

Вы не захотите иметь первый ObjectOuputStream, так как он сериализует объект массива байтов JAVA. Вы должны просто передать GZIpOuputStream байтами напрямую. Если вы не можете найти подходящий метод, очень легко настроить свой собственный, используя кодек apache commons:

public String compressAndEncode(byte[] data) throws Exception {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    GZIPOutputStream gz = new GZIPOutputStream(out);
    ByteArrayInputStream in = new ByteArrayInputStream(data);
    int c;
    while ((c = in.read()) != -1)
        gz.write(c);
    gz.finish();
    Base64 b = new Base64(0);
    return b.encodeToString(out.toByteArray());
}
27.10.2011

3

Я не могу говорить о значении ответа из сорока двух. Если это сработало, пожалуйста, ответьте, сказав так. У меня это работает в игре, которую я пишу, и проблема в используемом вами формате.

Когда вы создаете файл TMX, в котором данные сжаты и заархивированы gzip, как это требуется для TiledMapPlus и slick2d, вы НЕ используете теги <tiled>, как в обычных несжатых файлах. Это контринтуитивно, но так оно и работает.

Чтобы создать данные в теге <data>, вам нужно создать строку/поток каждого gid, используя 32-битное целое число, а затем преобразовать его в UTF-8, а затем сжать и закодировать.

Вот пример, который я нашел где-то в Интернете:

                Element data = doc.createElement("data");
            data.setAttribute("encoding", "base64");
            data.setAttribute("compression", "gzip");

                String bytestring = new String();
                for (int x = 0; x < w; x++) {                       
                    for (int y = 0; y < h; y++) {
                        switch(this.data[x][y]){

                            case 0: bytestring += "1000";
                                break;
                            case 1: bytestring += "2000";
                                break;
                            case 2: bytestring += "3000";
                                break;
                            case 3: bytestring += "4000";
                                break;
                            case 4: bytestring += "5000";
                                break;
                            case 5: bytestring += "6000";
                                break;
                            case 6: bytestring += "7000";
                                break;
                            case 7: bytestring += "8000";
                                break;
                            case 8: bytestring += "9000";
                                break;

                        }
                    }
                }

                Text value = doc.createTextNode(compress(bytestring));
                data.appendChild(value); 

Сжатие и кодирование выполняются следующим образом:

private static String compress(String str){

    byte byteAry[] = null;

    try{
        byteAry = str.getBytes("UTF-8");    
    }catch( UnsupportedEncodingException e){
        System.out.println("Unsupported character set");
    }

    for(int i = 0; i < byteAry.length; i++) {
        if(byteAry[i] == 48)
            byteAry[i] = 0;
        if(byteAry[i] == 49)
            byteAry[i] = 1;
        if(byteAry[i] == 50)
            byteAry[i] = 2;
        if(byteAry[i] == 51)
            byteAry[i] = 3;
        if(byteAry[i] == 52)
            byteAry[i] = 4;
        if(byteAry[i] == 53)
            byteAry[i] = 5;
        if(byteAry[i] == 54)
            byteAry[i] = 6;
        if(byteAry[i] == 55)
            byteAry[i] = 7;
        if(byteAry[i] == 56)
            byteAry[i] = 8;
        if(byteAry[i] == 57)
            byteAry[i] = 9;
    }
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();

    try {
        OutputStream deflater = new GZIPOutputStream(buffer);
        deflater.write(byteAry);
        deflater.close();
    }catch (IOException e) {
        throw new IllegalStateException(e);
    }
    String results = Base64.encodeBase64String(buffer.toByteArray());
    return results;
}   

Теперь вот более сложный вопрос, который очень связан. В приведенном выше примере вы можете видеть, что каждый GID представлен 32-битной строкой, такой как 1000. Они напрямую связаны с включенным файлом набора тайлов. У меня проблема в том, что я могу использовать эту технику, чтобы подняться выше GID 9 (показать как 9000). Я считаю, что это как-то связано с самим ByteStream. Если я ввожу 1100, он вылетает из-за нулевого значения для GID этой плитки (при чтении файла), даже если в наборе плиток около 20 плиток. Итак, что-то не так с тем, что возвращается после кодирования и сжатия для любого двузначного числа. Это кажется довольно специфичным для Java, поскольку люди, работающие с obj-c, похоже, не сталкиваются с этой проблемой.

Любая помощь будет принята с благодарностью.

25.02.2012
  • Следует отметить, что я являюсь создателем библиотеки TiledMapPlus, которая может записывать файлы TiledMap. 26.02.2012
  • Извините за путаницу, но эта статья всплывает при изучении случайно сгенерированных карт. Так как это везде, надеюсь, мои дополнения помогут людям в этом. Моя «продвинутая» проблема решена в моем другом посте. По сути, есть лучший способ, чем эта струнная техника, которую я нашел. Лучший способ - это то, как это делает Лиам в методе write() TiledMapPlus, найденном здесь. Еще раз спасибо за вашу впечатляющую работу над этой библиотекой Лиам. Кстати, что-нибудь о передаче данных между состояниями? 26.02.2012
  • Был ли я прав, предполагая, что ответ сорок два на самом деле не решил проблему? Дело в том, что вы кодировали теги «плитка», верно? Это возникает из-за множества проблем с генерацией карт, поэтому я добавил некоторые детали, потому что у многих людей, похоже, возникают проблемы со случайными картами и т. Д. Может быть, это поможет другим. 26.02.2012
  • Спасибо, да, это было проблемой. Хм, данные передаются из штатов, насколько мне известно, на самом деле нет. Я решаю проблему с помощью синглетонов, но это только я. 27.02.2012
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..