Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / База данных игровых объектов: архитекстура системы сериализации и репликации произвольных объектов (7 стр)

База данных игровых объектов: архитекстура системы сериализации и репликации произвольных объектов (7 стр)

Страницы: 1 2 3 4 5 6 7
tacПостоялецwww3 июня 20188:09#90
Sh.Tac.
> третьего персонажа как я думал не получится ввести
мм .. тут не догоняю, что за третий персонаж? бухгалтер, который не платит деньги, за херово сделанную работу? ;)
tacПостоялецwww3 июня 20188:11#91
Delfigamer
> не указано, насколько сложным процессом является выпечка хлеба
на самом деле это не важно, хоть по пару строк в методе ... указана бизнес модель и как она менялась со временем
ZabПостоялецwww3 июня 20188:52#92
Sh.Tac.
> вспомнилось https://habr.com/post/153225/
А теперь представьте, уволили Бориса и Маркуса, взяли кого-то третьего ;)
Документации никакой не осталось, какой же программист пишет документацию... Менеджер даже если не сменился, выдает уже новую версию задачи, что он там говорил ранее уже и сам забыл. Программа что-то делает, наверное что-то важное, но явно не то.
Новому программисту ставится задача - "исправить".

Какие у него шансы с пользой применить наследство?
Наследство Бориса - можно сразу в топку. Если его абстракции нигде не описаны, догадаться практически невозможно как предполагалось оно должно работать, чтобы иметь возможность как-то менять систему.
Наследство Маркуса - вполне читаемо, если догадаться какую задачу он решал. Это не значит, что надо делать как он, работать совсем не выделяя инструментального уровня, но чужак в проекте может выделить свои абстракции, преобразовать, почистить код.

tacПостоялецwww3 июня 201810:22#93
Zab
> А теперь представьте, уволили Бориса и Маркуса, взяли кого-то третьего ;)
> Документации никакой не осталось, какой же программист пишет документацию...
> Менеджер даже если не сменился, выдает уже новую версию задачи, что он там
> говорил ранее уже и сам забыл. Программа что-то делает, наверное что-то важное,
> но явно не то.
> Новому программисту ставится задача - "исправить".
тут представлять ничего не надо, две недели назад устроился на полставки на вторую работу тим лидом, и ебс, ситуация один в один такая, документации нет, основные разработчики ушли, а те кто остался толком не знают как запустить проект, а их только в одном офисе трое ... а проектов порядка десяти .. директор загружен общением с клиентами и по остаточному принципу гоняет программеров .. а у тех нет даже понимания зачем писать комментарии ... а клиенты ставят новые задачи ...

Zab
> Наследство Бориса - можно сразу в топку. Если его абстракции нигде не описаны,
> догадаться практически невозможно
не факт

Zab
> Наследство Маркуса - вполне читаемо
гавнокод читаем? точно нет

мои действия?
объяснил директору, что у него за ад, что в теории, он скоро закроется, а на практике это вопрос времени, изучил два проекта и убив работу всего отдела на двое суток, написал readme  как запускать эти проекты, вытавщив клещами у каждого часть информации, один человек смог после этого запустить отладчик и наконец то приступить к решению своей небольшой задачи

Директор понял, что написание кода это 20% разработки и остальное время тратится на документацию и отладку .. если бы директор бы не понял, я попросил бы расчет, ну или нашел бы для себя один проект и делал бы сам только его, если бы он платил неплохо .. но вроде понял, в пятницу как раз провел 2 часовой семинар о пользе документации, что и как надо документировать, какая документация нам нужна ... работы приостановлены, пока не разберемся

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

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


думал что на основной работе бардак, теперь оценил как там все поставлено, но на основной работе я в свои 40 самый молодой :) а на второ даже директор примерно моего возраста, а остальные много меньше

Правка: 3 июня 2018 10:44

ZabПостоялецwww3 июня 201812:25#94
tac
Директору деваться некуда. Он конечно может приказать "чтобы завтра все было готово", но готово то от этого не будет. Уволил он предыдущую команду, нанял новую, минимум полгода лихорадки себе обеспечил. Как-либо напирать на тебя он может только если есть альтернатива, не думаю что она у него есть, другой человек на твоем месте работу существенно не ускорит. Так что, можно спокойно работать, надо все переделывать - значит переделывай.

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

DelfigamerПостоялецwww3 июня 201817:24#95
Это ещё одна причина существования треда - это ещё и черновик документации, который подробно описывает применяемые в системе абстракции.

tac
> Забанен
Так вот почему тут вдруг стало так тихо. :V

Правка: 4 июня 2018 10:41

tacПостоялецwww18 июня 201817:44#96
Delfigamer
> Так вот почему тут вдруг стало так тихо

:) ну тут как бы все поняли, и успокоились ...

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

Я вообще возмущен действиями модератора !!


Разберем ошибки Бориса, хотя Г. Буча тут читали мало кто .. но я уже начинаю думать, что паттерны нанесли программированию больше вреда, чем пользы .. т.к. те кто думают, раз они их используют, они мол автоматически его выполняют

Паттерн фабрика противоречит ООП, забудьте его .. Борис должен был на первой итерации создать только один класс Хлеб и метод Спечь() .. он создал излишнию иерархию, которой небыло в постановке, и отделил сущность от его поведения ..

на втором шаге, он добавляет класс печь с методом Включить(Хлеб ХлебКлиента) и внутри вызывает метод Спечь хлеба

третий шаг, все хорошо, добавляем наследников от печи, и доопределяем метод включить печи /а они включаются по разному/ , но все равно вызываем метод Спечь хлеба

на четвертом шаге снова бред автора статьи, причем там сингл вообще не понятно, но в любом случае он нарует всегда ООП, и поэтому его не используем почти всегда.

Все что там надо сделать, да сделать метод типа IsGas() и в методе включить проверить перед тем как печь есть ли газ.

да, на пятом шаге мы конечно же добавляем все сущности которые хотим печь, но без общей иерархии, в них самих реализуем как они пекутся, выделяем интерфейс ИВыпечка с методом Спечь , и в печь передаем теперь не Хлеб, и интерфейс ИВыпечка , по Бучу мы спрятали ряализацию внутри класса ..

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

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

дальше автор как то не объясняет, чем отличается обжигать кирпичи от спечь хлеб, по сути ничем ... разве что температурой , но подразумевает, что нужна видимо не печь, а суперпечь .. ок .. вы вводим супер печь, надо ли вводить родителя Нагревателя, пока не очевидно, но допустим что у печи и супер печи есть чтото общие, тогда вводим, но между обжечь и спечь я общего ничего не вижу, да и так у нас там общие что? вызов метода интерфейса, да по сути пофиг, или ввести новый интерфейс ИОбжечь, или переименовать и сделать всего одни ИСделать


итак, я использовал ООП, не разу не изменил архитектуру на всем протяжении .. природа вещей полностью соответствует реальности, ни одного лишнего класса нет ..

поэтому это несостоятельное применение ООП Борисом ну не о чем не говорит


по сути, я единственным правилом от Буча, перенаправил проект в правильное русло .. каким? ну давайте специалисты найдите, что ту было ключевым, и что многие, кто думают что понимают ООП, почти никогда не знают?

DelfigamerПостоялецwww19 июня 20182:31#97
Зря старался, эти рассуждения всё равно не имеют смысла.
Delfigamer
> Данный пример плох тем, что в нём не указано, насколько сложным процессом
> является выпечка хлеба. Это вызов одной функции? Два с половиной экрана кода?
> Или в выпечку включается доставание велосипеда из гаража и поездка за 16 км в
> райцентр за мукой, яйцами и углём для печек?
tacПостоялецwww20 июня 201820:16#98
Delfigamer
> в нём не указано, насколько сложным процессом
> > является выпечка хлеба
на самом деле нет, от сложности процесса это не зависит ... показана структура процесса, и какая бы не была сложность, от этого декомпозиция не меняется .. .
DelfigamerПостоялецwww10 июля 20188:17#99
Ещё подумав над системой, я решил сгрузить с ней ещё пачку смысла и тем самым сделать её ещё проще и разделённее.
Для "стандартной формы" решил применить просто термин форма. То, что хранится на диске - это сериализация. То, что работает в оперативной памяти - это объект. Совокупное название для "идеи", выражением которой они являются - это сущность.
Преобразование форма→сериализация называется кодированием, а обратное - декодированием.
Преобразованию объект→форма дано отдельно название редукция, а преобразованию форма→объект - восстановление.
Ради сохранения ортогональности, каждой сущности соответствует пара (идентификатор, форма).
Число различных форм сильно уменьшено, в текущем варианте определены четыре класса форм:
1. Число - как целые, так и вещественные числа представлены одним классом.
2. Блоб.
3. Таблица - используется для хранения как агрегатов, так и списков. Таблица - это последовательность троек (индекс, идентификатор, форма). Система не накладывает каких-либо ограничений на порядок и структуру этих троек - они могут идти в любом порядке, повторятся сколько угодно или не быть вообще; эти тройки обретают смысл только в контексте конкретного восстановителя. В частности, разрешается интерпретировать 'форму' согласно типу, отличному от названного в 'идентификаторе', что может быть использовано для хранения производных типов - ссылок и массивов - путём записи аргумента в тройке и учёта фактического типа в восстановителе.
4. Идентификатор - произвольная последовательность из 16 байт. Может использоваться для ссылок на типы, восстановители, другие объекты или для хранения совершенно произвольных структур соответствующего размера.

Набор интерфейсов планируется таким:

type Id -- opaque 16-byte sequence
type ElementIndex -- opaque 32-bit value

Для представления произвольных идентификаторов и индексов в таблице вводятся специальные типы.

function registerobject( entityid :Id, :optional object )

Для разрешения перекрёстных ссылок хранится глобальное отображение идентификатор→объект.
Эта функция устанавливает элемент отображения. Если второй аргумент пуст - элемент очищается.
function registerloader( entityid :Id, :IEntityLoader )
function unregisterloader( entityid :Id, :IEntityLoader )

Эти функции устанавливают и очищают загрузчик, которым в случае надобности можно загрузить сущность из пакета.
Ради экономии времени и памяти, при загрузке пакета, из него сначала берётся только перечень хранящихся в нём сущностей. Согласно этому перечню, загрузчик пакета заполняет эту таблицу соответствующими инстансами IEntityLoader, в которых содержится слабая ссылка на пакет вместе с информацией, позволяющей быстро загрузить эту сущность, например - положение в файле, с коротого начинается сериализация.
При выгрузке пакета, загрузчики удаляются из таблицы.
Одна и та же сущность может быть переопределена в нескольких пакетах. В этом случае приоритет загрузчиков определяется порядком регистрации.
function setobjecttoload( entityid :Id ) :bool

Эта функция делает асинхронный заказ на загрузку сущности по его id.
Если в таблице уже есть готовый объект - функция ничего не делает и возвращает true.
Если в таблице есть загрузчик - функция готовит его к запуску и возвращает true.
В противном случае, если данный id нигде неизвестен - функция ничего не делает и возвращает false. Это позволяет немедленно обнаружить недоступные объекты и сообщить об ошибке в случае необходимости.
function getobjectbyidimmediately( entityid :Id ) :optional object

Эта функция возвращает готовый объект по его id, если он есть в таблице. Загрузчики этой функцией не учитываются.
Эти две функции используются для загрузки связанных сущностей. При первом проходе, во время конструирования объекта из форм, восстановитель делает заказы через setobjecttoload, что может добавить дополнительные сущности к загрузке в первом проходе. По его окончании, через getobjectbyidimmediately во втором проходе в места для ссылок подставляются действительные объекты.
function [[yields]] getobjectbyid( entityid :Id ) :optional object

Эта функция возвращает объект, если он доступен.
Если в таблице уже есть готовый объект - функция возвращает его.
Если в таблице есть загрузчик - функция начинает процедуру загрузки сущности, по окончании которой возвращает объект. Во время выполнения этой процедуры, управление может быть передано другому волокну.
function registerrestorer( :Id, :IRestorer )

Для полиморфной загрузки объектов хранится глобальное отображение идентификатор→восстановитель.
Эта функция регистрирует восстановитель по указанному идентификатору.
Отмена регистрации не предусмотрена.
function getrestorerbyid( :Id ) :optional IRestorer

Эта функция возвращает восстановитель по его идентификатору, если таковой зарегистрирован.
function generateid() :Id

Эта функция генерирует уникальный идентификатор.
interface IEntityLoader:
    function [[yields]] load() :object

Объекты этого типа инкапсулируют информацию и поведение, достаточные для загрузки определённой сущности из определённого пакета.
Поскольку род информации зависит от формата пакета, каждый класс пакета использует собственную реализацию этого типа.
interface IRestorer:
    function [[yields]] restore( :IDecoder ) :object
    function postrestore( :object )

Объекты этого типа реализуют процедуру восстановления конкретного типа объектов.
Система вызывает restore в первом проходе по графу сущностей. Этот метод должен прочитать форму из предоставленного декодера, сконструировать из него объект и вернуть его.
Система вызывает postrestore во втором проходе по тому же графу. Этот метод должен разрешить ссылки сконструированного ранее объекта.
enum FormClass:
    number
    blob
    table
    id
interface IDecoder:
    function getformclass(): FormClass
    function [[yields]] readnumber() :number
    function [[yields]] readblob() :string
    function getblobreader() :IInputStream
    function [[yields]] readelement() :optional IElementDecoder
    function [[yields]] readid() :Id
    destructor [[yields]] release()
interface IElementDecoder:
    function getindex() :ElementIndex
    function getid() :Id
    function getvalue() :IDecoder
    destructor [[yields]] release()

Декодер позволяет получить информацию о текущей форме и считать её.
Изначально, декодер находится в состоянии ожидания числа, в состоянии ожидания блоба, в состоянии ожидания таблицы или в состоянии ожидания идентификатора, согласно классу текущей формы
В состояниях ожидания, getformclass возвращает класс текущей формы.
В состоянии ожидания числа, readnumber считывает текущую форму как число типа double и переводит декодер в завершённое состояние.
В состоянии ожидания блоба, readblob считывает текущую форму как блоб, сохраняя всё его содержимое в один буфер памяти, и переводит декодер в завершённое состояние.
В состоянии ожидания блоба, getblobreader считывает текущую форму как блоб, возвращая объект двоичного потока в содержимое блоба, и переводит декодер в состояние считывания блоба. Закрытие потока, возвращённого функцией, переводит декодер в завершённое состояние.
В состоянии ожидания таблицы и в состоянии считывания таблицы, readelement считывает очередной элемент текущей формы как таблицы. Если достигнут конец таблицы, функция возвращает nil и переводит декодер в завершённое состояние, в противном случае функция возвращает дочерний декодер элемента и переводит декодер в состояние считывания элемента. Уничтожение дочернего декодера элемента переводит декодер в состояние считывания таблицы.
В состоянии ожидания идентификатора, readid считывает текущую форму как идентификатор и переводит декодер в завершённое состояние.
В состояниях ожидания и в состоянии считывания таблицы, уничтожение декодера пропустит всё несчитанное содержимое формы.
В состоянии считывания блоба и в состоянии считывания элемента, уничтожение декодера является ошибкой.
Эти ограничения позволяют реализовать декодер как интерфейс к парсеру поточных данных, где класс формы определяется просмотром вперёд, а вызов считывающего метода поглощает сериализацию этой формы из потока.
DelfigamerПостоялецwww10 июля 20188:17#100
interface IMutablePackage:
    function [[yields]] setentity( localid :Id )
    function [[yields]] setentity( localid :Id, :IReducer, :object )

Один из способов сохранения сущности - это явный запрос, в котором указывается пакет, идентификатор, редуктор и объект.
Время сохранения сериализации в конечном хранилище не фиксируется - в зависимости от реализации, setentity может направить сериализацию как непосредственно в хранилище, так и в промежуточный буфер в памяти. Тем не менее, по возвращении из метода, процедура редукции должна быть завершена и дальнейшие изменения состояния объекта не должны отражаться на сохранённой форме и сериализации.
Вариант setentity без редуктора и объекта используется для удаления сущности из пакета.
interface IReducer:
    function [[yields]] reduce( :object, :IEncoder )

Объекты этого типа реализуют процедуру редукции конкретного типа объектов.
Метод reduce должен записать форму в предоставленный энкодер.
interface IEncoder:
    function [[yields]] writenumber( :number )
    function [[yields]] writeblob( :string )
    function getblobwriter() :IOutputStream
    function [[yields]] writeelement( name :ElementIndex, :Id ) :IEncoder
    function [[yields]] writeid( :Id )
    destructor release()

Энкодер позволяет сериализовать форму в конкретный формат.
Изначально, энкодер находится в пустом состоянии.
В пустом состоянии, writenumber записывает текущую форму как число и переводит энкодер в завершённое состояние.
В пустом состоянии, writeblob записывает текущую форму как блоб, содержимое которого передаётся цельным буфером, и переводит энкодер в завершённое состояние.
В пустом состоянии, getblobwriter возвращает объект двоичного потока, позволяющий записать содержимое поблочно, и переводит энкодер в состояние записи блоба. Закрытие потока, возвращённого функцией, переводит энкодер в завершённое состояние.
В пустом состоянии и в состоянии записи таблицы, writeelement записывает один элемент, возвращает дочерний энкодер, в который запишется формовое значение этого элемента, и переводит энкодер в состояние записи элемента. Уничтожение дочернего энкодера, возвращённого функцией, переводит энкодер в состояние записи таблицы.
В пустом состоянии, writeid записывает текущую форму как идентификатор и переводит энкодер в завершённое состояние.
В состоянии записи блоба и в состоянии записи элемента, уничтожение энкодера является ошибкой.
В пустом состоянии, уничтожение энкодера может привести к неопределённым изменениям в сериализации текущей сущности. Такая ситуация обычно появляется в случае ошибки в процессе редукции.
Аналогично декодеру, эти ограничения позволяют использовать энкодер как интерфейс к сериализатору в поточный формат.
DelfigamerПостоялецwww12 июля 20187:18#101
Правила следуют семантике PEG.
Правила определяются как функции, которые принимают в качестве аргументов содержимое файла и положение текущего байта и либо возвращают маркер соответствия и новое положение, либо возвращают маркер несоответствия.
interface IRule:
    function invoke( input :string, pos :number ) :optional number

#числом обозначено конечное правило, соответствующее байту с указанным номером.
function ByteRule:invoke( input :string, pos :number ) :optional number
    if tobyte( input[ pos ] ) == self.value then
        return pos + 1
    else
        return nil
    end
end

Диапазоном чисел #от .. #до обозначено конечное правило, соответствующее любому байту на отрезке [от, до].
function RangeRule:invoke( input :string, pos :number ) :optional number
    local byte :number = tobyte( input[ pos ] )
    if byte >= self.lowest and byte <= self.highest then
        return pos + 1
    else
        return nil
    end
end

none обозначает конечное правило, соответствующее пустой строке.
function NoneRule:invoke( input :string, pos :number ) :optional number
    return pos
end

{ фигурными скобками } обозначено повторение правила от нуля до бесконечности раз.
function ZeroOrMoreRule:invoke( input :string, pos :number ) :optional number
    local lastpos :number = pos
    while true do
        local nextpos :number = self.rule:invoke( input, lastpos )
        if nextpos then
            lastpos = nextpos
        else
            return lastpos
        end
    end
end

Пробелами на одной строке обозначена последовательность правил.
`литералом` обозначено правило, проверяющее серию байт на соответствие шаблону.
function SequenceRule:invoke( input :string, pos :number ) :optional number
    local currentpos :number = pos
    for rule in self.rules do
        currentpos = rule:invoke( input, currentpos )
        if not currentpos then
            return nil
        end
    end
    return currentpos
end

Умножением на * число обозначено повторение правила фиксированное число раз.
function RepetitionRule:invoke( input :string, pos :number ) :optional number
    local currentpos :number = pos
    for repetition from 1 to self.count do
        currentpos = self.rule:invoke( input, currentpos )
        if not currentpos then
            return nil
        end
    end
    return currentpos
end

Последовательностью строк обозначена альтернатива между правилами.
Вертикальными чертами | на одной строке так же обозначена альтернатива между правилами.
!маркером показаны условия, которые в случае выполнения исключают соответствие правила.
В случае неоднозначности, альтернатива, определённая ранее, обладает приоритетом.
function AlternativeRule:invoke( input :string, pos :number ) :optional number
    for rule in self.exceptions do
        if rule:invoke( input, pos ) then
            return nil
        end
    end
    for rule in self.rules do
        local nextpos = rule:invoke( input, pos )
        if nextpos then
            return nextpos
        end
    end
    return nil
end

Текстовые пакеты следуют грамматике, определённой на двоичном потоке.
Файлы текстовых пакетов рекомендуется оформлять как корректные текстовые файлы в кодировке UTF-8.

- ::=
    { whitespace-element }

whitespace-element ::=
    line-comment
    whitespace-class

line-comment ::=
    `#` { line-comment-class }

whitespace-class ::=
    #0 .. #32

line-comment-class ::=
    ! newline-class
    any-class

newline-class ::=
    #10 | #13

any-class ::=
    #0 .. #255


Некоторые элементы языка разрешено разделять пустым пространством. Эти места в грамматике обозначены дефисом -.
Пустым пространством считаются все байты на отрезке [0, 32]. Сюда в том числе входят символы перевода строки #10 и #13, табуляция #9 и пробел #32.
Помимо этого, в пустое пространство входят комментарии. В данном языке, комментарием считается последовательность любых байтов, начинающаяся с символа `#` и заканчивающаяся символом перевода строки.

main ::=
    { - entity-def } -

entity-def ::=
    id - type-decl - `|=` - serial

type-decl ::=
    `:` - id
    none

serial ::=
    number-serial
    blob-serial
    table-serial
    id


Файл пакета является последовательностью сериализаций сущностей - определений.
Определение состоит из идентификатора сущности, опционального типа сущности и значения.
Тип сущности, если присутствует, обозначается символом `:`, за которым следует идентификатора типа. Если он отсутствует, типом сущности принимается тип по умолчанию, соответствующий классу формы, сериализованной в значении этого определения.
Значение обозначается диграфом `|=`, за которым следует сериализация сущности.
number-serial ::=
    number-sign hex-prefix { hexd-class } `.` { hexd-class } hex-exp-part
    number-sign hex-prefix hexd-class { hexd-class } hex-exp-part
    number-sign { decd-class } `.` { decd-class } dec-exp-part
    number-sign decd-class { decd-class } dec-exp-part

number-sign ::=
    `+` | `-` | none

hex-prefix ::=
    `0x` | `0X`

hex-exp-part ::=
    hex-exp-prefix number-sign decd-class { decd-class }
    none

hex-exp-prefix ::=
    `p` | `P`

hexd-class ::=
    `a` .. `f`
    `A` .. `F`
    `0` .. `9`

dec-exp-part ::=
    dec-exp-prefix number-sign decd-class { decd-class }
    none

dec-exp-prefix ::=
    `e` | `E`

decd-class ::=
    `0` .. `9`


Сериализация числа может быть выполнена в десятичной и в шестнадцатеричной системе.
Число состоит из опционального знака, префикса основания, основной части и опциональной экспоненты.
Знаками числа являются символы `+` и `-`.
Для шестнадцатеричных чисел, префикс основания - это `0x` или `0X`. Для десятичных чисел префикс отсутствует.
Основная часть является последовательностью цифр, среди которой может быть включена одна десятичная точка. Основная часть должна занимать не менее одного символа, будь то цифра или десятичная точка.
Для десятичных чисел, цифрами являются десятичные цифры от `0` до `9`. Для шестнадцатеричных чисел, к этому множеству добавляются буквы от `a` до `f` и от `A` до `F`.
Для обоих оснований, десятичной точкой является символ `.`.
Экспонента состоит из префикса экспоненты, опционального знака экспоненты и показателя степени.
Для десятичных чисел, префиксами экспоненты являются символы `e` и `E`; а для шестнадцатеричных чисел - символы `p` и `P`.
Знаками экспонент являются символы `+` и `-`.
Показателем степени является последовательность десятичных цифр. Показатель степени должен занимать не менее одного символа.
Для шестнадцатеричных чисел, основание экспоненты - 2; для десятичных чисел - 10.
Следует обратить внимание, что, в данной грамматике, сам по себе символ `.` является корректной сериализацией числа 0.
DelfigamerПостоялецwww12 июля 20187:18#102
blob-serial ::=
    blob-path-serial
    blob-quoted-serial
    blob-base64-serial

Сериализация блоба может быть выполнена в виде ссылки на файл, в виде строкового литерала и в виде base64-литерала.
blob-path-serial ::=
    `<` { path-class } `>`

path-class ::=
    ! `>` | newline-class
    any-class


Ссылка на файл оформляется как путь к файлу, заключённый между символами `<` и `>`. Путь может содержать любые символы, кроме `>` и символа перевода строки.
Содержимое блоба является содержимым файла по указанному пути.
blob-quoted-serial ::=
    `"` { quoted-element } `"`

quoted-element ::=
    quoted-name-escape
    quoted-dec-escape
    quoted-hex-escape
    quoted-unicode-escape-16
    quoted-unicode-escape-24
    quoted-whitespace-escape
    quoted-newline-escape
    quoted-class

quoted-name-escape ::=
    `\a` | `\b` | `\f` | `\n` | `\r` | `\t` | `\v` | `\"` | `\\`

quoted-dec-escape ::=
    `\` decd-class decd-class decd-class
    `\` decd-class decd-class
    `\` decd-class

quoted-hex-escape ::=
    `\x` hexd-class hexd-class

quoted-unicode-escape-16 ::=
    `\u` hexd-class * 4

quoted-unicode-escape-24 ::=
    `\U` hexd-class * 6

quoted-whitespace-escape ::=
    `\z` -

quoted-newline-escape ::=
    `\` #13 #10
    `\` #10 #13
    `\` #13
    `\` #10

quoted-class ::=
    ! `"` | `\` | newline-class
    any-class


Стоковым литералом является последовательность строковых элементов, заключённая между двумя символами `"`.
Содержимое блоба является конкатенацией байтовых строк, образованных строковыми элементами литерала.
Определяются строковые элементы следующих видов: именованный элемент, десятичный элемент, шестнадцатеричный элемент, базовый юникод-элемент, расширенный юникод-элемент, элемент пустого пространства, элемент новой строки и простой элемент. Все элементы, кроме простого, начинаются с символа `\`.
Именованный элемент `\a` соответствует байту 7.
Именованный элемент `\b` соответствует байту 8.
Именованный элемент `\f` соответствует байту 12.
Именованный элемент `\n` соответствует байту 10.
Именованный элемент `\r` соответствует байту 13.
Именованный элемент `\t` соответствует байту 9.
Именованный элемент `\v` соответствует байту 11.
Именованный элемент `\"` соответствует байту 34.
Именованный элемент `\\` соответствует байту 92.
Десятичный элемент состоит из символа `\`, за которым следует от одной до трёх десятичных цифр. Этот элемент соответствует байту с указанным номером.
Если после десятичного элемента следует десятичная цифра простым элементом, то десятичный элемент должен содержать все три цифры, иначе следующий символ будет воспринят как часть номера байта, а не как отдельный элемент литерала.
Шестнадцатеричный элемент состоит из символов `\x`, за которыми следует строго две шестнадцатеричные цифры. Этот элемент соответствует байту с указанным номером.
Базовый юникод-элемент состоит из символов `\u`, за которыми следует строго четыре шестнадцатеричные цифры. Расширенный юникод-элемент состоит из символов `\U`, за которыми следуют строго шесть шестнадцатеричный цифр. Эти элементы соответствуют последовательности байт, которая представляет символ с указанным номером в кодировке UTF-8.
Элемент пустого пространства состоит из последовательности `\z`, за которой следует пустое пространство. Этот элемент соответствует пустой последовательности байт.
Следует обратить внимание, что в данной грамматике комментарии так же являются пустым пространством, следовательно, они так же будут поглощены элементом пустого пространства.
Элемент новой строки состоит из символа `\`, за которым следует серия символов новой строки без повторений. Этот символ соответствует байту 10. На большинстве систем, под данное правило попадает один перевод строки.
Простым элементом является любой символ кроме `\`, `"` и символа новой строки. Этот элемент соответствует собственному байту в сериализации.
Для защиты содержимого блоба от случайных изменений инструментами для работы с текстом, сериализатору не рекомендуется представлять простыми элементами байты от 0 до 31 и байты, которые не образуют корректный символ в кодировке UTF-8.
blob-base64-serial ::=
    `@b64(` - base64-content - `)`

base64-content ::=
    { - base64d-class }

base64d-class ::=
    `a` .. `z`
    `A` .. `Z`
    `0` .. `9`
    `+`
    `/`
    `=`


base64-литералом является base64-нагрузка, заключённая между символами `@b64(` и `)`.
base64-нагрузка является последовательностью base64-цифр и символов `=`. В любом месте посреди нагрузки может быть вставлено пустое пространство (включая переводы строки и комментарии).
Содержимое блоба является декодированием нагрузки согласно кодировке Base 64, описанной в RFC 4648, со следующими изменениями:
- пустое пространство, как определено в этой грамматике, игнорируется,
- заполняющие символы `=` не обязательны и игнорируются.
table-serial ::=
    `{` { - table-element - `,` } - table-element - `}`
    `{` { - table-element - `,` } - `}`
    `{` - `}`

table-element ::=
    element-name - type-decl - `=` - serial

element-name ::=
    hex-prefix hexd-class { hexd-class }
    decd-class { decd-class }
    name-first-class { name-class }
    none

name-first-class ::=
    `a` .. `z`
    `A` .. `Z`
    `_`

name-class ::=
    `a` .. `z`
    `A` .. `Z`
    `0` .. `9`
    `_`
    `.`


Сериализация таблицы выполняется в виде последовательности элементов таблицы, заключённой между символами `{` и `}`. Элементы одной таблицы разделяются символом `,`. Между последним элементом и закрывающей скобкой разрешён дополнительный символ `,`.
Элемент таблицы состоит из имени элемента, опционального типа элемента и значения элемента.
Имя элемента может быть десятичным, шестнадцатеричным, текстовым и пустым.
Десятичные и шестнадцатеричные имена отображаются на записанное число.
Текстовое имя состоит из буквы или символа `_`, за которым следует ноль или более букв, цифр и символов `_` и `.`. Текстовое имя отображается на значение хеша [TBD].
Пустое имя отображается на число 0.
Тип элемента, если присутствует, обозначается символом `:`, за которым следует идентификатора типа. Если он отсутствует, типом элемента принимается тип по умолчанию, соответствующий классу формы, сериализованной в значении этого элемента.
Значение элемента обозначается символом `=`, за которым следует сериализация значения элемента.
id ::=
    `[` hexd-class * 32 `]`
    name-first-class { name-class }

Идентификатор может быть выполнен в виде литерала идентификатора и в виде именного определения.
Литерал идентификатора состоит из 32 шестнадцатеричных цифр, заключённых между символами `[` и `]`.
Именное определение состоит из буквы или символа `_`, за которым следует ноль или более букв, цифр и символов `_` и `.`.
Декодер определяет отображение имя->идентификатор. Если именное определение присутствует в отображении - оно равнозначно сериализации идентификатора, соответствующего этому имени в отображении. Использование именных определений, не известных декодеру, является семантической ошибкой.

Грамматика текстового пакета является LL(1)-грамматикой.
В частности, класс формы можно однозначно определить по первому байту её сериализации:
- десятичные цифры и символ `.` соответствуют числу,
- символы `"`, `<` и `@` соответствуют блобу,
- символ `{` соответствует таблице,
- буквы и символ `_` соответствуют идентификатору в виде именного определения,
- символ `[` соответствует идентификатору в виде литерала.
Это позволяет парсеру реализовать интерфейс декодера с минимумом промежуточной буферизации.

Страницы: 1 2 3 4 5 6 7

/ Форум / Программирование игр / Общее

2001—2018 © GameDev.ru — Разработка игр