Перейти к содержанию
Arkada

Как оптимизировать моды на S.T.A.L.K.E.R.

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

 

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

Спойлер
Спойлер
  1. Память безусловно играет большую роль. Особенно на высоких настройках графики. Но в скриптах безусловно есть функции, которые не используются. Их следует просто удалить.
  2. _G. Глобальная область видимости. Обычно в этот скрипт добавляют функции, которые используются повсеместно.
    Но там могут быть функции, которые используются только в одном скрипте, возьмём к примеру utils. И всё. Эта самая функция видна в каждом скрипте, т.к. она помещена в _G. А зачем? Зачем помещать в _G, если эта функция используется лишь в одном файле? Функцию следует переместить в тот файл, к примеру в utils.
    Также нужно сделать и с глобальными переменными.
  3. Локальные и глобальные объекты. Разные вещи, всё-таки. Некоторые скрипты содержат в себе глобальные переменные, например скрипт modules. Другие скрипты во время своей работы могут обратиться к какой-то глобальной переменной из modules.
    Но, везде но... в скрипте создаётся глобальная переменная, но она используется только в этом скрипте. То есть, по сути она используется как локальная, но она глобальная. Доступ к глобальным переменным происходит немного медленнее, чем к локальной. В данном случае необходимо все такие глобальные переменные, которые в этом скрипте, сделать локальными.
  4. Функции и локальные функции (local function ()). Первое - это те функции, к которым можно обратиться из других скриптов, глобальные функции. Абсолютно в каждом скрипте есть глобальная функция, и это нормально. Но есть те функции, которые как и переменные (тавтология), используются только в данном файле, но они объявлены как глобальные. Повторюсь,
    Цитата

    Доступ к глобальным переменным происходит немного медленнее, чем к локальной.


    это касается и функций, поэтому эти функции должны быть объявлены как локальные.
  5. Каждый символ в строке весит 1 байт. Например, пустая строка "" весит 1 байт (в конце всегда нуль-терминатор, \0).
    Поэтому не рекомендую вам делать длинные названия чего-либо (их названия - это строки), ибо займёт много памяти, особенно, если это какой-нибудь класс, который используется у нескольких объектов.
Спойлер
  1. Цикл for i = 0, 65535 do. Это цикл, перебирающий все спавн-объекты в игре. Много где используется.
    Итак, первое замечание, это конец цикла - итерация №65535. Это максимально допустимое число типа unsigned short (int), и это максимум спавн-объектов, который может быть в игре. В игре по умолчанию объект с ID 65535 это "Invalid". От него ничего нельзя получить, никаких данных. Просто это сигнализирует о том, что дальше объектов быть не может, этот последний.
    Следовательно, необходимо делать не 65535 итераций, а 65534.
    Второе замечание, ID, с которого начинается итерация, ноль. Ноль это всегда ID игрока, абсолютно всегда, так как самым первым на уровне создаётся и загружается именно игрок. В некоторых случаях, например, поиск и удаление каких-то предметов с помощью такого цикла. В таком случае, актёр - не предмет, следовательно он нам вообще не нужен, и итерацию нужно начинать с единички. Вот вполне вероятно, что ID 1 - это предмет.
  2. Балячка сталкерских скриптов, - передача аргумента в качестве объекта, от которого будет взят только один параметр. Зачем передавать целый объект, если используется один лишь его параметр, можно передать тот самый параметр.
    Спойлер
    
    
    
    --КАК НЕ НАДО ДЕЛАТЬ!!!
    local function IsActor(obj)
    	return obj:id() == 0
    end
    --представим, что мы откуда-то взяли НПС, CGameObject* (именно указатель на него!)
    print(IsActor(who)) --результат неизвестен
    
    --КАК НАДО ДЕЛАТЬ
    local function IsActor(obj_id)
    	return obj_id == 0
    end
    --представим, что мы откуда-то взяли НПС, CGameObject* (именно указатель на него!)
    print(IsActor(who:id())) --результат неизвестен

     

    Думаю, вы уловили суть.

  3. Удалите все функции, которые вызываются, но в результате они ничего не делают. Например, функция printf и её аналоги (print_table,store_table). Это - лишние действия, которые затрачивают ресурсы компьютера в результате на ничего. Зачем? Каждой программе безусловно нужно тестирование и отладка, printf та самая функция.
    Но дело тут в том, что она просто не нужна. Если движовая функция log доступна, то printf выводит в лог кучу информации. Которая модмейкеру, уверен, не нужна. Если модмейкеру нужно что-то отладить, исправить какой-то баг, то ОН САМ может в нужном месте запихнуть вывод в лог, а потом закомментировать. И ещё, иногда это забывают делать, и в итоге, в логе мода, который выпустили в открытую сеть, много ненужной инфы. И в некоторых случаях это только затрудняет поиск причины вылета.

  4. Создание таблицы, и после её создания сразу же внесение данных. Это смотрится красиво, но код от этого замедляется ох как хорошо. Таких таблиц вообще не следует допускать. Lua проще записать всю информацию в таблицу на этапе её создания, чем после неё.

    
    
    --ТАК НЕ ДОЛЖНО БЫТЬ!!!!
    local t = {}
    t[1] = false
    t[2] = true
    t[3] = false
    
    --ВОТ ТАК ДОЛЖНО. Эквивалетно прошлому примеру, но побыстрее.
    local t =
    {
    	[1] = false,
      	[2] = true,
      	[3] = false
    }
  5. Постоянная проверка на неравенство значений. Это лишнее!
    По факту ведь ничего не изменится, если такой код
    
    
    --Допустим это функция вызывается из bind_stalker.actor_binder:update(dt)
    local lst = 10
    function update(dt)
    	--съедает фпс
    	if dt ~= lst then
    		lst = dt
    	end
    end

    можно переделать в код вида

    
    
    --Допустим это функция вызывается из bind_stalker.actor_binder:update(dt)
    local lst = 10
    function update(dt)
    	--ускорение примерно в 3,5 раза за удаление ОДНОГО неравенства
    	lst = dt
    end

    который будет быстрее.

Спойлер
  1.  Соединения строк. В Lua можно со строкой соединять и число, без использования функции tostring. Быстрее работает тот код, который без использования tostring.
    
    
    local c = "math"..tostring(7) --медленнее
    --Эквивалентно
    local c = "math"..7 --быстрее

     

  2. Математические операции со строками. Да, именно так, но есть одно но:
    
    
    --Такой код будет работать
    local c = "70"
    c = c - 5
    c = c + 2
    c = c * 2
    c = c / 4
    print(c) --выведет 33.5
    
    --ТАКОЙ КОД НЕ БУДЕТ РАБОТАТЬ
    local c = "70f"
    c = c - 5 --выведет ошибку
    c = c + 2
    c = c * 2
    c = c / 4
    print(c)
    --[[
    lua: main.lua:2: attempt to perform arithmetic on a string value (local 'c')
    stack traceback:
    	main.lua:2: in main chunk
    	[C]: in ?
    ]]

    Если в строке есть символы, не определяющиеся как число (буквы, например) - то будет ошибка в коде. Тогда в строке должны быть только цифры (точка, минус).
    Работает и с шестнадцатеричной системой исчисления (0xff).
    Даже если в строке целое число, то в результате действия с любыми математическими операторами, встроенными в Lua, оно преобразуется во float.

 


Спойлер

Мелочи, которые тоже придают прирост ФПС.

  1. Старайтесь избегать деления. Да, именно так. Процесс деления происходит немного медленнее, чем процесс умножения. Например:
    Спойлер
    
    
    local test = 150
    test = test * 0.1 --В данном случае эквивалентно test = test / 10
    print(test) --Выведет 15

    Список замен:
    /10 = * 0.1
    /100 = * 0.01
    /1000 = * 0.001 и т.п.
    /2 = * 0.5
    /4 = * 0.25
    /5 = * 0.2
    /8 = * 0.125

  2. Не используйте степень. Вообще. Когда я проводил тесты, то просто поразился результату. Например, если какое-то число умножать само на себя два раза, то это будет в полтора раза быстрее, чем возвести в квадрат.
  3. Удалите лишние аргументы из функции, которые не используются, но передаются. Например:
    
    local function test(param) -- param не используется!!! но передаётся
      print("Test?")
    end
    test(true)

    В данном случае нужно удалить аргумент param в функции, и убрать его при передаче. Зачем лишний раз передавать "ничего"?

  4. Удалите пустые блоки кода. Даже в оригинальных скриптах они есть.
     

    
    function test()
       return math.random(3)
    end
    --ПУСТОЙ БЛОК КОДА!!!
    if test() == 2 then
      --print(true)
    end
    
    --НУЖНО ЗАМЕНИТЬ НА
    --if test() == 2 then
      --print(true)
    --end
    
    --ИЛИ ВОВСЕ УДАЛИТЬ!
  5. Если вдруг какой-то файл после каких-то действий не будет использоваться, то лучше его удалить из памяти, ведь он в дальнейшем не пригодится. Сделать это можно так:
    
    _G["имя скрипта"] = nil
    --или (эквивалентно)
    _G.имя_скрипта = nil

    Или, если похожая ситуация с функцией (например, каллбэк на старт игры)

    
    имя_скрипта["имя_функции"] = nil
    --или (эквивалентно)
    имя_скрипта.имя_функции = nil
  6. Умножить, разделить сложить и вычесть все известные числа.
    
    local a = 12*12
    --Сделать так. Умножить известные числа
    local a = 144

     

 

Изменено пользователем liner
  • Жму руку 2
  • Хабар 2
  • Спасибо 3

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


Ссылка на сообщение
Поделиться на другие сайты
 

1)Никогда не ставьте 8К текстуры в свой мод
2)Отключайте использование 0 ядра

  • Смех 2

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


Ссылка на сообщение
Поделиться на другие сайты
 

Я тут вычитал в описании к одному моду на Anomaly, что якобы движок сталкера подгружает при работе и те файлы, которые лежать в геймдате, но нигде не используются. Это правда? 

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


Ссылка на сообщение
Поделиться на другие сайты
 

baraholschik Я то откуда знаю. Спросите у разработчиков аномали.

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


Ссылка на сообщение
Поделиться на другие сайты
 
3 часа назад, baraholschik сказал:

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

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

И да, тут нужно уточнить, какие именно файлы, файлы оригинальной игры, или вообще левые файлы.

Левые файлы по любому никак не будут грузиться. А вот оригинальные файлы игры, они и так всегда грузятся(читаются), хоть они и не используются модом. Но вопрос, что они делают в геймдате, они в самой игре и так есть)))

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

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


Ссылка на сообщение
Поделиться на другие сайты
 

alex5773 И причем здесь эта тема? Оффтопите. Не пишите здесь об этом.

  • Мастер! 1
  • Смущение 1

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


Ссылка на сообщение
Поделиться на другие сайты
 

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

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


Ссылка на сообщение
Поделиться на другие сайты
 

liner, так удалите, не против. 

33 минуты назад, baraholschik сказал:

может ли движок обрабатывать эти ненужные файлы

Нет, не нужные он не читает вообще. 

Каким образом он будет читать то, до чего нет пути.

Можешь в мод хоть весь мусор скинуть. Просто размер будет больше.

А вот мусор в скриптах, которые используются, это другое дело.

  • Мастер! 1

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


Ссылка на сообщение
Поделиться на другие сайты
 

baraholschik Если подумать, допустим:
В system.ltx включаются файлы (директива include). И допустим мы включили специально лишний конфиг, в котором много лишних секций.
В результате, если мы хотим вычитать какую-то строчку из какой-то секции, то итераций будет больше, т.к. ещё будет проверяться новый конфиг. Думаю вы поняли к чему я.
Но вот просто валяющиеся текстуры не нагружают игру, я думаю, и если они не занесены в список заранее загружаемых текстур (кэш текстур).
alex5773 Удалять могут только модераторы.

  • Мастер! 1
  • Хабар 1

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


Ссылка на сообщение
Поделиться на другие сайты
 

Закину свои 5 копеек. r3_sm_minmax следует отключать. Из-за неё на DX10 и выше имеется просадки ФПС со временем. На DX10 и выше у нас есть доступ к волшебному ключику запуска -no_staging, благодаря которому мы можем отключить кеширование текстур в оперативную память, тем самым разгружая место под что-то более важное. Многопоточность. Как известно GSC пытались реализовать многопоточность (особенно это заметно на бенчмарк сборке, но и в релизной версии она тоже есть, хоть и порезана). Проблема в том, что на многоядерных системах этот многопоток хуже только делает. Но решение есть! Используя ключик -max-threads 1-... можно задавать количество потоков помощников. В идеале ставить 1, чтобы этих потоков вообще небыло, но можно попытаться подобрать идеальное значение. Главное не делать его слишком большим.

Изменено пользователем Hozar_2002
  • Лайк 1
  • Спасибо 1

Еще один злодей!
6 ГБ ОЗУ DDR3 1094 мГц (Разносорт) Процессор Intel Xeon E5420 4/4 2.57 ГГц (OC)
Видеокарта Gigabyte Radeon RX 580 8192 МБ GDDR5 (Micron) DirectX v12.0

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


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

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

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу