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

Скриптование


Svoboда

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

Artos,

Т.е. интересуют все таблицы, которые ключем имеют индексную последовательность, а не собственное значение ключа.

Совсем я запутался. Таки надо определить, массивом или таблицей общего вида является таблица? Или что-то другое?

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Недавно нарвался на интересную и неприятную особенность метода перебора с 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

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

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Gun12,

По поводу определения типа таблиц.

Набросок без итераторов. Проверку на пустую таблицу и скорость не делал.

function GetTabStatus(tab)
    if #tab ~= 0 and not  next(tab, #tab) then
        return 'index' -- индексирудмый массив
    else
        return 'hash' -- всё подряд
    end
end

Увы, здесь не учитывается тот случай, когда в таблице произвольного вида имеются несколько ключей, отвечающих правилам "массивов". Т.е. если есть хотя бы ключ [1], то так таблица будет распознана как массив, хотя там может быть что угодно ещё.

 

Я думаю, что здесь без полного перебора не обойтись. Что же касается исходно заявленной задачи сохранения таблиц/массивов, то очевидным решением будет делать отдельную функцию сохранения на разные варианты и не пытаться определять "тип" автоматически. В конечном счёте, конкретная таблица как правило в силу дизайна либо является массивом, либо имеет произвольный вид. Ключевой момент "в силу дизайна", т.е. программист заранее знает природу этой таблицы. Это означает, что в подавляющем большинстве случаев задача определять тип не стоит вовсе, поскольку тип и так известен заранее.

 

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

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Gun12,

Не пойму, чего вы хотите от iраirs?

Всё происходит так как и положено.

Какому-то индексу присвоили значение nil. Сборщик мусора удалил это поле. Осталось дырка в индексах. Вот он и тормознул на этом поле. Совершенно правильно работает.

Сборщик мусора удаляет не ссылки, а значения. Между тем в таблице собственно хранятся именно ссылки. Будет ли удалена из таблицы ссылка зависит от ряда обстоятельств. Вот пример различного поведения:

t = {1, nil, 2, 3} -- завёл массив с "дыркой посередине"

print(#t) -- его длина 4

t[3] = nil -- занулил элемент со значением 2

print(#t) -- длина по прежнему 4

 

t = {} -- исходно пустая таблица

t[3] = 1 -- заполняем с конца, здесь оператор длины даёт 0

t[2] = 2 -- здесь тоже 0

t[1] = 3

print(#t) -- имеем 3

-- типа получили массив? Как бы не так!

t[2] = nil -- зануляем элемент посередине

print(#t) -- получаем 1

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

 

Это бы всё не стоило обсуждения (работает так и работает, надо только знать), но в документации Lua декларируется, что таблицы - это всегда ассоциативные массивы, а разница массив/не массив - это только детали внутренней оптимизации, которые как-бы не должны сказываться на поведении. К примеру, то, что там внутри используется для реализации ассоциативного массива, в принципе не должно быть важно. Хеш, ну и хорошо. Могло быть и что-то другое, бинарные деревья к примеру. А в реальности выходит, что детали реализации и подробности внутренней оптимизации очень даже важны и заслуживают обсуждения.

 

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

 

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

 

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

Artos,

2. Делаю все же универсальный вариант и для тех кто порой не понимает разницы в типах таблиц (т.е. не готов определять директивный аргумент) и ... порой таблицы могут иметь различный тип ... упаковка 't должна быть всегда и по возможности максимально экономная.

Рискну заметить, что это не самая лучшая идея сама по себе, а в соединении с теми, кто "порой не понимает разницы в типах таблиц" идея приобретает совершенно разрушительную мощь. Если функция заранее знает, какого типа аргумент будет на входе, то можно будет сделать проверки и остановить работу с вразумительным сообщением. Если на входе возможные варианты, то функция уже никак не сможет сказать, а что на самом деле хотел сделать программист. Здесь ошибка в данных, или это неправильно использованный вызов или что-то ещё? Вариантов становится слишком много, проверить их все уже невозможно. Остаётся только довериться программисту, но ведь программист подразумевается такой, что "порой не понимает разницы в типах таблиц". Такому только доверься... Это готовый бардак в коде, испорченные сейвы, практическая невозможность отлаживать и вообще сопровождать код. IMHO, не стоит этого делать.

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Gun12,

Теперь о 'дырах' и собственно моем варианте без перебора...

...

Вот я и пошел таким путем.

if #tаb~=0

Определяю, есть ли в таблице элементы списка (индексов от 1 и до упора).

Если нет, то это уже не список. Ответ - хэш.

Если есть такие элементы, то последний из них по любому найдется.

И теперь проверяя nехt(tаb,#tаB)

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

Дальше, первая часть алгоритма так и не сможет определить наличие дырок в массиве в случае, как я приводил выше. В принципе не критично. Надо только не пользоваться ipairs и проверять на эти дырки при сохранении.

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

 

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

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Gun12,

Наверное ты всё-таки прав. Не нужно высовываться

Где я такое сказал?

 

Artos,

мне интересно, что ты будешь делать с этой функцией дальше. Вот ты проверил, что это массив. Но ведь это только говорит об упорядоченности ключей. А что насчёт значений? Ведь в качестве значений может быть что угодно: числа, строки, таблицы, пользовательские объекты. До какой степени ты будешь пытаться автоматизировать обработку?

 

 

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

_Призрак_,

Можно ли каким то способом получить объект инвентарь или же просто открыть его?

Ты можешь получить это окно через MainInputReciever, когда оно уже открылось, но не можешь открыть штатными средствами.

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

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Shadows,

1) Имеется ли способ отлова открытой вкладке в ПДА? Если нет, то какими-нибудь обходными путями это можно выяснить?

через модификации движка. Колмогор ещё делал выдачу инфопорции по переходу на конкретную закладку.

 

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

У статика прокрутки нет, на то он и статик. complex_mode кстати не отвечает за перенос, а только за то, чтобы работали вручную расставленные переносы.

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

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

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Real Wolf,

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

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

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Zander_driver,

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

Принципиально неверный подход. Ты смешиваешь понятия "представление" и "конверсия/преобразование". Преобразовывать надо значения тогда и только тогда, когда надо чтобы значение изменилось, как бы тривиально это ни звучало. Задача представить значение в каком-то виде: сколько-то знаков после запятой или в некой системе счисления, - это совсем другое. Значение при этом не меняется, только создаётся некая временная строка для показа её хуману. Так вот, round и иже с ними - это конверсия, format - это создание представления.

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

KD87,

Кстати, а битовый сдвиг в сталкерском lua есть?

Нету

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Dennis_Chikin,

или я чего-то не понимаю, или set_relation() работает только для актора.

По идее, работает для CInventoryOwner, к коим относятся актор, сталкеры, монстры и торговец (отдельный класс, единственным представителем является Сидор).

Только правильно ли ты эту функцию используешь? Вот нормальное описание, которое всё руки не доходят выложить в справочник.

    void set_relation(enum ALife::ERelationType <relation>, game_object* <who>) // установка отношения 
    // на самом деле это просто установка персональной благосклонности (что можно напрямую сделать с помощью set_goodwill)
    // в соответствии с параметрами из секции "game_relations" 
    // (это как правило файл "config\creatures\game_relations.ltx", входящиё в system.ltx)
    // константа           | параметр в секции game_relations |  значение в оригинальной игре
    // --------------------+----------------------------------+------------------------------
    // game_object.enemy   | goodwill_enemy                   | -1000
    // game_object.neutral | goodwill_neutal                  |  0
    // game_object.friend  | goodwill_friend                  |  1000

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Artos,

1. Если ты (или кто-то ...) считаете такую строку кода валидной:
second_speaker:set_relation(1--[[first_speaker:relation(obj)]], obj)

а что не так? Закомментирован кусок кода блочным комментарием, но фрагмент синтаксически корректен.

 

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

_Призрак_,

Есть ли на данный момент возможность повернуть объект типа physic_object? Пытался выбирать кость и хитовать ее - не подходит. Смотрел m_net_utils, но судя по коду возможности изменить direction у объекта при помощи нет_пакетов еще нет. А можно ли как нибудь по другому?

Доуточню то, что выше сказал Artos. Поля из cse_abstract доступны в STATE_Write только в момент создания объекта. При этом нетпакет уже заполнен этими данными, но они ещё не прочитаны движком. Если в этот момент перепаковать пакет, то можно всё там поменять.

 

По поводу физики и вращения. Это требует специального визуала для объекта. Надо добавить что-то типа маховика с вращательной степенью свободы. Затем методами класса сочленения (джоинта, вроде как) вращаешь маховик в одну сторону, а весь объект крутится при этом в другую. Точных названий классов сейчас не припомню, но можешь глянуть модуль управления дверью. Двери открываются как раз физическим вращением, и эти команды для этого и были экспортированы.

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Artos,

Немало обьектов периодически перезаписывают свои нет-пакеты в процессе игры и при этом можно получить доступ к секции 'cse_abstract', распарсив нет-пакет.

Это противоречит тому, что я знаю. По моим данным, вызов STATE_read/write не при записи/сохранении - результат прямого вызова этих методов со стороны скриптов, и при этом всегда в нём отсутствует начальная часть cse_abstract по понятным причинам. В немодифицированной игре эти вызовы происходят строго при загрузке/сохранении за исключением пары случаев, когда этими манипуляциями занимаются сами авторы игры (они и сами этим грешили, есть такое дело).

Серверные данные переписываются постоянно, это факт, но вызовы STATE_read/write в этом не участвуют. Внутри движка клиентская часть имеет прямой доступ к серверной, и в этом попросту нет необходимости.

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Artos,

Смотрим 'se_item.script', в котором к счастью имеются все классы для оружия (кстати и класс физ.объекта там же).

Да, в оригинальном скрипте в этих классах отсутствуют коды с методами STATE_Read|Write, но внеся эти коды мы видим, что они работают(!) и есть доступ к начальной части нет-пакета с секцией 'cse_abstract'.

...

Причем, чтение/запись нет-пакетов происходит не только при старте/сейве игры или при спавне соотв. объекта, но и в процессе(!) игры.

...

При необходимости (и возможности) принудительно вызвать для объекта его 'штатные' STATE_Read|Write можно, например, переводом объекта он-офф-лайн ...

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

 

Проверь сам, только возьми чистую игру.

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Artos,

ты прав, на самом деле вызывается при переходе в онлайн. Однако, других моментов, когда это ещё вызывается, я пока не вижу.

 

хотя не возьму в толк - в чем именно в этом отношении имеется различие между каким-либо модом и чистой

разница может быть как небо и земля. Я сам, к примеру, использую перепаковку нетпакетом кастомдаты оружия. Это кстати можно в онлайне делать. А как сходу отличить вызов скриптом и вызов движком? Разве только по значению w_tell.

 

Почему то после первого пакета далее w_tell постоянно равен 2 (двум) и никак не могу определить начало пакета ...

Так вот это скорее всего скриптовые вызовы, поскольку в движковых в нетпакете уже есть данные cse_abstract и w_tell как раз и даёт их размер.

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

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Artos,

Хотя для активного оружия актора у меня как раз стоИт постоянное чтение из нет-пакета кол-ва патронов именно 'своим' скриптовым вызовом на чтение общего нет-пакета.

А зачем нетпакетом? Есть же вроде get_ammo_in_magazine

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Artos,

Для предметов классов cse_alife_item_document (II_DOC) и cse_alife_item_pda (D_PDA/S_PDA) имеется параметр 'info_portion', который в исходной игре никак не задействован (пустая строка).

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

 

Примечание: Очень не хочется быть привязанным только к all.spawn'у или перезаписывать нет-пакеты нужных объектов, чтобы использовать данный параметр.

Нет строки в конфиге. Только через SDK/аллспавн/нетпакеты.

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение

Artos,

'nil' - не записывается! ... Присваивание 'nil' ключу в массиве - это по сути удаление этого ключа (вместе с его значением), если такой ключ существовал.

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

 

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

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

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

 

Поделиться этим сообщением


Ссылка на сообщение
  • Недавно просматривали   0 пользователей

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