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

Прозекторская


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

"Вскрытие показало, что больной умер от вскрытия."

Тема для "крупной формы", то есть, на уровне скриптов целиком или больших частей оных скриптов. "Что у него внутри, зачем оно там, и что с этим можно сделать ?"

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

Пост к вот этому: http://www.amk-team.ru/forum/index.php?showtopic=13078&p=893616

просто слегка перекидываю кой-чего кое-куда. dc

 

Странный стиль программирования, т.е. форматирования, моск слегка зависает когда видишь несколько end-ов в одной строке.

В общем, жизнь показала что алгоритм удара, в оригинальном скрипте в принципе инвалидный и глючный, заменил своим из скрипта "гранаты с УДЗ", работает без ошибок и быстрей.

 

 

  Показать

 

Главное можно силу удара регулировать, а то ветка, и арт или СВУ срабатывают, так же если в верх выстрелить, то в верхней точки так же иногда срабатывает. Странно что кираг с маландринусом до такого просто алгоритма не додумались.

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

https://yadi.sk/d/XBIXdIv6eDTNo

 

Не бага, а фича. Они изменение траектории ловят. Но, да, наверное, не нужно.

Форматирование - так выделяется "законченный" блок. Когда часто пользуешься - удобнее.

 

P.S. комментарии перенес прямо в этот пост, для компактности. dc

Изменено пользователем Dennis_Chikin
  • Спасибо 1
  • Полезно 1

...в конце концов, важен лишь, машинный код.

СТАЛКЕР только для ПК!

Ссылка на комментарий
  Цитата
К использованию рекомендуются интегрированные системы компонентов, включающие систему хранения, событий и таймеры. Именно все три, поскольку они друг на друге строятся.

 

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

Я например, поразмыслив, этот момент так и не понял. Система хранения и таймеры - ну ладно еще допустим взаимосвязаны. Хотя я бы сказал не факт. А третье...

 

  Цитата

 

Если по факту раз n секунд надо лишь проверить, не наступило ли собственно время для события х. То есть, сравниваем нашу константу с game_time(). При чем здесь таймеры ?

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

 

DC: Можно я твой вопрос про таймеры перефразирую немножко иначе. Вот так: Для чего нужно ООП? для каких целей уместно применять, для каких нет. и почему. Сформулируй свой вариант ответа на такой вопрос?

Кстати ответ уважаемого маландринуса, на этот же вопрос, мне тоже любопытен.

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

Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на 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 писал(а):

почему эти три системы (все три) друг на друге строятся

Ну они конечно иерархически подчинены. Самая независимая - система событий (сигналов, ивентов и т.п.). Система хранения уже зависит от событий, поскольку использует события для инициализации себя в нужные моменты. Таймеры зависимы и от событий (в основном от апдейтов) и от системы хранения (если сохраняемые). Мои таймеры тесно используют особенности моей системы событий. Песочницу от xStream таким же образом будет использовать тяжеловато. Соответственно, компоненты xStream связаны примерно таким же образом и так же неотделимы друг от друга.

 

  Dennis_Chikin писал(а):

"Для чего нужно ООП?" - вот понятия не имею.

 

  Позволю себе порассуждать на эту тему. (Показать)
  • Спасибо 1
  • Полезно 2
  Полезный утиль (Показать)
Ссылка на комментарий

У себя уже давно использую оригинальный пысовский метод level.add_call() - как раз для таких "быстрых" таймеров. Каждый новый вызов этого метода, по сути и является созданием экземпляра класса и всё действо помещается в одну строку луашного кода. Но при такой компактности, конечно, и наворотов меньше чем у malandrinus'a - например из входных параметров только: имя таймера, время (таймаут), функция, которая будет вызвана по окончанию таймера и аргументы, переданные в эту функцию. То есть это именно таймер, с одним лишь условием - временем. Сохранение между сейвами так же не предусмотрено, но лично для моих нужд, пока этого хватает.

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

 

 

  Shadows писал(а):
использую оригинальный пысовский метод level.add_call()

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

 

 

 

  Desertir писал(а):
Получается, что приведенные методы (ну кроме конструктора), должны быть виртуальными

Если вкратце, то в Lua, в силу прототипного ООП, все методы заведомо виртуальные, поскольку определяются ссылками, хранящимися прямо в таблице/юзердате (что аналогично таблице виртуальных методов C++).

  Полезный утиль (Показать)
Ссылка на комментарий

 

 

  malandrinus писал(а):
Это не ООП, а типичный процедурный подход, поскольку отсутствует инкапсуляция кода и данных.

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

 

 

 

  malandrinus писал(а):
Ответь на простой вопрос, как ты при этом будешь хранить данные, которые надо "донести" от места/момента запуска до места/момента срабатывания?

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

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

я так понял, что ты сделал некую обёртку для level.add_call(), позволяющую хранить данные до вызова функции?

 

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

ogse_st_mgr.start_timer(timer_name, <задержка>, <имя функции>, <аргументы>)

Но это естественно сильно ограничивает поле применения. Аргументы не могут быть любого типа, срабатывает только по задержке. Хотя конечно написать ещё одну обёртку с дополнительной функцией-условием тоже можно, но как по мне - это уже извраты и лучше использовать собственно класс таймера.

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

 

 

  malandrinus писал(а):
я так понял, что ты сделал некую обёртку для level.add_call(), позволяющую хранить данные до вызова функции?

Можно и так сказать. Передаваемые аргументы хранятся в таблице, которая передается во вторую функцию, после чего эта таблица там распаковывается. Таким образом, можно передать любое количество аргументов и любого типа.

 

 

 

  malandrinus писал(а):
Но это естественно сильно ограничивает поле применения. Аргументы не могут быть любого типа, срабатывает только по задержке. Хотя конечно написать ещё одну обёртку с дополнительной функцией-условием тоже можно, но как по мне - это уже извраты и лучше использовать собственно класс таймера.

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

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

{}
Да, это все лирика была.

Вообще-то, планировал еще и расписывать: как, что и зачем сделано, но... В общем, попытаюсь.

В принципе, планировалось все по порядку описывать, с пляской от собственно _g, но можно и "с конца". Итак, собственно, с конца и пойдем:

  Показать

init() -- инициализация. Цепляем тогда, когда появился актор. Раньше просто смысла нет. Что делаем:

Из pstor берем табличку таймеров в формате { имя таймера, время срабатывания от момента старта, данные }

Сохранение pstor слегка переделано (см. прозекторскую), так что преобразование таблиц в строки и обратно дополнительно делать не нужно. Хранится все довольно компактно, самих таймеров и данных реально мало. Сиречь, ни каких дополнительных хранилищ тоже не нужно.

Далее осталась табличка для руками забиваемых функций - атавизм от "13Гб мода" . Поскольку все закомментировано - очевидно, что уже не нужна.

bind_stalker.task_add() - вешаем на апдейт актора (раз в 200 ms, чаще нет смысла), bind_stalker.add_on_save() - добавляем функцию, вызываемую при сохранении. (Да, руки дойдут - распишу, но вообще по аналогии с коллбэками по предметам - чтобы по 50 скриптов не трогать при подключении нового).

  Показать

on_save() -- вот та самая функция, вызываемая при сохранении. Что и зачем:

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

  Показать

check_timers() -- проверка таймеров. То самое, что добавляли на апдейт. В принципе, все прозрачно. Время срабатывания подошло - вызываем и удаляем. Практически как в оригинале. Только что табличка отсортирована по времени, то, что должно сработать раньше - в хвосте. Перебираем не все, а прекращаем проверку на первом же вхождении, которое "еще не пора".

  Показать

timer_stop() -- удаление таймера, если вдруг стал не нужен. Не дожидаясь сработки.

timer_start() и timer_g_start() -- запуск таймера для реального и игрового времени соответственно. Реальное здесь сразу преобразуется в игровое, по тому что смысла на самом деле нет хранить и считать по-разному. Все события игры привязаны так или иначе к игровому.

timer_add() -- добавление новой функции, которую будем вызывать по таймеру, из сторонних скриптов по инициативе этих скриптов. То есть, все а же система, что и с bind_stalker.task_add() и т.д.

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

Собственно, вот, такая вот процедурщина. По тому что именно на процедурщину заточено железо и среда.

Пример использования - в скрипте сна можно найти. По тому они в одной теме и лежат. Собственно, один из 2-х случаев из упомянутого 13Гб мода. ;)

2 Shadows: а вот ООП здесь почему-то оказалось ну вот совершенно незачем.

 

P.P.S. да, загадочная переменная game_time_ms - это время от загрузки игры.

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

 

 

  Dennis_Chikin писал(а):
function init()

local t = actor_data.get_pstor() -- хранилище данных актора

if t.timers then

Уже после этого места потерял желание читать дальше. За хранение всякой левой всячины в псторе актора, на кострах сжигать разве не пора еще?

 

 

  Dennis_Chikin писал(а):
из упомянутого 13Гб мода
Кажись, свой я еще не выкладывал.

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

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

У меня там всего 600 байт лежит. Из которых еще 300 подлежит сносу.
При том, что легким движением руки максимальный объем расширяется до бесконечности.

Ну так и почему бы не pstor тогда ?

P.S. Пф ! Можно подумать, что есть всего один мод на 13 Гб... Ну пусть не на 13, а на 14...

 

(Это хвост про таймеры, которые не нужны. Бурное обсуждение "обо всем" перехало во флудилку.)

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

Гм, методически неверно было с самого начала выкладывать что попало куда попало без объяснений, но, впрочем, объяснения были даны, про то что на форуме было отдельное спрятанное от большинства подполье, где предполагалось понаписать всякого разного, а потом все писатели куда-то делись, и в мир вышло вот это самое что попало и как попало.

 

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

 

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

 

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

 

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

И, да, я знаю, что "у всех уже сделано", и про "на лесоповал, чтоб не смели". Можно про это не повторяться. ;)

 

https://dl.dropboxusercontent.com/u/27871782/%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%BE%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%8B%20%D1%81%D0%BE%D0%BB%D1%8F%D0%BD%D0%BE%D1%87%D0%BD%D1%8B%D0%B5.zip

 

Основная часть этого - именно таблицы, позволяющие по какому-либо свойству объекта убедиться, что это именно тот объект, который нам нужен. Заменяют простыни "if .. then ... elseif ... end" на 100500 строк. Ну, то есть, ничего принципиально нового, но собрано в разные часто используемые комбинации.

Да, в этой теме я уже упоминал про class_registrator, и по-хорошему надо бы доработать все это дело, по тому как часть таблиц явно должна заполняться оттуда, а не руками, и наоборот, данные браться из таблиц, чтоб не дублировать набивание руками.

 

Из того, что заслуживает некоторого количества отдельных слов:

_tbl_protected.script - исторически сложилось, что делается куча проверок для противоестественого интеллекта неписей и прочих уборщиков, чтобы не уничтожали квестовые и уникальные предметы. По-хорошему, это бы надо всего 2 проверки: на флажок quest_item в конфиге (который препятствует продаже или выбрасыванию ценного предмета), и на уникальный story_id.

Но, опять таки исторически сложилось, что конфиги - священны и неприкосновенны, и конфигурист пишет там то, что левой пятке захотелось, а потом скриптами мы пытаемся все это как-то разобрать. Но, там где используется protected_items.script - скрипт этот, мягко говоря, тоже странен. Куча неочевидных странных и кривоработающих проверок десятками способов. На практике мне оказалось как-то проще сделать таблицы свойств, и поверять наличие нужного свойства в нужной таблице.

Да, в процессе еще вынесено куча "одноразовых секций", поскольку элементарно пересчитывается в конкретный объект непосредственно из логики ситуаций. Но это уже другой отдельный вопрос.

 

Далее, _tbl_outfit.scipt: как понятно из названия, позволяет получить свойства костюмов из визуалов неписей, и наоборот.

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

 

И, наконец, xl_imgr.script - это банальное "кэширование конфигов". Когда вместо упомянутых 100500 строк чтения конфигов мы просто берем нужное свойство из таблицы по секции конструкцией ( t[sect] or get_prm(sect) ).prm

Так реально помогает, а память даже и экономится. На данный момент кэшируются только те свойства тех предметов, с регулярным опросом которых я сталкивался.

 

Вот примерно так.

 

P.S. Да, тот код, который я время-от времени куда-нибудь выкладываю, именно на эти таблицы и опирается. Так что, опять же, если кого интересуют какие мои поделия, то вот можно глянуть сюда на предмет всяких "недостающих" частей.

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

Для поиска: диалоги, dialog_manager, адаптация

 

Все-таки, пожалуй, выложу свой вариант этого самого менеджера, раз спрашивают.

https://dl.dropboxusercontent.com/u/27871782/dialog_manager.script

 

Очень коротко: xr_logic.parse_condlist1 здесь - то же самое, что xr_logic.parse_condlist, но на входе - только строка, которую следует разобрать. actor - то же, что db.actor, вызов init() делается в любой удобный момент, например - из reinit() актора, но перед load(), из _g.script здесь вызывать ничего не надо.

 

В db.scipt нужна строка:

ver = script_server_object_version() or -1 -- метка весии игры

Это и есть вся "адаптация".

 

Основной смысл всего действа - зачистка мусора.

 

Несколько слов про сохранение: вообще оно здесь нафиг не нужно, поскольку сохраниться изнутри диалога все равно нельзя, и информация о выбранной фразе все равно пропадает. Но оставлено, поскольку лень было чистить.

Версия движка определяется ОДИН раз, поэтому определять script-версию непися в мотиваторе - не нужно, и передавать сюда - тоже не нужно.

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

 

То, что откомментировано как "устарело" - оно устарело и не нужно, кроме как для других скриптов, которые зачем-то могут пытаться это дергать.

 

А вообще, опять же, не нужен совсем. Нужны диалоги на скриптовом гуе: это избавит от сложных конструкций и вылетов на забытых треугольных скобках и прочих опечатках. ;)

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

 

p.s. разбор потрохов, надеюсь, воспоследует. Как руки дойдут.

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

 

 

  Dennis_Chikin писал(а):
Нужны диалоги на скриптовом гуе

А диалоги, оформленные как в Mass Effect, не хочешь? ;)

А то ведь будут, запросто.

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

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

Я б этот массэффект еще видел...

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

 

2 abramcumner: так они именно что в xml. 180 файлов, 6 мег в gameplay, и еще 4 в text\rus.

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

Для поиска: netpacket, нетпакеты, хранилище

Поскольку возник такой вопрос, выкладываю здесь для интересующейся общественности se_stor от @Artos (версия от 09.09.2013, последняя из опубликованных автором):
https://yadi.sk/d/AlA809oPehaqN
Авторские ссылки все устарели, а в середине темы «Ищу файлы ...» не каждый догадается посмотреть.


Перенесу, пожалуй, сюда. Ибо внутри темы на 3 сотни страниц очень не сразу найти можно. dc

Изменено пользователем Dennis_Chikin
  • Спасибо 1
  • Полезно 2

Свои работы и совместные проекты: ИнструментOGSM CSFinal StrokeHARDWARMOD

Полезное: модули АртосаXML парсер

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

xr_logic

 

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

 

https://dl.dropboxusercontent.com/u/27871782/xr_logic.script

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

try_switch_to_another_section можно сократить малость.

Так код читать легче. Заодно и убрать вспомогательную функцию "cond_name" можно

  Показать

 


С parse_infop тоже особо ничего не сделаешь.

Там вообще паттерн интересный - "([%-%+%~%=%!])([^%-%+%~%=%!%s]+)"

Тут дело такое.

Я поставил такой шаблон - "(%S)([^%-%+%~%=%!%s]+)" И вылетел. Но КАК !!!

 

Короче. Первый паттерн продолжает чтение данных, если какой-то из захватов не был найден.

Напр. есть запись - "+info1 info2 -info3"

Будут прочитаны +info1 и -info3info2 прочитан не будет, т.к. перед ним нет никакого знака.

На самом деле это ошибка. И, считаю, такие записи нужно пресекать.

 

Что и получилось при использовании шаблона  "(%S)([^%-%+%~%=%!%s]+)"

Еще не нашел где именно, но где-то нашлась запись 'npc_rank(novice)' без знака, которая разбилась на :

sign - 'n'

infop_name - 'pc_rank(novice)'

что и привело к, необходимому имхо, вылету.

 

Что и как нужно пока не знаю, поэтому оставил старый

  Показать

 

Ну и наконец вызов  abort_syntax_error_in_cond(npc, section, field) - это шедевр.   :)

Передается 'npc', которого и в помине тут нет, а в функции abort_syntax_error_in_cond из ничего

хотят получить id !?

 

....

 

Ага Нашел где 'npc_rank(novice)' без знака (это в оригинале).

Исправил и уже не вылетает ))

  Показать

 

Так что у себя однозначно ставлю шаблон "(%S)([^%-%+%~%=%!%s]+)"
Изменено пользователем Nazgool
  • Нравится 2
Ссылка на комментарий

Сдается мне, что в parse_infop надо ловить неалфавитный символ + строку (включая точку).

Как-то так. А потом ругаться, если непечатный символ не определится как осмысленный. И мне не нравится elseif-простыня, ПЕРЕД которой дергается parse_func_params.

 

Кажется, должно быть решение изящнее.

 

abort_syntax_error_in_cond - там в оригинале таких шедевров... Причем не работают - ВСЕ. По разным причинам, но не работают - дают глухой висяк + через непредсказуемое время после - наше любимое stack overflow/memory...

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

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

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

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

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

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

Войти

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

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

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