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

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

Ну и раз начали про код, то я бы добавил просто еще один аргумент для action, т.к. я ненавижу писать одно и тоже несколько раз. Совместимость? а для _first все равно надо будет переделать.

ИМХО для таких вещей "флудилку" бы надо, типа как же все таки круче, односточник или нет. Ссылка просто так.

Да и для тестов давно пора сделать "тестовый стенд" в духе

function test_me(action, times, ...)
  local pt = profile_timer()
  pt:start()
  for i = 1, times do
    action(...)
  end
  pt:stop()
  return pt:time()
end

ТЧ 1.0004. SAP и Trans mod

github

Ссылка на комментарий
Да при чем тут наносекунды?
for i = ... специально придуман для обхода правильных массивов.
Оператор ... как раз и создаёт такой массив. Если что, на первой же "дырке"
цикл прекратиться (в оригинале это сделано через if (arg ~= nil) ... break).
Кстати pairs не годится для этой функции. Он читает всё, т.е. и nil-ы.

@Desertir

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

local function call_timer(tab, name)
    local timer = {timer = profile_timer(), name = name or ''}
    
    function timer:start()
        self.timer:start()
        return self
    end
    
    function timer:stop(msg)
        self.timer:stop()
        self:print(msg)
        return self
    end
    
    function timer:point(name)
        self:stop("POINT '"..(name or '').."'"):start()
    end
    
    function timer:print(msg)
        print("TIMER '"..self.name.."' > "..(msg or 'STOP')..' >  TIME = '..self.timer:time())
    end
    
    return timer
end

debug.timer = setmetatable({}, {__call = call_timer})

Тут у меня  подключена Lua by RvP, но это не обязательно. Функция print тоже переписана.

И использую

local t1 = debug.timer('timer_1'):start()
...
t1:point('1') -- если нужно
...
t1:point('N') -- если нужно
...
t1:stop() -- тут в лог пишется
Изменено пользователем Nazgool
  • Нравится 1
Ссылка на комментарий
Ссылка на комментарий

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

 

call_source_timer = nil
call_source_markers = {}
max_ptime = 0
max_ptime_marker = ""
function add_call_source_marker(marker)
    if not (marker and marker:len() > 0) then
        abort("Blank string cannot be used as marker!")
    end
    check_markers()
    table.insert(call_source_markers, marker)
    if not call_source_timer then
        call_source_timer = profile_timer()
    end
    --printf("~ Marker %s called", marker)
    call_source_timer:start()
end


function remove_call_source_marker()
    if #call_source_markers > 0 then
        if call_source_timer then
            call_source_timer:stop()
            if call_source_timer:time() > max_ptime then
                  max_ptime = call_source_timer:time()
                  max_ptime_marker = call_source_markers[#call_source_markers]
                  print("~ maximum time marker "..call_source_markers[#call_source_markers].." time: "..(call_source_timer and call_source_timer:time()))
            --else
                  --print("~ marker "..call_source_markers[#call_source_markers].." time: "..(call_source_timer and call_source_timer:time()))
               end
               call_source_timer = nil
         end
         table.remove(call_source_markers)
    end
end


function check_markers()
    if #call_source_markers > 0 then
        print("! Hanged calls suspected:")
        for i, mark in pairs(call_source_markers) do
            print(mark)
        end
        clear_table(call_source_markers)
        if debug then
           print(debug.traceback())
        end
        call_source_timer = nil
    end
end

 
Как работает? В каждой функции, вызываемой движком, в самом начале пишу add_call_source_marker("название_маркера"), а в конце функции - remove_call_source_marker(). Чтобы не делать удаление маркера перед каждым return, который прописан в функции A, можно функцию A переименовать в функцию B, а на её прежнем месте поставить вызов функции B между вызовами установки/удаления маркера. Таким образом, если при вызове add_call_source_marker окажется, что маркер предыдущего вызова не удалён, значит функция зависла (или маркер был добавлен несколько раз внутри одного движкового вызова). При наличии правленой библиотеки XR_LUA.DLL можно точно узнать место, где проявилось зависание. Сначала эти функции использовались только для вылавливания зависаний, позже я добавил туда замер времени для поиска наиболее "тормозных" мест в коде.
 
И раньше я как-то не задумывался о том, чтобы немного доработать эти функции для того, чтобы на добавление или удаление маркера можно было вешать коллбек. При уникальных именах маркеров, или же при добавлении дополнительных параметров для идентификации, на основе этого можно сделать что-то отдалённо похожее на то, что нужно для простого и удобного подключения скриптов.
 
В xs_sandbox уже было реализовано что-то подобное. Но там для вызова подписанных на событие коллбеков каждый раз создаётся новый объект event, что не очень хорошо для производительности, когда это будет происходить практически в каждом вызове из движка. Но если этот недостаток исправить, будет достаточно подставить вызов события с именем маркера в мой код, чтобы в результате получилась удобная система подключения скриптов.
Изменено пользователем Полтергейст
Ссылка на комментарий

Более того, в оригинале на каждой из локаций достаточно ограниченное разнообразие всего.

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

А есть какой то глубинный смысл в том чтоб всем нпс писать в профиль, какое оружие и какой прочий лут у них должен быть?

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

На самом деле у GSC мотив так делать определенно был. Если делать живую, изменяющуюся зону - в нее будет интересно играть, она будет реиграбельна. А кому же это выгодно? точно не разрабам. им надо продать коммерческий проект, чтоб люди поиграли, потом им надоело, и они купили следующий. (ЧН, ЗП). Вот поэтому и было выгодно нанять орду офисного планктона, который сделал то что мы имеем в виде сталкера ТЧ, вместо того чтоб найти еще пару толковых программистов, которые бы написали жизнь зоны.
У вас, у меня, интересы другие. Мы же не коммерческие проекты делаем, а делаем так чтоб было интересно играть. Это разные вещи, совершенно.

  • Нравится 1
  • Согласен 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, ну вы батенька расписали.

Не в выгоде дело. А в том дело, что локациями занимались геймдизы, левелдизы, никак не программисты. Вот они и расставляли. Вообще, всегда этим занимаются как раз такие люди.

Все, кто стоит на моем пути: идите нахрен и там погибните! ©

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

Следующий вопрос, а вообще как-то где-то удивительный postprocess.PostProcess(ini_file(name_ini_file)) задействован? Я вот лично не видел что-бы им кто-то когда-то пользовался. Да и вообще слабо уловил смысл скрипта. А то там какие-то супер параметры передаются. Как я понял корнями уходит в CEffectorPP, ну мне это понять пока не под силу.

 

В ЗП, к слову, успешно выпилен. Ничего фатального не будет если и в ТЧ его зарубить? Ну он правда нигде вообще не используется.

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

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

Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на 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, я не путаю. Дизайнерам даются инструменты. В том числе и для "фоновой" заселенности. Другое дело то, как реализованы эти инструменты И как работают дизайнеры.

Все, кто стоит на моем пути: идите нахрен и там погибните! ©

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

Да и вообще слабо уловил смысл скрипта.

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

 

А почему никто не применил до сих пор - да просто потому, что для повседневных задач хватало экспортированных в пространство level методов (add/set/remove_effector).

  • Спасибо 1
Ссылка на комментарий

Просьба ко всем сюда заглядывающим, как по вашему мнению лучше всего переписать безобразие с level_tasks.script(?), там задумка то вроде и хорошая, но реализация просто насквозь пробагованная. Я всегда опасался этой системы, а сейчас решил заняться и так вжало меня от всех свистоплясок кои там имеют место быть.

 

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

 

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

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

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

   val_secret_0029 = 
     {
      items = "af_mincer_meat,energy_drink,bandage,3",
      condlist = "{=npc_rank(experienced)}2",
      description = "val_secret_0029_description",
      active = false,
      target = 5429,
      done = false,
      name = "val_secret_0029_name",
     },

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

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

      condlist = 
        {
          1 = 
            {
              infop_check = 
                {
                  1 = 
                    {
                      expected = true,
                      func = "npc_rank",
                      params = 
                        {
                          1 = "experienced",
                        },
                    },
                },
              infop_set = 
                {
                },
              section = "2",
            },
        },

Вариант очень так себе. И вот стоит вопрос как его оформить, либо оставить как есть и парсить как есть (так скорее всего и будет). Интересно было бы услышать мнения всяких тех кто со спавном (тайников в т.ч.) работает и все такое. Стоит что-то вообще менять, или нет?

 

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

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

 

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

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

 

А все распарсивания - это наносекунды, никому они не нужны и ни на что не влияют.

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

, дело не в выигрыше времени, дело в субъективной стилистике :). Я думаю оставить все как есть, то есть первый вариант, ну и еще несколько несколько ключей добавить.

 

Что думаешь о идее тайников ЗП?

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

Что думаешь о идее тайников ЗП?

Сама идея мне в ЗП понравилась, но:

1) предметы могут провалиться под геометрию;

2) предметы могут выпасть из места тайника из-за каких-либо воздействий;

3) предметы легко обнаружить до получения инфы о тайнике.

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

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

Параметры active и done дублируют друг друга с незначительными изменениями, можно оставить только один из них. А его уже определять по наличию метки (mapspot), чтобы не забивать сейвы ерундой.

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

@Полтергейст, если говорить о исходниках, то там есть нормальное хранилище данных, и сейвы забивать/не забивать становится вопросом скорости загрузки (он немаловажен). Экспортировать ничего не нужно, можно оставить как есть, можно сделать ивент (нужно только событие), а там все в хранилище забивать без пакета актора. Вот и все "как следует". active и done можно записывать с помощью побитовых операций, они ничего не жрут абсолютно, я выкладывал когда-то здесь примеры, не вижу смысла как-то урезать функционал ради каких-то сомнительных экономий.

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

все условия выдачи тайников лучше хранить в customdata самих тайников.

Условия выдачи тайников не надо хранить вообще.

Выкладывал же.

 

А вот "выданный" и "невыданный" тайники - на самом деле - тоже не надо. Тайник надо спавнить при выдаче. А лучше - вообще при заходе актора на локацию.

  • Нравится 1
  • Согласен 2
Ссылка на комментарий

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

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

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

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

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

Войти

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

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

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