Перейти к контенту

Справочник по функциям и классам


Рекомендуемые сообщения

По поводу >>класса FS<<

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

function read_ltx(filename)
    local fs = getFS()
    local inv_ltx = nil
    if filename then
        inv_ltx = fs:exist("$game_config$",filename)
    end
    if not inv_ltx then
        qqq("Parse_ltx: file "..tostring(filename).." not exist")
        return nil
    end
    local abs_name = inv_ltx.name
        qqq("abs_name = "..abs_name,1)
    local size = inv_ltx.size_real
        qqq("size = "..tostring(size),1)
    local r = fs:r_open(abs_name)
    r:r_seek(0)
        qqq("after r_seek(0)")
    local str = r:r_stringZ()
        qqq("after r_stringZ")
    if r:r_tell() > size then
        str = string.sub(str,1,size)
    end
    local str_del = str
-- дальше чищу от хлама, не суть
    return str_del
end

qqq - безобидный вывод в лог

 

 

Файл класс FS видит в любом случае - неважно, распакован ли он в геймдату, или остался в игровом архиве. Полное имя файла (abs_name) всегда пишется d:\games\и т.д., размер считается (не знаю уж, насколько правильно, но все-таки). Файл открывается на чтение в любом случае - метка "after r_seek(0)" в логе присутствует, вылетов не было.

 

Проблемы начинаются при попытке прочесть содержимое файла:

local str = r:r_stringZ()

Если файл распакован в геймдату, то все прекрасно читается, в лог идет метка "after r_stringZ", и программа работает дальше. Если файл в архиве, игра с 99% вероятности виснет (иногда, без видимых причин, все-таки прочитывает), и последняя метка в логе - "after r_seek(0)"

 

Не пойму только, это в принципе такое ограничение, или я что-то неправильно делаю...

 

 

Изменено пользователем Kirag

Мои работы:

Ночные прицелы + смена ножевого слота

AI вертолетов + ПЗРК

Soul Cube

 

Работаю только с ТЧ. С ковырянием ЧН/ЗП не связываюсь ни в какой форме. Совсем.

Ссылка на комментарий

Kirag,

а почему выбрана именно функция r_stringZ? может лучше на r_u32 проверять?

Просто функция r_stringZ читает строку до символа'/0', а такой в файлах конфигов, например, не встречается.

А так запросто может и переполнение буфера быть.

Ссылка на комментарий

Kirag

Не очень понятна конечная цель твоего поста.

Понять 'имеется ли некое ограничение' и есть ли более правильный вариант для 'твоего' способа чтения содержимого файла, чем ты пытаешься применить?

Или найти вариант чтения файлов, который даст приемлемые с точки зрения 'стабильности' применительно к классу FS?

 

На первое, могу только предполагать, что вероятно не зря сами разработчики игры, в версиях ЧН и ЗП ввели уже нормальное пространство 'io' для работы с файлами.

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

Ведь ни что не мешает скопировать любой файл (из пак-файла иль с виртуального диска) в удобное место и уже работать с ним. Т.о. работа с заведомо присутствующим файлом уже не имеет указанных тобою 'странностей и нестабильностей'.

По окончании - времянку можно и удалить, дабы не оставлять мусора. Используя этот вариант с промежуточным копированием, пока ни разу не замечал сбоев.

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

 

abramcumner

А откуда такая информация о чтении только до символа '/0' ? Может быть до '\000'?

Но ведь очевидно, что и суть вопроса и данный метод предназначен для конфиг-файлов (*.ltx, *.xml, и иже), а не для чтения иконок,текстур и пр. 'бинарников'. Читать в числовой массив дабы распарсивать по-битно далее - более ресурсоемко (ИМХО).

На практике читается все содержимое потребных файлов в строку ... с конечно же принудительным ограничением считываемого объема (при необходимости), дабы ненароком не переполнить буфер чтения. Размер файла может быть получен до чтения его содержимого.

 

Примечание: Прошу куратора топика не рассматривать данный пост как оффтопик и продолжение темы о парсере. По сути это уточнение особенностей использования класса FS.

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Artos,

Но ведь очевидно, что и суть вопроса и данный метод предназначен для конфиг-файлов (*.ltx, *.xml, и иже), а не для чтения иконок,текстур и пр. 'бинарников'.

Это не так совершенно. И класс FS и все его методы принципиально предназначены для работы с бинарными файлами. Метод типа readZ никак не может быть для текстовых файлов, поскольку в текстовых файлах строки не разделяются физическими нулями, а разделяются специальными символами. Почему может не работать, это другой вопрос.

 

Насчёт наличия в ЧН/ЗП пространства имён io, это вполне может быть недосмотр разработчиков. Сами они его не использовали, а о сообществе они не думали никогда даже в малейшей степени.

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

malandrinus

Исходные данные вопроса: Автор вопроса Kirag привел достаточно однозначный пример применяемой им функции:

- само название говорит о работе именно с текстовыми файлами типа LTX;

- конкретно указана папка ($game_config$), что говорит о работе с текстовыми конфиг-файлами;

- им применен именно метод r_stringZ.

 

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

Автор вопроса указал, что каких-либо затруднений чтения файлов указанным методом при условии их распаковки на физический диск не испытывает.

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

Причем замечу(!), я НЕ советую использовать, а только защищаю возможность применения метода 'r_stringZ', которую использовал Kirag, проверенную на практике в достаточно различных ситуациях игры и достаточным временем.

 

Ваше замечание о предназначении класса FS принципиально для бинарников - достаточно голословно. Можно получить/почитать аргументы/обоснования?

Но в любом случае - иного штатного метода работы с любыми файлами в игре (ТЧ) нет.

То, что строки в текстовых файлах разделяются спец.знаками ('\013','\010') - не относится к сути. В вопросе говорится о чтении всего содержимого файла в стринг, с последующим его построчным иль иным разбором и пр. - автор указал: 'дальше чищу от хлама, не суть'.

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

Но(!) Вы уверены в корректности своих советов относительно именно запакованных файлов? Не останется ли 'ограничение'?

 

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

 

 

Изменено пользователем Valerius

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

 

malandrinus

А как объяснить(?) такой факт с позиции применяемых методов:

- пробуем читать из корня конфиг-папки (gamedata\config\...) запакованные файлы - ошибок нет.

- пробуем прочитать методом 'r_stringZ' например файл из пак-файла по пути: gamedata\config\misc\zone_kampfire.ltx - ошибка.

- разархивируем этот файл и кладем в соотв. папку на диске - файл читается и распарсивается без проблем.

- читаем запакованный исходный файл вариантом:

  local sStr = ''
  for i=1,iSize do --/ iSize - длина файла (size_real)
    sStr = sStr .. string.char( r:r_u8() )
  end

- ошибка отсутствует и файл корректно парсится далее.

В принципе, последний вариант вполне применим и для Kirag'a, если не критична по-байтная итерация для получаемого стринга ...

Ну а предпоследний - читаем мой первый пост по вопросу (о временной копии на диск).

Изменено пользователем Valerius

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Artos,

Ваше замечание о предназначении класса FS принципиально для бинарников - достаточно голословно. Можно получить/почитать аргументы/обоснования?

Давайте по порядку. Метод r_stringZ своим названием говорит, что читается с-строка или иначе строка с нулевым терминатором. Это однозначно и безо всяких исключений означает, что в конце этой строки стоит нулевой байт. Текстовые же файлы - это файлы, имеющие достаточно определённую структуру:

1. Принимается соглашение, называемое кодировкой символов, относительно того, какой код символа какой букве соответствует. Часть кодов резервируется для специальных нужд и не соответствует никаким символам. В широко распространённой кодировке ASCII, которая по сути является основной для почти всех современных кодировок, отображаемые символы - это символы начиная с кода 32 (пробел). Ниже расположены управляющие символы. Их 32 и сейчас большая часть не имеет смысла (типа коды управления перфоратором). В том числе не имеет смысла код 0. Имеют смысл только некоторые типа табуляции или символов конца строки.

2. Принимается дополнительное соглашение о делении на строки. Сейчас используется один из двух символов "перевод строки", "возврат каретки" или их комбинация.

Всё.

Относительно символа с кодом "ноль". С самых доисторических времён этот символ имел значение "в строке не встречается". Именно поэтому в языке СИ этот символ был выбран как терминальный символ для хранения строк в памяти, потому что его ну никак не может быть в строке. В таком контексте под "строкой" разумеется не строка текстового файла, а "текст" в самом общем смысле, содержащий любые допустимые форматирующие элементы. Это может быть и текстовый файл целиком. Вот к примеру именно как z-строка хранится кастомдата в нетпакете - целиком файл конфигурации, содержащий несколько строк.

 

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

 

Я сейчас взглянул на пример из поста Kirag-а. Ошибка очевидна. Естественно эта функция вызывает сбой при чтении из текстового файла. Там же нет ни одного физического нуля. Как этот сбой будет проявляться, зависит от того, где находится этот файл. Если на диске, то возможно внутренние механизмы чтения обрабатывают ситуацию иначе, нежели при ситуации нахождения его в архиве. В одном случае тихо завершает чтение, в другом - генерирует вылет. Но и в том и в другом случае - это ошибка.

 

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

 

и относительно вот этого:

1. Метод r_stringZ читает байты до нуль-терминатора или до конца последовательности байтов (при отсутствии терминатора).

Это откуда? Я такого не писал - это точно. Подчёркнутое - неправильно. При отсутствии терминатора будет классический выход за границу массива со всеми вытекающими. Собственно, все ранее приведённые примеры это и показывают. Кстати, поэтому z-строки считаются небезопасными в использовании.

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

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

malandrinus

К сожалению все же не получил ответа на поставленные вопросы (например: о применимости именно к запакованным файлам любых методов 'r_'). :-(

 

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

1. 'Об обязательности наличия нуль-терминатора'

malandrinus: Метод r_stringZ своим названием говорит, что читается с-строка или иначе строка с нулевым терминатором.

Предлагаю иную трактовку:

Метод 'r_stringZ' предначен для чтения байт-последовательности до первого обнаруженного нуль-терминатора (zero). Результатом является последовательность символов кодировка которых соответствует прочитанным байтам.

- Название метода 'r_stringZ' говорит о чтении некоего байт-массива в строку (не путать с текст-строкою!), т.е. возвращает значение прочитанных байтов в формате type == "string";

- вероятно(!), окончание 'Z' можно трактовать как сокращение от 'Zero', намекающее на чтение последовательности байт до символа NULL (нуль-терминатора) ИЛИ до 'отсутствия' байта (zero);

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

- никакого намека на какие-либо ограничения чтения байт-массива и/или неконвертации считаных байт не имеется.

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

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

 

Итак в фразе:

malandrinus: Это однозначно и безо всяких исключений означает, что в конце этой строки стоит нулевой байт

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

 

2. 'О недопустимости применения метода 'r_stringZ' к текстовым файлам'

Нигде в исходном вопросе и моих пояснениях не упоминается о чтении текстовых файлов в текстовую строку.

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

Однако(!), речь идет о получении данным методом стринга прочитанного файла, т.е. сырой(!) последовательности символов, включая и переносы и пр. 'мусор'.

По сути, как я понял, и для Kirag'a и для меня требуется при прочтении файла это (упрощенно):

  local ltx = fs:exist("$game_config$", filename) --/< имя файла
  local size = ltx.size_real --/ размер файла
  local r = fs:r_open(ltx.name) --/ 'читалка' (объект/линк на файл)
  local str = '' --/ заготовка для 'сырого' стринга
  for i=1,size do --/ 'читаем' от начала и до конца файла
    local sym = r:r_u8() --/ прочитанный байт
    if sym > 0 then --/ нуль-терминатор?
      sStr = sStr .. string.char( sym ) --/ добавляем к стрингу
    else
      break --/ прерываем чтение по NULL
    end
  end
  return str --/> на выходе сырая последовательность прочитанных символов

- т.е. то, что и дает применение штатного метода 'r_stringZ'.

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

 

3. И последнее, о чем уже не раз повторяю, суть вопроса НЕ в применимости метода, а в том, что ТОЛЬКО с нерасспакованными файлами происходит сбой.

Т.к. природа сбоя непонятна, то (ИМХО) ни что не гарантирует наличия аналогичных сбоев и для других методов (того же r_u8()).

 

Пока же могу только предположить, что упомянутый тут в суе 'CreateFileMapping' и работа с созданной виртуальной областью запакованных файлов имеет некие особенности. Для гарантированной работы - стОит заморачиваться с распакованными копиями, если это не накладно для игры ...

 

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Artos,

 

1. 'Об обязательности наличия нуль-терминатора'

 

Предлагаю иную трактовку:

Метод 'r_stringZ' предначен для чтения байт-последовательности до первого обнаруженного нуль-терминатора (zero). Результатом является последовательность символов кодировка которых соответствует прочитанным байтам.

Здесь трактовкам не место. Я изложил факт. Так работают строки в языке СИ. Z-строки - это другое название СИ-строк, или C-строк. Это структура данных вполне однозначная и означает последовательность символов с нулём в конце.

 

3. И последнее, о чем уже не раз повторяю, суть вопроса НЕ в применимости метода, а в том, что ТОЛЬКО с нерасспакованными файлами происходит сбой.

Т.к. природа сбоя непонятна, то (ИМХО) ни что не гарантирует наличия аналогичных сбоев и для других методов (того же r_u8()).

Прочитайте внимательно. Природа сбоя в том, что при попытке чтения нуль-терминированной строки из обычного текстового файла происходит гарантированный выход позиции чтения за пределы файла. Это происходит в любом случае, находится файл в архиве или нет. Разница только в том, как реагирует система на это внештатную ситуацию. В одном случае (файл в архиве) происходит вылет, в другом (на диске), по какой-то причине вылета не происходит. Но это ошибка в обоих случаях! Скорее всего, при чтении другими методами проблем не будет ни в каком варианте, поскольку все остальные функции читают известное количество байт (1, 2, 4 и т.д.). Естественно, будет такая же ошибка, если я и другими функциями дойду до конца файла и попытаюсь оттуда прочитать.

 

К сожалению все же не получил ответа на поставленные вопросы (например: о применимости именно к запакованным файлам любых методов 'r_'). :-(

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

 

Для гарантированной работы - стОит заморачиваться с распакованными копиями, если это не накладно для игры ...

 

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

 

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

 

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

malandrinus

Спасибо за 'дебаты' и Ваши 'трактовки'. :-)

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

За себя (что-то автор вопроса не проявляет активности) могу только констатировать: тема на сегодня для меня исчерпана. Будем подстраиваться под то, что имеем и в том виде как понимаем.

:-)

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Artos,

К чему исходники?

 

Есть такая штука Утиный тест. Т.е. если нечто выглядит как утка, плавает как утка и крякает как утка, то это вероятно утка и есть.

 

Так вот есть функция, написанная программистами на C, на языке С, с именем r_sringZ и вылетающая на файлах, не содержащих нулей. ок, язык конечно С++, но это мало что меняет.

 

Не достаточно?

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

malandrinus,Artos, спасибо за подсказки :)

 

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

 

По большому счету нужно начиная с system.ltx выбирать из текста файла секции и инклуды, с каждым инклудом процедуру повторять. В каком виде при этом содержимое файла - не так важно, лишь бы читалось. В случае с парсером XML метод r_stringZ читал до конца файла, плюс иногда чуть-чуть мусора, который я обрезал по размеру.

 

Но с запакованным LTX-ом номер не удался, подозреваю, из-за того, что символ NULL не находит и читает строку, пока не повиснет...

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

 

 

Мои работы:

Ночные прицелы + смена ножевого слота

AI вертолетов + ПЗРК

Soul Cube

 

Работаю только с ТЧ. С ковырянием ЧН/ЗП не связываюсь ни в какой форме. Совсем.

Ссылка на комментарий

malandrinus

Не мне тебе говорить, что даже тот же LUA-интерпретатор в игре далеко не всегда соответствует исходному для LUA-языка. И то, что напсано разработчиками LUA не всегда соответствует тому, что мы имеем в оеальных кодах игры.

И к сожалению, тот же 'утиный' тест нами также трактуется по-разному и то, что 'вижу' я, тобою (не)видится иначе.

 

Т.к. все же люблю поковыряться в поисках ответа, проведу еще несколько тестов.

Пока в свете упомянутого тобою 'утиного' теста предлагаю все же не то что НЕ видно пояснить, а то что видно (плавает и крякает):

Выше уже приводил практические результаты чтения для взятого 'на бум' файла 'gamedata\config\misc\zone_kampfire.ltx'.

Итак, что же видим при применении метода 'r_stringZ':

- будучи на диске - файл читаем в стринг. Никаких намеков на ошибки нет даже в тредах (внешний перехватчик);

- будучи в пак-файле исходном(!) - чтение оканчивается ошибкой.

- будучи упакованным в дополнительный пак-файл - чтение заканчивается успехом.

 

Сорри, но я вижу ошибку чтения файла и пока только ее. Ошибка может быть вызвана и самим методом, но(!) ведь может не только им.

Даже перепаковка в другой пак-файл - не прерывает кряканья утки.

 

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

Вложить в исходный пак-файл чуть подправленный текстовый файл (с добавленным нуль-терминатором) и попытаться читать его и исходный.

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

Если же подправленный файл НЕ будет прочитан - Ваши заключения ошибочны. и 'крякание' утки оозначает именно крякание, а не то, что аналогично крякает и где-то называется манком. :-)

 

Добавлено через 10 мин.:

Kirag

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

Для меня пока остался единственный вопрос, касающийся 'конца файла'.

Если все же в метод 'r_stringZ' заложена проверка окончания файла - то какова природа сбоя именно на запакованных файлах. Причем сбой зависит от 'в какой запакован' и вероятно от пути (в корне или в подпапке).

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

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Artos

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

 

Кстати, не знаю, с чего я вбил себе в голову, что символ NULL = конец файла. В парсере XML мусор регулярно читается, может, я и в этом не прав...

 

 

 

Мои работы:

Ночные прицелы + смена ножевого слота

AI вертолетов + ПЗРК

Soul Cube

 

Работаю только с ТЧ. С ковырянием ЧН/ЗП не связываюсь ни в какой форме. Совсем.

Ссылка на комментарий

malandrinus,

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

 

Возможно это и стенка, но предпочитаю все же проверить, хотя бы и собственным лбом/носом, а не 'холст' ли это в каморке папы Карло?

:crazy:

 

Добавлено через 5 мин.:

Kirag

У меня и комп позволяет и познания/навыки имеются для копаний в любых файлах/архивах иль на дисках/блинах. В пак-файлах сами файлы ничем(!) не отделены. Используется (условно) таблица с указанием начального адреса для чтени и размер. Никаких добавочных нуль-терминаторов нет.

Все (ИМХО) сводится к реализации виртуального пространства, куда игра "распаковывает" и дает доступ. К сожалению это движок и тут только предполагалки доступны.

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Kirag,

Кстати, не знаю, с чего я вбил себе в голову, что символ NULL = конец файла. В парсере XML мусор регулярно читается, может, я и в этом не прав...

Нет никакого нулевого окончания файлов. ОС Windows к файлам ничего не дописывает. Поэтому так делать нельзя. Если читаете текстовый файл с помощью FS, то надо читать его побайтно, потом собрать строку из байтов. Для этого есть функция string.char(<список символов>), а для получения списка из таблицы (куда читали) есть функция unpack(<таблица>).

По байту конечно медленнее, чем разом файл. Но файлы здесь небольшие, это терпимо, а главное - так правильно.

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

malandrinus

Последний тест подтвердил корректность работы метода 'r_stringZ' при наличии в запакованных текстовых файлах нуль-терминатора.

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

Т.о. Ваше утверждение о недопустимости применения данного метода для запакованных файлов - верно.

По сути, можно это утверждение транслировать и на все остальные подобные случаи, т.к. заранее нет информации о том, какие файлы не на диске.

Примечание: При распаковке и обратной запаковке (утилитой 'converter.exe') ошибка чтения исходного файла все же отсутствовала, что говорит о зависимости от формата упаковки пак-файла.

 

Добавлено через 102 мин.:

P.S. В качестве бонуса для не имеющих достаточных навыков в скриптах:

--/ на входе: имя файла для прочтения в стринг (и опционально: кол-во считываемых байт)

function Read_FileToString( filename, max_size ) --/ чтение файла в стринг ('сырую' строку)
  local fs = getFS()
  local file = fs:exist("$game_config$", filename) --/ файл-объект в папке конфиг-файлов
  if file then --/ имеется ли заданный файл?
    local str = '' --/ заготовка для 'сырого' стринга
    if not max_size then max_size = 32768 end --/ если не задан ограничитель объема чтения
    if file.size_real < max_size then --/ размер файла не превышает допустимого?
      local reader = fs:r_open(file.name) --/ 'читалка' (объект/линк на файл)
      if reader then --/ условие возможности чтения
        reader:r_seek(0) --/ устанавливаем на 'начало' файла
        --/ последовательное по-байтовое считывание содержимого файла
        local byte = reader:r_u8() --/считываем 1-й байт
        while byte > 0 do --/ если не нуль-терминатор (NULL == 0x00)
          str = str .. string.char(byte) --/ конвертируем и добавляем к стрингу
          if reader:r_eof() then --/ если конец файла
            byte = 0 --/ приравниваем к нуль-терминатору
          else --/ считываем след.байт
            byte = reader:r_u8()
          end
        end
      end
    end
    --/ на выходе функции: 'сырая' последовательность прочитанных символов
    return str
  end
  return nil
end

Вариант с применением чтения в массив (плавающими r_u64 ... r_u8) с последующими 'unpack' и char(...) проигрывает по быстродействию и ресурсам.

 

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

P.S. В выше указаном варианте функции чтения, для модмейкеров, которые допускают наличие 'пустых' файлов в игре, можно внести доп.проверку на нулевую длину файла:

if file.size_real > 0  and file.size_real < max_size then --/ размер файла не 0 и не превышает допустимого?

В этом случае исключается возврат случайного символа для пустого файла.

 

(считаю тему затронутую Kirag'ом исчерпаной, 'бонус' дан для примера возможной реализации)

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Есть небольшое дополнение к классу client_spawn_manager()

Если использовать функцию add с 4 аргументами, то все работает так как написал malandrinus. Но если использовать в функции add только 3 аргумента, то в функцию, которая будут будет вызываться когда объект перейдет в оффлайн будет передаваться только 2 значения - id и game_object, а не как я думал nil, id и game_object. Будьте осторожнее

Freedom

Ссылка на комментарий

_Призрак_

Если уточняешь/дополняешь - стОит более тщательно применять слова:

а) Вызов функции коллбэка происходит НЕ при переходе в оффлайн, а при переходе объекта в онлайн.

б) Не только кол-во аргументов (3 иль 4) критично, а значение 4-го аргумента не 'nil'.

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

Т.о. следует учитывать, что при наличии этого 4-го аргумента функция отработки коллбэка должна имеь вид:

local function spawn_callback(user_data, id, obj)
  ...
end

если же 'user_data' не используется, то вид отрабатываемой функции должен иметь вид:

local function spawn_callback( id, obj)
  ...
end

Ну а если не известно значение 'user_data' при установке коллбэка и оно может отсутствовать (быть равным 'nil'), то в функции отработки придется применять спец.проверки на кол-во и тип входных аргументов ...

 

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

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти
  • Недавно просматривали   0 пользователей

    • Ни один зарегистрированный пользователь не просматривает эту страницу.
  • Куратор(ы) темы:

×
×
  • Создать...