Kirgudu 1 263 Опубликовано 31 Марта 2024 @BеST появление такой ошибки означает, что один из НПС, отношения между которыми устанавливаются - npc1 или npc2 - не пришёл в функцию. Удаляй, не удаляй изменённый конфиг game_relations, это делу не поможет. Почему в функцию приходит пустой НПС - сказать не могу, надо изучать там, где вызывается функция game_relations.set_npcs_relation(). В оригинале таких мест всего два. Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 263 Опубликовано 29 Сентября 2024 8 часов назад, Купер сказал: где искать/смотреть причину подобных вылетов Так это ж прямо там и прописано, по указанному в ошибке адресу. В той копии движка ЧН, что имеется у меня, максимальная длина строки при конкатенации составляет 1024 символа. 1 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 263 Опубликовано 29 Сентября 2024 (изменено) 3 часа назад, DarkSnowder сказал: sec=="gen_document_1354" and sec=="gen_document_1355" Одна и та же строковая переменная (ведь sec - это же переменная?) не может иметь сразу два разных значения. Никогда и нигде. Проверка такого условия всегда возвращает false со всеми вытекающими. Это первое. Второе: данный вопрос не имеет отношения к ковырянию ЧН, тебе в Скриптование. Или, на худой конец, в ковырялку ТЧ, где правильный ответ тебе уже дали пару дней назад. 55 минут назад, ted.80 сказал: actor:object=="gen_document_1354" and actor:object=="gen_document_1355" Что такое actor:object в данном примере? Такой скрипт даже не загрузится игрой. Вот если б ты написал db.actor:object("gen_document_1354") and db.actor:object("gen_document_1355") - это было бы верно. Изменено 29 Сентября 2024 пользователем Kirgudu 2 1 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 263 Опубликовано 29 Сентября 2024 @ted.80 так подставь то, что ты взял из полной функции, в своё условие. local actor = db.actor + actor:object=="gen_document_1354" and actor:object=="gen_document_1355" = db.actor:object=="gen_document_1354" and db.actor:object=="gen_document_1355" db.actor:object - это функция. Мало того, что ты сравниваешь её (не результат выполнения функции, а саму функцию) со строкой, так ещё и применяешь синтаксис, характерный для вызова метода (указание функции после двоеточия), без собственно вызова (забыл про круглые скобки). Это приведёт к немедленному отказу в загрузке такого скрипта движком, потому что его синтаксис некорректен. И даже такое написание, хоть синтаксически и правильное, будет неверным: db.actor:object()=="gen_document_1354" and db.actor:object()=="gen_document_1355" поскольку вызов этой функции требует передачи аргумента: db.actor:object("строка"), см. пример парой сообщений выше. Так-то по смыслу твоё предложение верно. Правильная же реализация будет такая: elseif ln=="l15_generators" and actor:object("gen_document_1354") and actor:object("gen_document_1355") then 3 1 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 263 Опубликовано 2 Ноября 2024 11 часов назад, imcrazyhoudini сказал: как этому скваду/НПС назначить story id Отряду никак, story_id может быть присвоен только объекту, но не группе объектов. Одному НПС из отряда, если этот отряд симуляционный (то есть один из многих отрядов с идентичным профилем, создающийся для целей войны группировок), тоже никак. Симуляционные скрипты не смогут решить самостоятельно НПС из какого отряда должен иметь уникальный story_id. А вот если такой отряд один на всю игру и спавнится по какому-то событию из логики или вручную, тогда есть лазейка. Для этого можно модифицировать следующую цепочку функций (см. места с комментариями, оформленными --<< ... >>): Скрытый текст function create_squad(actor, obj, p) if obj ~= nil then printf("pl:creating_squad from obj [%s] in section [%s]", tostring(obj:name()), tostring(db.storage[obj:id()].active_section)) end local squad_id = p[1] if squad_id == nil then abort("Wrong squad identificator [NIL] in create_squad function") end local smart_name = p[2] if smart_name == nil then abort("Wrong smart name [NIL] in create_squad function") end --<< добавляем чтение третьего параметра, в котором опционально может быть передан story_id >> local first_npc_story_id = p[3] local ltx = sim_board.squad_ltx if not ltx:section_exist(squad_id) then abort("Wrong squad identificator [%s]. Squad descr doesnt exist.", tostring(squad_id)) end local player_name = utils.cfg_get_string(ltx, squad_id, "faction", self, true, "") local board = sim_board.get_sim_board() local player = board.players[player_name] if player == nil then abort("Wrong player_name [%s] for squad [%s]", tostring(player_name), tostring(squad_id)) end local smart = board.smarts_by_names[smart_name] if smart == nil then abort("Wrong smart_name [%s] for [%s] faction in create_squad function", tostring(smart_name), tostring(player_name)) end --!!!!!!!!!!! Зыс из затычка против вылета, если кто-то пытается спаунить отряд с комьюнити отличным от того которым занят смарт!!!!!! if smart.player_name ~= player_name and smart.player_name ~= "none" then return end local squad local is_autogenerated_id = utils.cfg_get_bool(ltx, squad_id, "auto_id", self, false, false) --<< передаём параметр со story_id дальше, в симуляционный скрипт >> if is_autogenerated_id then squad = board:create_squad(player.player_name, sim_squad_scripted.sim_squad_scripted, smart, nil, squad_id, first_npc_story_id) else squad = board:create_squad(player.player_name, sim_squad_scripted.sim_squad_scripted, smart, squad_id, nil, first_npc_story_id) end board:enter_smart(squad, smart.id) for k,v in pairs(squad.squad_npc) do local obj = alife():object(k) board:setup_squad_and_group(obj) end squad:update() end Скрытый текст --<< добавляем в параметры функции ещё один для передачи story_id >> function sim_board:create_squad(player_id, squad_class, spawn_smart, sq_id, settings_id, first_npc_story_id) printf("create squad called") local squad_id = tostring(sq_id or self.id_generator:get_id()) if self.squads[squad_id] ~= nil then printf("---------------------------") print_table(self.squads) printf("------------------------last_id %s", self.id_generator.m_last_id) print_table(self.id_generator.m_given) printf("---------------------------") print_table(self.id_generator.m_free) printf("---------------------------") abort("Two or more squad with id[%s] found!!!", squad_id) end local squad = squad_class(self, player_id, squad_id, settings_id) squad:init_squad(spawn_smart) printf("Creating squad[%s] in smart[%s]", squad_id, spawn_smart:name()) self.squads[squad_id] = squad --' Определяем в каком смарте создать новый отряд --<< передаём добавленный параметр далее в функцию создания НПС >> squad:create_npc(spawn_smart, first_npc_story_id) squad:set_squad_sympathy() squad:set_squad_relation() self:assign_squad_to_smart(squad, spawn_smart.id) --' Пересчитываем Team, Squad, Group for k,v in pairs(squad.squad_npc) do local obj = alife():object(k) squad.board:setup_squad_and_group(obj) end --' Регистрануть новый отряд в его группировке. self.players[player_id]:register_squad(squad) self.players[player_id]:faction_brain_update() return squad end Скрытый текст --<< добавляем в параметры функции ещё один для передачи story_id >> function sim_squad_generic:create_npc(spawn_smart, first_npc_story_id) self.squad_power = 0 --' Высчитываем базовую позицию спауна local base_spawn_position = spawn_smart.position local base_lvi = spawn_smart.m_level_vertex_id local base_gvi = spawn_smart.m_game_vertex_id if spawn_smart.spawn_point ~= nil then base_spawn_position = patrol(spawn_smart.spawn_point):point(0) base_lvi = patrol(spawn_smart.spawn_point):level_vertex_id(0) base_gvi = patrol(spawn_smart.spawn_point):game_vertex_id(0) end local custom_resource = nil local min_npc, max_npc = 3,5 if self.player_id == "monster" then local level_name = alife():level_name(game_graph():vertex(spawn_smart.m_game_vertex_id):level_id()) local min, max = 0,5 if monster_resource_by_level[level_name] ~= nil then min = monster_resource_by_level[level_name][1] max = monster_resource_by_level[level_name][2] end custom_resource = math.random(min,max) min_npc = monster_num_by_resource[custom_resource][1] max_npc = monster_num_by_resource[custom_resource][2] end local player = self.board.players[self.player_id] local npc_in_squad = math.random(min_npc,max_npc) --<< определяем необходимость присвоения story_id (параметр передан или нет) >> local need_story_id = (type(first_npc_story_id) == "number") for i=1,npc_in_squad do local position = base_spawn_position position.x = position.x + math.random(-2,2) position.z = position.z + math.random(-2,2) local spawn_section = player:get_spawn_section(spawn_smart, custom_resource) local obj = alife():create(spawn_section, position, base_lvi, base_gvi) --<< если необходимо присвоить story_id, делаем это посредством редактирования net-пакета >> if need_story_id and obj then local pk = get_netpk(obj, 1) if pk:isOk() then local data = pk:get() data.story_id = first_npc_story_id pk:set(data) end --<< сбрасываем признак необходимости story_id, так как присвоить можно только один раз первому НПС из отряда >> need_story_id = false --<< добавляем id НПС и story_id в онлайн таблицу объектов, получивших связку со story_id уже после загрузки >> if not db.id_by_story_id then db.id_by_story_id = {} end db.id_by_story_id[first_npc_story_id] = obj.id end obj.squad_id = self.squad_id self.squad_npc[obj.id] = obj.id self.sound_manager:register_npc(obj.id) if self.commander_id == nil then self.commander_id = obj.id end self.npc_count = self.npc_count + 1 --printf("sim_squad_generic: npc_count is [%s], obj:rank is [%s], obj:name is [%s], self.squad_power is [%s]", tostring(self.npc_count), tostring(obj:rank()), obj:name(), tostring(self.squad_power)) self.squad_power = self.squad_power + 5*obj:rank()/1000 end self.smart_id = spawn_smart.id self:refresh() if self.squad_power > 25 then abort("Squad power couldnt be over 25!!!") end end Скрытый текст --<< добавляем в параметры функции ещё один для передачи story_id >> function sim_squad_scripted:create_npc(spawn_smart, first_npc_story_id) local spawn_sections = utils.parse_names(utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "npc", self, true, "")) self.squad_power = 0 local spawn_point = utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "spawn_point", self, false, "") --print_table(debug.getinfo(1)) printf("SPAWN SMART %s", spawn_smart:name()) --' Высчитываем базовую позицию спауна local base_spawn_position = spawn_smart.position local base_lvi = spawn_smart.m_level_vertex_id local base_gvi = spawn_smart.m_game_vertex_id if spawn_point ~= nil then base_spawn_position = patrol(spawn_point):point(0) base_lvi = patrol(spawn_point):level_vertex_id(0) base_gvi = patrol(spawn_point):game_vertex_id(0) elseif spawn_smart.spawn_point ~= nil then base_spawn_position = patrol(spawn_smart.spawn_point):point(0) base_lvi = patrol(spawn_smart.spawn_point):level_vertex_id(0) base_gvi = patrol(spawn_smart.spawn_point):game_vertex_id(0) end local player = self.board.players[self.player_id] local spawn_sections_ltx = system_ini() --<< определяем необходимость присвоения story_id (параметр передан или нет) >> local need_story_id = (type(first_npc_story_id) == "number") for k,v in pairs(spawn_sections) do local custom_data = utils.cfg_get_string(spawn_sections_ltx, v, "custom_data", self, false, "", "stalker_custom_data.ltx") if custom_data ~= "stalker_custom_data.ltx" then abort("INCORRECT npc_spawn_section USED [%s]. You cannot use npc with custom_data in squads", v) end local position = base_spawn_position position.x = position.x + math.random(-2,2) position.z = position.z + math.random(-2,2) local obj = alife():create(v, position, base_lvi, base_gvi) --<< если необходимо присвоить story_id, делаем это посредством редактирования net-пакета >> if need_story_id and obj then local pk = get_netpk(obj, 1) if pk:isOk() then local data = pk:get() data.story_id = first_npc_story_id pk:set(data) end --<< сбрасываем признак необходимости story_id, так как присвоить можно только один раз первому НПС из отряда >> need_story_id = false --<< добавляем id НПС и story_id в онлайн таблицу объектов, получивших связку со story_id уже после загрузки >> if not db.id_by_story_id then db.id_by_story_id = {} end db.id_by_story_id[first_npc_story_id] = obj.id end obj.squad_id = self.squad_id self.squad_npc[obj.id] = obj.id self.sound_manager:register_npc(obj.id) if self.commander_id == nil then self.commander_id = obj.id end self.npc_count = self.npc_count + 1 self.squad_power = self.squad_power + 5*obj:rank()/1000 end self.smart_id = spawn_smart.id self:refresh() end Скрытый текст --<< модифицируем оригинальную функцию поиска объекта по story_id, чтобы она учитывала свежесозданные (на этом же апдейте) объекты >> function level_object_by_sid( sid ) local sim = alife() if sim then local se_obj = sim:story_object( sid ) if se_obj then return level.object_by_id( se_obj.id ) end --<< серверный объект не найден, ищем среди добавленных после загрузки >> local se_obj_id = db.id_by_story_id and db.id_by_story_id[sid] if se_obj_id then return level.object_by_id( se_obj_id ) end end return nil end Тогда, например, создание из логики уникального отряда, первому (либо единственному) НПС из состава которого будет присвоен story_id, будет выглядеть так (показано на примере Васяна со Свалки): [sr_idle@story_messenger] on_info = {+gar_story_searched_digger_body} sr_idle@story_messenger_dogs_spawn %=create_squad(gar_digger_messenger_man:gar_smart_terrain_8_5:731)% где 731 - добавленный в том числе в game_story_ids.ltx персональный story_id. Примечание: для модификации net-пакета и присвоения story_id в данном примере использован модуль m_netpk от Артоса: https://www.amk-team.ru/forum/topic/13216-sborochnyj-ceh/?do=findComment&comment=971137 3 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 263 Опубликовано 2 Ноября 2024 @imcrazyhoudini придется подождать, я за компом буду уже не скоро, в лучшем случае дня через 3. Может кто быстрее подскажет. 1 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 263 Опубликовано 4 Ноября 2024 02.11.2024 в 22:59, imcrazyhoudini сказал: Не работает почему-то, проверил пару раз, можешь взглянуть, авось прозевал чего? 1. Я функцию create_npc в sim_squad_scripted.script выше сначала показал с ошибкой, затем поправил почти сразу после публикации поста, но в примере выше она осталась с ошибкой. Не исключено, что по каким-то причинам эта ошибка к вылету не ведёт, но при этом и не работать не даёт правильно, такое бывает. Рекомендую снова взять себе эту функцию из моего поста, теперь она там исправлена. 2. Не показано, где и как происходит создание нужного отряда. 3. Не показано, добавлен ли новый story_id в реестр. В остальном модификация оригинальных функций произведена правильно, кроме вышеупомянутой других ошибок не вижу. Опять же, по такой схеме story_id добавляется Васяну и потом используется в моде Final Stroke, там это проверено не раз и успешно работает. 1 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 263 Опубликовано 4 Ноября 2024 (изменено) @imcrazyhoudini, что такое второй параметр yan_ryaboy из твоего вызова спавна отряда? Вот этот: 1 час назад, imcrazyhoudini сказал: %=create_squad(yan_ryaboy:yan_ryaboy:3)% И ещё вопрос: что именно не работает-то? Спавн отряда? Или назначение НПС из этого отряда story_id? Если второе - как проверял? Изменено 4 Ноября 2024 пользователем Kirgudu Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 263 Опубликовано 5 Ноября 2024 (изменено) @imcrazyhoudini и не заработает таким образом. Ты пытаешься найти серверный объект по его story_id, но сервер ничего об этом номере не знает, поскольку ты вот только что его присвоил.. Обрати внимание на последний спойлер в моём примере, а именно _g.script и функцию level_object_by_sid, специально модифицированную для таких случаев. Используй её или, если нужен только id, можно вытащить кусочек функционала из функции с поиском в db таблице, куда мы положили нужную информацию при назначении story_id. Либо производи нужные действия не на том апдейте, когда story_id присваивался, а позже. 10 часов назад, imcrazyhoudini сказал: Название смарта + название сквада Самодобавленный смарт, значит. Ясно. А то одно из предположений было, что отряд не спавнится из-за указания невалидного смарта. Изменено 5 Ноября 2024 пользователем Kirgudu 1 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 263 Опубликовано 5 Ноября 2024 @imcrazyhoudini как связана инициализация квеста с использованием только что присвоенного story_id, непонятно: опять сделано что-то, что осталось за кулисами. Когда будет время (скорее всего, в предстоящие выходные), постараюсь сам воспроизвести ситуацию на файлах чистой игры и предоставлю результат для изучения. А пока дальше сам, мои советы на какое-то время иссякли. Не исключено, что успеешь сам найти решение проблемы раньше, метод-то вполне рабочий - подтверждается реальными опытами в существующем моде. Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 263 Опубликовано 5 Ноября 2024 @imcrazyhoudini всё, я понял, что у тебя за последовательность событий, раньше как-то туманно было. Ты спавнишь отряд, и из этой же логики в следующей секции запускаешь квест, целью которого является искомый story_id. Честно говоря, я не уверен, что между двумя частями логики проходит достаточное для получения сервером информации о story_id количество апдейтов. Если это так, рекомендую попробовать сделать запуск квеста во второй секции логики не на on_info, а, например, на on_timer с таймаутом в пару секунд. Однако если с промежутком между секциями логики всё в порядке, предлагаю посмотреть на содержимое функции task_objects.get_inited_task, где обрабатывается параметр квеста target_story_ids. Первые несколько строчек выглядят так (остальные нам не интересны): local sid = tonumber(self.target_story_ids) -- считываем из параметра квеста story_id if(sid) then self.target = id_by_sid(sid) -- находим серверный объект по story_id и берём у него id (функция в _g.script) if not(self.target) then -- проверяем, что полученный id не пустой abort("Target for storyline task doesnt exist. Story id [%s]", tostring(self.target_story_ids)) end ... Получается, что если бы story_id не был присвоен нашему объекту, мы неминуемо дошли бы до вызова функции abort. Вот и думай. Может стоит обложиться выводом в лог во всех ключевых точках и попытаться понять, что конкретно происходит. 1 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 263 Опубликовано 7 Ноября 2024 @imcrazyhoudini скинь, конечно, но я доберусь до проверки не ранее, чем в воскресенье, и не гарантирую, что смогу помочь. Нет, чисто со скриптовой точки зрения я проверю, что, например, story_id присваивается правильно и существует далее. А вот с логикой не особо в ладах, вряд ли получится понять, что там может ломаться. С этим к другим специалистам. 1 Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 263 Опубликовано 14 Ноября 2024 (изменено) @monk я в скриптах подсказал и сделал что мог, проверил: story_id назначается как надо, ошибок нет. Однако после присвоения story_id там действительно идёт сбой логики. Вот я и подумал: может, Васяну ты в процессе своих экспериментов что-то в профиле нахимичил, спец. логику, флаги или ещё что-либо, что позволяет ему такое улучшение игнорировать (в хорошем смысле). Я такого не помню, но я-то как раз только в скрипты и лез, оставляя остальное на тебя. Изменено 14 Ноября 2024 пользователем Kirgudu Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 263 Опубликовано 23 Декабря 2024 @ZeeK точно ничего не перепутал, есть пример? Насколько я помню, в классическом ЧН нет такого параметра у группировок. Есть параметр forbidden_point у смартов, который влияет на построение пути отрядов в войне группировок (да, можно запретить посещение точки отрядами определённой группировки), но это smart_terrain и sim_board. Инструмент Поделиться этим сообщением Ссылка на сообщение
Kirgudu 1 263 Опубликовано 26 Декабря 2024 16 часов назад, ZeeK сказал: подглядел в Sky Reclamation Project Понятно. Это те же яйца, только сбоку. В SRP взяли тот функционал, что я описал выше, и перенесли в настройки группировок. Так действительно удобней, поскольку для небольшого редактирования достаточно изменить только вынесенный в файлы конфиг группировки, а не пересобирать all.spawn, в котором находятся настройки смартов. Но по своему действию и та и эта реализации практически идентичны: оба параметра влияют на построение путей отрядов при войне группировок. Единственное, чтобы заработал вариант SRP, потребуются ещё и сопутствующие изменения в симуляционных скриптах, на ванильном ЧН не взлетит. 1 1 Инструмент Поделиться этим сообщением Ссылка на сообщение