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

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


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

С чего начинать и где взять.

 

Установка Lua:
http://www.amk-team.ru/forum/index.php?showtopic=11584&p=629106

 

Руководство «Программирование на языке Lua», третье издание:
http://www.amk-team.ru/forum/index.php?showtopic=11584&p=905308

Изменено пользователем Kirgudu
Ссылка на комментарий

Gun12

Спасибо, в справочнике на русском про popen() ничего не было написано. Сообщение тоже вывелось без проблем. :)

Но теперь столкнулся со следующей проблемой:

            local log_path = getFS():update_path("$logs$", "xray_"..user_name()..".log")
            error_log(log_path)
            os.execute("start "..log_path)

 

В консоль игры путь выводится правильный -

! [LUA][ERROR] f:\games\stalker - clear sky\save\winseven\stalker-stcs\logs\xray_winseven.log

А вот при попытке открыть текстовый файл через os или popen путь обрезается до -

f:\games\stalker и соответственно ничего не открывается. Как тогда поступить? Заменить пробелы на их код? И не повлияет ли на работоспособность русские буквы в пути?

___

 

log_path = string.gsub(log_path, "%s", "%20") --\\ вылет

log_path = string.gsub(log_path, "%s", " ") --\\ бестолку

log_path = string.gsub(log_path, " ", %s") --\\ заменяет пробелы на S

 

____

 

И в чём для Lua различия между "string" и 'string' ? (двойные и обычные кавычки)

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

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

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

*Shoker*

Пиши так :

os.execute([["D:\\name file.txt"]])
-- или
io.popen([["D:\\name file.txt"]])

Двойные кавычки в CMD защитят от пробелов в именах директорий\файлов.

 

Различия между "string" и 'string' в контексте lua нет никакого. Кому как удобнее, тот так и пишет.

А вот с использованием os.execute могут быть проблемы из-за синтаксиса CMD.

Поизучай его.

Я конечно совершил ошибку, что сразу не написал корректный код. Извиняюсь. Упустил.

 

Русские буквы не должны мешать.

Изменено пользователем Gun12
Ссылка на комментарий

Gun12

Да я просто думал, что одинарные кавычки в Lua не работают.

 

А по [[ ]]

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

Соответственно попробовал так:

 

os.execute("start "..[[log_path]]) но в итоге вышло "start log_path"

 

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

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

А я разве сказал писать"start" в начале?

Посмотри внимательнее мой код.

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

Напиши

os.execute('"'..log_path..'"')

Вот блин. Так непонятно. Так :

os.execute([["]]..log_path..[["]])

Изменено пользователем Gun12
Ссылка на комментарий

Ужос о_О

Но на удивление сработало, и лог открылся. :crazy:

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

 

-- ірешнуть игру (после вvвода сооб    ения об ошибке в лог) 
function abort(fmt, ...) 
    local reason = string.format(fmt, ...) or "<nil>"
    error_log("ВНИМАНИЕ! Игра была принудительно прервана из за ошибки. Строка ниже является причиной ошибки.")
    error_log("ОШИБКА: " ..reason)
    get_console():execute("flush")

    io.popen('start cmd /k echo ВНИМАНИЕ! Игра была принудительно прервана из за ошибки. Необходимо скопировать из лога игры последние 5-15 строчек и показать их автору.')        
    local log_path = getFS():update_path("$logs$", "xray_"..user_name()..".log")
    io.popen([["]]..log_path..[["]])
    os.exit()
end

 

Выводит мессагу в командную строку и открывает лог. Как отреагируют антивирусы не знаю, у меня молчат.

Работает на ЧН, возможно заработает на ЗП. В ТЧ без доп. библиотек соответственно не работает.

 

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

Поспешил радоваться. Тестировал когда игра была открыта в оконном режиме. А на полном экране игра не сворачивается а просто визуально зависает. Можно ли как то не останавливать выполнение приложения (игры) при открытии файлов?

___

Виснет из за os.execute. Переделал на popen, игра закрывается если в оконном, а если на весь экран то появляется курсор но опять виснет.

___

Решил проблему через os.exit(), финальный вариант там же.

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

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

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

Да всё верно. Просто плохо знаком с синтаксисом командной строки. Чтобы там засчитывались корректно пробелы, нужно команду и текст в кавычках писать.

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

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

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

Какая-то ерунда получается!

Ах, да. Забыл рассказать начало истории :)

Решил (по)использовать макет luabind для академического lua версии xStream (этот код был любезно предоставлен нам несколько выше).

Всё очень замечательно, но...

(Remark) Я в этом конечно не гуру, поэтому и высказываю свои эмоции в надежде на объяснение несостоятельности их возникновения.

Итак.

При объявлении класса (class "Х") в таблице _G создается поле-таблица(класс).

Пока всё верно.

Далее (по чтению кода) в этот класс добавляются поля. Но эти поля являются только методами (т.е. функциями). А где же свойства???

Так вот эмоции у меня вызвал метод "__init". В нём вроде бы и есть свойства, но...

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

Но, насколько я понимаю это не правильно. Свойства должны быть прописаны именно в таблице класса, а объекты (если не изменяют некоторых методов и свойств) должны просто ссылаться на родителя, но не заполнять эти поля в себе.

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

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

Что собственно пока и решает вопрос, но хочется знать, - "Как всё-таки сделать правильнее всего?"

Изменено пользователем Gun12
Ссылка на комментарий

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

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

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

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

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

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

Artos

В общем так и поступил. Переписал luаbind по-своему.

Теперь работает как нужно.

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

Короче, эмоции уже успокоились:)

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

Извиняюсь за дурацкий вопрос, но где можно найти расшифровку клавиш, которая приводится допустим в "Классе кнопок" для Луа. Многие клавиши там понятны, но там можно увидеть такие примеры:

 

C++ class DIK_keys {

const DIK_ADD = 78;

const DIK_APOSTROPHE = 40;

const DIK_AT = 145;

const DIK_AX = 150;

const DIK_CAPITAL = 58;

const DIK_CIRCUMFLEX = 144;

const DIK_COLON = 146;

const DIK_COMMA = 51;

const DIK_CONVERT = 121;

const DIK_DECIMAL = 83;

const DIK_DIVIDE = 181

const DIK_EQUALS = 13;

Конкретно меня интересует, как правильно позиционируется(называется) клавиша со звёздочкой (*), которая находится на правой цифровой клавиатуре.

Изменено пользователем Kontro-zzz
Ссылка на комментарий

Kontro-zzz,

const DIK_MULTIPLY = 55;

http://bascom.at.ua/2011/Klava_USB/Hid_kode.jpg

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

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

_zero_cool_,

эта цитата из lua-help не отвечает на поставленный выше вопрос.

 

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

 

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

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

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

 

Ссылка на комментарий
Извиняюсь за дурацкий вопрос, но где можно найти расшифровку клавиш, которая приводится допустим в "Классе кнопок" для Луа.
Вопрос конечно из категории - "Для ленивых"

Запусти тот же ... ну хоть Сократ ...

***ADD = 78;          -- +
***APOSTROPHE = 40;   -- `
***AT = 145;          -- @
***AX = 150;          -- #
***CAPITAL = 58;      -- $
***CIRCUMFLEX = 144;  -- ^
***COLON = 146;       -- :
***COMMA = 51;        -- ,
***DIVIDE = 181       -- /
***EQUALS = 13;       -- =

Примерно так, что ли?.....

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

Да мне и это надо было для частного случая, Шокер дал исчерпывающий ответ. Возможно что-то из этого еще и пригодится в дальнейшем. Спасибо. :rolleyes:

Изменено пользователем Kontro-zzz
Ссылка на комментарий

Ну, давайте еще раз поговорим об этом. ;) В смысле, о таблицах и добавлении/удалении записей в них.

Это я ведусь на провокацию.

 

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

 

Вообще говоря, ни кто не обещал какого-либо доступа к внтреннему счетчику, использующемуся при присваивании вида t = { v1, v2, ... }. Обещали только, что будет работать пара table.insert()/table.remove() и доступ вида v = t[n].

Тем не менее, когда операция t[n] = v делает внутри таблицы нечто непредсказуемое, а затем table.remove( t, n ) игнорирует наличие в таблице записи с индексом n, и удаляет фактически что попало - это вряд-ли можно считать как-то соотвествующим принципам гуманизма.

 

P.S. А вызов функций и передача параметров ( не говоря уже о вызове методов у "самодельных" объектов ) в текущей имплементации таки явно относятся к "тяжелым" операциям. Был бы оптимизатор, как практически во всех современных плюсях - разговор был бы совсем другой.

 

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

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

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

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

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

В смысле, была надежда, что table.remove при однократном вызове таки индексы исправит как надо.

 

И говорить здесь имеет смысл именно про гуманизм. ;)

По той причине, что если у нас в результате получилась хэш-таблица, хочется ожидать, что # вернет 0 (ну или сколько у нас там осталось от индексированного, а table.remove() просто не будет делать с ней ничего. Иначе лучше ими действительно не пользоваться.

В действительности же предложенное решение с t1000s = #t1000 не спасает, поскольку до момента, когда крах таблицы становится очевидным (нет записи, которая должна быть, есть та, которой быть не должно), # возвращает ровно то же самое, что и посчитано руками. И даже хуже того, если считая руками, мы получим вылет по попытке что-то делать с уже несуществующим элементом, то с использованием # - не узнаем даже о самом факте краха. Собственно, пару лет назад так и случилось, когда под девизом "заоптимизируем все" поменяли на автомате все табличные функции на доступ через #t+1 / #t - 1.

 

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

 

Ну и для "солянок" очевидно то, что "непредвиденное" с любой нелокальной таблицей скорее произойдет, чем не произойдет. А в свете того, что удаление одиночного элемента - операция крайне редкая, таблицы же по большей части не великих размеров - я вот для себя вижу скорее причину отказаться именно от использования table.remove(), чем от чего-либо еще, и таблицы по необходимости пересоздавать. Тем более, что многие и сами по себе живут не долго.

 

 

P.S. Да, видимо, формулировка про "делает непредсказуемое" внесла неоднозначность. Читать следует как "внутри таблицы происходит нечто непредсказуемое при".

 

Изменено пользователем Dennis_Chikin
Ссылка на комментарий

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

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

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

Artos,

в этом примере локальной переменной цикла является только i. К t1000s это не относится никаким боком, поскольку эта переменная в цикле не объявляется, а всего лишь используется.

 

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

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

 

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

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

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

 

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

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

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

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

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

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

Войти

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

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

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