Dennis_Chikin 3 658 Опубликовано 30 Января 2015 Автор Поделиться Опубликовано 30 Января 2015 (изменено) "Вскрытие показало, что больной умер от вскрытия."Тема для "крупной формы", то есть, на уровне скриптов целиком или больших частей оных скриптов. "Что у него внутри, зачем оно там, и что с этим можно сделать ?" Изменено 30 Января 2015 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 24 Ноября 2015 Автор Поделиться Опубликовано 24 Ноября 2015 (изменено) модераторское: дискуссия слегка переместилась в эмоциональную сферу, а предложения оппонентов, на сколько я вижу, читаются невнимательно. Ну и сами предложения эти несколько неконкретны. По крайней мере лично я понял предлагаемое совершенно иначе, чем остальные. Предлагаю внимательно перечитать хотя бы СОБСТВЕННЫЕ тексты, и попробовать сформулировать более четко и доходчиво. Я через некоторое время напишу, как именно понял. 2 Murarius: не совсем так. В некоторых случаях код не нужен. Или его еще нет. А вот описание в этих случаях желательно бы как можно более однозначное. Изменено 24 Ноября 2015 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Murarius 10 532 Опубликовано 24 Ноября 2015 Поделиться Опубликовано 24 Ноября 2015 попробуй приведи код того что ты предлагаешь, а то я себе по своему вижу, ты по своему, а там может че и порешим Вот именно. А то вы тонете в общих рассуждениях. Я вообще представлял себе посты в этой теме так: Утверждение -> Теоретическое обоснование (если требуется) -> Код. Уверен, Денис тоже хотел что-то подобное наблюдать. Самодисциплинируйтесь, пожалуйста. Литературка (избранное): "Координаты избушки" (2023) --- "Колобок времени" (2019) --- "Пиво и жлоб" (2018) --- "Лекарство против морщин" (2013) --- "Когда все пройдет" (2013) Креатив (бесперспективное): Dominanta --- Сон на земле Досвиданьице (слезное): Смена администратора (2024) Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 24 Ноября 2015 Автор Поделиться Опубликовано 24 Ноября 2015 (изменено) Вроде, 20 минут выкроил, выполняю обещанное. Итак, мне вот тоже не нравятся работы с состояниями. Не нравятся тем, что получается слишком много букв, и очень трудно контролировать все это глазами. Буквально пару дней назад описка с 0 вместо 1 - и пол дня на то, чтоб ее найти. Простыни получаются преразвесейшистые. Накладные расходы по получению/сортировке/переключению работ со стейтами - тоже не маленькие. Но в данном случае как раз имеем повод отбросить хакерские замашки в пользу читаемости, и даже не задумываться особо про то, какой же из вариантов будет быстрее на сотую микросекунды . Из собственно же методов борьбы с развесистыми простынями вижу два простых (в смысле, скриптовых, не дожидаясь, пока с неба свалится экзешник, чтоб сам кофе варил, и за пивом бегал): 1. Развернуть часть текущего ужаса и кошмара в плоские таблицы (все равно xr_gulag в итоге именно их хочет, и формирует). То есть, не вот вставка в переданную таблицу, и не проверка на каждый чих "подходящести", а отдать готовые. При некотором усилии можно эти работы со стейтами записывать так, что просто скользя глазом замечаешь отличия. И руками можно посчитать. А потом валидатор напустить, в сомнительных моментах. Этот код я вкладывал в более специализированной теме, ссылку давал, примеры давал, повторять смысла не вижу. Кому надо - найдет/посмотрит. 2. Перейти, вот как я понял прозвучавшие здесь предложения, к системе один смарт - несколько гулагов в нем. Преимущество - простыни становятся гораздо менее обширными, общие параметры из работ выносятся в параметры гулага, можно даже банально эти работы наследовать, подставляя отличия. То есть, для каждого стейта - один гулаг, в смарте - по гулагу для каждого стэйта. С точки зрения кода, навскидку, переключение между гулагами - будет проще-изящнее-быстрее. На самом деле даже "освобождать/переназначать/и т.д." ни кого не надо. Переключили гулаг, переинициализировали логику, и все. При покидании смарта - запустили "сборку мусора". В обоих случаях, заметим, НЕ требуется срочно переделывать все готовое. Оба варианта вполне дополняют стандартный. Собственно, в моем варианте с плоскими таблицами есть вариант такого вот одностейтового гулага, и осталось только "когда-нибудь" дополнить до "более одного гулага в смарте". Работа вот с этим одностейтовым - по факту проще и по факту, оно быстрее. Проверено. То есть, если коротко, то оно вот как-то так в итоге выглядит: local g_comms = { ["atp_brigada"] = "stalker", -- 14.08, Калинин ["atp_fabrika_bandit"] = "bandit", -- ["atp_stalk"] = "stalker", -- допа 2011 ... local g_jobs = { ["atp_fabrika_bandit"] = { -- Бандиты на АТП { section = "logic@atp_fabrika_bandit_walker1", idle = 0, prior = 10, state = {0}, in_rest = "", out_rest = "" }, { section = "logic@atp_fabrika_bandit_walker2", idle = 0, prior = 10, state = {0}, in_rest = "", out_rest = "" }, ... local t_states = { ["esc_blokpost"] = esc_blokpost, ["esc_lager"] = esc_lager, ["esc_bridge"] = esc_bridge, ["esc_fabrika_bandit"] = esc_fabrika_bandit, ["esc_dogs_to_fox"] = esc_dogs_to_fox, ["esc_specnaz"] = esc_specnaz, ["esc_boars_dogs"] = esc_boars_dogs, ["esc_killers"] = esc_killers, ["esc_dogs_swarm"] = esc_dogs_swarm, ["esc_stalker_camp"] = esc_stalker_camp, ["esc_corps"] = esc_corps, ["esc_assault"] = esc_assault } function load_states( gname, type ) -- стэйта нет - значит, всегда 0 return t_states[type] end function checkStalker( npc_community, gulag_type, npc_rank, obj ) local c = g_comms[gulag_type] if c then return c == npc_community end return ( obj["profile_name"] and obj:profile_name() == g_names[gulag_type] ) or false end function checkMonster( npc_community, gulag_type ) local c = g_comms[gulag_type] if c then return c == npc_community end if gulag_type == "esc_boars_dogs" then return npc_community == "dog" or npc_community == "boar" end return false end Ну вот как-то так, да. Это "дополнительный", альтернативный формат записи. Но все еще один смарт - один гулаг. С несколькими - в 2 раза сокращается количество строк, и сами строки упрощаются (от них в основном только секции логики и нужны) Вот что я не понял в звучавших предложениях - это заворачивать КАЖДУЮ работу в "псевдообъект". Подозреваю, что имелось в виду нечто иное. Изменено 24 Ноября 2015 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Полтергейст 37 Опубликовано 24 Ноября 2015 Поделиться Опубликовано 24 Ноября 2015 (изменено) сейчас-то что мешает стейты внутрь логики засунуть (пусть даже по вашему человекопонятному)? кондлист доступен абсолютно для всего, для чего не доступен - сделать доступным. профит, не? Так я об этом и пишу. Если специально не создавать на каждый чих новый gulag type с собственным condlist'ом (вместо использования логики там, где это возможно), то большой простыни из кучи секций и длинных condlist'ов не будет. И как раз получится, что вместо простыней из load_states станет достуен condlist. не реализацию а просто синтаксис, то есть конечный вид желательно во всех красках вроде "до"/"после", и красно-жирным выделить где упрощения для таких как я. В смысле, показать как должны выглядеть конфиги и описание работ? local t = { section = "logic@walker_1_logic", in_restr = "level_prefix_in_restictor1", out_restr = "level_prefix_out_restictor1", squad = squad, group = groups[1], predicate = function(...) return true end, prior = 5, -- вот это руки чешутся убрать, но пока не знаю, как лучше это сделать position_threshold = 50, -- от этого со временем тоже надо избавиться state = {0, 1} -- оставить обработку стейтов для совместимости, но в описании работ их стараться не использовать } [smart_terrain] type = general_lager squad = 0 groups = 1,2,3,4 capacity = 5 -- Не нужно. Ёмкость определяется количеством работ cond = {+info1} communities = dolg, freedom, monolith --Можно записать в виде condlist'а [smart_terrain] type = general_lager_normal, general_lager_alarm [general_lager_normal] squad = 0 groups = 1,2,3,4 cond = {+info1 !gulag_has_alarm} accept_npc_cond = {=npc_community(dolg:freedom:monolith)} --вместо checkStalker/checkMonster [general_lager_alarm] squad = 0 groups = 1,2,3,4 cond = {+info1 !gulag_has_alarm} accept_npc_cond = {=npc_community(dolg:freedom:monolith)} Это пока набросок, тут ещё есть куда стремиться и что исправлять. В частности, возможности этих самых condlist'ов используются не оптимально, хотя и лучше, чем было. То есть, не вот вставка в переданную таблицу, и не проверка на каждый чих "подходящести", а отдать готовые. Это подойдёт только туда, где список работ неизменен и заранее известен. В том же gulag_general подобное не прокатит. Изменено 24 Ноября 2015 пользователем Полтергейст Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 24 Ноября 2015 Автор Поделиться Опубликовано 24 Ноября 2015 prior = 5 - это нужно, когда есть работы, на которых должен быть кто-то конкретный, или когда нужно, чтобы из всех возможных заняты были именно эти. У меня работы с условиями всегда проверяются первыми, так что здесь уже задумываться слишком сильно не надо. Вообще, опять же, в мультигулаговый смарт такие отдельным гулагом имеет смысл оформлять. Избавились. сквады - имеет смысл менять динамически, раз пошла такая пьянка. группы - как выяснили, нужны там, где задействованы в путях с сигналами. position_threshold - это интересная такая штука... Смысл - надо ли в офлайне бежать к начальной точке пути. capacity - нужно для текущего формата, если используешь условия в работах. И для генералов. Плюс, если они у тебя прописаны для всех - можешь исправить разные косяки, дописав "запасные работы" (классика жанра - волк/фанат/шустрый, и наймы на кордоне, где при неудачном стечении обстоятельств получаещь сбежавшего непися или висяк.) Кондлисты - мне не нравятся. Медленные, и читаются плохо. Лучше иметь возможность задавать явно. Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Полтергейст 37 Опубликовано 24 Ноября 2015 Поделиться Опубликовано 24 Ноября 2015 Вот что я не понял в звучавших предложениях - это заворачивать КАЖДУЮ работу в "псевдообъект". Подозреваю, что имелось в виду нечто иное. Не заворачивать, а преобразовывать. Все данные из таблицы работ перекинуть в объект, потом получить имя пути и сам путь, и сохранить в объект. В класс можно перенести целую кучу методов, отвечающих за всякие проверки и назначения работ. Для человекочитаемости это точно пойдёт на пользу. position_threshold - это интересная такая штука... Смысл - надо ли в офлайне бежать к начальной точке пути. Разве? По-моему смысл другой. В оригинале это расстояние, ближе которого в онлайне персонажу устанавливается логика (setup_logic_что-то-там). Дальше этого расстояния логика не работает. Полезность - сомнительна. Некоторые схемы могут подглючивать, если они активируются далеко от первой точки пути. Но это проблема или реализации этих схем, или криво написанной логики. То, что отметка о начале работы (beginJob) устанавливается, можно не принимать во внимание. Просто устанавливать её при достижении первой точке пути и не заморачиваться. Запретить NPC идти к месту "работы" можно или установкой object_flags, или вызовом can_choose_alife_tasks(false) (но не абы-как и абы-где), или установкой ему нулевой скорости передвижения в оффлайне. Position_treshold не влияет ни на что из этого. capacity - нужно для текущего формата, если используешь условия в работах. Условия - это predicate что ли? Ну разве что для тех случаев, когда надо вытеснять кого-то из смарта, когда кто-то другой занял работы "с условиями"... но всё равно не вижу в этом смысла. Такой параметр больше подходит для самих работ, чтобы можно было назначить нескольким NPC одну и ту же логику, не создавая для этого несколько работ (это одна из причин для хранения работ в виде объектов, а не таблиц). Кондлисты - мне не нравятся. Медленные, и читаются плохо. Лучше иметь возможность задавать явно. Что читаются плохо - это дело привычки. Да и всё равно от них не уйти уже, используются везде. Задавать явно возможность остаётся - написать {=вызов_функции} и в самой функции уже расписывать все подробности. Ссылка на комментарий
dsh 3 824 Опубликовано 24 Ноября 2015 Поделиться Опубликовано 24 Ноября 2015 Ох, похоже тут опять мифы обсуждают. job_position_threshold - это расстояние, при котором считается, что моб в оффлайне пришел к месту работы и ему можно назначать логику. Если это расстояние сделать слишком маленьким, то логика мобу не будет назначена. В качестве примеру приведу Барьер на Складах и значение 120 из ОП-2 (из Солянки, полагаю, тоже). К этому нужно заметить, и это, похоже, все то-ли не знают, то-ли упускают из вида. Мобы в оффлайне про логику и пути понятия не имеют. Это все только в онлайне работает. А в оффлайне моб всегда идет на точку смарт террейна. Его туда движок гонит. Вот для этого и используется упомянутое выше расстояние. Что бы xr_gulag мог определить, что моб дошел. Так вот, про Барьер и ОП-2 (вероятно и про Солянку). Идя на Барьер мобы прекращают свое движение на расстоянии большем, чем 120 метров от смарта. Это приводит к тому, что соотв. логика мобам не назначается и когда игрок подходит к свободовцам, что там стоят, все мутанты вываливаются в онлайн на этом месте. На самом же деле, мутанты должны быть около перехода на Радар и атаковать свободовцев оттуда, а не сваливаться им на голову. Далее, can_choose_alife_task() не запрещает мобу идти к месту работы. Оно вообще к работам и логике прямого отношения не имеет. Эта функция управляет тем, будет-ли движок пытаться определить данного моба в какой-нибудь смарт террейн или нет. Если разрешено, то движок пойдет в цикле по всем смартам и каждый будет спрашивать: этого возьмешь? На самом деле не так прямо, но в данном случае это не важно. И вот когда движок закрепит моба за каким-то смартом, моб пойдет на точку этого смарта. И только дойдя до туда и выйдя в онлайн, ему xr_logic назначит онлайновую работу. Как только моб уйдет в оффлайн, движок опять погонит его на точку смарта и т.д. dsh mod: https://github.com/dsh2dsh/op2ogse Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 24 Ноября 2015 Автор Поделиться Опубликовано 24 Ноября 2015 Этот "миф" дан вполне в ощущениях. Вот так оно блин там сделано: да, когда дошел - считается заступившим, назначается логика и т.д. А вот пока НЕ дошел - регулярно вызывается self:free_obj_and_reinit(), и вот только тогда моб каким-то загадочным образом может сдвинуться с места. Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Полтергейст 37 Опубликовано 25 Ноября 2015 Поделиться Опубликовано 25 Ноября 2015 расстояние, при котором считается, что моб в оффлайнеНе обязательно "в оффлайне". Просто проверяется, дошёл ли. В онлайне это тоже можно наблюдать - сначала идут медленно (работает action_alife_planner), а потом с определённого расстояния немного меняет маршрут и идёт быстрее. Потому что в этот момент задействуется логика, скрипты, состояния в state_mgr.На запрет идти к месту работы в оффлайне параметр job_position_treshold вообще никак не влияет.Насчёт can_choose_alife_tasks надо смотреть исходники движка. в оффлайне про логику и пути понятия не имеютТоже не совсем верно. В оригинальном ТЧ идут к первой точке пути, от неё же и считается расстояние, из которого делается вывод - дошёл или не дошёл. Хотя при определённых переделках скрипта можно посылать их не в первую точку, а последовательно в 1, 2, 3 и т.д. Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 25 Ноября 2015 Автор Поделиться Опубликовано 25 Ноября 2015 (изменено) Закомментите освобождение с работы для недошедших, и посмотрите на результат. В оффлайне. Изменено 25 Ноября 2015 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 28 Декабря 2015 Автор Поделиться Опубликовано 28 Декабря 2015 (изменено) Продолжаем разговор про xr_logic: try_sw_time1, try_sw_time2 = 0, 0 function try_switch_to_another_section( npc, st, actor ) if _G.watchdog then return false end _G.watchdog = "try_switch" if not actor then abort( "try_switch_to_another_section, scheme: %s, no actor", st.scheme or "n/a" ) end local l = st.logic or abort( "try_switch_to_another_section, invalid logic, scheme: [%s] (%s)", st.active_scheme or "none", ( npc and npc:name() ) or "script" ) local npc_id = npc:id() local sw, sw1, f local chk = { ["on_actor_dist_le"] = function ( c ) if npc.alive and npc:alive() and npc:see( actor ) and c.v1 >= distance_between( actor, npc ) then return true end end, ["on_actor_dist_le_nvis"] = function ( c ) if c.v1 >= distance_between( actor, npc ) then return true end end, ["on_actor_dist_ge"] = function ( c ) -- составляет пару с on_actor_dist_le, где >= if npc.alive and npc:alive() and npc:see( actor ) and c.v1 < distance_between( actor, npc ) then return true end end, ["on_actor_dist_ge_nvis"] = function ( c ) -- составляет пару с on_actor_dist_le_nvis, где >= if c.v1 < distance_between( actor, npc ) then return true end end, ["on_signal"] = function ( c ) if st.signals and st.signals[c.v1] then return true end end, -- FIXME: не дублировать тут имена, оставить один on_info, -- но добавлять несколько его экземпляров в список ["on_info"] = function ( c ) return true end, ["on_timer"] = function ( c ) if global_time_ms >= db.storage[npc:id()].activation_time + c.v1 then return true end end, ["on_game_timer"] = function ( c ) -- GAMETIME added by Stohe. if game_time_time:diffSec( db.storage[npc:id()].activation_game_time ) >= c.v1 then return true end end, ["on_actor_in_zone"] = function ( c ) if utils.npc_in_zone(actor, db.zone_by_name[c.v1]) then return true end end, ["on_actor_not_in_zone"] = function ( c ) if not utils.npc_in_zone( actor, db.zone_by_name[c.v1] ) then return true end end, ["on_npc_in_zone"] = function ( c ) if utils.npc_in_zone( level.object_by_id( c.npc_id ), db.zone_by_name[c.v2] ) then return true end end, ["on_npc_not_in_zone"] = function ( c ) if not utils.npc_in_zone( level.object_by_id( c.npc_id ), db.zone_by_name[c.v2] ) then return true end end, ["on_actor_inside"] = function ( c ) if utils.npc_in_zone( actor, npc ) then return true end end, ["on_actor_outside"] = function ( c ) if not utils.npc_in_zone( actor, npc ) then return true end end } for n, c in pairs( l ) do local p = profile_timer() p:start() for i = 1, 100 do if cond_name( c.name, "on_actor_dist_le" ) then if npc.alive and npc:alive() and npc:see( actor ) and c.v1 >= distance_between( actor, npc ) then sw = true end elseif cond_name( c.name, "on_actor_dist_le_nvis" ) then if c.v1 >= distance_between( actor, npc ) then sw = true end elseif cond_name( c.name, "on_actor_dist_ge") then -- составляет пару с on_actor_dist_le, где >= if npc.alive and npc:alive() and npc:see( actor ) and c.v1 < distance_between( actor, npc ) then sw = true end elseif cond_name( c.name, "on_actor_dist_ge_nvis" ) then -- составляет пару с on_actor_dist_le_nvis, где >= if c.v1 < distance_between( actor, npc ) then sw = true end elseif cond_name( c.name, "on_signal" ) then if st.signals and st.signals[c.v1] then sw = true end -- FIXME: не дублировать тут имена, оставить один on_info, -- но добавлять несколько его экземпляров в список elseif cond_name( c.name, "on_info" ) then sw = true elseif cond_name( c.name, "on_timer" ) then if global_time_ms >= db.storage[npc_id].activation_time + c.v1 then sw = true end elseif cond_name( c.name, "on_game_timer" ) then -- GAMETIME added by Stohe. if game_time_time:diffSec( db.storage[npc_id].activation_game_time ) >= c.v1 then sw = true end elseif cond_name( c.name, "on_actor_in_zone" ) then if utils.npc_in_zone(actor, db.zone_by_name[c.v1]) then sw = true end elseif cond_name( c.name, "on_actor_not_in_zone" ) then if not utils.npc_in_zone( actor, db.zone_by_name[c.v1] ) then sw = true end elseif cond_name( c.name, "on_npc_in_zone" ) then if utils.npc_in_zone( level.object_by_id( c.npc_id ), db.zone_by_name[c.v2] ) then sw = true end elseif cond_name( c.name, "on_npc_not_in_zone" ) then if not utils.npc_in_zone( level.object_by_id( c.npc_id ), db.zone_by_name[c.v2] ) then sw = true end elseif cond_name( c.name, "on_actor_inside" ) then if utils.npc_in_zone( actor, npc ) then sw = true end elseif cond_name( c.name, "on_actor_outside" ) then if not utils.npc_in_zone( actor, npc ) then sw = true end else abort( "try_switch_to_another_section: invalid condition: [%s] (%s)", c.name, npc:name() ) end end p:stop() try_sw_time2 = try_sw_time2 + p:time() local p = profile_timer() p:start() for i = 1, 100 do f = chk[string_match( c.name, "^([%D]+)" )] if f then sw1 = f( c ) end end p:stop() try_sw_time1 = try_sw_time1 + p:time() if sw ~= sw1 then log( "error", "%s ~= %s (%s, %s, %s)", tostring( sw ), tostring( sw1 ), tostring( n ), tostring( c.name ), to_str( npc ) ) end if sw then sw = switch_to_section( npc, st, pick_section_from_condlist( actor, npc, c.condlist ) ) if sw then _G.watchdog = false; return sw end end sw, sw1 = nil, nil end _G.watchdog = false return false end Сорри за неряшливый вид. Однако: sw1: 2691772.75 sw2: 7585235 Есть в этом нечто удивительное, правда ? И, кстати, оно таки ЖРЕТ. Реально жрет. Пара десятков рестрикторов и десяток неписей - очень даже ой. И, кстати, здесь можно этот самый аппетит еще поурезать вполне. Изменено 3 Января 2016 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Zander_driver 10 334 Опубликовано 19 Апреля 2016 Поделиться Опубликовано 19 Апреля 2016 Дабы меня не закидали овощами в соседней теме, поделюсь-ка я в очередной раз своим сырым кодом. Просто что меня на эту мысль навело... функционал как бы востребованный до жути давным давно и настолько, что я нисколько не сомневаюсь в том что с десяток мододелов уже себе такое писали. Но никто на публику не выложил - начинающим взяться не за что, только самим писать. Я про съемку координат речь веду, если что. В моей подписи как раз есть ссылка на тему где можно посмотреть видео про "Пушку мододела" - инструмент для снятия координат в игре. Координат для чего? Ну в данном варианте для путей работ в гулагах, а вообще-то для чего угодно. Как оно работает: на стороне игры через всякие там интерфейсы задаем настройки, что мы хотим поставить, потом отлавливается выстрел, и в момент выстрела берутся координаты актора и с этими всеми настройками записываются эдаким пакетом информации в лог. И собственно все, на стороне игры работа инструмента закончилась. Потом на стороне Windows, рядом с логами игры лежит одна программа которую я сам для себя написал. Она открывает файл логов, находит там все эти пакеты данных с координатами, оставленные скриптом, обрабатывает и создает "текст" который можно уже вставлять в файлы распакованного аллспавна и компилировать в игру с помощью acdc. т.е. на стороне windows все что я делаю - открываю свою программу, тыкаю в ней кнопку, открываю созданный ею файл, нажимаю Ctrl+C, открываю файл распакованного спавна - Ctrl+V. запускаю батник компиляции спавна. все. Т.е. все просто на самом деле. Но в открытом доступе я таких инструментов не видел, почему-то. Наверное у всех под свои нужды заточены. У меня тоже. Скриптовую часть на стороне игры - ее в любом случае каждый под себя напишет, тут у всех предпочтения разные, и не так давно доказывали что больше одного стейта у гулагов быть не должно... в общем, мелочи это, несущественные. Поэтому игровую-скриптовую часть выладывать не буду. Выложу код программы которая на стороне виндовса выковыривает данные из логов и собирает из них то что можно копипастить прямо в аллспавн. Писал я ее в Делфи. Визуально программа простейшая, там одно текстовое поле, куда однажды надо ввести имя лог-файла (разные же бывают), и кнопка "конвертировать". собственно все. Кому надо и интересно - можно взять и заточить под свои нужды. { ***************************************************** PathGenerator - программа для извлечения и обработки данных в лог-файле игры С.Т.А.Л.К.Е.Р. ТЧ. сканирует лог-файл, находит пакеты данных, оставленные специальным скриптом. читает эти данные и формирует на их основе, массивы данных готовые для вставки в файлы аллспавна и последущей компиляции. Автор: Zander (skype zander700) г.Курск Copyright: Zander Последнее обновление: 3 марта 2016 г. ***************************************************** } unit PathGenerator; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls; type TPointXR = record lv: integer; lvn: integer; gv: integer; px: string; py: string; pz: string; dx: string; dy: string; dz: string; mode: integer; gulag_name: string; param_line: string; Res1: string; Res2: string; end; TForm1 = class(TForm) Button1: TButton; Label1: TLabel; Edit1: TEdit; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Edit1Change(Sender: TObject); procedure Button2Click(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; Paths: TStringList; Alife: TStringList; Scrpt: TStringList; NextCommand: integer; ArXr: array of TPointXR; gulag: integer; logfilename: string; implementation {$R *.dfm} function StF(S: string): extended; var S1: string; S2: string; L1: integer; L2: integer; P: integer; R: extended; a: integer; sl: TStringList; begin a:= 0; P:= -1; while (a < Length(S)) do begin If (S[a] = '.') then begin P:= a; a:= Length(S); end; a:= a + 1; end; S1:= Copy(S,1,P - 1); S2:= Copy(S, P + 1, Length(S) - P); L2:= Length(S2); a:= 0; L1:= 1; while (a < L2) do begin L1:= L1 * 10; a:= a + 1; end; S2:= Copy(S2, 1, 4); R:= Strtoint(S1) + (Strtoint(S2) / L1); sl:= TStringList.Create; sl.Append(S); sl.Append(S1); sl.Append(S2); sl.SaveToFile('proglog.txt'); Result:= R; end; procedure TForm1.Button1Click(Sender: TObject); // конвертация var kamp_n: integer; walk_n: integer; guard_n: integer; patrol_n: integer; sniper_n: integer; sleep_n: integer; lead_n: integer; stalker_n: integer; monster_n: integer; anomaly_n: integer; rest_n: integer; smart_n: integer; item_n: integer; a: integer; b: integer; c: integer; points_label: string; alife_number: integer; Dist: extended; begin //SetDecimalSeparator('.'); a:= 0; b:= 0; kamp_n:= 1; walk_n:= 1; guard_n:= 1; patrol_n:= 1; sniper_n:= 1; sleep_n:= 1; lead_n:= 1; stalker_n:= 1; monster_n:= 1; anomaly_n:= 1; rest_n:= 1; smart_n:= 1; item_n:= 1; alife_number:= 50000; while (a < Length(ArXr)) do begin Case (ArXr[a].mode) of 0: begin Paths.Append(''); Paths.Append('[' + ArXr[a].gulag_name + '_walker_' + inttostr(walk_n) + '_walk]'); // walk_n := walk_n + 1; Paths.Append('points = p0'); Paths.Append('p0:name = name00' + ArXr[a].param_line); Paths.Append('p0:flags = 0x400'); Paths.Append('p0:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz ); Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv)); Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lv)); Paths.Append(''); Paths.Append(ArXr[a].gulag_name + '_walker_' + inttostr(walk_n) + '_look]'); walk_n := walk_n + 1; Paths.Append('points = p0'); Paths.Append('p0:name = name00'); Paths.Append('p0:flags = 0x400'); Paths.Append('p0:position = ' + ArXr[a].dx + ',' + ArXr[a].dy + ',' + ArXr[a].dz ); Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv)); Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lvn)); end; 1: begin Paths.Append(''); Paths.Append('[' + ArXr[a].gulag_name + '_kamp_' + inttostr(kamp_n) + ']'); kamp_n := kamp_n + 1; Paths.Append('points = p0'); Paths.Append('p0:name = name00' + ArXr[a].param_line); Paths.Append('p0:flags = 0x400'); Paths.Append('p0:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz ); Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv)); Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lv)); end; 2: begin Paths.Append(''); Paths.Append('[' + ArXr[a].gulag_name + '_guard_' + inttostr(guard_n) + '_walk]'); // walk_n := walk_n + 1; Paths.Append('points = p0'); Paths.Append('p0:name = name00' + ArXr[a].param_line); Paths.Append('p0:flags = 0x400'); Paths.Append('p0:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz ); Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv)); Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lv)); Paths.Append(''); Paths.Append('[' + ArXr[a].gulag_name + '_guard_' + inttostr(guard_n) + '_look]'); guard_n := guard_n + 1; Paths.Append('points = p0'); Paths.Append('p0:name = name00'); Paths.Append('p0:flags = 0x400'); Paths.Append('p0:position = ' + ArXr[a].dx + ',' + ArXr[a].dy + ',' + ArXr[a].dz ); Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv)); Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lvn)); end; 3: begin // установить число точек в патрульном пути b:= 1; while not (ArXr[a + b].mode = 4) do begin b:= b + 1; end; /// a + b - последняя точка Paths.Append(''); Paths.Append('[' + ArXr[a].gulag_name + '_patrol_' + inttostr(patrol_n) + '_walk]'); patrol_n:= patrol_n + 1; points_label:= 'p0'; c:= 0; while (c < do begin c:= c + 1; points_label:= points_label + ',p' + inttostr(c); end; Paths.Append('points = ' + points_label); c:= 0; while (c < (b + 1)) do begin if (c = 0) then begin Paths.Append('p0:name = name00' + ArXr[a].param_line); end else begin Paths.Append('p' + inttostr(c) + ':name = name0' + inttostr(c)); end; Paths.Append('p' + inttostr(c) + ':flags = 0x400'); Paths.Append('p' + inttostr(c) + ':position = ' + ArXr[a + c].px + ',' + ArXr[a + c].py + ',' + ArXr[a + c].pz ); Paths.Append('p' + inttostr(c) + ':game_vertex_id = ' + inttostr(ArXr[a + c].gv)); Paths.Append('p' + inttostr(c) + ':level_vertex_id = ' + inttostr(ArXr[a + c].lv)); If (c = then begin Paths.Append('p' + inttostr(c) + ':links = p0(1)'); // автозамыкание патрульного пути end else begin Paths.Append('p' + inttostr(c) + ':links = p' + inttostr(c + 1) + '(1)'); end; Paths.Append(''); c:= c + 1; end; a:= a + b; end; 4: begin // empty end; 5: begin Paths.Append(''); Paths.Append('[' + ArXr[a].gulag_name + '_sniper_' + inttostr(sniper_n) + '_walk]'); // walk_n := walk_n + 1; Paths.Append('points = p0'); Paths.Append('p0:name = name00' + ArXr[a].param_line); Paths.Append('p0:flags = 0x400'); Paths.Append('p0:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz ); Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv)); Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lv)); Paths.Append(''); Paths.Append('[' + ArXr[a].gulag_name + '_sniper_' + inttostr(sniper_n) + '_look]'); sniper_n:= sniper_n + 1; Paths.Append('points = p0,p1,p2,p3'); Paths.Append('p0:name = name00'); Paths.Append('p0:flags = 0x400'); Paths.Append('p0:position = ' + ArXr[a + 1].px + ',' + ArXr[a + 1].py + ',' + ArXr[a + 1].pz ); Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a + 1].gv)); Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a + 1].lv)); Paths.Append('p0:links = p1(1)'); Paths.Append(''); Paths.Append('p1:name = name00'); Paths.Append('p1:flags = 0x400'); Paths.Append('p1:position = ' + ArXr[a + 2].px + ',' + ArXr[a + 2].py + ',' + ArXr[a + 2].pz ); Paths.Append('p1:game_vertex_id = ' + inttostr(ArXr[a + 2].gv)); Paths.Append('p1:level_vertex_id = ' + inttostr(ArXr[a + 2].lv)); Paths.Append('p1:links = p2(1)'); Paths.Append(''); Paths.Append('p2:name = name00'); Paths.Append('p2:flags = 0x400'); Paths.Append('p2:position = ' + ArXr[a + 3].px + ',' + ArXr[a + 3].py + ',' + ArXr[a + 3].pz ); Paths.Append('p2:game_vertex_id = ' + inttostr(ArXr[a + 3].gv)); Paths.Append('p2:level_vertex_id = ' + inttostr(ArXr[a + 3].lv)); Paths.Append('p2:links = p3(1)'); Paths.Append(''); Paths.Append('p3:name = name00'); Paths.Append('p3:flags = 0x400'); Paths.Append('p3:position = ' + ArXr[a + 4].px + ',' + ArXr[a + 4].py + ',' + ArXr[a + 4].pz ); Paths.Append('p3:game_vertex_id = ' + inttostr(ArXr[a + 4].gv)); Paths.Append('p3:level_vertex_id = ' + inttostr(ArXr[a + 4].lv)); Paths.Append('p3:links = p0(1)'); a:= a + 4; end; 6: begin // установить число точек в патрульном пути b:= 1; while not (ArXr[a + b].mode = 7) do begin b:= b + 1; end; /// a + b - последняя точка Paths.Append(''); Paths.Append('[' + ArXr[a].gulag_name + '_walker_' + inttostr(walk_n) + '_walk]'); points_label:= 'p0'; c:= 0; while (c < do begin c:= c + 1; points_label:= points_label + ',p' + inttostr(c); end; Paths.Append('points = ' + points_label); c:= 0; while (c < (b + 1)) do begin if (c = 0) then begin Paths.Append('p0:name = name00' + ArXr[a].param_line); end else begin Paths.Append('p' + inttostr(c) + ':name = name0' + inttostr(c)); end; Paths.Append('p' + inttostr(c) + ':flags = 0x400'); Paths.Append('p' + inttostr(c) + ':position = ' + ArXr[a + c].px + ',' + ArXr[a + c].py + ',' + ArXr[a + c].pz ); Paths.Append('p' + inttostr(c) + ':game_vertex_id = ' + inttostr(ArXr[a + c].gv)); Paths.Append('p' + inttostr(c) + ':level_vertex_id = ' + inttostr(ArXr[a + c].lv)); If (c = then begin Paths.Append('p' + inttostr(c) + ':links = p0(1)'); // автозамыкание патрульного пути end else begin Paths.Append('p' + inttostr(c) + ':links = p' + inttostr(c + 1) + '(1)'); end; Paths.Append(''); c:= c + 1; end; b:= 1; while not (ArXr[a + b].mode = 7) do begin b:= b + 1; end; /// a + b - последняя точка Paths.Append(''); Paths.Append('[' + ArXr[a].gulag_name + '_walker_' + inttostr(walk_n) + '_look]'); points_label:= 'p0'; c:= 0; while (c < do begin c:= c + 1; points_label:= points_label + ',p' + inttostr(c); end; Paths.Append('points = ' + points_label); c:= 0; while (c < (b + 1)) do begin Paths.Append('p' + inttostr(c) + ':name = name0' + inttostr(c)); Paths.Append('p' + inttostr(c) + ':flags = 0x400'); Paths.Append('p' + inttostr(c) + ':position = ' + ArXr[a + c].dx + ',' + ArXr[a + c].dy + ',' + ArXr[a + c].dz ); Paths.Append('p' + inttostr(c) + ':game_vertex_id = ' + inttostr(ArXr[a + c].gv)); Paths.Append('p' + inttostr(c) + ':level_vertex_id = ' + inttostr(ArXr[a + c].lvn)); If (c = then begin Paths.Append('p' + inttostr(c) + ':links = p0(1)'); // автозамыкание патрульного пути end else begin Paths.Append('p' + inttostr(c) + ':links = p' + inttostr(c + 1) + '(1)'); end; Paths.Append(''); c:= c + 1; end; walk_n:= walk_n + 1; a:= a + b; end; 7: begin // empty end; 8: begin // rudiment gulag:= gulag + 1; kamp_n:= 1; walk_n:= 1; guard_n:= 1; patrol_n:= 1; sniper_n:= 1; sleep_n:= 1; lead_n:= 1; // sleep end; 9: begin Paths.Append(''); Paths.Append('[' + ArXr[a].gulag_name + '_sleep_' + inttostr(sleep_n) + ']'); sleep_n := sleep_n + 1; Paths.Append('points = p0'); Paths.Append('p0:name = name00' + ArXr[a].param_line); Paths.Append('p0:flags = 0x400'); Paths.Append('p0:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz ); Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv)); Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lv)); end; 10: begin Paths.Append(''); Paths.Append('[' + ArXr[a].gulag_name + '_lead_' + inttostr(lead_n) + '_walk]'); // walk_n := walk_n + 1; Paths.Append('points = p0'); Paths.Append('p0:name = name00' + ArXr[a].param_line); Paths.Append('p0:flags = 0x400'); Paths.Append('p0:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz ); Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv)); Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lv)); Paths.Append(''); Paths.Append('[' + ArXr[a].gulag_name + '_lead_' + inttostr(lead_n) + '_look]'); lead_n := lead_n + 1; Paths.Append('points = p0'); Paths.Append('p0:name = name00'); Paths.Append('p0:flags = 0x400'); Paths.Append('p0:position = ' + ArXr[a].dx + ',' + ArXr[a].dy + ',' + ArXr[a].dz ); Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv)); Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lvn)); end; 20: begin Alife.Append(''); Alife.Append('[' + inttostr(alife_number) + ']'); Alife.Append('; cse_abstract properties'); Alife.Append('section_name = stalker'); Alife.Append('name = uniqstalkername');// + inttostr(stalker_n)); Alife.Append('position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz); Alife.Append('direction = 0,0,0'); Alife.Append(''); Alife.Append('; cse_alife_trader_abstract properties'); Alife.Append('money = 5000'); Alife.Append('character_profile = uniqstalkerprofile');// + inttostr(stalker_n)); Alife.Append(''); Alife.Append('; cse_alife_object properties'); Alife.Append('game_vertex_id = ' + inttostr(ArXr[a].gv)); Alife.Append('distance = 0'); Alife.Append('level_vertex_id = ' + inttostr(ArXr[a].lv)); Alife.Append('object_flags = 0xffffffbf'); Alife.Append('custom_data = <<END'); Alife.Append(''); // Alife.Append('[logic]'); //Alife.Append('cfg = uniqstalkerlogic' + inttostr(stalker_n) + '.ltx'); // Alife.Append(''); Alife.Append('; cse'); Alife.Append('[smart_terrains]'); Alife.Append('none = true'); Alife.Append('END'); Alife.Append(';story_id = ' + inttostr(stalker_n)); Alife.Append(''); Alife.Append('; cse_visual properties'); Alife.Append('visual_name = actors\neytral\stalker_neytral_balon_1'); Alife.Append(''); Alife.Append('; cse_alife_creature_abstract properties'); Alife.Append('g_team = 0'); Alife.Append('g_squad = 1'); Alife.Append('g_group = 2'); Alife.Append('health = 1'); Alife.Append('dynamic_out_restrictions = '); Alife.Append('dynamic_in_restrictions = '); Alife.Append(''); Alife.Append('upd:health = 1'); Alife.Append('upd:timestamp = 0'); Alife.Append('upd:creature_flags = 0'); Alife.Append('upd:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz); Alife.Append('upd:o_model = 0'); Alife.Append('upd:o_torso = 0.0280130300670862,0,0.999607563018799'); Alife.Append('upd:g_team = 0'); Alife.Append('upd:g_squad = 1'); Alife.Append('upd:g_group = 2'); Alife.Append(''); Alife.Append('; cse_alife_monster_abstract properties'); Alife.Append(''); Alife.Append('upd:next_game_vertex_id = 65535'); Alife.Append('upd:prev_game_vertex_id = 65535'); Alife.Append('upd:distance_from_point = 0'); Alife.Append('upd:distance_to_point = 0'); Alife.Append(''); Alife.Append('; cse_alife_human_abstract properties'); Alife.Append('predicate5 = 1,2,2,1,2'); Alife.Append('predicate4 = 0,1,1,1'); Alife.Append(''); Alife.Append('; cse_ph_skeleton properties'); Alife.Append(''); Alife.Append('upd:start_dialog = '); Alife.Append(''); Alife.Append('; se_stalker properties'); stalker_n:= stalker_n + 1; alife_number:= alife_number + 1; end; 21: begin Alife.Append(''); Alife.Append('[' + inttostr(alife_number) + ']'); Alife.Append('; cse_abstract properties'); Alife.Append('section_name = stalker'); Alife.Append('name = uniqstalkername' + inttostr(stalker_n)); Alife.Append('position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz); Alife.Append('direction = 0,0,0'); Alife.Append(''); Alife.Append('; cse_alife_trader_abstract properties'); Alife.Append('money = 5000'); Alife.Append('character_profile = uniqstalkerprofile' + inttostr(stalker_n)); Alife.Append(''); Alife.Append('; cse_alife_object properties'); Alife.Append('game_vertex_id = ' + inttostr(ArXr[a].gv)); Alife.Append('distance = 0'); Alife.Append('level_vertex_id = ' + inttostr(ArXr[a].lv)); Alife.Append('object_flags = 0xffffffbf'); Alife.Append('custom_data = <<END'); Alife.Append(''); Alife.Append('[logic]'); Alife.Append('cfg = uniqstalkerlogic' + inttostr(stalker_n) + '.ltx'); Alife.Append(''); Alife.Append('; cse'); Alife.Append('[smart_terrains]'); Alife.Append('none = true'); Alife.Append('END'); Alife.Append(';story_id = ' + inttostr(stalker_n)); Alife.Append(''); Alife.Append('; cse_visual properties'); Alife.Append('visual_name = actors\neytral\stalker_neytral_balon_1'); Alife.Append(''); Alife.Append('; cse_alife_creature_abstract properties'); Alife.Append('g_team = 0'); Alife.Append('g_squad = 1'); Alife.Append('g_group = 2'); Alife.Append('health = 1'); Alife.Append('dynamic_out_restrictions = '); Alife.Append('dynamic_in_restrictions = '); Alife.Append(''); Alife.Append('upd:health = 1'); Alife.Append('upd:timestamp = 0'); Alife.Append('upd:creature_flags = 0'); Alife.Append('upd:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz); Alife.Append('upd:o_model = 0'); Alife.Append('upd:o_torso = 0.0280130300670862,0,0.999607563018799'); Alife.Append('upd:g_team = 0'); Alife.Append('upd:g_squad = 1'); Alife.Append('upd:g_group = 2'); Alife.Append(''); Alife.Append('; cse_alife_monster_abstract properties'); Alife.Append(''); Alife.Append('upd:next_game_vertex_id = 65535'); Alife.Append('upd:prev_game_vertex_id = 65535'); Alife.Append('upd:distance_from_point = 0'); Alife.Append('upd:distance_to_point = 0'); Alife.Append(''); Alife.Append('; cse_alife_human_abstract properties'); Alife.Append('predicate5 = 1,2,2,1,2'); Alife.Append('predicate4 = 0,1,1,1'); Alife.Append(''); Alife.Append('; cse_ph_skeleton properties'); Alife.Append(''); Alife.Append('upd:start_dialog = '); Alife.Append(''); Alife.Append('; se_stalker properties'); Paths.Append(''); Paths.Append('[uniqstalker' + inttostr(stalker_n) + '_walker_walk]'); // walk_n := walk_n + 1; Paths.Append('points = p0'); Paths.Append('p0:name = name00'); Paths.Append('p0:flags = 0x400'); Paths.Append('p0:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz ); Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv)); Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lv)); Paths.Append(''); Paths.Append('[uniqstalker' + inttostr(stalker_n) + '_walker_look]'); // walk_n := walk_n + 1; Paths.Append('points = p0'); Paths.Append('p0:name = name00'); Paths.Append('p0:flags = 0x400'); Paths.Append('p0:position = ' + ArXr[a].dx + ',' + ArXr[a].dy + ',' + ArXr[a].dz ); Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv)); Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lvn)); stalker_n:= stalker_n + 1; alife_number:= alife_number + 1; end; 22: begin Alife.Append(''); Alife.Append('[' + inttostr(alife_number) + ']'); Alife.Append('; cse_abstract properties'); Alife.Append('section_name = monster_section'); Alife.Append('name = uniqmonstername' + inttostr(monster_n)); Alife.Append('position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz); Alife.Append('direction = 0,0,0'); Alife.Append(''); Alife.Append('; cse_alife_object properties'); Alife.Append('game_vertex_id = ' + inttostr(ArXr[a].gv)); Alife.Append('distance = 36.3999977111816'); Alife.Append('level_vertex_id = ' + inttostr(ArXr[a].lv)); Alife.Append('object_flags = 0xffffffbf'); Alife.Append(''); Alife.Append('; cse_visual properties'); Alife.Append('visual_name = monsters\mutant_boar\mutant_boar_strong'); Alife.Append(''); Alife.Append('; cse_alife_creature_abstract properties'); Alife.Append('g_team = 0'); Alife.Append('g_squad = 0'); Alife.Append('g_group = 0'); Alife.Append('health = 1'); Alife.Append('dynamic_out_restrictions = '); Alife.Append('dynamic_in_restrictions = '); Alife.Append(''); Alife.Append('upd:health = 1'); Alife.Append('upd:timestamp = 0'); Alife.Append('upd:creature_flags = 0'); Alife.Append('upd:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz); Alife.Append('upd:o_model = 0'); Alife.Append('upd:o_torso = 0,0,0'); Alife.Append('upd:g_team = 0'); Alife.Append('upd:g_squad = 0'); Alife.Append('upd:g_group = 0'); Alife.Append(''); Alife.Append('; cse_alife_monster_abstract properties'); Alife.Append(''); Alife.Append('upd:next_game_vertex_id = 65535'); Alife.Append('upd:prev_game_vertex_id = 65535'); Alife.Append('upd:distance_from_point = 0'); Alife.Append('upd:distance_to_point = 0'); Alife.Append(''); Alife.Append('; cse_ph_skeleton properties'); Alife.Append(''); Alife.Append('; cse_alife_monster_base properties'); Alife.Append(''); Alife.Append('; se_monster properties'); monster_n:= monster_n + 1; alife_number:= alife_number + 1; end; 23: begin Alife.Append(''); Alife.Append('[' + inttostr(alife_number) + ']'); Alife.Append('; cse_abstract properties'); Alife.Append('section_name = zone_mosquito_bald_weak'); Alife.Append('name = uniqanomalyname' + inttostr(anomaly_n)); Alife.Append('position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz); Alife.Append('direction = -0.367405563592911,0.0629953369498253,0.17383885383606'); Alife.Append(''); Alife.Append('; cse_alife_object properties'); Alife.Append('game_vertex_id = ' + inttostr(ArXr[a].gv)); Alife.Append('distance = 36.3999977111816'); Alife.Append('level_vertex_id = ' + inttostr(ArXr[a].lv)); Alife.Append('object_flags = 0xffffff3e'); Alife.Append(''); Alife.Append('; cse_shape properties'); Alife.Append('shapes = shape0'); Alife.Append('shape0:type = sphere'); Alife.Append('shape0:offset = 0,0,0'); Dist:= sqrt((sqr(StF(ArXr[a].px) + StF(ArXr[a + 1].px))) + (sqr(StF(ArXr[a].py) + StF(ArXr[a + 1].py))) + (sqr(StF(ArXr[a].pz) + StF(ArXr[a + 1].pz)))); Alife.Append('shape0:radius = ' + Floattostr(Dist)); Alife.Append(''); Alife.Append('; cse_alife_space_restrictor properties'); Alife.Append('restrictor_type = 0'); Alife.Append(''); Alife.Append('; cse_alife_custom_zone properties'); Alife.Append('max_power = 0'); Alife.Append(''); Alife.Append('; cse_alife_anomalous_zone properties'); Alife.Append('offline_interactive_radius = 30'); Alife.Append('artefact_spawn_count = 32'); Alife.Append(''); Alife.Append('; se_zone_anom properties'); anomaly_n:= anomaly_n + 1; a:= a + 1; // вторая точка для определения радиуса шейпа alife_number:= alife_number + 1; end; 24: begin Alife.Append(''); Alife.Append('[' + inttostr(alife_number) + ']'); Alife.Append('; cse_abstract properties'); Alife.Append('section_name = space_restrictor'); Alife.Append('name = uniq_restrictor' + inttostr(rest_n)); Alife.Append('position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz); Alife.Append('direction = 0,0,0'); Alife.Append(''); Alife.Append('; cse_alife_object properties'); Alife.Append('game_vertex_id = ' + inttostr(ArXr[a].gv)); Alife.Append('distance = 0'); Alife.Append('level_vertex_id = ' + inttostr(ArXr[a].lv)); Alife.Append('object_flags = 0xffffff3e'); Alife.Append('custom_data = <<END'); Alife.Append('[logic]'); Alife.Append('active = sr_idle'); Alife.Append(''); Alife.Append('[sr_idle]'); Alife.Append('on_actor_inside = %+esc_close_door%'); Alife.Append('END'); Alife.Append(''); Alife.Append('; cse_shape properties'); Alife.Append('shapes = shape0'); Alife.Append('shape0:type = sphere'); Alife.Append('shape0:offset = 0,0,0'); Dist:= sqrt((sqr(StrtoFloat(ArXr[a].px) + StrtoFloat(ArXr[a + 1].px))) + (sqr(StrtoFloat(ArXr[a].py) + StrtoFloat(ArXr[a + 1].py))) + (sqr(StrtoFloat(ArXr[a].pz) + StrtoFloat(ArXr[a + 1].pz)))); Alife.Append('shape0:radius = ' + Floattostr(Dist)); Alife.Append(''); Alife.Append('; cse_alife_space_restrictor properties '); Alife.Append('restrictor_type = 3'); rest_n:= rest_n + 1; a:= a + 1; alife_number:= alife_number + 1; end; 25: begin Alife.Append(''); Alife.Append('[' + inttostr(alife_number) + ']'); Alife.Append('; cse_abstract properties'); Alife.Append('section_name = smart_terrain'); Alife.Append('name = ' + ArXr[a].gulag_name); Alife.Append('position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz); Alife.Append('direction = 0.062321275472641,0.00316426996141672,0.0140644172206521'); Alife.Append(''); Alife.Append('; cse_alife_object properties'); Alife.Append('game_vertex_id = ' + inttostr(ArXr[a].gv)); Alife.Append('distance = 4'); Alife.Append('level_vertex_id = ' + inttostr(ArXr[a].lv)); Alife.Append('object_flags = 0xffffffbe'); Alife.Append('custom_data = <<END'); Alife.Append('[smart_terrain]'); Alife.Append('type = general_lager'); Alife.Append('capacity = ' + inttostr(ArXr[a].lvn)); Alife.Append('communities = ' + ArXr[a].param_line); Alife.Append('stay = medium'); Alife.Append('END'); Alife.Append(''); Alife.Append('; cse_shape properties'); Alife.Append('shapes = shape0'); Alife.Append('shape0:type = sphere'); Alife.Append('shape0:offset = 0,0,0'); Alife.Append('shape0:radius = 1'); Alife.Append(''); Alife.Append('; cse_alife_space_restrictor properties'); Alife.Append('restrictor_type = 3'); Alife.Append(''); Alife.Append('; se_smart_terrain properties'); smart_n:= smart_n + 1; alife_number:= alife_number + 1; end; 26: begin Alife.Append(''); Alife.Append('[' + inttostr(alife_number) + ']'); Alife.Append('; cse_abstract properties'); Alife.Append('section_name = wpn_ak74u'); Alife.Append('name = item' + inttostr(item_n)); Alife.Append('position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz); Alife.Append('direction = 0,-1.63260018825531,-1.58220040798187'); Alife.Append(''); Alife.Append('; cse_alife_object properties'); Alife.Append('game_vertex_id = ' + inttostr(ArXr[a].gv)); Alife.Append('distance = 0'); Alife.Append('level_vertex_id = ' + inttostr(ArXr[a].lv)); Alife.Append('object_flags = 0xffffff07'); Alife.Append('custom_data = cond = 0.2'); Alife.Append(''); Alife.Append('; cse_visual properties'); Alife.Append('visual_name = weapons\ak-74u\ak74u'); Alife.Append(''); Alife.Append('; cse_alife_item properties'); Alife.Append('condition = 1'); Alife.Append(''); Alife.Append('upd:num_items = 0'); Alife.Append(''); Alife.Append('; cse_alife_item_weapon properties'); Alife.Append('ammo_current = 90'); Alife.Append(''); Alife.Append('upd:condition = 1'); Alife.Append('upd:weapon_flags = 0'); Alife.Append('upd:ammo_elapsed = 0'); Alife.Append('upd:addon_flags = 0'); Alife.Append('upd:ammo_type = 0'); Alife.Append('upd:weapon_state = 0'); Alife.Append('upd:weapon_zoom = 0'); Alife.Append(''); Alife.Append('upd:current_fire_mode = 0'); item_n:= item_n + 1; alife_number:= alife_number + 1; end; 27: begin Scrpt.Append(ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz + ',' + Inttostr(ArXr[a].lv) + ',' + Inttostr(ArXr[a].gv)); end; 28: begin Scrpt.Append('treasure' + inttostr(alife_number) + ' = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz + ',' + inttostr(ArXr[a].lv) + ',' + inttostr(ArXr[a].gv)); alife_number:= alife_number + 1; end; end; a:= a + 1; end; // Form1.Memo1.Text:= Paths.Text; Paths.SavetoFile('Way_Generated.ltx'); Alife.SavetoFile('Alife_Generated.ltx'); Scrpt.SavetoFile('Script_Generated.ltx'); end; procedure TForm1.Edit1Change(Sender: TObject); begin logfilename:= Form1.Edit1.Text; end; procedure TForm1.Button2Click(Sender: TObject); // прочитать лог-файл var DLog: TStringList; a: integer; s: string; Command: string; P: TPointXR; begin NextCommand:= 0; gulag:= 1; Paths:= TStringList.Create; Alife:= TStringList.Create; Scrpt:= TStringList.Create; DLog:= TStringList.Create; DLog.LoadFromFile(logfilename); a:= 0; while (a < DLog.Count) do begin s:= DLog.Strings[a]; Command:= s; //copy(s,12,Length(s) - 11); If (Command = 'Command_create_point_way') then begin s:= DLog.Strings[a + 1]; Command:= s; //copy(s,12,Length(s) - 11); If (NextCommand = strtoint(Command)) then begin // BEGIN WORK //scan mode s:= DLog.Strings[a + 2]; Command:= s; //copy(s,12,Length(s) - 11); P.mode:= strtoint(Command); //game vertex s:= DLog.Strings[a + 3]; Command:= s; //copy(s,12,Length(s) - 11); P.gv:= strtoint(Command); //level vertex s:= DLog.Strings[a + 4]; Command:= s; //copy(s,12,Length(s) - 11); P.lv:= strtoint(Command); // level vertex look s:= DLog.Strings[a + 5]; Command:= s; //copy(s,12,Length(s) - 11); P.lvn:= strtoint(Command); //position s:= DLog.Strings[a + 6]; Command:= s; //copy(s,12,Length(s) - 11); P.px:= Command; s:= DLog.Strings[a + 7]; Command:= s; //copy(s,12,Length(s) - 11); P.py:= Command; s:= DLog.Strings[a + 8]; Command:= s; //copy(s,12,Length(s) - 11); P.pz:= Command; //direction s:= DLog.Strings[a + 9]; Command:= s; //copy(s,12,Length(s) - 11); P.dx:= Command; s:= DLog.Strings[a + 10]; Command:= s; //copy(s,12,Length(s) - 11); P.dy:= Command; s:= DLog.Strings[a + 11]; Command:= s; //copy(s,12,Length(s) - 11); P.dz:= Command; // gulag_name s:= DLog.Strings[a + 12]; Command:= s; //copy(s,12,Length(s) - 11); P.gulag_name:= Command; // param_line s:= DLog.Strings[a + 13]; Command:= s; //copy(s,12,Length(s) - 11); P.param_line:= Command; // reserved 1 param_line s:= DLog.Strings[a + 14]; Command:= s; //copy(s,12,Length(s) - 11); P.Res1:= Command; // reserved 2 param_line s:= DLog.Strings[a + 15]; Command:= s; //copy(s,12,Length(s) - 11); P.Res2:= Command; SetLength(ArXr,Length(ArXr) + 1); ArXr[NextCommand]:= P; NextCommand:= NextCommand + 1; end; end; a:= a + 1; end; Form1.Label1.Caption:= 'Точек найдено: ' + inttostr(Length(ArXr)); if (Length(ArXr) > 0) then begin Form1.Button1.Enabled:= true; end; end; procedure TForm1.FormCreate(Sender: TObject); begin logfilename:= 'xray_user.log'; end; end. 2 Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на X-Ray) На базе модифицированного движка OGSR Engine. Бывший мододел на X-Ray / Начинающий игродел на Unreal Engine. Программист. AMD Ryzen 9 7950X (16 ядер, 32 потока, 5.75 ГГц); RTX 3080; 128 ГБ DDR5; Arctic Liquid Freezer II-420; 3 ТБ SSD PCIe 4.0; 4ТБ HDD. Ссылка на комментарий
abramcumner 1 145 Опубликовано 19 Апреля 2016 Поделиться Опубликовано 19 Апреля 2016 @Zander_driver, гайд по выкладыванию чего-либо Ведь не сложно же было выложить еще и dpr и dfm, чтобы дельфевый проект можно было собрать без приседаний. И скрипты/конфиги к нему приложить, чтобы не приходилось гадать, что же нужно писать в лог, чтобы программа работала. В общем возвращаясь к гайду по ссылке - "надо так давать, чтобы можно было взять". 1 1 Ссылка на комментарий
Zander_driver 10 334 Опубликовано 19 Апреля 2016 Поделиться Опубликовано 19 Апреля 2016 дельфевый проект Я же говорил что там минимум program PathGeneratorProject1; uses Forms, PathGenerator in 'PathGenerator.pas' {Form1}; {$R *.res} begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end. object Form1: TForm1 Left = 200 Top = 126 Width = 275 Height = 143 Caption = #1043#1077#1085#1077#1088#1072#1090#1086#1088' '#1087#1091#1090#1077#1081' '#1089#1090#1072#1083#1082#1077#1088#1072 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object Label1: TLabel Left = 8 Top = 8 Width = 3 Height = 13 end object Button1: TButton Left = 8 Top = 72 Width = 249 Height = 25 Caption = 'Save' Enabled = False TabOrder = 0 OnClick = Button1Click end object Edit1: TEdit Left = 8 Top = 32 Width = 169 Height = 21 TabOrder = 1 Text = 'xray_user.log' OnChange = Edit1Change end object Button2: TButton Left = 184 Top = 32 Width = 75 Height = 25 Caption = 'Open' TabOrder = 2 OnClick = Button2Click end end log("Command_create_point_way") --- ключевое слово, по которому программа опознает что начался пакет данных предназначенный для нее log(tostring(point_number)) --- номер пакета - нужен чтобы программа могла контролировать, что ничего не перепуталось point_number = point_number + 1 --- прибавляем при каждой записи log("8") --- число - номер исполняемой команды. указание что делать программе log(tostring(gv)) --- геймвертекс актора log(tostring(lv)) --- левел-вертекс актора log(tostring(lvn)) --- левел-вертекс куда смотрит актор log(tostring(pos.x)) --- позиция актора log(tostring(pos.y)) log(tostring(pos.z)) log(tostring(pos2.x)) --- позиция куда смотрит актор log(tostring(pos2.y)) log(tostring(pos2.z)) --- фрагменты вектора передаются и читаются на той стороне как строки. если где-то понадобится, это можно использовать. log(R_param_1) --- дополнительные строковые параметры. log(R_param_2) --- для разных команд, их назначение различно. 1 Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на X-Ray) На базе модифицированного движка OGSR Engine. Бывший мододел на X-Ray / Начинающий игродел на Unreal Engine. Программист. AMD Ryzen 9 7950X (16 ядер, 32 потока, 5.75 ГГц); RTX 3080; 128 ГБ DDR5; Arctic Liquid Freezer II-420; 3 ТБ SSD PCIe 4.0; 4ТБ HDD. Ссылка на комментарий
Это популярное сообщение. Zander_driver 10 334 Опубликовано 30 Апреля 2016 Это популярное сообщение. Поделиться Опубликовано 30 Апреля 2016 И снова я. На этот раз, оптимизация загрузки звуков. Платформа: ТЧ. Помнится кто-то здесь долго и упорно толковал про оптимизацию много чего применительно к солянке. И когда я спрашивал как бы звуки оптимизировать - был послан в те скрипты солянки, еще 2010 года, а как их прикручивать к моему/какому угодно моду - черт его знает. Ну и в общем, дошли руки, оптимизировал сам, посмотрел на то что получилось - и есть у меня такое подозрение, что пойдет это на любой мод на платформе ТЧ. Почему в таком случае не в "сборочный цех" это выкладываю? а потому что в файле присутствуют списки звуковых тем, и для модов в которых добавляются свои звуки/темы, придется их совмещать вручную через WinMerge. собственно сам код: https://yadi.sk/d/x-9OfcydsPRp2 1. положить файл из архива в папку скриптов 2. Если в вашем моде добавлены/изменены звуки, вооружиться WinMerge и перенести свои изменения в оптимизированный файл, обратите внимание что объявление таблицы themes теперь упаковано в функцию reinit, не снесите ее случайно. 3. В bind_stalker.script в функции actor_binder:net_spawn добавить такую строчку: sound_theme.init() 4. Готово, можно запускать игру и радоваться. Во первых, часть данных которую возможно загрузить/обработать заранее, загружается и обрабатывается при нетспавне актора. т.е. до загрузки всех неписей вообще. Во вторых, при появлении в онлайне нового нпс скрипт сначала проверит, а есть ли в онлайне похожие нпс (загружены ли наборы звуков для нпс такой же группировки/профиля и т.д.) - и если да, похожие данные имеются, он их просто копирует а не загружает по второму-десятому разу то же самое. В результате этого, при загрузке звуков для толпы похожих/идентичных нпс, находящихся рядом в одном гулаге, достигается максимальный эффект оптимизации т.к. для 10, 100 похожих нпс звуки (одни и те же) будут загружены не 10 или 100 раз, а всего 1. Во третьих, если все же производится загрузка, улучшен алгоритм загрузки данных при появлении нпс в онлайне. Тут у многих товарищей была долгое время нехорошая привычка - говорить что мол, вот это быстрее, а это нет. почему и на сколько? а вот я так сказал мол, верьте мне на слово и все. Я по их стопам идти не собираюсь. Если речь идет о быстродействии - любое утверждение на тему оптимизации должно подтверждаться тестами, фактами. И числами. До оптимизации, родной sound_theme.script оригинала. * DBG: sound_theme:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * DBG: sound_theme:Start load sound for object: 7446 * DBG: sound_theme:sounds loaded = 280 * DBG: sound_theme:время загрузки: 689.61376953125 миллисекунд * DBG: sound_theme:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * DBG: xr_motivator:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * DBG: xr_motivator:Вход NPC в онлайн:7446 * DBG: xr_motivator:Время db.add_obj 0.0083737866953015 миллисекунд. * DBG: xr_motivator:Время self.object:set_callback 0.020855639129877 миллисекунд. * DBG: xr_motivator:Время xr_info.loadInfo 1.7214480638504 миллисекунд. * DBG: xr_motivator:Время not self.object:alive() 0.0030716524925083 миллисекунд. * DBG: xr_motivator:Время manager 0.0021360206883401 миллисекунд. * DBG: xr_motivator:Время xfsnds 758.39764404297 миллисекунд. * DBG: xr_motivator:Время xr_gulag.setup_gulag_and_logic_on_spawn 57.310382843018 миллисекунд. * DBG: xr_motivator:Итого с учетом вывода в лог: 817.66247558594 миллисекунд. * DBG: xr_motivator:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ После оптимизации, загрузка первого НПС на локе: * DBG: sound_theme:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * DBG: sound_theme:Start load sound for object: 7448 (new system) * DBG: sound_theme:sounds loaded = 280 * DBG: sound_theme:время загрузки: 229.58290100098 миллисекунд * DBG: sound_theme:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * DBG: xr_motivator:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * DBG: xr_motivator:Вход NPC в онлайн:7448 * DBG: xr_motivator:Время db.add_obj 0.0080105112865567 миллисекунд. * DBG: xr_motivator:Время self.object:set_callback 0.020090805366635 миллисекунд. * DBG: xr_motivator:Время xr_info.loadInfo 1.6084860563278 миллисекунд. * DBG: xr_motivator:Время not self.object:alive() 0.0035129971802235 миллисекунд. * DBG: xr_motivator:Время manager 0.0024669475387782 миллисекунд. * DBG: xr_motivator:Время xfsnds 229.81428527832 миллисекунд. * DBG: xr_motivator:Время xr_gulag.setup_gulag_and_logic_on_spawn 42.045860290527 миллисекунд. * DBG: xr_motivator:Итого с учетом вывода в лог: 273.69644165039 миллисекунд. * DBG: xr_motivator:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ загрузка 15-го подряд нпс в одном и том же гулаге: * DBG: sound_theme:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * DBG: sound_theme:Start load sound for object: 17124 (new system) * DBG: sound_theme:sounds loaded = 280 * DBG: sound_theme:время загрузки: 1.6716794967651 миллисекунд * DBG: sound_theme:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * DBG: xr_motivator:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * DBG: xr_motivator:Вход NPC в онлайн:17124 * DBG: xr_motivator:Время db.add_obj 0.0065423832274973 миллисекунд. * DBG: xr_motivator:Время self.object:set_callback 0.019425256177783 миллисекунд. * DBG: xr_motivator:Время xr_info.loadInfo 0.010625801980495 миллисекунд. * DBG: xr_motivator:Время not self.object:alive() 0.0025873512495309 миллисекунд. * DBG: xr_motivator:Время manager 0.0019161499803886 миллисекунд. * DBG: xr_motivator:Время xfsnds 1.7876405715942 миллисекунд. * DBG: xr_motivator:Время xr_gulag.setup_gulag_and_logic_on_spawn 2.4578604698181 миллисекунд. * DBG: xr_motivator:Итого с учетом вывода в лог: 4.4502859115601 миллисекунд. * DBG: xr_motivator:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 3 10 Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на X-Ray) На базе модифицированного движка OGSR Engine. Бывший мододел на X-Ray / Начинающий игродел на Unreal Engine. Программист. AMD Ryzen 9 7950X (16 ядер, 32 потока, 5.75 ГГц); RTX 3080; 128 ГБ DDR5; Arctic Liquid Freezer II-420; 3 ТБ SSD PCIe 4.0; 4ТБ HDD. Ссылка на комментарий
aromatizer 4 429 Опубликовано 30 Апреля 2016 Поделиться Опубликовано 30 Апреля 2016 (изменено) Zander_driver, очень нужная и полезная работа. К сожалению, ввиду все возрастающей производительности домашних компьютеров, оптимизации не уделяется должного внимания: "ракета" все переварит. Однако, у подавляющего большинства людей компьютер далеко не "ракета" и некоторые моды идут с заметными фризами из-за кривых /не оптимизированных скриптов. А ведь, чем менее требователен мод к железу- тем больше людей будут в него играть. А чем больше людей играет в мод, тем приятнее автору: старался ведь не только для себя. Такую полезную штуку все же лучше в "Сборочный цех". Изменено 30 Апреля 2016 пользователем aromatizer 1 Отношения между людьми- главная ценность в человеческом обществе.Любая полученная информация- это только повод для размышлений, а не побуждение к действию.Это должен знать каждый: уроки боевой подготовки Дяди Саши https://yadi.sk/d/60Ec2B06goLAEНакопано и накнопано:https://yadi.sk/d/mzVY5jQEspwpt Ссылка на комментарий
ddww 267 Опубликовано 30 Апреля 2016 Поделиться Опубликовано 30 Апреля 2016 очень нужная и полезная работа. Я тоже так считаю. ... "ракета" все переварит. Однако, у подавляющего большинства людей компьютер далеко не "ракета" ... Ну я видел несколько жалоб от людей с очень хорошими и дорогими компьютерами на фризы/лаги именно в этих же ситуациях в различных модификациях. Так что предпологаю, что и "ракета" - не поможет. А вот Zander_driver - очень помог этой своей работой. Такую полезную штуку все же лучше в "Сборочный цех". И я тоже так считаю, а то тут в Прозекторской на неё не многие наткнуться, как мне кажется. Перенести свои изменения в оптимизированный файл - совсем не трудно, а польза то - большая. Хорошо бы, чтоб все модмейкеры использовали эту наработку; особенно, если в их моде есть толпы похожих/идентичных нпс, находящихся рядом в одном гулаге и т.п.. Ссылка на комментарий
Zander_driver 10 334 Опубликовано 1 Мая 2016 Поделиться Опубликовано 1 Мая 2016 А я все же думаю пока оставить это дело тут. В "Сборочном цехе" есть свои правила, которые я сам же писал, и нарушать их не намерен. А эта работа в те правила не вписывается. 1 Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на X-Ray) На базе модифицированного движка OGSR Engine. Бывший мододел на X-Ray / Начинающий игродел на Unreal Engine. Программист. AMD Ryzen 9 7950X (16 ядер, 32 потока, 5.75 ГГц); RTX 3080; 128 ГБ DDR5; Arctic Liquid Freezer II-420; 3 ТБ SSD PCIe 4.0; 4ТБ HDD. Ссылка на комментарий
aromatizer 4 429 Опубликовано 1 Мая 2016 Поделиться Опубликовано 1 Мая 2016 (изменено) Тогда, пожалуйста, добавь эту революционную наработку себе в подпись. Я уже адаптировал ее к ТТ2: полет нормальный. Изменено 1 Мая 2016 пользователем aromatizer 1 1 Отношения между людьми- главная ценность в человеческом обществе.Любая полученная информация- это только повод для размышлений, а не побуждение к действию.Это должен знать каждый: уроки боевой подготовки Дяди Саши https://yadi.sk/d/60Ec2B06goLAEНакопано и накнопано:https://yadi.sk/d/mzVY5jQEspwpt Ссылка на комментарий
Zander_driver 10 334 Опубликовано 1 Мая 2016 Поделиться Опубликовано 1 Мая 2016 Вы мне так подпись взорвете она же не резиновая. Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на X-Ray) На базе модифицированного движка OGSR Engine. Бывший мододел на X-Ray / Начинающий игродел на Unreal Engine. Программист. AMD Ryzen 9 7950X (16 ядер, 32 потока, 5.75 ГГц); RTX 3080; 128 ГБ DDR5; Arctic Liquid Freezer II-420; 3 ТБ SSD PCIe 4.0; 4ТБ HDD. Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти