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

Язык Lua. Общие вопросы программирования


Malandrinus

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

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

Твой нынешний вариант тоже гонял в игре, рабочий. Оба варианта идентичны по результату.

Посто данный подход позволяет внутри класса замыкать именно его нюансы и следовать формату ACDC, а не выводить каждый раз во внешнюю примочку. Это вполне может быть актуальным, если далее подстраивать/расширять коды под версии игры (+ЧН, +ЗП) и дополнять недостающие классы.

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

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

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


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

Не буду продолжать спор о фломастерах ... ;-), хотя можно указать, что тогда уж и всему подобному не место в классах, т.е. все _read/_write из классов поубирать, оставив на откуп net_base и внешним функциям ... (ниже как раз такой "кандидат" на вынос).

 

По делу: Похоже в "-- item packet hooks" (класс cse_alife_item) есть неточность. По условию 'num_items' == 0 должны отсекаться чтение/запись всех(!) последующих пропертей, а в настоящей реализации отсекаются (в skip_updprops) только последние два, обусловленные своими доп.условиями. Более павильно вроде бы так (для _read):

  --/ item packet hooks
  local skip_updprops = {}
  for _,prop in ipairs(self.updprops) do
    if not skip_updprops[prop.name] then
      ret[prop.name] = this["_r_"..prop.type](updpk, prop.len)
      if prop.name == 'num_items' then
        if ret.num_items == 0 then
          break
        else
          if bit_and(ret.num_items, 64) ~= 64 then
            skip_updprops.ph_angular_vel = true
          end
          if bit_and(ret.num_items, 128) ~= 128 then
            skip_updprops.ph_linear_vel = true
          end
        end
      end
    end
  end

(для _write по аналогии)

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

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

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


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

Тоже пока не обнаруживал вылетов, но обуславливаю это тем, что в игре может вообще не правятся такие объекты (с 'num_items' ~= 0), а может редко читаются/изменяются эти апдейт-параметры, тем более пока экспериментировал не отловил предметов с 'num_items' ~= 0.

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

 

P.S. В приведенном тобою куске кода из ACDC невозможно понять какая версия или хотя бы о каких пропертях идет речь в коде. Кусок из универсального не выкладываю, т.к. ... "много буковок" и много веток. ;-)

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

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

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


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

xStream, опять ... ;-(

Не буду надоедать, но обрати внимание, что пропущенное при чтении - НЕ скипится при записи(!) и из дефолтов вылезут несуществующие в 'data' проперти. (в ЧН/ЗП еще к этим поприбавится)

 

P.S. Тут параллельно идет обсуждение о подписках/отписках, что конечно важно, но ... в теме (пере)записи нет-пакетов каждый байт/бит важен и при ошибке - никакие отписки не помогут. Поэтому и такая с моей стороны дотошность. (сорри, но это я еще не выверял каждый класс начисто, а только в черновую).

 

P.P.S. Пока пишу некоторые куски с заделом/запасом для ЧН/ЗП расширения. Заменить break на return можно в конце (начисто), а вот если потребуется и забыть что завершил - можно долго в код всматриваться ... Сейчас у меня эта строка так: break --/ => return --/>

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

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

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


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

Рабочий вариант модуля для работы с нет-пакетами в игре.

 

- модуль сделан на базе xs_netpk и m_net_utils;

- работа с нет-пакетами версий ТЧ/ЧН/ЗП (патч ТЧ 1.0004 и выше);

- наличие единого вызова для всех игровых объектов (не исключающий указание конкретного класса);

- раздельная работа с обоими типами пакетов (state|update), что не исключает и объединенный пакет данных;

- максимально упрощенная работа с изменением свойств 'cse_abstract';

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

- автономность работы (коды необходимых хелперов интегрированы в модуль);

- недоделаны только несколько "сложных" классов объектов типа smart_terrain ...

 

ссылка: m_netpk_120120 (~21.2 кБ)

 

Прошу заинтересовавшихся проверить (перед выкладыванием в общую тему по скриптам) и дать комментарии/замечания/пожелания.

(в дальнейшем по работе модуля - в топик по скриптам)

 

P.S. Обновил архив, исправлены отдельные ощибки, добавлен функционал классу шейперов.

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

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

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


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

Andrey07071977, собственно про coroutine в начале топика нам напомнил и дал информацию Gun12 (#301), а тут (#112) конкретный практический пример использования в игре подпрограммы (созданной не движком, а скриптом) для постоянного сканирования всех локаций по всем игровым объектам.

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

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

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

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


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

Unnamed Black Wolf

Что-то нередко попадаешь 'не в тему', читая НЕ внимательно написанное.

Сказано конкретно:

Artos: ... но именно применительно к движковым потокам коллбэков для модмейкеров малоупотребима, т.к. пока практически из скриптов невозможно получить статусы этих потоков ...
Подскажи, плз, как получить в скриптах игры для, например, потока actor_binder:update(...) иль stalker_binder:hit_callback(...) его статус (coroutine.status)! :crazy: Изменено пользователем Artos

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

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


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

Ну а по "нормальному", т.е. с проверками корректности заданных строк:

prefetch(new_scr) --/ не обязательно, но не помешает ...
if type(_G[new_scr]) == 'table' and  type(_G[new_scr][func_1]) == 'function' then
  _G[new_scr][func_1]() --/ вызов функции
end

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

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

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


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

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

Ну а что более обще иль гибче - все же опять и от конкретного контекста зависит и от вкусов.

Вариант с _G[file_name][func_name] использован разработчиками в том же xr_logic.script, что дает возможность "вспомнить" тем, кто подзабыл как вызвать функцию.

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

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


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

Согласен с таким резюме.

Может быть добавил бы еще для _G[<имя модуля>]:

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

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

 

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

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


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

Что-то вы заспорились ...

*Shoker*, задал, как обычно, вопрос с общей формулировкой для довольно локальной своей задачи и стОит ли копья ломать?

Если требуется "изнутри" скрипта (игры) определить имя - лучше script_name() не придумать (чего и *Shoker*'у уже достаточно).

Если же "снаружи", то вариантов три:

1. Смотрим, как сами разработчики передавали имя скрипта как аргумент в ту же функцию _g.debug_log ...

2. Используем debug.getinfo (для SHoC имеется расширитель от RvP), что и сами разрабы использовали: local script_тame = debug.getinfo(2).short_src:gsub('%.script', "")

3. Парсим, как предложил Gun12, глобальную метатаблицу _G и сравниваем поля с искомой функцией.

Каждый выбирает свой путь, исходя из потребностей и возможностей. ИМХО.

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

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

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


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

alpet, очень интересная инфорамция и обнадеживающая. Обязательно попробую потестровать и проверить наличие многопоточности именно в игре.

Однако ... халь, что по сути подобное носит "новостной характер", т.к. без хоть каких-то кодов/исходников остается или только использовать то что доступно или, засучив рукава, торить новый путь по указанному курсу ... чтобы иметь возможность подстраивать под иные версии и варианты расширения движка.

 

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

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


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

*Shoker*, в Lua имеется пространство io, которое доступно в версии игры CS (ЧН).

1. Тот же мод "Faction commander" на полную катушку использует запись в свои конфиг и лог.

2. Странно видеть подобный вопрос от того, кто в своем моде использует (по сути) это:

function save_to_file(filename)
    local fname = getFS():update_path("$game_saves$", filename..".msf") --/#~#
    local file = io.open( fname, "w" ) --/#~#
    if file then
...

Если же вопрос не про открытие/использование своего файла со своими сообщениями, а о том, чтобы (и) "штатые" строки лога сохранять в каком-то вторичном файле помимо "штатного" лог-файла - то так и нужно писать об этом. И вопрос бы не в топик по Lua, а в топик по ковыряниям в файлах игры ...

Средств Lua для подобного нет, т.е. 'что и куда' указано - 'то и туда' и пишет. Консоль - это уже не Lua, а движек игры.

Т.о. без стороннего модуля, который бы мониторил "штатный" лог (консоль) и дублировал бы куда захотелось - не обойтись.

 

P.S. Ну тогда ты точно топиком обшибся. Средствами Lua можно многое делать, в том числе и тебе потребное, но ... тебе же нужно ИЗ ИГРЫ, т.е. и не самим Lua, а его кастрированным куском и не столь Lua, сколь абы чем лишь бы ... покомандовать на компе пользователя без его участия (хотя бы и в благих целях).

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

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

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

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


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

Выскажу ИМХО:

Правильнее в данном случае следовать контексту, т.е. делать так как требуется именно тебе в данном конкретном случае.

Собственно свойства могут быть (условно) глобальными и частными, т.е. зависеть от тех или иных условий (как, например, в твоем случае "не нужно этого делать до определенного времени").

Смотрим аналогии в тех же классах игры: При создании объекта (метод "__init") далеко не все свойства сразу же присваиваются. Какие-то добавляются в методе 'on_register' и т.д. Т.о. класс "обрастает" свойствами по мере его вхождения в игру.

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

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


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

Dennis_Chikin, наверное чтобы был ясен предмет и предпосылки 'этого' разговора, стОит дать ссылку: #1246.

 

Честно говоря, "убить неделю" для того чтобы сделать вывод о недопустимости удалений "из таблиц вообще" - дело конечно скорее субективное, но ... не для модмейкеров, которые работают над общим проектом (ИМХО). Но это лирика ... не будем углубляться. ;-)

Ну а с точки зрения программирования, то чем же так штатные табличные методы Lua (и в частности движковые) провинились, что ими даже пользоваться нельзя?

Предлагая понятие "гуманизма" не поминать, к программированию иль логике игры это понятие не имеет никакого отношения.

 

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

 

ИМХО, основная ошибка и подобных действий и рассуждений в том, что игнорируется тип таблиц, и к индексированным таблицам ( типа: { v1, v2, ... } ) начинают применяться недопустимые методы изменения, что приводит к смене типа => { [1]=v1, [2]=v2, ... }, т.е. таблица становится хеш-массивом.

Программист, работая с таблицами, НЕ имеет права допускать чтобы:

Dennis_Chikin: ... когда операция t[n] = v делает внутри таблицы нечто непредсказуемое
. Если он работает с индексированными таблицами, то все его действия не должны нарушать структуру таблицы и тогда любые table.insert()/table.remove() и выборки v = t[n] работают безукоризненно.

Если же в любом месте, и тем более внутри цикла итерации по таблице, происходит приравнивание поля таблицы к nil - то и работать с такой таблицей следует как с хеш-таблицей!

 

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

 

Судя по обрывку кодов из поста в теме по ссылке:

t1000s = t1000s + 1
t1000[t1000s] = { ["fn"] = task, ["name"] = task_name }

for i = 1, t1000s do
  if t1000[i]["name"] == task_name then
    table_remove( t1000, i )
    t1000s = t1000s - 1
    return
  end
end

- можно однозначно сказать, что таблица t1000 изначально может не являеться индексированной, т.к. ЛЮБОЙ сбой или нештатное вмешательство при ее заполнении подобным методом чреват нарушением индексов.

Раз уж используется table_remove, то и наполнение таблицы должно быть по аналогии (а не как с чеш-таблицей):

table_insert( t1000, { ["fn"] = task, ["name"] = task_name } )

t1000s = #t1000

Т.е. не задавать исскуственно индекс, а отслеживать его конечное значение.

И при удалении, не считать t1000s = t1000s - 1, а просто определять оставшейся об'ем таблицы: t1000s = #t1000

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

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

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


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

Dennis_Chikin, хочется донести две мысли:

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

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

Понятно желание обращаться к нужному полю по ключу (да еще и по понятному числу), и получать размер таблички одним штатным методом (#), но первое - свойство хеш-таблиц, а второе - индексированных!

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

Раз и формируете хеш-таблицы, то и итерацию проводите как с хеш-таблицами (if k,v in pairs(tab) do) и удаляйте на здоровье tab[k] = nil.

Подмена вами понятия 'ключ' (k) на 'индекс' (i) - просто иллюзия, которая врядли облегчает понимание и работу с кодами, но ... из-за возникшего где-то бага - и служит вам плохую службу.

ИМХО, вариантов тут три:

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

б) перейти на коды для хеш-таблиц и итерации и чистки проводить соотв.методами, т.е. отказаться и табле remove и #. и if i=1,n do ...

 

2/ Ну и третий с) вариант:

Глядя на вашу систему 'watchdog' и кучу табличек для коллбэков, хочется не про язык Lua говорить, а напомнить: "Количество должно переходить в качество", тем более для солянки, в которой уже чрезмерно много ... Ведь то, о чем сейчас говорим - это сердце/каркас всего мода, на котором он держится и от надежности и качества его зависит очень многое.

Совсем без таблиц конечно же не обойтись, но стоить ли пытаться об'ять все и вся, вместо того, чтобы распределить это по самим скриптам/модулям?!

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

 

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

P.S. И, кстати, не тут ли ваша проблема(?):

По всем канонам языка переменные для циклов являются локальными для циклов(!).

Ваша конструкция некорректна(!):

local t1000s = 0 --/ это локальная переменная для скрипта 

for i = 1, t1000s do --/< об'явлены переменные для цикла!
  if t1000[i]["name"] == task_name then
    table_remove( t1000, i )
    t1000s = t1000s - 1 --/< !!! а это уже локальная для цикла!!!
    return
  end
end

Об'яви для цикла именно свою переменную типа n = t1000s и сам цикл for i = 1, n do - может перестанет сыпаться? ;-)

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

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

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


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

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

Насчет "и та и другая часть в таблице присутствуют всегда" - это несколько перебор, т.к. "часть с интексом" может отсутствовать.Пример: пустая таблица не имеет ни одной части, пример2: {k1=v1,k2=v2,...} при k1 ~= 1, и т.п. Т.е. любая таблица с t[1]==nil - может иметь только хеш-часть, хотя ... можно и говорить "а почему индекс только в единицы? должен начинаться" ...

Если таблица имеет вид {v1,v2,...} и подразумевается, что ни одно поле не пустое - наверное правомочно говорить именно о не-хеш таблице, а о индексированной. Кому такое не по вкусу, то следует избавиться от употребления table.insert/remove и #.

 

Собственно не столь о строении таблиц затеян разговор, а о допустимости/целесообразности применения именно методов для таблиц с индексами.

Категоричное отрицание этого для любых, ИМХО, неверно, и обедняет как коды самого программиста, так и нередко идет вразрез с оптимизацией кода.

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

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

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

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

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


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

Dennis_Chikin, совершенно верно, итерация при помощи pairs не то что не гарантирует, а даже не предусматривает какую либо последовательность. Как в данный момент "карта легла" - так и выдает из таблицы. Это один из минусов пи пользовании такими таблицами и склоняет порою чашу весом именно на индексированные.

 

Однако, к чему эти коды? Повторю, почему, применяя методы именно для хеш-таблиц, ты все одно используешь удаление как для индексированных и продолжаешь упорно сетовать? Сравни:

function test_tbl()
  local t, s = {}, 0
  for i=1, 10 do
    table.insert( t, i ) --/ каждое значение добавляется в конец таблицы
  end
  table.remove( t, 10 ) --/ удаляется поле под 10-ым индексом
  table.insert( t, 10 ) --/ добавляется 10-ка в конец таблицы
  table.remove( t, 10 ) --/ удаляется поле под 10-ым индексом
  --/ ...
end

- и НИКАКИХ пробелов (потерь значений) в индексах.

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

Ну а насчет солянки: все же не вправе жестко высказываться, трудов многие положили немало и это уже одно заслуживает уважения. А вот то, что ее в порядок приводить нужно "

потихоньку" - вот с этим не соглашусь. В ней (ИМХО) требуется кардинально заменить многое и не потихоньку, а сразу, т.к. тягомотина в конце концов приведет к тому, что энтузиазм улетучится а в сухом остатке так и будет ... сырая солянка.

 

 

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

Gun12, нет _util["list_tbl"]( t, "test_tbl" ) тут не при чем ...

Просто вроде как банальное t[10] = 10 на самом деле не в конец таблицы (на десятый индекс) добавляет, а уже в хеш-часть, разбивая таблицу на два типа.

А вот table.remove( t, 10 ) и даже table.remove( t, 11 ) - удаляет поле с ПОСЛЕДНИМ индексом, а это как раз 9-ка.

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

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

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


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

Gun12, Gun12

Я пробую как миниум именно на компиляторе игры (SciTE- это в черне), поэтому и результат именно таков, каков он в игре.

Про некоторые особенности именно сталкеровского Lua мы уже гвоворили (вспомним arg.n ...) Вот и тут, table.remove( t, NN ) - удаляет не именно индекс NN, а если отсутствует, то первый имеющийся до него. Ну и t[10] = 10 - именно разбивает таблицу на две части разного типа, а не вроде как продолжает последовательную индексацию.

 

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

Gun12, говорим о том, что в солянке используются таблицы. Эти таблицы заполняются способом для хеш-таблиц, хотя и упорядоченной индексацией: for i = 1, 10 do t = i end. Далее, из этих таблиц удаляются некоторые индексы методом table.remove.

Ну и ... как говорит Dennis_Chikin, таблицы начали сыпаться ... Возникло подозрение, что виноват именно table.remove.

Так вот, если у них в моде хоть где-то после создания и удаления хоть раз проскакивает t[10] = 10 - то и не удивительно ... т.к. таблица уже НЕ чисто индексная и начинается удаление того, чего и не подразумевается.

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

 

Dennis_Chikin, не используй добавление таблицы по ключам (что меняет структуру таблицы!), хотя и это вроде как и удобно - и не будет проблем.

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

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

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


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

Gun12, но мы в форуме именно по Сталкеру и имеем то, что дадено. <_<

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

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

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

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


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

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