Winsor 177 Опубликовано 6 Августа 2015 Поделиться Опубликовано 6 Августа 2015 h0N0r - читал и раньше, и сейчас, но к сожалению, хоть там и разбирается xr_kamp - но там нет ни слова о том как отвязать нпс временно от какой то схемы, или примера использования set_weight для action.... Ссылка на комментарий
Zander_driver 10 334 Опубликовано 6 Августа 2015 Поделиться Опубликовано 6 Августа 2015 При использовании se_stor от Артоса. Если этот модуль действительно используется, а не просто лежит в папке скриптов, то проблем с переполнением нетпакета, а тем более актора, у вас никаких не должно быть. Как использовать - Артос вроде давно все пояснял. Везде где вам надо что-то сохранить, сохраняете в se_stor, потом везде где надо что-то прочитать, читаете оттуда же. Соответственно в вашем случае пройтись по коду, найти все места чтения-записи каких либо данных, и вместо вызовов костылей насилующих нетпакет актора, поставить вызовы se_stor. 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. Ссылка на комментарий
Wlad777 24 Опубликовано 6 Августа 2015 Поделиться Опубликовано 6 Августа 2015 Соответственно в вашем случае пройтись по коду, найти все места чтения-записи каких либо данных, и вместо вызовов костылей насилующих нетпакет актора, поставить вызовы se_stor. О, уже немного понятнее, спасибо. Буду разбираться. --------------------------------- www.amk-zone.de Ссылка на комментарий
Zander_driver 10 334 Опубликовано 8 Августа 2015 Поделиться Опубликовано 8 Августа 2015 (изменено) Решил таки выложить тут одну свою работу небольшую. Что это такое - функция для вывода в лог любого количества каких-угодно аргументов любого типа. Грубо говоря так: У вас какая-то переменная(ые), и вы допустим вообще понятия не имеете что они из себя представляют. тип, значение - вообще без понятия. Этот инструмент даст в этой ситуации исчерпывающий ответ. С одной стороны, это должно быть, у каждого скриптера свое есть, а многие вообще скажут что это не надо никому. С другой стороны, начинающим ведь приходится подобное самостоятельно писать, т.к. готового нигде нет. Помнится, около релиза ОГСЕ, я в их разделе спрашивал, "где у вас взять универсальную функцию для вывода в лог чего-угодно?" ответ мне показался странным. Для тех аргументов - то, для таблиц - вон то, для юзердаты - еще там что-то... ну имхо, это не удобно. Каждый сам для себя решает конечно. Просто выложу тут может пригодится кому то. local table_read = false local table_shiftindex = 0 local go_read = false function any_data_tostring(v) local string_returned = "" local t = type(v) if t == "string" then --- COMPLETE string_returned = " STRING:"..v elseif t == "number" then --- COMPLETE string_returned = " NUMBER:"..tostring(v) elseif t == "boolean" then --- COMPLETE if v then string_returned = " BOOLEAN:true" else string_returned = " BOOLEAN:false" end elseif t == "nil" then --- NIL ТЕРЯЕТСЯ ПРИ МАССОВОЙ ПЕРЕДАЧЕ АРГУМЕНТА. COMPLETE string_returned = " NIL" elseif t == "function" then --- COMPLETE string_returned = " FUNCTION" if not v then string_returned = string_returned.."<nil>" end elseif t == "userdata" then --- COMPLETE string_returned = " USERDATA" go_read = true if not v then string_returned = string_returned.."<nil>" end elseif t == "table" then string_returned = " TABLE:" table_read = true if not v then string_returned = string_returned.."<nil>" end else string_returned = "UNKNOWN DATA" if not v then string_returned = string_returned.."<nil>" end end return string_returned end function table_to_str(tbl) if type(tbl) ~= "table" then return end table_shiftindex = table_shiftindex + 1 local s = string.rep(" ", table_shiftindex * 3) log(s.."{") for k,v in pairs(tbl) do --log(s.."[KEY: "..zander_utils.any_data_tostring(k).."] = VALUE: "..zander_utils.any_data_tostring(v)..";") log(string.format("%s[KEY: %s] = VALUE: %s;", s, zander_utils.any_data_tostring(k), zander_utils.any_data_tostring(v))) if table_read then table_read = false if type(k) == "table" then log(s.."Table key:") zander_utils.table_to_str(k) end if type(v) == "table" then log(s.."Table value:") zander_utils.table_to_str(v) end end if go_read then --game_object_tostr(v) end end log(s.."}") table_shiftindex = table_shiftindex - 1 end function userdata_to_log(go) if type(go) == "userdata" then if go.id ~= nil and type(go.id) == 'function' and go.section ~= nil and type(go.section) == 'function' then local t = { id = go:id(), parent = go:parent(), section = go:section(), position = v_to_str(go:position()), lv = go:level_vertex_id(), gv = go:game_vertex_id(), clsid = go:clsid(), story_id = go:story_id() --- } log(";*game_object parameters") table_to_str(t) elseif go.x and type(go.x) == 'number' then --- attempt unpack as vector if go.y and go.z and type(go.y) == 'number' and type (go.z) == 'number' then log(";vector parameters") local v = { x = go.x, y = go.y, z = go.z } table_to_str(v) else log("unknown userdata") end elseif go.id and type(go.id) == 'number' and go.section_name and type(go.section_name) == 'function' then local ts = { id = go.id, section = go:section_name(), name = go:name(), clsid = go:clsid() } log(";*server_object parameters") table_to_str(ts) else log("unknown userdata") end end end function zander_log(...) table_shiftindex = 0 local o = {...} for k,v in pairs(o) do log(zander_utils.any_data_tostring(v)..";") if table_read then table_read = false zander_utils.table_to_str(v) end if go_read and type(v) == "userdata" then zander_utils.userdata_to_log(v) end end end Как использовать: для удобства можно в _g.script глобально объявить, я так у себя сделал: if zander_utils then zander_log = zander_utils.zander_log end Ну и потребуется рабочая функция log. У меня для этого луа-расширение RvP, честно не в курсе насчет других вариантов, но поидее должно быть у каждого) Ну так вот, как это работает. В любом месте какого угодно кода, где вам надо вывести в лог _что угодно_ - пишем zander_log(любое, число, каких-то, ваших, переменных) Причем, вам вообще не надо переживать по поводу того, к какому типу относятся эти переменные. В лог будет выведено, и тип переменных, и их значение. В случае таблиц любой структуры, производится их разбор с разжевыванием типов и значений всех ключей и всех значений в таблице и всех ее подтаблицах независимо от уровня вложенности, и структура таблицы наглядно отображается в логе. Если где-бы то ни было обнаруживается значение типа юзердата, производится попытка его опознать как клиентский объект, как серверный объект, как вектор. Если окажется что юзердата является клиентским/серверным объектом/вектором, будут выведены в лог некоторые основные параметры объекта. Если опознание не удалось, то просто пишем unknown userdata - неизвестный тип юзердаты. TABLE:; { [KEY: NUMBER:1] = VALUE: USERDATA; [KEY: NUMBER:2] = VALUE: STRING:smart; [KEY: NUMBER:3] = VALUE: STRING:scrhud_dangicon_sa; [KEY: NUMBER:4] = VALUE: TABLE:; Table value: { [KEY: NUMBER:1] = VALUE: NUMBER:14; [KEY: NUMBER:2] = VALUE: NUMBER:14; } [KEY: NUMBER:5] = VALUE: STRING:atp_killer_barlager; } Изменено 8 Августа 2015 пользователем Zander_driver Добавлено Dennis_Chikin, 8 Августа 2015 Уверен, что это - именно сюда ? Добавлено Kirgudu, 10 Августа 2015 Пока перенёс в «Скриптование» - эта тема всё-таки больше подходит для собственной функции, чем справочник по движковым функциям и классам. Если найдёшь тему, которая подойдёт ещё лучше - черкни мне или любому другому модератору в личку. 3 Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на 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. Ссылка на комментарий
Полтергейст 37 Опубликовано 8 Августа 2015 Поделиться Опубликовано 8 Августа 2015 Написал я тут небольшой скриптик по INI-файлам, но, к сожалению, не имею возможности его проверить. Скрипт добавляет методы чтения значений, при использовании которых не нужно вручную вызывать section_exist и line_exist Также скрипт добавляет экспериментальную функцию для работы с несколькими ini-файлами как с одним (здесь может что-то не заработать, поэтому надо потестировать). Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 8 Августа 2015 Поделиться Опубликовано 8 Августа 2015 Ты "историю одной пессимизации" читал ? Ну, там, правда, целый набор тормозов, но тем не менее. Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Полтергейст 37 Опубликовано 8 Августа 2015 Поделиться Опубликовано 8 Августа 2015 Ты "историю одной пессимизации" читал ? Перечитал сейчас. Думаю, что можно это обойти через переопределение ini_file. local ini_table = {} __ini_file = ini_file ini_file = function(file_name) local result_file = __ini_file(file_name) ini_table[file_name] = result_file return result_file end Должно работать. Сейчас подумал над своим скриптом ещё раз, и теперь сомневаюсь в том, что стоило делать create_ini_multifile. Оно может и хорошо, но для набора только статических ini-файлов нецелесообразно, а для динамических можно использовать include (что кое-где и делалось). К тому же include работает всегда, а create_ini_multifile даст объект, с которым можно работать только из скриптов. Так что оставить только добавление "_safe" методов и будет нормально. Для удобства можно ещё и функции чтения из ini (cfg_get_что-то_там и подобные) объявить как методы ini_file, чтобы не искать их по разным файлам. Ссылка на комментарий
Карлан 1 049 Опубликовано 8 Августа 2015 Поделиться Опубликовано 8 Августа 2015 @Полтергейст, лучше тогда их переопределить в system_ini(), чем этот огород городить, вообще странная оболочка, шило на мыло меняешь. Денис вон давно еще это описал, на старте прямо кешируй все что нужно распределяя еще по фазам загрузки, например system_ini() прям сразу, а alife() при старте и пользуй . Ссылка на комментарий
Полтергейст 37 Опубликовано 8 Августа 2015 Поделиться Опубликовано 8 Августа 2015 лучше тогда их переопределить в system_ini(), чем этот огород городить, вообще странная оболочка, шило на мыло меняешь Надо проверять. Возможно, при добавлении "_safe" методов в ini_file они добавятся и в system_ini. Если нет, то для него это нужно делать отдельно. И для game_ini тоже. Плюсы в том, что не надо обращаться к файлу и явно передавать сам ini в аргументы, достаточно написать что-нибудь такое: ini:r_string_safe(...), ini:cfg_get_string(....) Что до кеширования, при переопределении самого ini_file больше ничего не надо писать, всё само будет кешироваться при первом обращении. А кешировать ещё и значения по-моему излишне. По производительности может и будет небольшая выгода, но вряд ли это стоит затраченной памяти. К тому же, одно и то же значение может быть считано как строка и как clsid, или как строка и как число - это ещё больше будет забивать память. Ссылка на комментарий
Карлан 1 049 Опубликовано 8 Августа 2015 Поделиться Опубликовано 8 Августа 2015 Надо проверять. Возможно, при добавлении "_safe" методов в ini_file они добавятся и в system_ini. Нет, они не добавятся. Плюсы в том, что не надо обращаться к файлу и явно передавать сам ini в аргументы, достаточно написать что-нибудь такое: ini:r_string_safe(...), ini:cfg_get_string(....) При обращении в system/game_ini() ты обращаешься уже к кешированным данным из этих файлов, к файлам ты обращаешься только в случае ini_file, а create_ini_file создает конфиг в памяти, который если надо можно и сохранить. А кешировать ещё и значения по-моему излишне. По производительности может и будет небольшая выгода, но вряд ли это стоит затраченной памяти. К тому же, одно и то же значение может быть считано как строка и как clsid, или как строка и как число - это ещё больше будет забивать память. Тот кто делает полное кеширование обычно следит за дампом и не допускает такого. Ссылка на комментарий
Полтергейст 37 Опубликовано 8 Августа 2015 Поделиться Опубликовано 8 Августа 2015 Нет, они не добавятся. Тогда добавить их вручную также, как и ко всему классу ini_file. При обращении в system/game_ini() ты обращаешься уже к кешированным данным из этих файлов Я имел в виду обращение к файлам скриптов (или к соответствующим им таблицам, если файлы уже закешированы). Например - вместо utils.cfg_get_string или %author%_utils.get_что-то_там пишем ini:cfg_get_string и ini:r_float_safe. Ссылка на комментарий
Карлан 1 049 Опубликовано 8 Августа 2015 Поделиться Опубликовано 8 Августа 2015 Тогда добавить их вручную также, как и ко всему классу ini_file. В смысле в ручную? Я тебе говорю переопределить их там с помощью метатаблиц, чтобы перед чтением шла проверка на существование. Я имел в виду обращение к файлам скриптов (или к соответствующим им таблицам, если файлы уже закешированы). Например - вместо utils.cfg_get_string или %author%_utils.get_что-то_там пишем ini:cfg_get_string и ini:r_float_safe. Опять не понял, какие файлы скриптов? cfg_get_* читает конфиги. Зачем еще увеличивать количество функций, когда можно переопределить? Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 8 Августа 2015 Поделиться Опубликовано 8 Августа 2015 (изменено) Я пришел в общем к тому, что лучше "родного", движкового кэша - ничего нет. Все остальное - очень большие накладные расходы прежде всего на сам вызов функций, с их копированиями аргументов. Однако, есть некоторые категории конфигов, которые стоит считать, РАЗОБРАТЬ, провести нужные вычисления, и отдавать как t_*[section].prm (где * - категория). Собственно, по той же причине - медленные вызовы функций. Ну и лишние вычисления одни и те же по сотни-тысячи раз - зачем ? Это, однозначно, оружие, патроны, костюмы, арты, ну и плюс цена/вес прочих инвентарных предметов. Там же сразу добавляется разрешение на манипуляцию с предметом неписям. Собственно, вот примерно так и делаю. См, к примеру, "уборщик": https://dl.dropboxusercontent.com/u/27871782/xl_offline.script А вот то, что подключается не через system.ltx - этому всему отказать вообще. В скрипт их, в таблицу. cfg_get_* читает конфиги. Зачем еще увеличивать количество функций, когда можно переопределить? cfg_get_* - еще хуже, из за навешенного совершенно излишнего кривого функционала. Как бы, "инкапсуляция", да, однако по факту получилось запутывание, ненужные ограничения и злостное тормозилово. Переопределять - это значит, либо тащить в новое всю старую кривизну, либо - перелопачивать все, и менять весь синтаксис. С гарантией в 146% наполучать ошибок на ровном месте. Изменено 8 Августа 2015 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Карлан 1 049 Опубликовано 8 Августа 2015 Поделиться Опубликовано 8 Августа 2015 @Dennis_Chikin, переопределение я смотри что имел ввиду, например вместо r_string(section. line) сделать return ini:section_exist(section) and ini:line_exist(section, line) and ini:r_string(section, line) or что-то там. Посмотрим как лучше сделать, пока лучшее что я придумал это парсить все на старте в динамический массив, это если давать управление, либо переносить в статичные массивы, как я с менеджером трупов делал, я тебе показывал. Ссылка на комментарий
Полтергейст 37 Опубликовано 9 Августа 2015 Поделиться Опубликовано 9 Августа 2015 (изменено) В смысле в ручную? Если при добавлении в класс ini_file новые методы автоматически не добавятся для самого system_ini, надо их добавлять для него явно. Как-то так. Я тебе говорю переопределить их там с помощью метатаблиц, чтобы перед чтением шла проверка на существование. С помощью метатаблиц - это каким образом? Для userdata нельзя вызывать setmetatable. А если просто взять ссылку на r_string, а потом подменять (как я делал с самим классом ini_file) - скорее всего будет ругаться на "pure virtual call". Во всяком случае, с методами других классов у меня так было. Есть вариант сделать это через наследование, но опять же - system_ini и game_ini это не коснётся. Опять не понял, какие файлы скриптов? Имелось в виду, что лучше все функции, которые просто читают из ini и больше ничего не делают, определить как методы ini_file. Чтобы было "всё в одном месте". Чтобы не было так, что в каждом моде всё это лежало в %мододел_name%_utils.script, но по сути было реализацией одного и того же (чтения конфигов в данном случае). Оригинальный cfg_get_* я просто взял для примера. Изменено 9 Августа 2015 пользователем Полтергейст Ссылка на комментарий
Карлан 1 049 Опубликовано 9 Августа 2015 Поделиться Опубликовано 9 Августа 2015 (изменено) Если при добавлении в класс ini_file новые методы автоматически не добавятся, надо добавлять их для самого system_ini. Как-то так. Для system_ini() они тоже не добавятся . С помощью метатаблиц - это каким образом? Для userdata нельзя вызывать setmetatable. А если просто взять ссылку на r_string, а потом подменять (как я делал с самим классом ini_file) - скорее всего будет ругаться на "pure virtual call". Во всяком случае, с методами других классов у меня так было. Есть вариант сделать это через наследование, но опять же - system_ini и game_ini это не коснётся. Зачем его вызывать? Получаешь его метатаблицу и переопределяешь метод, у нас еще сделано так: если "новый" метод дает нифига, вызывается стандартный. Работает для любого поля. Имелось в виду, что лучше все функции, которые просто читают из ini и больше ничего не делают, определить как методы ini_file. Чтобы было "всё в одном месте". Чтобы не было так, что в каждом моде всё это лежало в %мододел_name%_utils.script, но по сути было реализацией одного и того же (чтения конфигов в данном случае). Оригинальный cfg_get_* я просто взял для примера. Они и так являются методами ini_file. system_ini() и game_ini() это указатели, если хочешь можешь свой добавить. Чем тебя не устраивает вариант с кешем и прямым вызовом? Где-то в глубине: _G.sini = system_ini() _G.gini = game_ini() Где надо: local check, default_param = ((sini:section_exist(section) and sini:line_exist(section, line) and true) or (gini:section_exist(section) and gini:line_exist(section, line) and false)) or nil, "" some_param = ((check and sini:r_string(section, line)) or (check==false and gini:r_string(section, line))) or (check == nil and default_param) А вообще так подумать, не проще на уровне движка это все сделать? Там это пару минут работы, ну и эррор месадж поставить для незадачливых. Изменено 9 Августа 2015 пользователем Карлан Ссылка на комментарий
Полтергейст 37 Опубликовано 9 Августа 2015 Поделиться Опубликовано 9 Августа 2015 Зачем его вызывать? Получаешь его метатаблицу и переопределяешь метод, у нас еще сделано так: если "новый" метод дает нифига, вызывается стандартный. Работает для любого поля. Вот этого не знал. А есть примеры, где этот способ применяется и работает? Они и так являются методами ini_file Это только r_string, r_line и прочие движковые. Я же пишу о том, что было бы лучше вспомогательные скриптовые функции чтения чего-то из конфига сделать доступными из класса ini_file и его объектов. Из-за этого будет меньше обращений к внешним скриптам. Что до кеша, мой вариант хранит ссылку на system_ini так, что даже такое обращение local ini = ini_file("system.ltx") никаких проблем с производительностью не вызовет. Можно кроме этого ещё и в _G хранить ссылку на system_ini, это не помешает. Ссылка на комментарий
Карлан 1 049 Опубликовано 9 Августа 2015 Поделиться Опубликовано 9 Августа 2015 Вот этого не знал. А есть примеры, где этот способ применяется и работает? Скоро выложу все что есть. Это только r_string, r_line и прочие движковые. Я же пишу о том, что было бы лучше вспомогательные скриптовые функции чтения чего-то из конфига сделать доступными из класса ini_file и его объектов. Из-за этого будет меньше обращений к внешним скриптам. Все что можно представить уже там есть. В любом случае лучше дополнять движок, там либо дополнить существующие методы, либо добавить новые. Что до кеша, мой вариант хранит ссылку на system_ini так, что даже такое обращение system_ini() по сути и есть ссылка (в движке), зачем ее хранить? Она вполне явно задана, ее надо закешировать в глубине, так как с кешированной ссылкой методы работают быстрее (см. пессимизацию). Твои обертки ни к чему более положительному не приводят по сути, здесь тот случай когда побеждает простота. Ссылка на комментарий
Полтергейст 37 Опубликовано 13 Августа 2015 Поделиться Опубликовано 13 Августа 2015 Есть у меня одна мысль насчёт системы событий - сделать конфиги, секции которых будут наименованиями событий, а внутри секций уже набор condlist'ов. Как-то так: [binder_update] on_info = {=precondition_function} %=complete_function% То есть что-то типа логики, только по одной секции на каждое событие. Пока не знаю, стоит ли делать ещё и возможность переключения между такими конфигами целиком и между отдельными секциями. Стоит ли вообще это делать, какие плюсы и минусы? Ссылка на комментарий
Карлан 1 049 Опубликовано 13 Августа 2015 Поделиться Опубликовано 13 Августа 2015 @Полтергейст, эта система делается для удобности и увеличения автономности, зачем ее опять убивать? 1 Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти