Norman Eisenherz 354 Опубликовано 8 Апреля 2019 Какое сильное колдунство… В оригинальном коде всего одно упоминание такого callback'а, и то в качестве теста. Всем спасибо, противная недоработка наконец-то "подпернута" костылем. Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 10 Апреля 2019 Я опять встрял, и не могу понять, во что именно… Есть две функции: одна привязана к "info_callback" и спавнит предмет в момент начала торговли, другая запускается после спавна предмета и должна получить его id. Как только я пытаюсь добавить в аргументы второй функции "info_id" для дальнейших действий на основании инфо-поршней из основного колбэка, функция перестает видеть созданный объект, хотя вызывается строго после его создания. Может ли проблема быть в том. что в первой функции создаются два объекта, а колбэк только на одном? Код ниже, требуется передать (info_id) в функцию "transfer". Spoiler function box_id(sect) for i = 0, 65535 do local obj = level.object_by_id(i) if obj and obj:section() == sect then return obj:id() end end end function box_spawn(info_id) local act = db.actor if info_id == "ui_trade" then local act_pos = act:position() alife():create( "box_ex", vector():set( (act_pos.x + 1), (act_pos.y), (act_pos.z) ), act:level_vertex_id(), act:game_vertex_id() ) local spawn = alife():create( "box_eq", vector():set( (act_pos.x), (act_pos.y), (act_pos.z + 1) ), act:level_vertex_id(), act:game_vertex_id() ) level.client_spawn_manager():add(spawn.id, -1, transfer) end end function transfer() local act = db.actor local box_1 = box_id("box_eq") local box_2 = box_id("box_ex") if box_1 and box_2 then news_manager.send_tip(act, "spawned") else news_manager.send_tip(act, "missing") end end Переделал вызовы так, чтобы "info_id" читался непосредственно в "bind_stalker", а функция, зависящая от спавна, только перебрасывала предметы. С одной коробкой работает, с двумя – не переносятся предметы из второй коробки, хотя id второй коробки читается правильно и предметы _в_ эту коробку точно переносятся, если что-нибудь купить (коробки на время теста не удаляются). Посмотрите, пожалуйста, кто-нибудь, где я косячу: https://drive.google.com/open?id=1ak0_jspeRXxoTxxHIDLCe-J0-Psp41DS Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 11 Апреля 2019 @Kirgudu Не "возможно", а так и есть – надо дождаться выхода в онлайн, чтобы потом переносить объекты в созданные коробки. Ссылку на id я могу передать только на один объект в одном колбэке, поэтому второй все равно придется искать через перебор (если только колбэк не понимает две пары аргументов "id, obj"). Во втором посте как раз вариант с прямой передачей одного id вместо ссылки на info_id общего колбэка. Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 11 Апреля 2019 @AndreySol Попробовал создать два объекта в одной функции – получается два тестовых сообщения с разными id объектов. Это предполагаемый результат, или как-то можно передать две пары "id, obj" в одном вызове функции? Spoiler function drop_check(obj) -- [bind_stalker] on_item_drop(obj) if obj:section() == "hand_radio" then spawn() end end function spawn() local act = db.actor local item = { "bandage", "medkit" } for k, v in pairs(item) do local spawn = alife():create(v, act:position(), act:level_vertex_id(), act:game_vertex_id()) level.client_spawn_manager():add(spawn.id, -1, test_msg) end end function test_msg(id, obj) news_manager.send_tip(db.actor, "obj: " .. obj:section() .. ", id: " .. id) end Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 11 Апреля 2019 Вопрос по функции transfer_item: ссылка дается на секцию предмета, и если в инвентаре несколько предметов с одинаковыми секциями, часто передается не тот, что в слоте. Попытка сослаться на id() вместо секции (как в варианте alife():release) делает функцию "пустышкой" – вылета нет, но и эффекта тоже никакого. Какую проверку можно ввести для точного определения предмета? Spoiler function items_out(box_id) local act = db.actor local box = level.object_by_id(box_id) local n = {1, 2, 6} for k, v in pairs(n) do local slot = act:item_in_slot(v) if slot then act:transfer_item( act:object( slot:section() ), box ) -- здесь ошибка end end end Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 11 Апреля 2019 (изменено) @AndreySol Есть контакт. Уже не помню, где я нашел образец с секцией, но это явно сбило меня с толку. Изменено 11 Апреля 2019 пользователем Norman Eisenherz Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 14 Апреля 2019 (изменено) Здрасьте. При использовании скрипта для исключения экипированных предметов на время торговли/обыска случается вылет со ссылкой на слоты экипировки в порядке "пистолет > автомат > броня" (при наличии), если открыть и тут же закрыть труп или контейнер. Можно ли эту ошибку обойти в самом коде? Триггер скрипта – info_callback в [bind_stalker.script] Spoiler Expression : e_entity->ID_Parent == id_parent Function : xrServer::Process_event_reject File : E:\stalker\sources\trunk\xr_3da\xrGame\xrServer_process_event_reject.cpp Line : 23 Description : wpn_sig22029705 Arguments : single_player Spoiler local act = db.actor local box_1 = 0 local box_2 = 0 -- // проверка наличия активного противника в радиусе охвата мини-карты // -- function enemy() for i = 0, 65535 do local obj = level.object_by_id(i) if obj and obj:alive() and ( obj:relation(act) == game_object.enemy or IsMonster(obj) ) and obj:position():distance_to( act:position() ) < 30 then return true end end return false end -- // спавн коробок и отслеживание ввода в онлайн // -- function spawn_box_1(info_id) if info_id == "ui_trade" or info_id == "ui_car_body" then local act_pos = act:position() local spawn = alife():create( "box_eq", vector():set( (act_pos.x + 1), (act_pos.y), (act_pos.z + 1) ), act:level_vertex_id(), act:game_vertex_id() ) level.client_spawn_manager():add(spawn.id, -1, transfer_out) end end function spawn_box_2(info_id) if info_id == "ui_trade_hide" or info_id == "ui_car_body_hide" then local act_pos = act:position() local spawn = alife():create( "box_ex", vector():set( (act_pos.x + 1), (act_pos.y), (act_pos.z + 1) ), act:level_vertex_id(), act:game_vertex_id() ) level.client_spawn_manager():add(spawn.id, -1, transfer_back) end end -- // перенос предметов // -- function transfer_out(id, obj) box_1 = id -- news_manager.send_tip(act, "out_1: " .. box_1) items_out(box_1) end function transfer_back(id, obj) box_2 = id -- news_manager.send_tip(act, "out_2: " .. box_2) items_out(box_2) -- news_manager.send_tip(act, "back_1:" .. box_1) items_back(box_1) spawn_dl() end function spawn_dl() -- костыль для задержки на время переноса предметов в доп. коробку local act_pos = act:position() local spawn = alife():create( "box_dl", vector():set( (act_pos.x + 1), (act_pos.y), (act_pos.z + 1) ), act:level_vertex_id(), act:game_vertex_id() ) level.client_spawn_manager():add(spawn.id, -1, transfer_end) end function transfer_end(id, obj) alife():release( alife():object(id) ) -- удаление костыля -- news_manager.send_tip(act, "back_2:" .. box_2) items_back(box_2) if enemy() == false then -- news_manager.send_tip(act, "все тихо, выбор болта") act:activate_slot(5) elseif enemy() == true and act:item_in_slot(2):section() == "wpn_vintorez" and act:item_in_slot(1) then act:activate_slot(2) -- небольшая правка - винторез стабильно пролетает в слоты до пистолетов end end -- // перенос предметов в коробку // -- function items_out(box_id) local box = level.object_by_id(box_id) local n = {1, 2, 6} for k, v in pairs(n) do local slot = act:item_in_slot(v) if slot then act:transfer_item(slot, box) end end end -- // перенос предметов из коробки и ее удаление // -- function items_back(box_id) local box = level.object_by_id(box_id) local storage = {} for i = 0, 65535 do local obj = level.object_by_id(i) if obj and obj:parent() and obj:parent():id() == box_id then table.insert(storage, i) end end if next(storage) ~= nil then for k, v in pairs(storage) do local item = level.object_by_id(v) box:transfer_item(item, act) end -- else news_manager.send_tip(act, "empty box") end alife():release( alife():object(box_id) ) end Изменено 14 Апреля 2019 пользователем Norman Eisenherz Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 17 Апреля 2019 Разрядность, 2 в 16 степени (65 536) + сдвиг на 1 назад с учетом отсчета от 0 Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 3 Мая 2019 Здрасьте. Слепил уборщик бесхозного оружия: • вызов из [scripts\bind_stalker.script] actor_binder:net_spawn(data); • удалять все, кроме списка исключений; • на текущей локации удалять, если рядом нет трупов; • на других локациях удалять просто так. Проблема: если вызывать скрипт каким-нибудь триггером (сброс бинта, например) в уже прогруженной локации, то ближайшие трупы учитываются и пушки, соответственно, лежат на месте. При вызове из "net_spawn" трупы в процессе прогрузки не обнаруживаются. Вариант 1: https://drive.google.com/open?id=1-K5gPW3q3AUPN1bGXfEjBZ1Uj8kecjwh Добавил задержку запуска через level.client_spawn_manager: трупы обнаруживаются и при вызове из "net_spawn", хотя задержка всего ничего. Вариант 2: https://drive.google.com/open?id=1eEcuoF9Daw150FPWxpsAkXodliqAE2x1 Выходит, трупы на текущей локации загружаются чуть позже ГГ. Как это обойти без костылей? Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 3 Мая 2019 @AndreySol Теперь на текущей локации вообще пушки не удаляются (вариант скрипта 1). Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 3 Мая 2019 @naxac Старый уборщик всего и вся от мифического Сяка так и сделан, и я тоже планирую добраться до такой схемы. Но вопрос с загрузкой трупов остается. Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 4 Мая 2019 (изменено) Проблема: к серверному объекту невозможно применить проверку if not obj:alive(), хотя такая проверка есть в коде от Сяка. Код оригинального уборщика (солянка 2010): Spoiler for a=1,65534,1 do local obj = alife():object(a) if obj and game_graph():valid_vertex_id(obj.m_game_vertex_id)then local obj_clsid = obj:clsid() local obj_level = game_graph():vertex(obj.m_game_vertex_id):level_id() if IAmAStalker[obj_clsid] and obj_level~=actor_level then if not obj:alive() then Мой код: Spoiler local act_lv = game_graph():vertex( act:game_vertex_id() ):level_id() local bodies = {} for i = 0, 65535 do local obj = alife():object(i) if obj and game_graph():valid_vertex_id( obj.m_game_vertex_id ) then local obj_lv = game_graph():vertex( obj.m_game_vertex_id ):level_id() if IsStalker(obj) and obj_lv == act_lv then if not obj:alive() then table.insert(bodies, obj) end end Изменено 4 Мая 2019 пользователем Norman Eisenherz Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 4 Мая 2019 Попробовал проверку через свойство вместо метода: if IsStalker(obj) and not obj.alive and obj_lv == act_lv Обнаруживается единственный труп – сам Меченый. Настоящие трупы и еще живые NPC в список не попадают. Меченый – вампир? 2 Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 4 Мая 2019 @naxac То, что в другом коде работает, я знаю, но я ловлю вылет с ошибкой "attempt to call method 'alive' (a nil value)". Может, вообще не в этой проверке ошибка? Вот последняя версия (пока что "not obj.alive"): https://drive.google.com/open?id=1-K5gPW3q3AUPN1bGXfEjBZ1Uj8kecjwh Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 5 Мая 2019 @Fenrir02 Это шаг обхода, и по умолчанию он как раз равен 1. Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 5 Мая 2019 @naxac Просмотрел, что кроме шага еще и отсчет с 1 начинается. В таком виде работает даже без задержки запуска. Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 10 Мая 2019 Здрасьте. Сделал иконку состояния брони (набор статиков) с вызовом из function actor_binder:update(delta): на двух старых сейвах статик загружается и успешно работает, еще примерно на 10 старых сейвах и в новой игре не загружается, а при попытке сохранения и перезагрузки игры приводит к вылету с одним из двух приведенных ниже сообщений. Методом исключения удалось выяснить, что статикам мешает работать уборщик – мешает даже не перебором объектов на сервере, а конкретно той частью, которая удаляет бесхозное оружие. Добавил к запуску уборщика условие if device().precache_frame <= 1 – проблема разрешилась, но все-таки хочется знать, что вызывало эту проблему. ТЧ 1.0006, без глобальных модов. https://drive.google.com/open?id=1Yp4s8CvySYUsv0j2EolZYWdAan0JHsfN Spoiler Expression : fatal error Function : CScriptEngine::lua_error File : E:\stalker\sources\trunk\xr_3da\xrGame\script_engine.cpp Line : 73 Description : <no expression> Arguments : LUA error: ...ow of chernobyl\gamedata\scripts\bind_stalker.script:411: attempt to concatenate field '?' (a nil value) для справки – указанная строка [bind_stalker.script] (с модами): get_console():execute("g_game_difficulty "..game_difficulty_by_num[game_difficulty]) Expression : fatal error Function : CScriptEngine::lua_error File : E:\stalker\sources\trunk\xr_3da\xrGame\script_engine.cpp Line : 73 Description : <no expression> Arguments : LUA error: ...alker shadow of chernobyl\gamedata\scripts\_g.script:20: bad argument #2 to 'format' (string expected, got no value) Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 10 Мая 2019 @naxac Можно ли подробнее? Куда копать? Потестил еще: условие precache_frame привело к тому, что теперь уборщик не срабатывает на текущей локации. @mole venomous Нет-пакеты я точно не трогал. Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 12 Мая 2019 @naxac Проверил еще раз уборщик – старая логика действительно должна была сбоить: проверяется расстояние до 1-го трупа из списка, объект (возможно) удаляется, потом проверяется расстояние от этого же объекта до 2-го, 3-го трупа и т. д., и тот же объект снова удаляется (по крайней мере, делается такая попытка). Оператор break можно поставить только на негативное условие: если при переборе расстояний найдено значение меньше 5 , то закончить перебор для данного объекта и перейти к следующему, в противном случае удалить объект и перейти к следующему. Не до конца понимаю, как это правильно оформить, чтобы проверка не стопорилась на первом же значении > 5. Пошел другим путем: создать таблицу расстояний от текущего объекта до всех трупов, взять минимум, сравнить его с заданной величиной (5) и удалить, если этот минимум больше. Spoiler if next(wpn_near) ~= 0 then for i = 1, #wpn_near do local del = wpn_near[i] if del.position:distance_to(act:position()) > 10 then if next(bodies) ~= 0 then local distance = {} for j = 1, #bodies do local dist = del.position:distance_to(bodies[j].position) table.insert(distance, dist) end table.sort(distance) if distance[1] > 5 then alife():release(del) end else alife():release(del) end end end end @AndreySol Если функций несколько, лучше обозначать такие переменные в каждой из них или в общей области? Поделиться этим сообщением Ссылка на сообщение
Norman Eisenherz 354 Опубликовано 12 Мая 2019 @WinCap Кроме способа перебора (ну и еще остановки), это опять старая логика: "если до первого трупа в списке > 5 метров, то удалить оружие". Должно быть "если до всех трупов на локации > 5 метров, тогда удалять". Поделиться этим сообщением Ссылка на сообщение