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

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


Svoboда

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

(изменено)

Полтергейст, не заблуждайся на счет панацеи в виде 'db.creatures' (как в прочем и 'родная' db.storage).

 

Во-первых, эта таблица создается не мгновенно при старте игры, а динамически пополняется/чистится по мере появления объектов в он-лайне.

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

 

Во-вторых, в более сложных случаях можно нарваться и на момент, когда серверный объект уже удален из игры, а в таблице 'db.creatures' он еще не удален соответствующим биндером/скриптом.

 

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

 

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

TRAMP14, таблицы 'db.creatures' (как и db.storage) содержит почти(!) все объекты, которые обрабатываются биндерами, т.е. не только сталкеров, но и всех монстров, ящики, прожекторы, и пр. ... Но(!) только на текущей локации и только те, что уже в онлайне. Так что экономия по кол-ву перебираемых объектов (их идентификаторов) на пару порядков меньше, чем при полной итерации.

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

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

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


Ссылка на сообщение
(изменено)

Полтергейст, мой мост спровоцирован не текущим вопросом/ответом, а тем, что не первый раз вижу твое "восторженое" отношение к отказу от перебора массива игровых идентификаторов объектов в сторону именно db'шных таблиц.

Дабы и другие не вводились в заблужление - и дал пояснение. Естественно истина - в использовании обоих вариантов.

 

Повторю основное: Не стОит безоговорочно отказываться от одного варианта в пользу другого. Какой таблицей пользоваться зависит от ситуации/момента. Порой необходимо перебирать весь массив идентификаторов, а порой и стОит свою табличку заранее сделать, дабы с'экономить немало времени/ресурсов в дальнейшем.

 

Да и собственно корячиться с 'db.creatures', как ты предлагаешь по прежнему, не имеет особого смысла. Уже в самом АМК (v1.4x) эта таблица по сути стала почти рудиментом, т.к. почти полностью повторяет таблицу 'db.storage'. А на 'сегодня' - подобное уже подустарело ...

Лучше бы обратил внимание на то, как аналогичное сделано в Zenobian-Mod'е, в котором в отдельную таблицу селектируются только гуманоиды и монстры с установкой соотв.флага, дабы проще/быстрее было их различать. :-)

 

P.S. Предлагаемый автором вопроса скрипт/кусок искал онлайновых неписей, но(!) ни намека в какое время это делает скрипт/автор скрипта. Поиск онлайновых объектов может потребоваться и на старте игры, когда 'твоя' таблица еще (полу)пуста.

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

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

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


Ссылка на сообщение
(изменено)

Полтергейст

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

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

 

Строка: cse_alife_human_stalker.STATE_Write (self, packet) - считывает из пакета сталкера основные базовые байты, но(!) вслед за ними идет байт 'job_online' (u8) с флагом онлайновой работы , после которого могут присутствовать стринговые байты собственно 'job_online_condlist' (stringZ). Далее имеем байт 'was_in_smart_terrain' (bool). И уже за всем этим следует байт 'death_droped' (bool/u8), с которым ты намереваешься поэкспериментировать с целью сохранения бита 'раненый'.

Как видно из выше изложенного (или можешь взглянуть на структуру нет-пакета сталкера в том де бардаковском ACDC) ты вместо заключительного байта 'death_droped' пытаешься перепрописывать 'job_online' ...

К хорошему такие эксперименты не приведут.

 

Т.о. ответ на вопрос: "Что делать?":

- вариант а) Правильно использовать нет-пакеты с их структурой;

- вариант б) Не изобретать велосипед и использовать из того же АМК все то (уже давно сделанное), что ты пытаешься с битом ранения (причем ... с теми же названиями переменных ;-) ).

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

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

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


Ссылка на сообщение
(изменено)

Полтергейст, вот когда ты сам себе ответишь на вопросы:

а) "Чем отличается класс 'se_stalker' от 'cse_alife_human_stalker'?" (с точки зрения нет-пакетов)

и

б) "А могу ли я изменять структуру нет-пакетов для уже имеющегося в игре класса?" - и если 'да' то 'что и как' конкретно?

 

- тогда приступай к экспериментам.

 

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

 

Или создавай свой класс объекта со своей структурой пакета или ... используй

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

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

 

 

P.S. Твоя попытка усечь пакеты в классе 'se_stalker' бессмысленна, если ты конечно не делаешь что-то совершенно свое и на другом движке.

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

 

P.P.S. Перепрочитал и понял в чем твое основное заблуждение:

При старте новой игры объект(ы) создаются сервером в соответствии со своими классами и с применением параметров из all.spawn'а. И только после этого ты их их можешь читать с клиентской стороны и соответственно перезаписывать. Т.о. любая попытка удалить из уже заданной структуры нет-пакета объекта соответствующего класса или даже изменить разрядность базовых для класса байт - бессмысленна изначально. Сервер конечно примет с твоей стороны измененный нет-пакет, но вот применить его к объекту ...?

Удачи в экспериментах! :-)

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

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

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


Ссылка на сообщение
(изменено)

Garry_Galler

Все же стОит сравнивать НЕ сами объекты (их юзердаты), а например их игровые идентификаторы (Id), т.е. типа:

 

local currentOutfit = nil

заменить на:

local idOutfit = nil

 

if currentOutfit and oOutfit and currentOutfit==oOutfit then

заменить на:

if idOutfit and oOutfit and idOutfit == oOutfit:id() then

...

currentOutfit=oOutfit

заменить на

idOutfit = oOutfit:id()

 

Также стОит добавить ветку/условие обнуления 'запомненного броника' (currentOutfit/idOutfit), т.к. актор может и снять его ...

 

 

Если еще принять во внимание, что броник ГГ может снять/одеть/поменять только в двух ситуациях:

а) если 'голенький' - подобрал/купил/заспавнился в инвентори броник - это коллбэк на получение предмета (on_item_take);

б) при 'ручном' переодевании, т.е. игроком в окне инвентори - коллбэк на закрытие окна инвентори.

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

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

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

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


Ссылка на сообщение
(изменено)

Zander_driver

Во-первых,

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

Биндить коллбэк - тупое сочетание несочитаемого. Коллбэк можно 'ставить', и не только в биндерах, а и во многих других местах.

 

Во-вторых, если коллбэк, как выше сказано не обязательно устанавливать в биндере объекта, то что мешает тебе ставить его в любом удобном и подходящем тебе месте? Берешь объект и ставишь ему коллбэк, типа:

oDropBox:set_callback(callback.hit, my_script.hit_callback, nil) - и ловишь его в своем скрипте.

 

К сути:

Ключ к ответу уже имеется в оригинальных кодах биндера физ.объектов: "Биндить предмет нет смысла, если у него нет секции logic" (это из комментов разрабов). Также там имеется фраза: "Прожектор нужно биндить даже без logic"

Иными словами, физ.объекты не имеющие логики (или параметра "drop_box") и не прожекторы не добавляются и не обрабатываются биндером (не биндятся).

 

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

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

Коллбэк не вызывается НЕ для пустых ящиков, а для ящиков не имеющих логики (точнее условия "drop_box"). Поэтому то они и пустые, что ничего в них не спавнится из-за отсутствия обработки события "death".

 

Честно говоря, неясно для чего тебе коллбэк на хит (hit_callback), а не на разрушение (death_callback), но в любом случае - придется или логику ("drop_box") добавлять или делать нечто аналогичное прожекторам, исключая конечно в 'xr_box.script' обработку твоих пустых добавок ...

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

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

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


Ссылка на сообщение
(изменено)

Zander_driver, теперь немного попонятнее из какой области твой вопрос и куда стоит 'копать'.

 

Несложно найти, что clsid у подобных разрушающихся ящиков и пр. (секция из конфига [physic_destroyable_object]) - P_DSTRBL / clsid.obj_phys_destroyable.

Если среди подобных объектов встречаются не нужные тебе - придется фильтровать по маскам имени.

 

С "ящиками поменьше" (т.е. железными и иже ...) посложнее тебе будет (clsid.inventory_box), т.к. коллбэк на хит или разрушение для них не обрабатывается.

 

Логика (точнее секция 'drop_box') - подразумевает обработку данного объекта схемой 'xr_box.script' и конечно же подразумевает что-то дропить ...

Но(!) ни что не мешает замутить что-то типа 'фейк-дропа', т.е. спавн фейкового предмета или даже спавн 'ничего'. Ведь даже изначально секция дефолтного спавна подразумевает спавн предметов в кол-ве 0. Запретив рандомный спавн (по какой-дибо метке/признаку/условию/...), можно получить просто всегда разрушаемые ящики без спавна.

 

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

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

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

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


Ссылка на сообщение
(изменено)

Svoboда

При прописывании своего НПС в all.spawn'е ты допустил ошибку НЕ указав ничего про 'smart_terrains', а только указал наличие секции.

Дополни пустую секцию до:

 

[smart_terrains]

none = true

 

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

 

Или же можешь включить 'свое патрулирование' в работы (например ближайшего к точкам) гулага, обусловив 'именно для твоего НПС', и пусть патрулирует, заодно и может чего еще надумаешь в контексте гулага (не все ж ему разгуливать ...).

 

---

Zander_driver

ИМХО, схожесть визуалов далеко не основной критерий одинаковости для разрушения.

Важна точка приложения силы, а не столь сама сила и уж конечно же не внешний вид.

Для меня, например, более странным будет, если каждый ящик будет разрушаться всегда с одного и того же кол-ва выстрелов (если более 1).

Но это уже лирика пошла ... :-)

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

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

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


Ссылка на сообщение
(изменено)

Zander_driver

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

Упомянутый в логе 'amk.script' явно отличен от оригинального (из чистого АМК) и далее только погадалки предстоят ... В таких случаях стОит предоставлять 'неизвестный' скрипт или хотя бы ссылку на 'где его увидеть можно' (может кто и поможет ...).

 

Лог ошибки говорит, что переменная/аргумент 'respawner' в 1795-ой строке является функцией, а от нее хотят нечто иное. В АМК-моде это должен быть объект (юзердата класса "se_respawn").

Не помню достаточно точно всего амк-алгоритма респавна, могу только предположить, что кто-то накосячил в 'se_respawn.script', в коем и организован амк-контроль за респавном объектов (неписи/монстры) и вызов из 'amk.script' перевода объекта в он(офф)лайн.

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

Варианта два: а) отключать мешающий амк'шный контроль или б) корректно прописывать своих неписей/монстров в конфиги респавна (благо примеров предостаточно).

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

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

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


Ссылка на сообщение
(изменено)

Disord

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

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

 

Обоснование: Проверка происходит по по клиентскому объекту актора, а удаление - у серверного объекта. Уже удаленный(!) предмет будет обнаружен и при следующей 'проверке наличия', если делается в одном и том же цикле, т.к. на синхронизацию серверного и клиентских объектов требуется время (несколько циклов апдейта актора).

Т.о. упрощенные функции имеют область ограничений на применение.

 

Более безопасный вариант может выглядеть так:

function del_from_player_inventory(item_name)
  local obj = db.actor:object(item_name)
  if obj then
    local se_obj = alife():object(obj:id() --/ получаем серверный объект искомого предмета
    if se_obj then --/ проверка наличия объекта в игре
      alife():release(se_obj, true)
    end
  end
end

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

 

Или же можно использовать методы выставления флагов 'исключения' для предметов, типа:

function del_from_player_inventory(item_name)
  local obj = db.actor:object(item_name)
  if obj and not db.actor:marked_dropped(obj) then --/ и отсутствует метка 'исключения'
    db.actor:mark_item_dropped(obj) --/ ставим метку 'исключения'
    alife():release(alife():object(obj:id()), true)
  end
end

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

 

---

Готовых функций 'удара по лицу' не существует, вероятно ты имеешь ввиду схему 'abuse'. Требуется вызывать соответствующие состояния/анимации (или использовать подходящее из схемы 'abuse' или самописное). Есть моды, в которых имеется схема 'мордобоя'.

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

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

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


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

Valerich

Помести это:

function del_val_zapis()
  for i=1,20 do
    local item_name = "val_zapis_"..i
    local obj = db.actor:object(item_name)
    if obj then
      local se_obj = alife():object(obj:id() --/ серверный объект i-ой записки
      if se_obj then --/ проверка наличия записки в игре
        alife():release(se_obj, true)
      end
    end
  end
end

в файл 'valerich_dialog.script' и вызывай из диалога строкою:

<action>'valerich_dialog.del_val_zapis</action>

И не стОит адресовывать ко мне подобные посты ...

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

 

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

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


Ссылка на сообщение
(изменено)

Kirag'

Поправлю:

Допускается и строка с аргуметами как у Ulman'а, т.е. 'play_at_pos' выполняется не 'от имени кого-то', а относительно какого-либо объекта (1-ый аргумент).

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

Т.е.

snd:play_at_pos(db.actor, vector():set( 0, 0, 0), 0, sound_object.s2d) --/ играть звук 'в голове' актора (без задержки, моно)

snd:play_at_pos(db.actor, vector():set( 1, 0, 1), 3, sound_object.s3d) --/ играть звук относительно актора впереди-справа (с задержкой 3 сек, стерео)

snd:play_at_pos(db.actor, vector():set(-1, 0, 1), 0, sound_object.s2d+sound_object.loop) --/ играть звук относительно актора впереди-слева (без задержки, моно,зацикленно)

и т.п.

 

3-ий аргумент - задержка звука (сек)

4-ый аргумент - константа (из набора свойств класса 'sound_object': s2d|s3d|loop -> моно/стерео/зацикленно)

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

 

Примечание: vector():set(0,0,0) - просто некий вектор(объект) 'нулевой длины' (а не относительно начала координат локации)

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

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

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


Ссылка на сообщение
(изменено)

antreg

При запуске игры, в момент спавна актора в АМК вызывается 'on_game_load()' для первичных проверок/настроек и пр.

 

alife():object(2972) - проверка наличия объекта в игре с номером секции из all.spawn'a. В АМК 1.41 секции 9272 и 9275 - аномалии в ТД. (можно выкинуть)

 

Далее идет проверка и если требуется - предустановка pstor'аджа актора (хранилище сохраняемых в сэйвах переменных).

 

npc_spawner= из сэйва считывается массив заспавненных , но еще не инициализированных объектов (если таковые были в момент сохранения игры).

 

mod_call("first_run") - важный(!) вызов 'first_run()'первичных настроек в amk_mod.script ...

 

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

 

gg_kick - флаг для алгоритма "шальная пуля" - можно выкинуть

 

mod_call("test_sleep_pp") - вызов 'test_sleep_pp()' из amk_mod.script ... (спальник)

 

mod_call("check_spawn") вызов 'check_spawn()' из amk_mod.script ... (ре)спавн объектов (npc_spawner, динамич.аномалии, ...)

 

val_actor_has_borov_key - пробуждение Кочерги ...

 

amk_mod.on_repbox() - это уже чье-то левое ...

 

gps_habar.on_game_load() - ну а это мод GPS-маячков для тайничков с пометками на карте

 

---

ERROR:___[bind_stalker.script]SAVE___FILE___IS___CORRUPT - говорит о том, что из пакет актора был некорректно считан из сэйва. У АМК есть свои нюансы работы чтения/записи пакета. Вполне вероятно проблема в упаковке в сэйв массива 'npc_spawner' ...

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

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

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


Ссылка на сообщение
(изменено)

*Shoker*

Как говорится "зри в корень" ... Не ищи готовых вариантов, т.к. потребное тебе выходит за рамки как оригинальной игры, так и отдельных модов.

а гранаты в момент убийства у НПС уже может не быть, тоже касается игрока

Вот и отталкивайся от этой правильной мысли.

Информацию о том 'кто/что' убило непися - несет аргумент 'who' в коллбэке хита. В случае монстров, аномалий и т.п. - все вроюе как просто и понятно.

Если же киллер - сталкер, то в основном тоже все просто, определяется по уже упоминавшемуся тут active_item().

Однако при игре с модами возникают и пожелалки типа определения: "а не гранатой ли убит"?

Тут тоже в принципе все просто, если 'who' - граната, то и убит ею ...

 

В чем же заковыка? А в том, что если игрок (ГГ) кидает гранату, то 'who' даст возвратом не гранату, которая и взорвалась то через секунды, а именно ГГ, т.е. того кто бросил(!), а точнее - владельца гранаты.

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

Если граната/подствольный заряд/мина, которая убила непися имеет 'parent_id' - то именно владелец этого предмета и будет указан как 'who' в коллбэке хита. Если же в схеме кидания/стрельбы 'граната' заменяется на некий фейк-объект, то будет указана именно 'граната', а не тот кто кинул ее.

 

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

Если хочется единообразия, то придется доработать соответствующие схемы, для того, чтобы кинутые и 'убивающие' предметы заведомо получали соответствующий 'parent_id' с занесением в некий краткосрочный массив {item => parent}, и уже тогда по 'who' можно будет определять кто и из чего замочил ...

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

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

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


Ссылка на сообщение
(изменено)

*Shoker*

Уничерсальная функция вывода в лог-файл любой строки с параметрами выглядит например так:

--/-------------------------------------------------------------------
--/ Functions for Print-Log
--/-------------------------------------------------------------------
function printf(fmt,...) --/ вывод в лог-файл
  --/ локальная функция перевода в стринг иных типов переменных
  function to_string(val)
    local sType = type(val)
    if sType == "string" then
      return val --/>
    elseif sType == "number" then
      return tostring(val) --/>
    elseif sType == "boolean" then
      return tostring(val) --/>
    elseif sType == "table" and type(val.x) == "number" and type(val.y) == "number" and type(val.z) == "number" then
      return string.format("x=%d:y=%d:z=%d", val.x, val.y, val.z) --/>
    elseif sType == "userdata" and type(val.x) == "number" and type(val.y) == "number" and type(val.z) == "number" then
      return string.format("%d:%d:%d", val.x, val.y, val.z) --/>
    end
    return string.format("<%s>",sType) --/>
  end
  --/ основная функция
  if fmt ~= nil then
    fmt = to_string(fmt)
    if fmt:match("%\%s") then --/ имеются патерны
      local tArg = {...} --/ список аргументов
      if tArg and next(tArg) then --/ имеются аргументы
        for i=1,#tArg do
          fmt = fmt:gsub("%\%s",to_string(tArg[i]),1) --/ последовательно заменяем по одному патерну
        end
      end
    end
    fmt = fmt:gsub("%\%s","<<<NOT_arg!>>>") --/заглушка от отсутствующих аргументов
    fmt = fmt:gsub("%s",'\160')--/ замена обычных пробелов (sym_space='\032') на печатные ('\160')
    fmt = "*INFO:"..fmt:sub(1,250) --/ ограничение (первые 250 символов) длины строки выводимой в лог-файл (опционально)
  else --/ отсутствует информационная строка
    fmt = '*INFO:<zero_string>'
  end
  --/ для SHoC
  get_console():execute( fmt )
  get_console():execute( "flush" ) --/ 'фиксация' (запись) строки в лог-файле (опционально)
  --/ для CS или SCoP
  --error_log( fmt )
end
--/-------------------------------------------------------------------

Позволяет выводить в лог осмысленную строку при любой комбинации входных параметров, попутно переводя векторы в значения координат (x:y:z) и др..

Замена пробелов, по которым отсекается дальнейший вывод в лог в оригинальном коде НЕ на символ подчеркивания ('_') а на печатный пробел ('\160) позволяет читать строку в том виде, который задан в исходном коде.

Небольшая подстройка последних строк позволяет использовать в CS или SCoP, а исходный вариант расчитан на SHoC.

 

В вашем конкретном примере исходная строка из функции 'get_last_IDS(...)' скрипт-файла 'xr_sound.script':

printf("LAST INTO ID for [%s] = [%s], max [%s]", theme, last_table[snd_table.into_id], snd_table.into_max)

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

 

Инструмент нужно подбирать не абы какой, а ... каКчественный! :-)

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

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

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


Ссылка на сообщение
(изменено)

malandrinus, все же это уже 'технические' моменты и естественно конкретные варианты фиксации в общий лог-файл или еще куда могут быть самыми различными и зависить от конкретных задач.

При поиске проблем/ошибок, ИМХО, важно иметь синхронизированный вывод 'своих' технологических строк с основным игровым логом. Это помогает понять когда/что/из-за чего ...

При наличии достаточно рабочего варианта луа-перехватчика (by alpet) это уже довольно тривиально и не требует особых усилий, но(!) как раз завязано на парсинг общего игрового лога.

 

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

 

*Shoker*

Различные 'if', грузят систему ровно настолько насколько ума вложил в них кодер ... :-)

Уж поверь, сотня 'if' в предложенном варианте грузит систему не более чем одна строка 'get_console():execute("flush")'.

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

Еще АМК в своем 1.3 придумали 'watchdog', позволяющий разложить подобный поиск ошибок на этапы, не применяя сплошного вывода в лог. Да и в оригинальных кодах видны следы от разработчиков, позволявшие им не сильно напрягать ресурсы, подвергая дебагам отдельные скрипты/схемы/группы, а не сплошняком ...

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

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

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


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

Чуть дополню о сути watchdog'а, раз уж заикнулся и опять заглянул сюда.

 

Понятие 'watchdog' довольно непростое, но суть: сделить за работой чего-то и в случае несоответствия заданных критериев - предпринимать некие действия. Например подобное используется в серверных системах, котоорые контролируют работту различных систем и в случае сбоя/зависания - дают команду на жесткий ресет/рестарт сервера. Т.о. обеспечивается относительная безперебойность работы системы.

 

Касательно скриптов и конкретного варианта применения принципа watchdog'а в АМК-скриптах:

Наверное уже многим известно, что в игре движок и скрипты работают по некоему циклу, который по определению постоянно повторяется. Именно методы update() и работают в этих циклах, в том числе и апдейт актора ( function actor_binder:update(delta) ).

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

Основная масса вероятных ошибок возникает именно в части цикла апдейта актора. abramcumner, выше уже описал суть применения и использования watchdog'а применительно к этой части. В motivator_binder:update() стоит проверка условия корректного завершения работы апдейта актора, а если нет - выводится информация (если модмейкер озаботился) о причине и месте (по индексу переменной). Это позволяет при сбоях/зависаниях треда (потока) апдейта актора локализовать место сбоя и далее разбираться в этом скрипте/функции.

 

Однако, следует помнить, что весь цикл не ограничивается только апдейтом актора. Далее отрабатывают свои куски апдейты NPC, монстров, иных объектов, которые зарегистрированы в биндерах. Работают для этих объектов различные схемы (xr_, sr_, hp_, ...).

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

 

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

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

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


Ссылка на сообщение
(изменено)

Ulman

Оружие, которое не использует НПС в схеме менеджера оружия (AI additions - Rulix (Bak)) не пропадает навсегда. По крайней мере так при штатной работе схемы. Это оружие перемещается в 'хитрый' ящик-хранилище и лежит там. В зависимости от ситуации НПС может менять оружие 'в руках' на более подходящее оружие из ящика. Все это для игрока (тебя) незаметно.

При сэйвах игры возможны некоторые комбинации условий, когда оружие из ящика не будет возвращено НПС и ... оно действительно пропадет навсегда.

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

Но твой вопрос интересен! Действительно, при разговоре/торговле НПС не меняет оружия и вполне может продать 'последний патрон' к оружия в ящике (ведь для него этого оружия не существует) и в последующем и патроны в магазине возвращенного оружия запросто могут кончиться.

Нужно будет доработать ... :-)

 

Ну а с твоим Психом, которого лечат - тебе дали дельный совет с внесением его в табличку схемы:

local excluded_npcs={
    esc_fox=true,
    esc_vagon_wounded=true,
    gar_bandit_stroyka3=true,
    gar_wounded_bandit=true,
    val_sos_wounded=true,
    val_escort_bandit_halfdead=true,
    bar_bar_psih = true --/ это твой Псих!
}

- если его имя именно таково ('bar_bar_psih') - его никак не могут лечить этой схемой. Ищи тогда или ошибку с внесением в табличку или дублера схемы лечения.

Чтобы его не обирали - требуется аналогично запретить в схеме собирательства (обычно это watcher_act.script). Однако там в кодах придется создавать такую аналогичную табличку исключений самому и добавлять в условия.

 

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

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

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


Ссылка на сообщение
(изменено)

Виталкер

Выше abramcumner уже дал основную информацию для ответа.

Немного дополню упущенное.

Вычислить (без SDK) достаточно точно требуемые координаты для спавна объектов довольно сложно, тем более еще и параметр(ы) 'направление/direction' важны.

Чтобы заспавненная машина стояла как 'вкопанная', в секции спавна объекта (в all.spawn) можно применить 'стопор' типа: '[collide] ignore_static' и/или 'привязку кости' - 'fixed_bones = root'. Конкретные примеры см. в исходных кодах игры, их немало

Однако так машина будет всегда 'вкопаной' и покататься на ней не удасться.

 

Если требуется спавн машины для 'покататься', то самым разумным решеним (которое давно используется в модах и в том же АМК) - заспавнить машину чуть выше требуемой точки и дать ей скриптом после старта игры небольшой импульс (хитом и/или apply_force). Так она опустится на землю и встанет на колеса и не будет 'драться'. Но и 'вкопанной' она не будет - при касаниях может и укатиться ... :-)

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

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

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


Ссылка на сообщение
(изменено)

Виталкер

В моде АМК в 'bind_physic_object.script' имется функционал для отслеживания 'жизни' БТРов.

Ипользуя уже имеющееся (или заново) следует в 'generic_physics_binder:net_spawn(data)' определить, что объект именно машина, и дать 'пинок', например так:

  if self.object:clsid() == clsid.car_s then
    --/ Опускаем технику на землю (on_the_ground):
    local ph_shell = self.object:get_physics_shell() --/ получаем управление над физикой
    if ph_shell then
      ph_shell:apply_force(0,-1,0) --/ прикладываем небольшую силу (вниз)
    end
    local h = hit()
    h.draftsman = self.object
    h.direction = vector():set(0,-1,0) --/ направление 'вниз'
    h.power     = 0.001
    h.impulse   = 1
    h.type      = hit.strike
    self.object:hit(h) --/ наносим небольшой импульс
  end

 

Для 'нпсов' подобное не применимо, точнее ... по аналогии в соотв. биндере можно также дать хит, но физической оболочки (ph_shell) в отличии от тех же машин у гуманоидов и монстров нет. Т.е. придется обходиться только хитом. Но и это не требуется - неписи сами начитают двигаться (как только окажутся в онлайне) и сами 'опускаются' на землю. :-)

 

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

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

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

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


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

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

AMK-Team.ru

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