| 1 | = Принцип работы с наборами тайлов (тайлсетами) = |
| 2 | |
| 3 | Версия №1. '''В процессе проектирования'''. |
| 4 | |
| 5 | Более старые версии: |
| 6 | * нет. |
| 7 | |
| 8 | Данный текст описывает только проект, т.е. относительно подробное, и в то же время достаточно абстрактное описание того как все должно быть устроено и как должно работать. |
| 9 | |
| 10 | ---- |
| 11 | |
| 12 | == Организация файлов тайлсетов == |
| 13 | |
| 14 | Все тайлсеты расположены в одном каталоге. Внутри этого каталога - по подкаталогу на каждый тайлсет, имя каталога является именем тайлсета. Внутри каждого каталога тайлсета содержатся следующие файлы: |
| 15 | |
| 16 | * !TileSet.ini - настройки тайлсета. Формат файла описан [wiki:TileSetIniFormat_v1 тут]. |
| 17 | * Если набор не сжатый - то куча *.bmp-файлов с тайлами с именем вида {!TileName}.bmp, где {!TileName}=T_{Layer}_{Terrains}_{!VarNumber}, где {Layer} - двузначное число, номер слоя (любое число от единицы до 99, ибо номер слоя 00 зарезервирован); {!VarNumber} - двузначное число, номер варианта данного тайла; {Terrains}={Terr1}_{Terr2}_{Terr3}_{Terr4}, где {Terr1}-{Terr4} соотв названия террейнов в углах тайла - по строчкам, справа-налево, сверху-вниз, вот так: |
| 18 | ||Terr1||Terr2|| |
| 19 | ||Terr3||Terr4|| |
| 20 | * Если набор сжатый - куча *.7z-файлов с bmp-хами с тайлами с именем вида {!TileName}.bmp, где {!TileName} - то же самое, что описано выше. |
| 21 | * Пустые файлы с именами вида Deny_{Terr1}_{Terr2} где Terr1 и Terr2 - имена террейнов, между которыми запрещены переходы. Именем террейна может быть зарезервированное имя All что означает все террейны того же слоя что и второй террейн. По-умолчанию все переходы разрешены. Наличие такого файла запрещает переход. Порядок следования террейнов в имени значения не имеет. Смысловые дубли не должны мешать правильной работе реализации, но в то же время реализация должна стараться не допускать появления таких дублей, а также отслеживать их и при обнаружении вычищать. Имена Deny имеют более высокий приоритет над разрешением всех переходов по умолчанию и более низкий к именам Allow, поэтому можно сначала запретить все переходы для какого-либо террейна, а затем уже разрешать определенные переходы через Allow. Писать Deny_All_All нельзя, такой файл если он появится - должен быть удален, ибо настройки переходов в реализации должны идти для каждого террейна отдельно. |
| 22 | * Пустые файлы с именами вида Allow_{Terr1}_{Terr2} где Terr1 и Terr2 - имена террейнов, между которыми разрешены переходы. Использование имени All в данном случае бессмысленно, ибо по умолчанию все переходы уже разрешены. Отношение к дублям - такое же как для Deny. |
| 23 | |
| 24 | ---- |
| 25 | |
| 26 | == Принцип реализации == |
| 27 | |
| 28 | Работа с тайлами реализуется несколькими взаимозависимыми классами, связанными через их элементы-ссылки. Основным классом, связывающим все остальные является TTileSet, который реализует работу с содержимым одного набора тайлов. Есть более высокий уровень - TTileSetsCollection - фактически контейнер, содержащий ссылки на объекты типа TTileSet для всех доступных программе тайлсетов. '''TTileSetsCollection содержит''': |
| 29 | * Массив ссылок на все объекты тайлсетов. |
| 30 | * Путь по которому располагаются тайлсеты. |
| 31 | * Путь к временному каталогу для временных файлов при работе с тайлсетами. |
| 32 | * Ссылка на !CallBack-метод, для синхронизации при многопоточной работе, с учетом того что !CallBack будет иметь доступ к инфе объекта и всей вложенной инфе. |
| 33 | Также содержит методы: |
| 34 | * Удалений, добавлений тайлсетов. |
| 35 | * Методы, осуществляющие собственно чтение тайлсетов. Предусмотреть основной метод, выполняющий всю работу и своевременные вызовы !CallBack, а также открытые методы-обертки для вызова с и без использования !CallBack, при этом основной метод можно спрятать от простых смертных и оставить доступными только обертки. |
| 36 | * Метод, возвращающий true если в каком-либо из тайлсетов есть "неправильные" (с нестандартной структурой) тайлы и false если таких нет. |
| 37 | |
| 38 | '''TTileSet содержит''': |
| 39 | * Обратную ссылку на объект TTileSetsCollection. |
| 40 | * Ссылку на объект, реализующий работу с файлом !TileSet.ini для этого тайлсета (TTileSetIni). |
| 41 | * Массив ссылок на все тайлы, принадлежащие тайлсету - точнее на объекты класса TTile, реализующего работу с тайлом. |
| 42 | * Массив ссылок на все тайлы, файлы которых реально существуют. |
| 43 | * Массив ссылок на все тайлы, конфигурация которых неправильна (т.е. является одним из вариантов поворота для одной из стандартных конфигураций, а значит такой тайл требуется перевернуть в стандартную конфигурацию при нулевом повороте и переименовать). |
| 44 | * Массив ссылок на все террейны, принадлежащие тайлсету - т.е. на объекты класса TTerrain, реализующего работу с террейном. |
| 45 | * Массив ссылок на объекты класса TLayer, который по-сути является контейнером ссылок на объекты TTerrain и содержит ссылки на все террейны своего слоя. |
| 46 | * Список строк Allow и Deny для информации из имен файлов разрешений-запретов переходов. |
| 47 | * Дополнительная информация о тайлсете, например номер ревизии в случае если используется svn. |
| 48 | * Объект класса TFlistFormat для списка тайлов в сжатом тайлсете. |
| 49 | * Объект класса TFlistFormat для списка тайлов в временном каталоге с тайлами тайлсета. Последние 2 элемента - используются только если работаем со сжатым тайлсетом. |
| 50 | * Список строк - имена всех террейнов тайлсета, мне выполнения методов должен быть в алфавитном порядке и соответствовать приоритету террейнов. |
| 51 | * Булево значение - true если есть "неправильные" тайлы и false если таковых нет. |
| 52 | * Булево значение - true если есть тайлы без реального файла с картинкой и false если таковых нет. |
| 53 | * Ссылка на объект класса TMasksSet - описание класса смотри на [wiki:WorkingWithMasks странице] с описанием работы масок. |
| 54 | Также тут есть методы для: |
| 55 | * Удалений, добавлений тайлов (по имени, влияющая на все три массива ссылок на тайлы). |
| 56 | * Удалений, добавлений террейнов (по имени). |
| 57 | * Удалений, добавлений слоев (по номеру слоя, с удалением принадлежащий слою террейнов). |
| 58 | * Удалений, добавлений Allow и Deny, влияющее и на соответствующие объекты террейнов. |
| 59 | * Метод для синхронизации временного распакованного варианта тайлсета со сжатым реальным тайлсетом. |
| 60 | * Метод для обратной синхронизации содержимого временного каталога со сжатым реальным тайлсетом. |
| 61 | * Метод, собственно выполняющий чтение информации о тайлсете. |
| 62 | * Метод, ищущий неправильные тайлы, добавляющий их в соотв. списки, помечающий и выставляющий соотв. булево значение о их наличии в данном объекте. |
| 63 | * Метод, генерящий на основе информации о слое и переходах террейна конфигурации всех возможных для террейна тайлов, проверяющий наличие каждого такого тайла, если его нету - добавляющий "несуществующий" (т.е. для него отсутствует файл с картинкой) тайл в систему и все нужные списки, помечающий правильным образом этот тайл и ставящий в нужную метку соотв. булево значение этого объекта о наличии "несуществующих" тайлов. |
| 64 | * Метод, исправляющий тайлы с неправильной структурой (поворачивает и дает правильное имя). |
| 65 | * Метод, осуществляющий генерацию конкретного переходного тайла (в аргументе линка на объект тайла). |
| 66 | * Метод, осуществляющий генерацию всех переходных тайлов, для которых еще нету картинок. |
| 67 | |
| 68 | Удаление тайлов, разрешений\запретов переходов, если оно связано с реальным файлом набора - автоматически приводит к удалению соответствующих файлов из набора. Юзверь этой системы классов должен сам обеспечить предупреждение пользователя проги о возможном безвозвратном удалении файлов до вызова таких методов. |
| 69 | Кроме этого - следует организовать выделение и освобождение памяти так, чтобы памятью всех слоев, террейнов и тайлов заведовал именно класс TTileSet. Другие классы также могут иметь подобные ссылки, и даже выделять память под новые объекты - но в любом случае такой объект должен попасть в массив объекта TTileSet и в дальнейшем уничтожаться должен под управлением именно TTileSet, если же вложенные в него объекты сами новых объектов не создают, то использоваться может только копирование ссылки на уже созданный объект. Таким образом, в других классах может использоваться new, но delete всегда выполняется только классом TTileSet, причем гарантированно для всего, что могло быть создано по любому такому new. |
| 70 | |
| 71 | '''Класс TLayer''' весьма прост и содержит только номер слоя (в виде числового значения), массив ссылок на террейны и обратную ссылку на тайлсет, которому принадлежит слой. |
| 72 | |
| 73 | '''Класс TTileSetIni''' по сути также более чем прост, типичен для любого класса, работающего с конфигами в ini, содержит в себе структуры и переменные с данными секций !TileSet.ini, а также методы Load, Save, Clean для загрузки, чтения информации в\из файла и очистки (простановке значений по умолчанию) соответственно. Метод Load должен проверять соответствие номера версии формата в файле текущей реализации - если в файле версия новее - давать ошибку, если старее - конвертировать файл в новую версию (без записи на диск), если тот же - просто читать. |
| 74 | |
| 75 | На уровне террейна работа обеспечивается объектами '''класса TTerrain, который содержит''': |
| 76 | * Имя террейна. |
| 77 | * Число - приоритет террейна. Если приоритет неизвестен то значение = 0. |
| 78 | * Ссылку на объект класса TLayer, которому принадлежит террейн. Если имеются проблемы с идентификацией единственного номера слоя - присваивается ссылка на слой с индексом 00 (ноль). |
| 79 | * Численное значение слоя террейна. Если это 00 значит имеются проблемы с идентификацией номера слоя (например есть тайлы для одного террейна и разных слоев). |
| 80 | * Массив чисел со всеми найденными для этого террейна значениями слоя. |
| 81 | * Списки Allow и Deny содержащие имена террейнов, на которые, соответственно, разрешен или запрещен переход. |
| 82 | * Массив ссылок на все тайлы террейна. |
| 83 | * Обратная ссылка на тайлсет, которому принадлежит террейн. |
| 84 | Также тут есть методы для: |
| 85 | * Удаления\добавления тайлов. Работают по имени или индексу. Убеждаются что такой тайл имеется в террейне, затем удаляется на уровне тайлсета. |
| 86 | * Удаления\добавления элементов Allow и Deny - с синхронизацией с вовлеченными террейнами и списками реальных имен файлов в объекте тайлсета. |
| 87 | * Смена слоя. Работает независимо от того, есть ли проблемы со слоями, меняет слой, переименовывает файлы тех тайлов, от которых есть какой-то смысл, остальные тайлы (т.е. те переходы, которые больше не нужны) либо удаляются, либо переименовываются как будто бы в них был смысл (в зависимости от аргументов метода) - второй вариант может использоваться при смене слоя сразу для нескольких террейнов без потери перехода между ними. При наличии проблемы со слоями, даже если работает с удалением |
| 88 | |
| 89 | На уровне тайла вся работа обеспечивается классом '''TTile, который содержит''': |
| 90 | * Ссылку на свой тайлсет. |
| 91 | * Ссылку на свой слой. |
| 92 | * Путь к bmp-файлу, с именем файла (строка). |
| 93 | * Путь к файлу в тайлсете, с именем файла (может не совпадать с bmp если оно например 7z). |
| 94 | * Ссылка на объект типа TTileTerrs - содержит информацию о структуре тайла (территории) в удобном для быстрой программной обработки виде. |
| 95 | * Номер варианта тайла с такой структурой. |
| 96 | * Булевое значение Exists - true если тайл реально существует в тайлсете а не только должен наличествовать в теории исходя из структуры террейнов на слоях и возможных переходов. |
| 97 | * Булевое значение !IsValid - true если структура тайла соответствует одной из стандартных, если соответствия нет - тайл является одним из вариантов поворота для одной из стандартных конфигураций, а значит такой тайл требуется перевернуть в стандартную конфигурацию при нулевом повороте и переименовать. |
| 98 | Также тут есть методы для: |
| 99 | * Загрузки информации о тайле по его имени (смотрит свойства тайлсета и ищет нужные файлы). |
| 100 | * Метод, возвращающий строку с именем тайла. |
| 101 | * Метод, возвращающий повернутую нужное количество раз bmp-ху тайла. |
| 102 | * Метод, возвращающий bmp-ху тайла без поворотов (вызывает предыдущий метод с нулевым поворотом). |
| 103 | |
| 104 | '''Класс TTileTerrs''' был бы простой структурой если бы не имел методы сравнения двух объектов этого типа, поэтому он класс. '''Содержит''': |
| 105 | * Строки A,B,C,D с именами террейнов в соотв. углах (справа налево, по строкам сверху вниз, A соответствует {Terr1} а D соответствует {Terr4} в имени тайла). Вот табличка расположения углов: |
| 106 | ||A||B|| |
| 107 | ||C||D|| |
| 108 | * Ссылка на родной тайл. |
| 109 | Также содержит методы: |
| 110 | * Для чтения террейнов в углах (т.е. ABCD) из имени-строки тайла (и записи в инфу объекта). |
| 111 | * Для генерации имени тайла по ABCD без той части где указывается вариант тайла. |
| 112 | * Метод, возвращающий integer - если аргумент не совпадает по структуре с тайлом (аргумент также типа TTileTerrs) - вернет -1, иначе - вернет количество поворотов которое нужно применить к аргументу чтобы структура тайла совпадала со структурой аргумента. Таким образом если возвращает 0 значит структура тайла и аргумента метода идентичны. |
| 113 | * Перегрузка оператора == - при сравнении двух объектов этого типа этим оператором - соотв. возвращает true если объекты идентичны и false если чем-либо различаются. |
| 114 | |
| 115 | ---- |
| 116 | |
| 117 | == Как определяется правильна ли структура тайла == |
| 118 | |
| 119 | Для начала определимся с приоритетом террейнов. Приоритет определяется по имени террейна, в алфавитном порядке (не только для первой, для всех букв имени террейна). Чем выше в списке по алфавиту идет имя террейна тем выше его приоритет. В дальнейшем буду считать что террейн с наивысшим приоритетом имеет номер 1, террейн с приоритетом ниже номер 2, ниже номер 3 и так далее. На основе этого допущения определим стандартные структуры террейнов: |
| 120 | |
| 121 | * Из двух террейнов-1: |
| 122 | ||2||2|| |
| 123 | ||1||2|| |
| 124 | * Из двух террейнов-2: |
| 125 | ||1||1|| |
| 126 | ||2||2|| |
| 127 | * Из трех террейнов-1: |
| 128 | ||1||1|| |
| 129 | ||2||3|| |
| 130 | * Из трех террейнов-2: |
| 131 | ||1||1|| |
| 132 | ||3||2|| |
| 133 | * Из трех террейнов-3: |
| 134 | ||1||2|| |
| 135 | ||3||1|| |
| 136 | * Из четырех террейнов-1: |
| 137 | ||1||2|| |
| 138 | ||3||4|| |
| 139 | * Из четырех террейнов-2: |
| 140 | ||1||2|| |
| 141 | ||4||3|| |
| 142 | * Из четырех террейнов-3: |
| 143 | ||1||3|| |
| 144 | ||2||4|| |
| 145 | * Из четырех террейнов-4: |
| 146 | ||1||3|| |
| 147 | ||4||2|| |
| 148 | * Из четырех террейнов-5: |
| 149 | ||1||4|| |
| 150 | ||2||3|| |
| 151 | * Из четырех террейнов-6: |
| 152 | ||1||4|| |
| 153 | ||3||2|| |
| 154 | |
| 155 | ---- |
| 156 | |
| 157 | == Как это все по идее должно работать == |
| 158 | |
| 159 | В начале программа создает верхний уровень - объект класса '''TTileSetsCollection'''. Все остальные уровни создаются конструкторами и прочими методами этого объекта и его вложенными объектами. Освобождение памяти во избежание утечек - там же, деструкторами классов и их методами. Программа должна позаботиться только о правильном удалении объекта '''TTileSetsCollection''' когда он станет не нужен. |
| 160 | |
| 161 | После создания объекта класса '''TTileSetsCollection''' - программа пробивает в его опции все необходимые пути, если нужно - !CallBack-метод, а затем вызывает нужный метод чтения информации тайлсетов. |
| 162 | |
| 163 | Данный метод - читает имена тайлсетов, их количество - и создает нужное количество подобъектов класса '''TTileSet'''. Обращаю внимание, что все вложенные в '''TTileSetsCollection''' объекты имеют обратные ссылки на "родительский" объект, т.е. тот объект в который они вложены - что позволяет этим объектам использовать информацию своего владельца и даже своих соседей и вложенных в соседей объектов. |
| 164 | |
| 165 | Для каждого объекта '''TTileSet''' вызывается метод чтения информации тайлсета. Причем перед запуском чтения тайлсета при необходимости вызывается !CallBack что позволяет индицировать процесс загрузки, например, в окошко с прогрессбаром. |
| 166 | |
| 167 | Метод чтения информации тайлсетов - для начала читает свой конфиг, если используется svn - читает информацию о ревизии. Если тайлсет сжат - первым делом выполняет синхронизацию с временной, несжатой версией тайлсета. Затем - производит поиск всех файлов с тайлами, подсчитывает их количество, после чего (либо одновременно - смотря как будет реализовано и как оптимальнее работает) выделяет нужное количество объектов в массив с тайлами и загружает в эти объекты информацию по всем найденным тайлам. Обновременно со вбивкой информации в основной массив - создаются объекты террейнов, слоев, в них вбивается соответствующая информация, в т.ч. присваиваются ссылки на объекты тайлов. По завершению всего этого процесса - все объекты террейнов и слоев уже созданы, в них есть массивы со ссылками на тайлы. После этого становится возможным составление списка террейнов по алфавиту и установка приоритета для них. |
| 168 | |
| 169 | После того как приоритеты расставлены - становится возможным понять - какой тайл имеет правильную конфигурацию, а какой, увы, нет. Сканируется список тайлов, обнаруженные неправильные тайлы добавляются в соответствующие списки и помечаются. Автоматического исправления таких тайлов не происходит, это делает отдельный метод, вызываемый программой, например по команде пользователя. |
| 170 | |
| 171 | Затем осуществляется генерация всех возможных тайлов-переходов - если такой переходный тайл уже наличествует, хотя-бы в количестве 1 (адЫн) штука - ничего не происходит, если же ни одного такого тайла найдено не было - создается объект тайла, с пометкой что файла картинки у него нет, ссылка на него добавляется во все соответствующие массивы соответствующих объектов. |
| 172 | |
| 173 | Собсно это все что касается механизма чтения информации о тайлсете. После его завершения - в объекте класса '''TTileSetsCollection''' содержится вся необходимая информация о всех имеющихся тайлсетов, более чем достаточная для вывода любой информации в интерфейс программы, в т.ч. дерева террейнов и тайлов. |
| 174 | |
| 175 | Кроме этого у всех объектов системы имеются дополнительные методы, которые не вызываются при чтении тайлсетов, и предназначены для непосредственного их вызова программой - например методы удаления\добавления тайлов, генерации переходных тайлов, исправления "неправильных" тайлов и т.д. Подробно расписывать эти методы смысле нет, ибо механизм их действия понятен их простого их описания, а описания же для них наличествуют выше в данном тексте, в списках методов классов. |
| 176 | |
| 177 | Спасибо за то что прочитали весь этот бред :). |