Как я могу хранить все свои данные уровня в одном файле, а не распределять по многим файлам?

8

В настоящее время я генерирую данные уровня и сохраняю их на диск, чтобы сохранить все изменения, внесенные в уровень.

Я сохраняю "куски" размером 2048x2048 пикселей в файл. Всякий раз, когда игрок перемещается по секции, у которой нет файла, связанного с позицией, создается новый файл.

Это прекрасно работает и очень быстро. Моя проблема в том, что по мере того, как вы играете, количество файлов становится все больше и больше.

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

jgallant
источник
5
В основном вам нужно написать миниатюрную файловую систему, чтобы иметь возможность хранить все в одном файле. Это добавит сложности и может не стоить того.
Thedaian
1
У меня нет особого опыта в следующем, но, возможно, вариант с nosql db на основе файлов ( stackoverflow.com/questions/2403174/… ) может быть вариантом.
Крис
Сколько файлов мы говорим здесь? Плееры генерируют десятки тысяч файлов или только сотни? Что меняют игроки в чанке? Является ли порция генерацией дорогим шагом (т.
Е.
Minecraft также прошел через это преобразование. Я считаю, что это началось как мод, а затем был включен в основную сборку. Стоит посмотреть. minecraftwiki.net/wiki/Region_file_format
MichaelHouse
1
@thedaian немного сложнее, но вы можете делать некоторые интересные вещи и реально сократить время поиска, если вы готовы к дополнительной работе в памяти, чтобы файловая система не выполняла ее на диске.
ClassicThunder

Ответы:

7

Самый быстрый способ сделать это - сохранить все в одном файле и переместить курсор на блок, который вы хотите прочитать. Как только вы нажимаете на диск, читая последовательность с этого момента, он довольно быстро.

Несколько попаданий в разные INodes для определения местоположения файла на физическом томе, что занимает большую часть времени, а также что плохо масштабируется.

Кроме того, поскольку это динамично, вам также понадобится карта, которая хранит смещение в файле для каждого чанка.

На диске

[Chunk 1][Chunk 2][Chunk 3][Chunk 4][Chunk 5][Chunk 6][Chunk 7][Chunk 8][Chunk 9]

видимый

[7][8][9]
[6][1][2]
[5][4][3]

Тогда вам просто нужно открыть поток, который читает из файла, но не блокирует другие потоки / процессы от доступа к нему. Затем вам нужно прочитать с правильного смещения для правильного расстояния. Я верю в C # это ниже.

var chunk = new byte[4194304];
using (var file = new FileStream (openFileDialog1.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    using (var reader = new StreamReader (file, Encoding.Unicode)) {
        reader.Read(chunk, offset * 4194304, 4194304);
    }
}

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

PS вы не захотите использовать блок using, поскольку вам понадобится только 1 поток чтения в течение жизни того уровня, который вы используете. Также вам, вероятно, придется сохранить отображение чанка в другой файл при выходе, но это всего лишь одна загрузка, когда вы загружаете свой уровень.

ClassicThunder
источник
Это дает мне отличные идеи. Требуется ли для этого метода запись в каждом блоке одинакового количества байтов? Я бы вообразил, как этого потребовал бы поиск смещения.
jgallant
Пока у вас есть первый байт и длина каждого куска, они не должны быть одинакового размера. Вам просто нужно иметь что-то в памяти, чтобы отслеживать эти две части данных.
ClassicThunder
1
Конечно, если бы у вас не было их одинакового байтового размера, вам пришлось бы много сдвигаться, если бы вы увеличивались в размере.
MichaelHouse
1

В зависимости от времени, необходимого для создания чанка, вы можете просто сохранить различия или текущее состояние (вражеские локации и т. Д.). Когда проигрыватель возвращается в блок, он генерирует снова, используя сохраненное начальное значение, а затем загружает любые изменения, которые были сделаны из файла.

Если игрокам разрешено вносить существенные изменения, это может быть медленным, и файл diff все равно будет довольно большим, но только для небольших изменений должна быть недорогая операция. Несколько различий фрагментов также могут быть объединены в один файл - что-то разумного размера, который может быть загружен в память.

Вы, вероятно, не захотите перемещать все различия в один файл - это открывает ряд других проблем с памятью или изменением середины файла.

снисходительность
источник
1

Я знаю, что это довольно старая ветка, но я бы хотел сказать, что я думаю, что ZIP-архив может быть лучшим способом для этого. Вы получаете сжатие с вашими данными (особенно если вы используете сырые растровые изображения), удобочитаемость в операционной системе, и вы получаете один файл, как вам нужно.

Вон Хилтс
источник
0

Как насчет сканирования в режиме dir для проверки метки времени файлов в каталоге данных уровня по сравнению с текущим активным файлом и предоставления отсрочки для предыдущего файла и файла, идущего вперед каждые 10 секунд или около того, и того, что не используется просто удалите их.

Если вы не требуете, чтобы игрок вернулся. Затем просто очистить данные уровня после завершения уровня или контрольной точки? Могло бы быть достаточно большим, но я не думаю, что здесь есть много вариантов

RedactedProfile
источник
0

Как насчет нескольких кусков на файл? Вы говорите, что ваши куски имеют размер 2048 x 2048, как насчет размещения 16384 x 16384 в файле. Отметьте, какие из них как-то существуют, чтобы вы знали, нужно ли вам это создавать.

Лорен Печтель
источник
0

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

Они могут быть сохранены в одном файле, и могут быть записаны последовательно и отсортированы в ОЗУ при загрузке; нет необходимости в сложной отсортированной структуре в самом файле на диске. Вы можете читать из него только при запуске и писать в него, когда вы генерируете новые «страницы» (как их называют) в игровом мире.

Будет
источник