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

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

 

Если вылет при перезапуске сэйва (не выходя из игры) связан

Он с этим не связан, я могу перезапустить сейв и играть себе спокойно дальше, хоть всю игру пройти, НО если я начну диалог после которого спавнится вертолет, то будет вылет. И параметр 'startup_animation' я изменил, как сказал Shoker, если раньше вылеты были практически всегда, то сейчас только так, как я описал выше.

 

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

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

@Старлей, я немного перепутал, motion_name можно вернуть как было, из за того что ты используешь какой то старый скрипт (видимо прямиком из ТЧ) и там параметр startup_animation назван как cse_alife_helicopter__unk1_sz поэтому я его и не увидел.

 

Тебе советую сделать вот что:
Попросить у Artos-а свежий скрипт для работы с нэт-пакетами (т.к его ссылка мертва): Либо взять тут прошлую версию, но я не гарантирую что там нету косяков. И спавнить вертолёт через него.

 

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

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

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

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

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

[spoiler=Актуальная версия модуля "Интерфейс чтения/записи net-пакетов" (m_netpk)]

 


Название: Модуль "Интерфейс чтения/записи net-пакетов" (m_netpk)
Автор(ы): Artos (по материалам: bardak, Red75, Sokol_jack, KD87 (uACDC), xStream (xs_netpk))
 
Версия/Дата: - (20.09.2013)
Платформа: Универсальный (ТЧ/ЧН/ЗП), начиная с ТЧ 1.0004
Сложность подключения: Простая
 
Модуль (скрипт) реализует в игре интерфейс чтения и изменения параметров игровых объектов посредством net_packet'ов.
Интерфейс чтения/записи net-пакетов (SHoC:6/7(118),CS:8(124),SCoP:12(128))
m_netpk.script
==============================================================================================
 "Правильная" работа с нет-пакетами. (© xStream)
------------------------------------------------
Интерфейс работы с классами нет-пакетов:
 
0) Что это вообще такое и с чем едят?
0.1) 'Нет-пакет' (net_packet) - это специальный объект (бинарный буфер), который содежит информацию,
которой серверные объекты в игре обмениваются со своими клиентскими копиями, изменяя соответствующие параметры/свойства друг-друга.
Позиция в пространстве, поворот, текущий режим стрельбы у оружия и т.п.
Просто так эта информация не доступна стандартныи средствами из скриптов.
0.2) Нет-пакет для каждого объекта в игре имеет две части/типа, независимых друг от друга: 'state' и 'update'.
Возможна работа с каждым типом по отдельности или с обоими вместе.
Все, что представлено в этом модуле (скрипте) - специальные классы,
которые позволяют организовать ПРОСТОЙ доступ к этим данным и, в случае надобности, их изменять.
Итак...
 
1) Сначала необходимо создать объект необходимого класса, передав серверный или клиентский объект:
В случае интеграции модуля в глобальную таблицу скриптов (модуль инициализирован):
а) local pk = get_netpk(obj,flag) -- по классу переданного объекта будет автоматически подобран нужный класс нет-пакета.
При прямых обращених к модулю и/или классу пакета:
б) local pk = m_netpk.get(obj,flag) -- аналогично а).
в) local pk = m_netpk.net_XXXXXX(obj,flag) -- указываем КОНКРЕТНЫЙ класс требуемого пакета, как подобрать, см. ниже
 
Использование дополнительного аргумента (flag) при вызове модуля позволяет использовать один из трех вариантов получения типов пакетов
для любого объекта игры или получить доступ к управлению специальным пакетом:
а) flag: nil (опущен) - 'полный' пакет, т.е. оба типа пакетов 'state' и 'update' в едином объекте (нет-пакете);
б) flag: 1 - пакет типа 'state';
в) flag: 2 - пакет типа 'update'.
г) flag: 0 - пакет для управления свойствами 'abstract' (об этом ниже);
Учитывая, что в большинстве модификаций игры используется в основном работа со свойствами из 'state' пакетов,
гонять в холостую коды обработки получения изменения и записи полного пакета (с 'update' частью) - расточительно.
 
1.1) Чтобы узнать, все ли прошло хорошо, можно вызвать pk:isOk(), он вернет true, если класс пакета успешно создан. false - в случае неудачи.
 
1.2) Все прочитанные/записываемые свойства (параметры) пакета расположены в таблице data (см. п.2).
Если класс пакета содержит тип 'update' - все свойства этого пакета расположены в суб-таблице data.upd.
 
1.3) Имеется возможность:
Даже если пакет не создался правильно, можно это проигнорировать, так как функция возвращает специальный пакет net_dummy,
с ним можно производить те же операции, что и с остальными, только просто он ничего не делает.
Зачем он нужен? Он полезен при условных обработках пакетов.
Пример:
local pk = m_netpk.net_se_monster(obj,2)
if not pk:isOk() then
pk = m_netpk.net_se_stalker(obj,2)
end
local data = pk:get()
data.upd.health = health -- свойство в 'update' пакете
pk:set(data)
 
Здесь НЕ проверяется, правильный ли пакет получился, когда и НЕ монстр и НЕ сталкер.
Потому что в результате получаем net_dummy и работаем как с обычным пакетом.
Меньше кода и проверок. Но злоупотреблять этим свойством не рекомендуется.
Используйте лучше isOk() в критичных на ошибки местах. (Код, приведенный в примере, станет понятен ниже)
 
2) Чтение данных из пакета:
local data = pk:get() -- в результате получаем таблицу, содержащую ВСЕ свойства объекта (в зависимости от запрошенных типов!)
                     -- напоминание: все свойства пакета 'update' расположены в суб-таблице data.upd
 
3) Меняем нужные нам свойства:
data.xxx = yyy -- простое присваивание значения нужному элементу таблицы
3.1) Для некоторых сложных свойств (custom_data, shapes, ...) имеются встроенные классы со своим интерфейсом доступа/изменения.
local tbl = data.custom_data:getTable() -- получения массива из строки кастом-даты
local status = data.custom_data:setTable(tbl) -- запись таблицы в строку кастом-даты с возможностью контроля выполнения
3.2) Если мы не знаем, какие свойства есть у объекта, то используем функцию:
local description = pk:dumpDesc() -- возвращает строку, содержащую читабельное описание пакета (его можно, например, вывести в лог)
 
4) После изменения, данные записываем в собственно нет-пакет объекта:
pk:set(data)
 
5) А все :) Работа сделана.
Дополнительный профит: такие "пакеты" - это объекты, их можно передавать в разные функции, хранить в таблицах и т.д.
Они "помнят", с каким игровым объектом они связаны.
 
6) Существует специальный пакет 'abstract', о котором читаем ниже.
 


 

 

 

P.S. Рабочий пример спавна вертолета при помощи модуля m_netpk:

function Create_Vehicle(section, pos, idLv, idGv, custom_data)
  local class_id = system_ini():line_exist(section,"class") and system_ini():r_clsid(section,"class")
  if class_id and class_id == clsid.script_heli and m_netpk then
    local sobj = alife():create(section, pos, idLv, idGv)
    local pk = m_netpk:get(sobj,1) --/ запрос пакета
    if pk:isOk() then --/ если получен доступ к  пакету
      local data = pk:get() --/ считываем параметры в таблицу
      --/> заполняем параметры
      if custom_data and type(custom_data) == 'string' then
        data.custom_data:setString(custom_data)
      end
      --data.object_flags = bit_and(data.object_flags,bit_not(5)) --/#x# сброс флагов: UseSwitches(1) + SwitchOffline(4) (выполняется в m_netpk)
      --data.skeleton_name = "idle" --/#x# (выполняется в m_netpk)
      --data.startup_animation = "idle" --/#x# (выполняется в m_netpk)
      data.engine_sound = "alexmx\\helicopter" --/ опционально
      pk:set(data) --/< запись
      return sobj --/>
    end
  end
  return nil --/>
end

 

 

Изменено пользователем Artos
  • Нравится 1

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

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

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

if start_real_timer(3) then

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

Судя по мануалу я возможно не правильно делаю, возможно нужно вот так:
 

start_real_timer(3):set_name("my_timer_name")
if not timer_exists("my_timer_name") then
Изменено пользователем Карлан
Ссылка на комментарий

@Карлан, по пртведенной строке и пояснениям невозможно понять сути и причины...
Сама строка: if start_real_timer(3) then - неверна и непонятна!
 Для запуска таймера требуется в качестве аргументов указать:
- время (в секундах);
- функцию, которая будет вызвана таймером по окончании времени, указанную 1-м аргументом;
- параметры для функции, которая указана во 2-ом аргументе.
Примечание: 2-ой аргумент может быть nil, т.е. seyrwbz не указывается, но в этом случае должны быть указаны параметры для внутреннего обработчика (читаем readme к модулю).
Т.о. ты просто не запустил таймер, т.к. указал время и НИЧЕГО для того, чтобы таймер хоть как-то сообщил о событии 'окончания времени'.
 
Вот пример запуска таймера реального времени на 8 секунд, после чего будет вызвана функция OnTimer_Test:
 
 


...
  start_real_timer(8,OnTimer_Test,{id=21249}) --/ запуск таймера ~8sec [time(sec),func,params]
...

function OnTimer_Test(t)
  log("OnTimer_Test: %s", tostring(t.id)) --/#~#
end

Если требуется проверить запустился ли таймер (и заодно время), то делать это можно так:
 
 

...
  local timer = start_game_timer(3*60, nil, {info_id = "my_infoportion"}) --/ через 3 game-minutes выдать инфопоршень
  if timer then --/ запущен ли таймер? (получент ли объект таймера)
    local time_rest = timer:get_time_rest() --/ оставшееся время
...

 


 


Название: Модуль "Универсальные таймеры" (m_timers)
Автор(ы): Artos & Gr1ph00n

Версия/Дата: - (21.09.2013)
Платформа: Универсальный (ТЧ/ЧН/ЗП), начиная с ТЧ 1.0004
Сложность подключения: Простая
 
Модуль (скрипт) реализует в игре удобный интерфейс для работы с таймерами различного назначения (реального и игрового времени).
Для работы требуется подключить скрипты "Расширения Lua", "Общие функции" (см. выше).
Для хранения в сэйвах игры табличных данных запущенных таймеров может использоваться модуль "Универсальное хранилище" (см. выше),
в противном случае данные сохраняются в pstor актора (что может вызвать переполнение при интенсивном использовании таймеров).
Примеры использования имеются в самом скрипте модуля и в описании (внутри архива).

Менеджер универсальных таймеров (SHoC:6/7(118),CS:8(124),SCoP:12(128))
m_timers.script
==============================================================================================
Модуль (скрипт) реализует в игре удобный интерфейс для работы с таймерами различного назначения (реального и игрового времени).
Для работы требуются скрипты "Расширения Lua"(lua_extension) и "Общие полезные функции" (lua_helper).
Для хранения в сэйвах игры табличных данных запущенных таймеров может использоваться модуль "Универсальное хранилище" (se_stor),
в противном случае данные сохраняются в pstor актора (что может вызвать переполнение при интенсивном использовании таймеров).
 
--/---------------------------------------------------------------------
Подключение:
1. Скопировать в папку скриптов игры скрипт: m_timers.script;
2. Добавить в биндер актора (см. bind_stalker.script) вызовы событий "сохранение игры", "загрузки сохранения" и запуска обновлений модуля;
3. Добавить в _g.script инициализацию дополнительного функционала (lua_extension и lua_helper).
4. (настоятельно рекомендуется) Подключить модуль "Универсальное хранилище" (se_stor).
 
Примечание:
В комплекте файл '_g_ADD.script является строками, которые требуется добавить в исходный _g.script.
Файл bind_stalker.script от оригинальной версии игры SHoC v.1.0006 дан в качестве рабочего примера.
В файл bind_stalker.script добавляются строки (в три разных метода биндера) отмеченные знаком --/#+# и имеющие подстроки 'm_timers.'
 
Использование:
1. Запрос существования (запущенного) таймера (по имени):
  timer_exists("my_timer_name") --/ boolean
2. Получение объекта таймера (по имени):
  get_timer("my_timer_name") --/ object from class 'RealTimer|GameTimer'
3. Получение текущего значения таймера:
  get_timer("my_timer_name"):get_time_rest()
4. Удаление запущенного таймера:
  get_timer("my_timer_name"):remove()
5. Таймер на игровом экране (HUD-Timer) допускается в единственном экземпляре:
  get_hud_timer() --/ object 'HUD-Timer' from class 'RealTimer'
6. quick-таймеры не имеют имен и недоступны извне.
7. Имена таймерам выдаются автоматически и эксклюзивны.
При необходимости имя может быть задано при запуске таймера (см.ниже).


Изменено пользователем Artos
  • Нравится 1

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

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

@Artos, а как им воспользоватся при таком запросе:

Если прошло 3 секунды то
 выполняем функцию
завершить

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

 

Еще вопрос, таймер по умолчанию цикличен? Т.е. мне для своих нужд делать как-то так?

start_multi_timer(2*60, "my_file.my_func") --/ я так понял, что цикличны только мульти-таймеры

И что-то я не совсем понял, после выполнения всех моих условий таймер отключится, или так и будет крутится вечно?

 

А, по моему до меня дошло...сейчас проверю и отпишусь, чето туплю под вечер :)



start_real_timer(2, "my_file.my_func")

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

 

Можно конечно все на нем и оставить(time_global())... но не хочется.

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

@Карлан

1. Твое "если прошло 3 секунды то -> выполняем функцию -> завершить" полностью эквивалентно собственно запуску таймера: "запуск таймера с выполнением через 3 секунды функции". Т.е. когда пройдут 3 секунды с момента запуска таймера будет вызвана указанная функция и таймер завершит свою работу.

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

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

 

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

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

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

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

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

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

Именно так и сделал, даже вот код:

 

function my_update() --/ update
start_real_timer(2, "my_file.my_func1")
start_real_timer(2, "my_file.my_func2")
start_multi_timer(2, "my_file.my_func3", nil, true)
end

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

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

@Карлан, что-то ты действительно "тупишь под вечер"...

 

 

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

Говоришь о цикличности, а запускаешь: start_real_timer(2, "my_file.my_func") - одноразовый таймер реального времени. И чего ты ждешь?!  :crazy:

Включи режим отладки в модуле (local __DEBUG__ = true), позаботившись о рабочем выводе в лог и посмотри - у тебя вообще модуль работает(?), таймеры вообще запускаются ли? Не стОит засорять топик...

 

И не нужно поминать про time_global() - это всего лишь функция возвращающая время и она тоже испльзуется и в универсальных таймерах (если потребно). Если твои таймеры (по твоим алгоритмам/кодам) работают и устраивают тебя - то и используй их.  ;)

 

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

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

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

@Карлан

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

local bStarted = false
function my_update() --/ update
 if not bStarted then
  start_multi_timer(2, "my_file.my_func3", nil, true)
  bStarted = true
 end
end

И дальше таймер уже сам будет вызывать функцию my_file.my_func3 каждые 2 секунды\минуты или что там.

Это мульти-таймер. 

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

 

UPD: Поправил код.

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

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

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

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

@*Shoker*, разумеется, я это все понимаю :) Твой флаг бесполезен, т.к. таймеру дается каждый раз новое имя.

 

@Artos, таймеры у меня работают(тестовый из bind_stalker по крайней мере), так что проблема явно не в модуле, и явно не в моих функциях. Пока я считаю, что проблема в моих руках, т.к. они модуль не так как-то используют... Ладно, пойду поковыряюсь, больше не буду засорять топик. 

 

Upd:

 

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

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

@*Shoker*, можно даже проще, если задать таймеру свое эксклюзивное имя, или получить с уже запущенного и контролировать его: 

function my_update() --/ update
  if not timer_exists("MY_TIMER") then
    start_multi_timer(2, "my_file.my_func3", nil, true):set_name("MY_TIMER")
  end
end

@Карлан, ты действительно "тупишь" (без обид, плз). В варианте Shoker'а используется флаг запуска таймера (bStarted), и если какой-либо таймер из апдейта был запущен (с любым именем) - то уже не будет других запусков. Но(!) это в течении игры, но после перезапуска игры - будет запущен новый таймер...

Изменено пользователем Artos
  • Нравится 1

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

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

Так, стоп, давайте по порядку. А то я запутался, если я и сейчас тупану, то хоть баньте(и посты потрите, если нужно).

 

1 Я установил таймеры и все работает нормально:

--/ Пример запуска таймера:
start_real_timer(15, nil, {tip = {self.object, "Text test_RT"}}, "RT_test") --/ 15 real-seconds + set name
--/<

это отрабатывается.

 

2 Я создал свой скрипт my_file. Написал туда следующее:

 

function t1()
news_manager.send_tip(db.actor, text, 0, "Hello", 10000)
end
local bStarted = false
function update() --/ update
if not bStarted then
start_multi_timer(1, "my_file.t1", nil, true)
 bStarted = true
 end
end

3 В update биндера актора написал следующее:

...
function actor_binder:update(delta)
object_binder.update(self, delta)

my_file.update()
-- DEBUG slowdown
...

И у меня нихрена не работает. По идее, как я понял, должен вылетать типс с текстом "Hello" каждую секунду, но у меня ничего не происходит.

 

 

 

 

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

Обновил модуль "Универсальные таймеры":

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

- обновлено описание (добавлены описания доступных методов)

--/ для объекта таймера доступны:
timer:id() --/ чтение(получение) идентификатора запущенного таймера (не путать с игровыми идентификаторами объектов!)
timer:name() --/ чтение(получение) имени запущенного таймера
timer:set_name(timer_name) --/ установка/изменение имени таймера
timer:restart(time_sec, action, properties, timer_name) --/ перезапуск работающего таймера (аргументы аналогичгы запуску)
timer:get_time_rest() --/ получение оставшегося времени работающего таймера (real mseconds or game seconds)
timer:get_time_end() --/ получение времени (число mseconds), когда таймер сработает
timer:get_time_end(true) --/ получение времени (строка), когда таймер сработает
timer:get_property(property) --/ чтение значения параметра заданного таймеру
timer:set_property(property,value) --/ установка/замена параметра заданного таймеру
timer:remove() --/ удаление таймера

(ссылка прежняя, указана тут)

 

@Карлан, поставь перед (и после) строки запуска таймера вывод информации в лог или на экран и смотри - у тебя вообще делается ли попытка запуска таймера... И вообще вызывается ли твоя функция из апдейта актора? (как понимаю, с логами ты не дружишь :wacko: )

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

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

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

почему не передавать сразу функцию:

Встречный вопрос. Как таймер узнает после загрузки игры, какую функцию ему передали до этого?
 

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

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

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

 

Ссылка на комментарий
почему не передавать сразу функцию:

Пояснение: (пока не отраженное в описании)

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

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

Для последнего случая предназначены QUICK-таймеры, которые никогда не запоминаются.

Все остальные таймеры (real/game/multi/hud) обязательно запоминаются при условии(!) что заданная таймеру функция задана строкою (string)! В противном случае, таймер не будет сохранен.

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

Т.о. при запуске любого (кроме quick) таймера можно непосредственно типом данных линка на задаваемую функцию устанавливать свойство таймера: должен он запоминаться в сэйвах или нет.

Примечание: Если функция вообще не задана (nil), но заданы параметры для внутреннего обработчика таймеров (выдача инфопоршня/типса/...) - такой таймер обязательно будет сохранен в сэйве. Чтобы такой таймер не запоминался - используем quick-timer.

 

Так что ответ на вопрос: "Задавай как тебе хочется, исходя из потребностей, но учитывая возможности..."

(универсальность в действии  ;) )

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

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

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

Подскажите пожалуйста, еще вот в чем: требуется от ГГ передать НПС 2 артефакта. Для этого я использую  функции ColR_iT(в посте под спойлером), однако от ГГ передается НПС только 1 артефакт, сделал не большую эхо-печать в лог, для проверки счетчика - все правильно, вот только вылазиет одна строчка странная:

! Cannot find saved game ~:psi:__i_=_1,_count_=_2
* Log file has been saved successfully!
! Cannot find saved game ~:psi:__i_=_2,_count_=_2
* Log file has been saved successfully!
! ERROR: SV: can't find children [39427] of parent [270253968]
! Cannot find saved game ~:psi:__i_=_1,_count_=_2
* Log file has been saved successfully!
! Cannot find saved game ~:psi:__i_=_2,_count_=_2
* Log file has been saved successfully!
! ERROR: SV: can't find children [39425] of parent [270253968]

Я нашел в этой же теме, год назад такой вопрос задавал *Shoker*, только он пытался переместить предмет с земли нпс, и у предмета не было родителя и т.д., поэтому как сказали и вылазили эти ошибки. Но у меня 2 вопроса:

1. Почему перемещается только 1 предмет.

2. Почему вылазиют сообщения, ведь изначально родитель артефакта ГГ, потом НПС?

P.S. Или поделитесь своими функциями :)

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

Я могу ошибаться, но возможно в цикле who:object(section) возвращает один и тот же предмет. Т.е. только на следующем апдейте после who:transfer_item метод who:object(section) вернёт другой предмет. Т.е. по сути, в цикле будет попытка передать один и от же предмет count раз, из-за этого и запись в лог. Это предположение.

 

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

Доберусь до домашнего ПК, посмотрю осталось ли доделанная функция... ну или доделаю.

ColR_iT

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

@Shredder, ты прав, именно в данном случае, когда цикл НЕ привязан к итерации по инвентарю,  who:object(section) может возвращать один и тот же предмет, т.к. who:transfer_item(...) ассинхронна и предмет исчезнет из инвентаря 'who' только на следующем апдейте.

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

Как вариант, можно использовать и не iterate_inventory, а получать кол-во объектов в инвентаре:

  local count = npc:object_count()

и сразу перебирать предметы используя (но это опять же итерация):

  for i = 0, count - 1 do
    local item = npc:object(i)
    ...

Есть, правда, один "хитрый" способ, который вероятно задумывался разработчиками GSC, для обхода подобных ситуаций, для чего были добавлены методы:

  npc:mark_item_dropped(item) --/ отметка предмета с которым совершается действие (удаление/передача)

  npc:marked_dropped(item) --/ проверка наличия метки о совершенном действии над предметом (уже удаляется/передается)

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

 

@Старлей, строка в логе "! ERROR: SV: can't find children [ХХХХХ] of parent [ХХХХХХ]" - вполне может говорить о том, что предмету уже дана команда трансфера и движок удалил информацию о владельце... Повторное обращения к нему (предмет все еще в инвентаре у 'who') приводит к подобной информации об ошибке (без вылета!).

Если есть желание покопаться и поэкспериментировать то можешь поискать подходящее (например, Relocate_Items)

в этой "полезняшке" из моего набора:


 
Название: Скрипт "Общие функции" (m_helper)
Автор: Artos (сборка с использованием материалов STALKER-community)
 
Версия/Дата: - (27.09.2013)
Платформа: Универсальный (ТЧ/ЧН/ЗП), начиная с ТЧ 1.004
Сложность подключения: Простая
 
Скрипт, добавляет в игру различные часто употребляемые и/или полезные функции, которые могут использоваться модмейкерами.
Модуль(скрипт) различных автономных 'общих' функций (SHoC:6/7(118),CS:8(124),SCoP:12(128))
lua_helper.script
==============================================================================================
Скрипт, добавляет в игру различные часто употребляемые и/или полезные функции которые могут использоваться модмейкерами.
--/---------------------------------------------------------------------
Подключение:
1. Скопировать в папку скриптов игры скрипт: lua_helper.script;
2. Добавить в конец _g.script строку инициализации:
  prefetch("lua_helper") --/#+# подключение модуля 'общих' хелп-функций
--/---------------------------------------------------------------------
Список функций добавляемых в глобальное пространство _G:
--/-----------------------------------------------------
HasVar - проверка наличия переменной в хранилище 'storehouse'
DelVar - удаление переменной из хранилища 'storehouse'
SetVar - запись/изменение переменной в хранилище 'storehouse'
GetVar - чтение переменной из хранилище 'storehouse'
has_info - проверка наличия инфопоршня у актора
has_info_portions - проверка наличия инфопоршней у актора
has_any_info_portions - проверка наличия какого-либо из инфопоршней у актора
check_info_portions - проверка наличия/отсутствия инфопоршней у актора
give_info - установка инфопоршня для актора
give_info_portions - установка инфопоршней для актора
disable_info - удаление инфопоршня у актора
disable_info_portions - удаление инфопоршней у актора
Get_CheckedFunc -
GetVarA - проверка наличия переменной в pstor'e актора
GetVarA_Table
SetVarA
DelVarA
GetVarObj - проверка наличия переменной в pstor'e объекта
GetVarObj_Table
SetVarObj
DelVarObj
GetSizeVar - размер переменной в pstor'ах или в хранилище (в байтах)
Get_MobClass
Dlg_AddPhrase
Get_Actor_NPC
Get_Actor
Get_NPC
 
ReadFromIni
Get_AmmoList
Get_GrenadeList
Get_IniSection
Get_IniSections
Get_Cfg_String
Get_Cfg_Bool
Get_Cfg_Number
Get_Cfg_Num32
Get_Cfg_2Prm
Get_InvName
Get_InvShortName
Get_WeightSection
Get_CostSection
Get_ClassSection
Get_CharName
Get_Community
get_object_community
IsSobjOb
Release_Obj,
Spawn_Obj
Spawn_NPC
create_ammo
SendTip
Send_ReceivedInfo
SpellingBeginning
SpellingTermination
Spelling
Has_Item
Has_Items
Has_AnyItems
SwitchToOffLine
SwitchToOnLine
Clear_Inventory
Spawn_AmmoInInv
Spawn_ItemInInv
Spawn_ItemsInInv
Give_Money
Lost_Money
Relocate_Money
Relocate_Items
Relocate_AnyItems
Reload_Item
Take_Item
Lost_Items
Add_MapSpot
Del_MapSpot
Get_MapIdObj
Get_MapNameObj
VecToStr
Parse_Names
Parse_StrToTbl
Parse_CustomData
Fill_CustomData
Dir2TabRad
Dir2TabDeg
Deg2Rad
Rad2Deg
AngleDiffRad
AngleDiffDeg
 
Get_StrTime
Get_StrTimeOrDate
set_seconds2ctime
Get_RestSeconds
Set_RestSeconds
Add_RestSeconds
Get_PastSeconds
Get_PastMinutes
Get_PastHours
ms2string
sec2string
... и др.

 

 

Изменено пользователем Artos
  • Нравится 3

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

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

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

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

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

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

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

Войти

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

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

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