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

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


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

...Как тут поможет разделение и творчество?

Прямо пропорционально.

Теоретически - пробуй разделять диалог по две фразы(точнее в тех местах, где необходимо "слушать" собеседника). Первая ГГ, вторая НПС. Диалог закрывается, но перед ним вызывается action, в котором после ожидания проигрывания звука вызывается start_stop_menu (я где-то делал - лень искать, спроси у Garry_Galler-а, он этим серьёзнее занимался) и следующие две фразы...В последней фразе start_stop_menu не вызывается.

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

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


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

Kirag

Разреши и я свои 5 копеек вставлю.

В функции find_teg всю эту конструкцию :

local open = string.find(str,"<") or 1
local len = string.len(str)
local declare_close = string.find(str,">",open+1,true) or len
local declare_space = string.find(str," ",open+1,true) or len
local declare_slash = string.find(str,"/",open+1,true) or len
local name_end = math.min(declare_close, declare_space, declare_slash) -- ближайший к открытию пробел или ">"

local teg_name = string.sub(str,open+1,name_end-1)

можно заменить на :

teg_name = str:match("<%s-(%S+)")

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

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


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

По совету Artos-а решил изложить материал, касающийся работы с coroutine тут, поскольку данная таблица входит в пакет Lua СТАЛКЕР-а, и более подходящей темы трудно найти.

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

Тем не менее есть люди интересующиеся, поэтому продолжу...

Итак, обо всё по порядку (malandrinus-у. Можно я буду писать частями? Хочется сделать не только информативно, но и придать внешний вид. А вот со свободным временем у меня не очень.) :

----------------------------------------------------------------------------------------------------------------------------------------

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

Эта таблица содержит всего шесть функций :

 

create

wrap

resume

yield

status

running

 

Я их подразделяю на основные :

create и wrap - создают подпрограмму

resume - запускает или продолжает выполнение подпрограммы

yield - приостанавливает выполнение подпрограммы

 

И служебные :

status - возвращает состояние подпрограммы

running - возвращает саму подпрограмму

 

Рассмотрим их подробнее.

coroutine.create (f)

 

Создает новую подпрограмму, с телом f.

Параметр f должен быть Lua функцией (или именем функции).

SubProg = coroutine.create (function()
                                -- code
                            end)

Или

function Body_SubProg()
    -- code
end

SubProg = coroutine.create (Body_SubProg)

Возвращает указатель на новую подпрограмму как объект типа нить ("thread").

(Не знаю как Вам будет лучше? Кто хочет для просмотра пишите в лог. Короче кому как удобнее.

Далее буду проверочный код писать именно в таком виде. Не все же умеют даже в лог писать.)

news_manager.send_tip(db.actor, type(SubProg)) -- Результат : "thread"

Функция create только создает новую подпрограмму, запуск подпрограммы не выполняется.

Он выполняется с помощью coroutine.resume (подробнее о этой функции ниже).

В примере ниже переменным n1 и n2 присваиваются соответственно значения 5 и 7

SubProg = coroutine.create(function (n1, n2)
                              local amount = n1+n2
                              return amount
                           end)
local bool, result = coroutine.resume(SubProg, 5, 7) -- Вызываем подпрограмму SubProg с параметрами 5 и 7
news_manager.send_tip(db.actor, tostring(bool)..'-->'..tostring(result)) -- Результат :  "true-->12"

Функция coroutine.create защищённая. Если вызвать эту функцию с ошибкой, то возвратится false и ошибка покажется как результат.

В данном примере аргументу n1 присваивается значение (number) 5, а аргументу n2 значение true (boolen).

Теперь попробуем сложить number и boolen.

SubProg = coroutine.create(function (n1, n2)
                              local amount = n1+n2
                           end)
-- и где-нибудь вызов
local bool, result = coroutine.resume(SubProg, 5, true)
news_manager.send_tip(db.actor, tostring(bool)..'-->'..tostring(result)) -- Результат : false-->А тут у каждого свои данные"

 

Подпрограмму также можно создать с помощью:

coroutine.wrap (f)

 

Она создает новую подпрограмму с телом f .

Параметр f должен быть Lua функцией (или именем функции).

SubProg = coroutine.wrap(function ()
                          -- code
                      end)

Или

function Body_SubProg()
    -- code
end

SubProg = coroutine.wrap(Body_SubProg)

Возвращает функцию, с помощью которой можно осуществить её запуск.

news_manager.send_tip(db.actor, type(SubProg)) -- Результат : "function"

Поскольку подпрограмма является функцией (в отличии от coroutine.create), то и вызываем её как функцию.

Параметры, передаваемые в неё в качестве дополнительных аргументов (в пр. ниже это 4 и 5), попадают в неявный вызов resume.

Эта функция возвратит только результат, т.е. первого булевого значения (как при вызове coroutine.resume) не будет :

function Body_SubProg(n1, n2)
    local amount = n1+n2
    return amount
end

SubProg = coroutine.wrap(Body_SubProg)

local result = SubProg(4, 5)
news_manager.send_tip(db.actor, tostring(result)) -- Результат : 9

coroutine.wrap не перехватывает ошибки - все ошибки попадают на уровень вызывающей функции. Т.е. она незащищённая.

Вызвав функцию (например) так :

local result = SubProg(4, nil)

Получите вылет (опять же - в отличии от подпрограммы, созданной при помощи coroutine.create).

 

coroutine.yield (···)

 

Приостанавливает выполнение вызываемой подпрограммы.

coroutine не может быть выполняющейся C функцией, метаметодом или итератором.

Любые параметры, передаваемые в yield в дальнейшем передаются как дополнительные параметры при вызове resume (об этом позже).

function Body_SubProg()
    coroutine.yield('pause')
    return 'end'
end

SubProg = coroutine.create(Body_SubProg)

local _,result = coroutine.resume(SubProg)
news_manager.send_tip(db.actor, tostring(result)) -- Результат : 'pause'

Разберём подробнее.

В строке local _,result = coroutine.resume(SubProg) происходит вызов подпрограммы.

Она начинает выполняться, и... "упирается" в строку coroutine.yield. Поэтому она приостанавливает выполнение и возвращает то, что находится в её аргументе ('pause').

Вернёмся к строке local _,result = coroutine.resume(SubProg). Вызов coroutine.resume(SubProg) "отработал". Она возвратила первое (обязательное) значение boolen и все значения, возвращаемые coroutine.yield. Поскольку из вышеупомянутой функции возвратилось одно значение ('pause'), соответственно оно и присвоиться переменной result.

Всё. На данный момент подпрограмма находится в "режиме ожидания".

 

Пошлём ей второй вызов :

local _,result = coroutine.resume(SubProg)
news_manager.send_tip(db.actor, tostring(result)) -- Результат : 'end'

Подпрограмма (функция, находящаяся в теле подпрограммы) продолжит своё выполнение с того места, где она "упёрлась". Т.е. начнёт выполнять код после coroutine.yield('pause').

В функцию coroutine.resume(SubProg) , ту, что вызывалась второй раз, возвращается строка 'end'.

И снова переменной result присваивается значение. Теперь уже строку 'end'

 

coroutine.resume (co [, ···])

 

Запускает или продолжает выполнение подпрограммы с указанным именем (co).

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

Опциональные значения [, ···] передаются как параметры в эту функцию.

 

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

В случае возникновения ошибок, resume возвращает false плюс сообщение об ошибке (см. coroutine.create).

В принципе мы это уже "проходили", но всё же...

Ситуации :

1. Подпрограмма запустилась без ошибок, возвратила true и значение, возвращённое coroutine.yield :

function Body_SubProg(var)
    coroutine.yield(var)
    return 'end'
end

SubProg = coroutine.create(Body_SubProg)

local bool, result = coroutine.resume(SubProg, 'pause')
news_manager.send_tip(db.actor, tostring(bool)..'-->'..tostring(result)) -- Результат :  "true-->pause"

2. Подпрограмма запустилась без ошибок, возвратила true и значение, возвращённое функцией Body_SubProg.

Для этого вызовем coroutine.resume ещё раз - рестартуем её.

(В данном примере вызов coroutine.resume можно производить без дополнительных аргументов. Все они будут проигнорированы, т.к. сама функция Body_SubProg возвращает только одно значение - строку 'end'):

local bool, result = coroutine.resume(SubProg)
news_manager.send_tip(db.actor, tostring(bool)..'-->'..tostring(result)) -- Результат :  "true-->end"

3. Подпрограмма выполнилась с ошибкой, resume возвращает false плюс сообщение об ошибке :

function Body_SubProg(var)
    coroutine.yield(var+1)
    return 'end'
end

SubProg = coroutine.create(Body_SubProg)

local bool, result = coroutine.resume(SubProg, 'v')
news_manager.send_tip(db.actor, tostring(bool)..'-->'..tostring(result)) -- Результат :  "false-->тут путь к файлу, строка ошибки, описание ошибки"

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

 

Если подпрограмма была в состоянии yield, resume рестартует подпрограмму, передавая ей параметры [, ···] а также результаты, полученные при вызове yield.

Сначала напишу код, затем его разберём :

function Body_SubProg(a, b)
    local c = coroutine.yield(a+b, a-b)
    return a, b, c
end

SubProg = coroutine.create(Body_SubProg)

local bool, var_1, var_2 = coroutine.resume(SubProg, 5, 2)
news_manager.send_tip(db.actor, tostring(bool)..'-->'..tostring(var_1)..'-->'..tostring(var_2)) -- Результат : "true-->7-->3"

local bool, var_1, var_2, var_3 = coroutine.resume(SubProg, "str")
news_manager.send_tip(db.actor, tostring(bool)..'-->'..tostring(var_1)..'-->'..tostring(var_2)..'-->'..tostring(var_3)) -- Результат : "true-->5-->2-->str"

В строке - local bool, var_1, var_2 = coroutine.resume(SubProg, 5, 2) - происходит первый вызов подпрограммы с именем SubProg.

Функция Body_SubProg ( a, b ) начинает работу с аргументами 5 и 2 для a и b соответственно.

В следующей строке объявляется переменная (local c), которой присваивается значение... и тут СТОП. Вызывается coroutine.yield.

А это значит что подпрограмма прерывается, так и не присвоив переменной c никакого значения.

Раз уж подпрограмма ждёт, то и мы подождём, что же из этого выйдет :-)

coroutine.yield( a+b, a-b ) возвращает в вызвавшую её функцию coroutine.resume(SubProg, 5, 2) результат своей работы ( a+b, a-b ), т.е. 7 и 3.

Как мы уже знаем, coroutine.resume(SubProg, 5, 2) присваивает переменной bool значение true, а переменным var_1 и var_2 принятые от yield - 7 и 3.

Ожидаем следующего вызова...

 

Он происходит в строке - local bool, var_1, var_2, var_3 = coroutine.resume(SubProg, "str").

И, как видим, в этом вызове происходит передача в функцию Body_SubProg нового (дополнительного) параметра - строки 'str'.

Именно значение этого параметра и присваивается переменной с.

Подпрограмма продолжила свою работу и строкой - return a, b, c - возвратила значения переменных a, b и c и закончила свою работу.

функция coroutine.resume(SubProg, "str") принимает эти возвращённые значения и присваивает их переменным var_1, var_2, var_3 соответственно.

 

 

 

Перед описанием оставшихся функций немного отвлечёмся.

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

С подпрограммами такое дело не проходит.

 

Она "живёт' только один цикл функции, находящейся в её теле (в нашем примере Body_SubProg).

Т.е. дойдя до последнего end-а этой функции все попытки последующего вызова будут приводить :

 

1. При создании подпрограммы с помощью wrap - к вылету.

2. При создании подпрограммы с помощью create - к возврату из resume двух значений, false и строки "cannot resume dead coroutine".

 

Второй вариант кажется не очень и критичным (вылета нет), но если вдруг функция, вызвавшая resume будет ждать от неё (скажем) число, а тут "на те - здрасьте", строка.

Результат может превзойти все ожидания.

Но одноразовая подпрограмма мало кого устроит.

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

 

 

Теперь продолжим :

coroutine.running ()

Возвращает выполняемую подпрограмму, или nil, если вызвана из главной нити.

 

Тут мне сказать особо нечего, т.к. использовать ещё не было нужды.

Только пример :

function Body_SubProg()
    news_manager.send_tip(db.actor, 'SubProg-->'..tostring(SubProg)) -- Результат : "SubProg-->thread: тут ID подпрограммы SubProg"
    news_manager.send_tip(db.actor, 'coroutine.running-->'..tostring(coroutine.running())) -- Результат : "coroutine.running-->thread:  тут ID той подпрограммы, которая запущена"
end

SubProg = coroutine.create(Body_SubProg)

coroutine.resume(SubProg)
news_manager.send_tip(db.actor, 'main_thread-->'..tostring(coroutine.running())) -- Результат : "main_thread-->nil"

Оба сообщения, выводимые из тела функции Body_SubProg, после "thread", покажут один и тот же ID.

Этим самым мы убедимся в том, что подпрограмма SubProg и найденная запущенная подпрограмма являются одним и тем же объектом.

Сообщение из главной нити ("main_thread") покажет, что выполняющихся в данный момент подпрограмм нет (nil)

 

 

coroutine.status(co)

 

Возвращает статус подпрограммы co, в виде строки:

 

"running" (выполняется), если подпрограмма в данный момент выполняется

"suspended" (приостановалена), если подпрограмма приостановлена с помощью вызова yield, либо она еще не запущена на выполнение

"normal" (норма) если подпрограмма активна, но еще не запущена на выполнение (т.е. она активизирована другой подпрограммой)

"dead" (остановлена) если подпрограмма завершилась или если остановлена по ошибке.

 

Каждый элемент отдельно описывать не буду, а приведу все варианты в едином коде. Затем разберём :

AnySubProg = coroutine.create(function ()
                                 news_manager.send_tip(db.actor, '3-'..coroutine.status(SubProg)) -- 'normal'
                              end)
                      
SubProg = coroutine.create(function ()
                              news_manager.send_tip(db.actor, '2-'..coroutine.status(SubProg)) -- 'running'
                              coroutine.resume(AnySubProg)
                              coroutine.yield() -- coroutine.yield('s'+1)
                           end)

news_manager.send_tip(db.actor, '1-'..coroutine.status(SubProg)) -- 'suspended'
coroutine.resume(SubProg)
news_manager.send_tip(db.actor, '4-'..coroutine.status(SubProg)) -- 'suspended'
coroutine.resume(SubProg)
news_manager.send_tip(db.actor, '5-'..coroutine.status(SubProg)) -- "dead"

В результате на экране (или в логе, кто как) Вы увидите ряд сообщений :

 

1-suspended

2-running

3-normal

4-suspended

5-dead

 

Для облегчения навигации по коду я отметил строки с вызовом сообщений числами (типа ID) от 1 до 5 (напр. news_manager.send_tip(db.actor, '4-'..coroutine.status(SubProg)) ).

 

Итак, после создания подпрограммы сначала выдаётся сообщение с ID 1, которое напечатает suspended.

Это соответствует второй части определения suspended (см. описания стасусов), в частности "...либо она еще не запущена на выполнение".

Действительно, подпрограмма ещё не запускалась.

 

Следующей после неё строкой запускается подпрограмма SubProg, и в её теле выдаётся сообщение с ID 2 и результатом running.

Это также соответствует истине. Подпрограмма запущена и выполняется.

 

После этого запускается некая сторонняя подпрограмма AnySubProg в теле которой выдаётся сообщение с ID 3 - normal.

И снова верно. Подпрограмма SubProg на данный момент активна (мы же её уже вызвали), но не запущена.

Сейчас запущена другая (AnySubProg) подпрограмма, из которой и запрашивается статус SubProg.

 

После завершения работы AnySubProg, продолжается работа SubProg и строкой coroutine.yield() приостанавливает своё выполнение.

Работа первого вызова coroutine.resume(SubProg) завершается, и следующей строкой даёт сообщение с ID 4 - suspended

Теперь выполняется соответствие первой части определения suspended - "если подпрограмма приостановлена с помощью вызова yield..."

 

Вызвав подпрограмму SubProg второй раз (coroutine.resume(SubProg)), она завершает свою работу (последний end).

И теперь, в сообщении с ID 5 мы запрашиваем состояние подпрограммы, которая уже завершилась.

Естественно нам отвечают, что такая подпрограмма уже завершилась (первая часть определения "если подпрограмма завершилась..") - dead

 

Если изменить строку coroutine.yield() на coroutine.yield('s'+1) (т.е. делаем ошибку), то вместо сообщения 4-suspended будет сообщение 4-dead, соответствующее определению "...или если остановлена по ошибке"

 

 

Итак, необходимые знания у нас уже есть. Можно двигать дальше...

Изменено пользователем Cyclone
  • Полезно 1

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


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

malandrinus, RvP

По следам разбора конкатенации...

Найду свободное время - поэкперементирую, но пока вот мои результаты в SciTE (??? не вписываются в заключение ???) :

table     1.875
concat    0.344
format    1.5

 

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

Ага. Увеличил размер строки и всё стало на свои места.

malandrinus, удали пожалуйста мой пост. При разных длинах строк происходят совершенно интересные вещи.

Разберу - отпишусь конкретнее.

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

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


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

Да, попробуйте сделать строки длиной по 99 символов (ужасная задержка), а затем по 100 (обыгрывает concat) и сравните результаты. Это только у меня format так себя ведет?

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

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


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

singapur22

Вот спасибо. Теперь можно внести дополнение в определение - "При работе с заведомо длинными строками (100 и более символов) следует использовать

string.format, который будет работать быстрее чем table.concat"

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


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

Теперь я забираю свои слова, сказанные выше, назад.

Если поставить все тестовые варианты в равные условия, то результаты сильно изменяться.

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

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

a = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaa" --100 символов
b = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbb" --100 символов
c = "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccc" --100 символов
d = "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
dddddddddddddddddddddddd" --100 символов
e = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeee" --100 символов

tb = {a, b, c, d, e} -- общая для всех таблица

t = os.clock()
for i=1, 1000000 do
    local q = table.concat(tb)
end
t2 = os.clock() - t
print("table", t2)

t = os.clock()
for i=1, 1000000 do
    local q = tb[1] .. tb[2] .. tb[3] .. tb[4] .. tb[5]
end
t2 = os.clock() - t
print("concat", t2)

t = os.clock()
for i=1, 1000000 do
    local q = string.format("%s%s%s%s%s", unpack(tb))
end
t2 = os.clock() - t
print("format", t2)

Результат

table     0.954
concat    1.015
format    1.547

 

 

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

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


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

Изначально, вместо unpack я писал tb[1], tb[2], tb[3], tb[4], tb[5].

Результат был ещё хуже. Как бы ещё немного помог ей.

P.S.

Что-то мне подсказывает, что мы не в той теме общаемся. Нам бы в "Скриптование..." перейти.

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

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


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

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

Совсем недавно подобный вопрос всплыл и тут. Вот и решил , за отсутствием специализированного топика по lua, выложить материал тут.

Но прежде всего хочу сказать, что всё сказанное мною относиться к заре моего познавания Lua.

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

Всё же лучше чем сухие предложения из официального мануала.

С вопросами (а также тонкостями) составления шаблонов обращаться либо в ПМ, либо (лучше в плане всеобщего образования) в теме "Скриптование, спавн и логика ".

Хватит лирики, вот ссылка на страничку из моего манула по Lua 2-x двухгодичной давности :

http://ifolder.ru/25675390

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

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


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

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

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