Artos 99 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) Вопрос-1: Как оптимально определить тип таблицы 'список' (list), т.е. типа: {"a","b","c","d"} или {1,5,2,4,3}? Интересует не просто что-то вроде 'if next(Tbl) == 1 then', что явно недостаточно, и не полный перебор списка на поиск 'дыр' в индексах, а что-то пооптимальнее. Т.е. 100%-ое, нересурсоемкое и быстрое определение именно списка, а не иного типа массива. Совместимость с LUA игры обязательна. Вопрос-2: Как перевести целочисленное число в хекс-стринг, т.е. типа: 65535 => "FFFF" и обратно? Интересуют быстрые оптимальные варианты совместимые с LUA игры. Изменено 12 Сентября 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Nazgool 250 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) Artos По первому вопросу боюсь что без перебора не получиться. В принципе есть идея чтобы не перебирать. Но это когда буду дома. По второму вопросу могу пока предложить string.format hex = string.format('%x', 65535) dec = string.format('%d', '0x'..hex) У меня есть доморощенная функция преобразования DЕС/НЕХ, но я сейчас с тела. Вечером сравню скорости и сообщу. Метод 'string.format('%d', '0x'..hex)' - не применим для игры, т.к. ожидается только численное значение и стринг не приемлем (=> фатал еррор) --/ Artos Изменено 12 Сентября 2011 пользователем Artos Ссылка на комментарий
Malandrinus 615 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 Artos, Как оптимально определить тип таблицы 'список' (list), т.е. типа: {"a","b","c","d"} или {1,5,2,4,3}? На мой взгляд нет такого способа. Ведь между этими таблицами нет никакой принципиальной разницы. Только в типе ключей и в наличии/отсутствии разрывов в последовательности ключей. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Artos 99 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) malandrinus, (уже позже, перечитав вопрос, понял о двузначности фразы ...) Не разница между этими таблицами интересует, а это два основных варианта таблиц именно интересующего типа 'список'. Т.е. интересуют все таблицы, которые ключем имеют индексную последовательность, а не собственное значение ключа. Изменено 12 Сентября 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Malandrinus 615 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 Artos, Т.е. интересуют все таблицы, которые ключем имеют индексную последовательность, а не собственное значение ключа. Совсем я запутался. Таки надо определить, массивом или таблицей общего вида является таблица? Или что-то другое? Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
singapur22 14 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) Artos, Тоесть. ты хочешь определить, имеет ли список строчные значения, или же числовые?! Но ведь список может иметь и оба типа значений. К кому такой список приравнять? А по сути, без полного перебора таблицы, невозможно определить типы всего списка значений. Но раз уж на то пошло, и тебя устроит использование классового списка, то всегда можно создать класс, отвечающий всем требуемым условиям. Изменено 12 Сентября 2011 пользователем singapur22 Опаа-а!!! Ливер вылез! Ссылка на комментарий
Malandrinus 615 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) Недавно нарвался на интересную и неприятную особенность метода перебора с ipairs. Я хотел парсить список аргументов переменной длины и написал что-то вроде такого function fun(...) for _,arg in ipairs({...}) do -- ... end end Так вот выяснилось, что перебор останавливается на первом же аргументе со значением nil даже если за ним имеются ещё аргументы. Это, вообще говоря, идёт вразрез с официальной документацией. Вот цитата (на русском, но на английском написано тоже самое): ipairs (t) Возвращает три значения: итератор, таблицу t, и 0, поэтому конструкция for i,v in ipairs(t) do body end будет выполнять цикл парами (1,t[1]), (2,t[2]), ···, до первого целого ключа, отсутствующего в таблице. Т.е. по идее значение имеют только ключи. Они должны быть целые, непрерывные от единицы. Ну вы понимаете. Это здесь естественно выполняется автоматом, но ipairs тем не мене не работает. Точнее ipairs то может и работает, но не работает алгоритм перебора, основанный на нём. Пришлось делать так: function fun(...) local args = {...} for k=1,#args do local arg = args[k] -- ... end end Самое интересное, что оператор получения длины # (решётка) при наличии значений nil работает без проблем и показывает полную длину, а не до ближайшего nil. Именно с этим столкнулся, когда делал безопасный универсальный вывод в лог-файл вместо штатного 'printf()', и пришел к аналогичному решению. Вот и в данном случае, в отношении таблиц-списков, интересует - как выделить такие 'args = {...}' даже с 'nil'-ами, отделив их от иных типов массивов/матриц. --/ Artos Изменено 12 Сентября 2011 пользователем Artos Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
singapur22 14 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) malandrinus, И всё же. Вопреки описанию, методы pairs и ipairs производят проверку значений на nil. И если таковой находится, итерация прекращается. Чтобы в этом убедиться, достаточно просмотреть исходник данного метода: ... static int pairsmeta (lua_State *L, const char *method, int iszero, lua_CFunction iter) { if (!luaL_getmetafield(L, 1, method)) { /* no metamethod? */ luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */ lua_pushcfunction(L, iter); /* will return generator, */ lua_pushvalue(L, 1); /* state, */ if (iszero) lua_pushinteger(L, 0); /* and initial value */ else lua_pushnil(L); } else { lua_pushvalue(L, 1); /* argument 'self' to metamethod */ lua_call(L, 1, 3); /* get 3 values from metamethod */ } return 3; } static int luaB_next (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 2); /* create a 2nd argument if there isn't one */ if (lua_next(L, 1)) return 2; else { lua_pushnil(L); return 1; } } //Метод вызываемый функцией pairs(tbl) static int luaB_pairs (lua_State *L) { return pairsmeta(L, "__pairs", 0, luaB_next); } static int ipairsaux (lua_State *L) { int i = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TTABLE); i++; /* next value */ lua_pushinteger(L, i); lua_rawgeti(L, 1, i); return (lua_isnil(L, -1)) ? 1 : 2; } //Метод вызываемый функцией ipairs(tbl) static int luaB_ipairs (lua_State *L) { return pairsmeta(L, "__ipairs", 1, ipairsaux); } ... Всё дерево используемых методов выкладывать не буду, оно слишком велико. Функционал большинства методов понятен из их названий. Небольшая (пока) ремарка: Прекращается при значении key == 'nil' , но(!) метод 'pairs' продолжается при key ~= 'nil' и 'value' == 'nil' . Т.е. критично для итерации значение 'key', а не 'value'. --/ Artos Изменено 12 Сентября 2011 пользователем Artos Опаа-а!!! Ливер вылез! Ссылка на комментарий
ksenobit 0 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) Приветствую. Возник вопрос в процессе разработки своего мода. После спавна нпс через скрипт постоянный вылет при старте игры Загрузка секторов и порталов... * Loading HOM: d:\namod\gamedata\levels\l01_escape\level.hom * phase time: 41 ms * phase cmem: 273647 K Загрузка ИИ объектов... - Loading music tracks from 'l01_escape_musics'... * phase time: 82 ms * phase cmem: 273686 K Клиент: Создание... - Game configuring : Started - Game configuring : Finished * phase time: 506 ms * phase cmem: 281511 K Загрузка текстур... * t-report - base: 976, 339154 K * t-report - lmap: 0, 0 K * phase time: 5219 ms * phase cmem: 281511 K Клиент: Синхронизация... * phase time: 42 ms * phase cmem: 281511 K * [win32]: free[942052 K], reserved[246088 K], committed[908948 K] * [ D3D ]: textures[339154 K] * [x-ray]: crt heap[281511 K], process heap[457918 K], game lua[26436 K], engine lua[216 K], render[0 K] * [x-ray]: economy: strings[5446 K], smem[26970 K] FATAL ERROR [error]Expression : fatal error [error]Function : CScriptEngine::lua_error [error]File : E:\stalker\patch_1_0004\xr_3da\xrGame\script_engine.cpp [error]Line : 73 [error]Description : <no expression> [error]Arguments : LUA error: d:\namod\gamedata\scripts\_g.script:20: bad argument #2 to 'format' (string expected, got no value) stack trace: Scheduler tried to update object escape_trader ! Invalid ogg-comment version, file: d:\namod\gamedata\sounds\wepack\weapons\oc14\reload.ogg Intro start 7147 * MEMORY USAGE: 301282 K FATAL ERROR [error]Expression : fatal error [error]Function : CScriptEngine::lua_error [error]File : E:\stalker\patch_1_0004\xr_3da\xrGame\script_engine.cpp [error]Line : 73 [error]Description : <no expression> [error]Arguments : LUA error: d:\namod\gamedata\scripts\_g.script:20: bad argument #2 to 'format' (string expected, got no value) stack trace: вылет идёт постоянно, не могу найти причину по логу. Скидываю выдержку из лога. Вылет сразу после загрузки игры и ролика. Пролистай несколько страниц назад (см. пост #2603 и далее), где была и аналогичная запись в логе и дана была рекоментация по замене 'кастрированной' функции 'abort()' для поиска причины ошибки. --/ Artos Изменено 12 Сентября 2011 пользователем Artos Ссылка на комментарий
Artos 99 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) Цель заданных вопросов по таблице-списку и переводам Hex->String->Hex: Уже немало модов, где требуется сохранять 'свои' параметры и в достаточно большом кол-ве и в виде таблиц. Вариантов сохранения по сути три: 1. Записывать в 'pstor' объектам; 2. Записывать в пакет объекта напрямуую; 3. Записывать во внешние файлы. Вариант 3 - для ТЧ практически отпадает, т.к. класс работы с файлами достаточно рудиментарен, тем более на запись. Да и 'мусорить' на компе игрока - не самый удачный вариант. Вариант 2 для разрабатываемых модов или опционально подключаемых мини-модов/модулей - неприемлем и-за несовместимости сэйвов. Остается вариант 1. Запись в 'pstor' (вариант 1) имеет два подварианта: 1.1. Штатный метод из 'xr_logic.script' (pstor_store/pstor_retrieve); 1.2. Расширеный метод, дополненный сохранением таблиц. Ярким (и наиболее часто используемым до сих пор) примером являются методы АМК-мода (amk.script -> save_variable/load_variable). Особенности использования варианта 1.1 'штатным' методом: В 'pstor' записываются только три типа значений "boolean", "string", "number". Запись таблиц невозможна. Если по булевым и строковым значениям нет вопросов, то для чисел уже появляются. Все(!) численные значения записываются в сэйвы единым методом "w_float", т.е. всем им в обязательном порядке выделяется 4 байта (float == w_u32). Т.о. даже числу '1' (единичке) выделяются те же 4 байта из потребного одного бита. В игре из числовых значений как правило сохраняются время, игровые идентификаторы объектов, некие кол-ва и флаги (0/1/2). Т.о. основная часть сохраняемых числовых значений вполне укладывается в два байта (u_16 -> 65535). Внеся в 'штатный' метод сохранения/чтения сэйвов доп.признак 'целое число не более FFFF' - можно сэкономить немало байт в сэйвах. Особенности использования варианта 1.2 'расширеным' методом: Расширеный вариант помимо некоторого удобства применения (не требуется указывать объект и можно записывать 'nil'), имеет возможность записи таблиц. Для записи таблиц используется перевод всех полей (кеу и value) в таблицах в строковые значения и конкатенация (слияние) их в единую строку, которая и сохраняется. При чтении - обратная операция по восстановлению таблицы. 1. При переводе все типы таблиц упаковываются едино, т.е. и ключ и значение его поля (key & value) переводятся в строки. Несложно заметить, что для таблиц типа 'список', в качестве ключей будут упаковываться индексы (1,2,3... и т.д.). Внимание(!). Но ведь для таких таблиц по сути и НЕ требуется запоминать ключи-индексы. Достаточно только запомнить, что это именно 'список' и сохранить значеня в порядке их следования. Минусом/плюсом является эффект 'чистки', если в списке есть 'дырки' (нилевые значения). Для сэйвов это плюс. 2. При переводе таблицы в строку, опять же используется единый метод 'tostring(number)' для всех численых значений. Т.к. переводится в строку десятичное значение(!), то кол-во знаков (а каждый знак - это байт при записи!) для чисел более 9 начинается 'растранжиривание' байтов. Если конвертировать в стринг не десятичное, а шестнадцатеричное значение - экономия на лицо. Практически реализовал вышеописанную оптимизицию для записей в 'pstor', которая совместима с нынешними играми/сэйвами (при отсутствии обратной совместимости). Осталось гарантированно (все же сэйв) определять признак (НЕ)списков и найти оптимальный вариант методов конвертеров Hex -> String -> Hex. Думаю к 'завтра' выложу для публичной критики и/или общего применения. Изменено 12 Сентября 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Nazgool 250 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) ....т.к. ожидается только численное значение и стринг не приемлем (=> фатал еррор) Я поленился на теле набирать, но ведь tonumber ещё не отменяли :-) dec = string.format('%d', tonumber('0x'..hex)) Или Сталкер и этого не понимает? К сожалению ... Метод 'tonumber' ожидает только десятичное представление числа символами строки. Любой не 'числовой' символ ('x') - воспринимается как буква и => 'nil'. --/ Artos P.S. Подзабыли про параметр '16' для метода ... :-) Изменено 12 Сентября 2011 пользователем Artos Ссылка на комментарий
Artos 99 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) _Призрак_ Хотя ты и немного ошибся с переводом в 'hex_num' (удалив и пост), но спасибо за подсказку! Это как раз перевод в 'dec_num'. Похоже это: local iDec = 12345 --/ исходное десятичное целочисленное local sHex = string.format('%X', iDec) --/ переводим в хекс-строку iDec = tonumber('0x'..sHex, 16) --/ переводим в десятичное число хекс-строку - то, что нужно! (Подзабыл про параметры для этого метода) Одна голова - маловато будет. Вот несколько - в самый раз. Изменено 12 Сентября 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
Nazgool 250 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) Можно без '0x' (на всякий случай уточню) в чистом lua hex = string.format('%x', 65535) dec = tonumber(hex,16) Спасибо. Проверил: в игре такой вариант работает. --/ Artos Изменено 12 Сентября 2011 пользователем Artos Ссылка на комментарий
panzyuza 43 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) У меня вопрос.Функции, относящиеся к гулагам из xr_conditions.script, применимы ли к смарттерейнам, работающими на основе схемы genelar_lager? Что означают эти параметры смартов switch_0 = {!is_day} switch_1 = {=is_day} switch_0 = {=gulag_empty(esc_stone_lager)} switch_1 = {=gulag_population_comed_ge(esc2_dogs_zamost:3) !gulag_empty(esc_stone_lager) =gulag_state(esc2_dogs2_exit:0)}? Заранее,спс. Я так понял, switch_0 = условия для дневной работы, а switch_1 = условия для ночной работы, да? Изменено 12 Сентября 2011 пользователем panzyuza AVS_LOCATION_MOD Ссылка на комментарий
Artos 99 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) panzyuza Функции из 'xr_conditions.script' - это функции общего применения и не привязаны к каким-то конкретным гулагам (если внутри функции нет конкретных указаний на имена/секции) и могут применяться в любых схемах логики. Да и простыми скриптами, при правильном указании входных аргументов. Параметры 'switch_0' и 'switch_1' - аналоги функции 'load_states()' из скриптов типа 'gulag_XXX.script' для 'именных' гулагов, возвращающей состояние гулага в зависимости от неких условий. Твое предположение почти верно - гулагам типа 'genelar_lager' именно этими параметрами задаются условия и проверяются их состояния. Изменено 12 Сентября 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
panzyuza 43 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) Artos, прошу еще пояснить. switch_0 = {=gulag_empty(esc_stone_lager)} switch_1 = {=gulag_population_comed_ge(esc2_dogs_zamost:3) !gulag_empty(esc_stone_lager) =gulag_state(esc2_dogs2_exit:0)} В данном смарте ночная работа доступна при отсутсвии кого-либо в гулаге esc_stone_lager. Во втором параметре дневная работа доступна, если в гулаге esc2_dogs_zamost больше трех обьектов, если в гулаге esc_stone_lager есть кто-то, если в гулаге esc2_dogs2_exit установлена дневная работа.Я правильно истолковываю понятия? Точнее наоборот, switch_1 = дневная работа, switch_0 = ночная. Я понял, что в скрипте xr_conditions функции работают по принципу = условие равно, ! = условие ложно. Изменено 12 Сентября 2011 пользователем panzyuza AVS_LOCATION_MOD Ссылка на комментарий
Artos 99 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 (изменено) panzyuza Все (почти), о чем ты спрашиваешь - лежит в кодах 'gulag_general.script' и конечно в 'xr_logic.script'. Условия же читаются из 'xr_conditions.script'. Что конкретно проверяет каждая функция из условий - зависит от нее. Строка: 'switch_0 = {=gulag_empty(esc_stone_lager)}' - приведет к тому, что при пустом гулаге 'esc_stone_lager' будет возвращено состояние '0' для гулага 'esc2_dogs_zamost' с этой стокою. Никакой тут ночной/дневной работой и не пахнет. Вероятно просто собаки вернутся в свой гулаг (не смотрел логику). Вторая строка с 'switch_1' - вернет состояние гулага '1' при упомянутых в строке (и растолкованных тобою) условиях. Вероятно собаки побегут нападать ... Не вешай себе шоры. Нет в этих строках конфига логики никакой привязки (условий) ночная иль дневная работа. Более правильно: Условие истино, если - '=' функция вернет true, Условие истино, если - '!=' функция НЕ вернет true (т.е. если вернет false). Изменено 12 Сентября 2011 пользователем Artos "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
panzyuza 43 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 Понял.Ошибься.Действительно, даже в скриптах gulag_xxx так регулируються состояния гулага.И нет дневной и ночной работы.Просто немного запуталься.Данные параметры также имитируют алайф в сталкере. Добавлено через 16 мин.: В статьях по логике написано, что схема xr_rest нормально не работает.Есть ли данная схема, доработанная и дополненная? AVS_LOCATION_MOD Ссылка на комментарий
Nazgool 250 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 По поводу определения типа таблиц. Набросок без итераторов. Проверку на пустую таблицу и скорость не делал. function GetTabStatus(tab) if #tab ~= 0 and not next(tab, #tab) then return 'index' -- индексирудмый массив else return 'hash' -- всё подряд end end Ссылка на комментарий
RvP 1 Опубликовано 12 Сентября 2011 Поделиться Опубликовано 12 Сентября 2011 Gun12, не обязательно сравнивать размер таблицы с нулем if #t then вполне достаточно, и не сработает если индексы в таблице не натуральные Vita sine libertate, nihil Vita sine litteris - mors est Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти