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

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

 

 

h0N0r
- читал и раньше, и сейчас, но к сожалению, хоть там и разбирается xr_kamp - но там нет ни слова о том как отвязать нпс временно от какой то схемы, или примера использования set_weight для action.... :(
Ссылка на комментарий

 

 

При использовании 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.

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

 

 

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

 

О, уже немного понятнее, спасибо. Буду разбираться.

---------------------------------

www.amk-zone.de

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

Решил таки выложить тут одну свою работу небольшую. Что это такое - функция для вывода в лог любого количества каких-угодно аргументов любого типа. Грубо говоря так: У вас какая-то переменная(ые), и вы допустим вообще понятия не имеете что они из себя представляют. тип, значение - вообще без понятия. Этот инструмент даст в этой ситуации исчерпывающий ответ.

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

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

 

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;
   }

 

 

Изменено пользователем Zander_driver
Добавлено Dennis_Chikin,

Уверен, что это - именно сюда ?

Добавлено Kirgudu,

Пока перенёс в «Скриптование» - эта тема всё-таки больше подходит для собственной функции, чем справочник по движковым функциям и классам.

Если найдёшь тему, которая подойдёт ещё лучше - черкни мне или любому другому модератору в личку.

  • Полезно 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.

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

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

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

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

Ты "историю одной пессимизации" читал ? Ну, там, правда, целый набор тормозов, но тем не менее.

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

 

 

Ты "историю одной пессимизации" читал ?

Перечитал сейчас. Думаю, что можно это обойти через переопределение 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, чтобы не искать их по разным файлам.

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

@Полтергейст, лучше тогда их переопределить в system_ini(), чем этот огород городить, вообще странная оболочка, шило на мыло меняешь. Денис вон давно еще это описал, на старте прямо кешируй все что нужно распределяя еще по фазам загрузки, например system_ini() прям сразу, а alife() при старте и пользуй :).

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

 

 

лучше тогда их переопределить в system_ini(), чем этот огород городить, вообще странная оболочка, шило на мыло меняешь

Надо проверять. Возможно, при добавлении "_safe" методов в ini_file они добавятся и в system_ini. Если нет, то для него это нужно делать отдельно. И для game_ini тоже. Плюсы в том, что не надо обращаться к файлу и явно передавать сам ini в аргументы, достаточно написать что-нибудь такое: ini:r_string_safe(...), ini:cfg_get_string(....)

 

Что до кеширования, при переопределении самого ini_file больше ничего не надо писать, всё само будет кешироваться при первом обращении. А кешировать ещё и значения по-моему излишне. По производительности может и будет небольшая выгода, но вряд ли это стоит затраченной памяти. К тому же, одно и то же значение может быть считано как строка и как clsid, или как строка и как число - это ещё больше будет забивать память.

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

Надо проверять. Возможно, при добавлении "_safe" методов в ini_file они добавятся и в system_ini.

 

Нет, они не добавятся.

 

 

Плюсы в том, что не надо обращаться к файлу и явно передавать сам ini в аргументы, достаточно написать что-нибудь такое: ini:r_string_safe(...), ini:cfg_get_string(....)

 

При обращении в system/game_ini() ты обращаешься уже к кешированным данным из этих файлов, к файлам ты обращаешься только в случае ini_file, а create_ini_file создает конфиг в памяти, который если надо можно и сохранить.

 

 

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

 

Тот кто делает полное кеширование обычно следит за дампом и не допускает такого.

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

 

 

Нет, они не добавятся.

Тогда добавить их вручную также, как и ко всему классу ini_file.

 

 

При обращении в system/game_ini() ты обращаешься уже к кешированным данным из этих файлов

Я имел в виду обращение к файлам скриптов (или к соответствующим им таблицам, если файлы уже закешированы). Например - вместо utils.cfg_get_string или %author%_utils.get_что-то_там пишем ini:cfg_get_string и ini:r_float_safe.

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

 

 

Тогда добавить их вручную также, как и ко всему классу ini_file.

В смысле в ручную? Я тебе говорю переопределить их там с помощью метатаблиц, чтобы перед чтением шла проверка на существование.

 

 

 

Я имел в виду обращение к файлам скриптов (или к соответствующим им таблицам, если файлы уже закешированы). Например - вместо utils.cfg_get_string или %author%_utils.get_что-то_там пишем ini:cfg_get_string и ini:r_float_safe.

Опять не понял, какие файлы скриптов? cfg_get_* читает конфиги. Зачем еще увеличивать количество функций, когда можно переопределить?

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

Я пришел в общем к тому, что лучше "родного", движкового кэша - ничего нет.

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

 

Однако, есть некоторые категории конфигов, которые стоит считать, РАЗОБРАТЬ, провести нужные вычисления, и отдавать как t_*[section].prm (где * - категория).

Собственно, по той же причине - медленные вызовы функций. Ну и лишние вычисления одни и те же по сотни-тысячи раз - зачем ?

 

Это, однозначно, оружие, патроны, костюмы, арты, ну и плюс цена/вес прочих инвентарных предметов. Там же сразу добавляется разрешение на манипуляцию с предметом неписям.

Собственно, вот примерно так и делаю. См, к примеру, "уборщик": https://dl.dropboxusercontent.com/u/27871782/xl_offline.script

 

А вот то, что подключается не через system.ltx - этому всему отказать вообще. В скрипт их, в таблицу.

cfg_get_* читает конфиги. Зачем еще увеличивать количество функций, когда можно переопределить?

cfg_get_* - еще хуже, из за навешенного совершенно излишнего кривого функционала. Как бы, "инкапсуляция", да, однако по факту получилось запутывание, ненужные ограничения и злостное тормозилово.

Переопределять - это значит, либо тащить в новое всю старую кривизну, либо - перелопачивать все, и менять весь синтаксис. С гарантией в 146% наполучать ошибок на ровном месте.

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

@Dennis_Chikin, переопределение я смотри что имел ввиду, например вместо r_string(section. line) сделать return ini:section_exist(section) and ini:line_exist(section, line) and ini:r_string(section, line) or что-то там.


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

Ссылка на комментарий
В смысле в ручную?

Если при добавлении в класс 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_* я просто взял для примера.

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

Если при добавлении в класс 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)

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

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

 

 

Зачем его вызывать? Получаешь его метатаблицу и переопределяешь метод, у нас еще сделано так: если "новый" метод дает нифига, вызывается стандартный. Работает для любого поля.

Вот этого не знал. А есть примеры, где этот способ применяется и работает?

 

 

Они и так являются методами ini_file

Это только r_string, r_line и прочие движковые. Я же пишу о том, что было бы лучше вспомогательные скриптовые функции чтения чего-то из конфига сделать доступными из класса ini_file и его объектов. Из-за этого будет меньше обращений к внешним скриптам.

 

Что до кеша, мой вариант хранит ссылку на system_ini так, что даже такое обращение

local ini = ini_file("system.ltx") 

никаких проблем с производительностью не вызовет. Можно кроме этого ещё и в _G хранить ссылку на system_ini, это не помешает.

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

Вот этого не знал. А есть примеры, где этот способ применяется и работает?

Скоро выложу все что есть.

 

Это только r_string, r_line и прочие движковые. Я же пишу о том, что было бы лучше вспомогательные скриптовые функции чтения чего-то из конфига сделать доступными из класса ini_file и его объектов. Из-за этого будет меньше обращений к внешним скриптам.

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

 

Что до кеша, мой вариант хранит ссылку на system_ini так, что даже такое обращение

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

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

Есть у меня одна мысль насчёт системы событий - сделать конфиги, секции которых будут наименованиями событий, а внутри секций уже набор condlist'ов. Как-то так:

[binder_update]
on_info = {=precondition_function} %=complete_function%

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

Стоит ли вообще это делать, какие плюсы и минусы?

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

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

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

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

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

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

Войти

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

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

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