Это популярное сообщение. Malandrinus 615 Опубликовано 8 Июля 2009 Это популярное сообщение. Поделиться Опубликовано 8 Июля 2009 (изменено) В данной теме собраны сведения по скриптовой модели сталкера: функции и классы, методы и свойства, взаимосвязь классов и последовательность работы с ними, связь работы классов и файлов конфигураций. К наполнению темы приглашаются все желающие. В наполнении темы непосредственно участвовали и существенно мне помогли: @Monnoroch, @Kolmogor, @Unnamed Black Wolf, @меченый(стрелок), @IQDDD, @Kirag, @Taroz, @dan, @7.9, @Garry_Galler, @AKKK1, @Bak и много других людей. Скрытый текст Скрытый текст класс alife_simulator. Базовые операции с серверными объектами. Пространства имён. Глобальные функции для большого числа задач. "Создание своего класса" и "Наследование от экспортированных классов". Базовые сведения об объектно-ориентированном программировании для сталкера. Необходимо прочитать, для понимания темы про биндер и некоторых других. В одном посте: Общие слова об архитектуре и скриптовой модели сталкера "Класс object_binder" расширение онлайновых объектов, колбеки, сохранение состояния. "Класс net_packet" Регистрация скриптовых классов с помощью object_factory Серверные классы. Часть 1 Иерархия серверных классов, описание не закончено. Серверные классы. Часть 2 Картинка структуры наследования и несколько заключительных слов Клиентские классы Скрытый текст Класс game_object Интерфейс ко всем онлайновым (клиентским объектам) Класс hit для нанесения урона скриптом и другая информация (IQDDD) Некоторая информация по управлению путями патрулирования здесь (Kirag) и здесь (Taroz) Неполная информация по управлению памятью неписей с примером здесь (Bak) Физическая оболочка объектов (Garry_Galler) Пост о выборе (подборе) оружия НПС и стрельбы (*Shoker*) Скрытый текст Управление заданиями Класс CGameTask и другие вспомогательные классы и функции. Управление инфопорциями Функции, колбеки, форматы файлов Список специальных системных инфопорций (Unnamed Black Wolf) Система профилей и алгоритм генерации имён. Форматы файлов, функции Дополнительная информация по параметрам профилей terrain_sect (Kolmogor) Диалоги. Часть 1 Форматы файлов, базовые сведения Диалоги. Часть 2 Скриптовые диалоги Диалоги. Часть 3 Тематическая подборка функций управления диалогами Скрытый текст Функции времени Тематическая подборка функций, связанных с управлением игровым временем. Класс CTime Вспомогательный класс для управления игровым временем Полезная скриптовая функция с использованием CTime (Garry_Galler) Скрытый текст class ini_file (меченый(стрелок)) Класс FS и CSavedGameWrapper Бинарный доступ к файлам, в том числе в игровых архивах, управление сохранёнными играми. Скрипт уровня. Забытая фишка с колбеком на заход на уровень Класс vector Некоторая полезная информация о разных вещах (меченый(стрелок)) "Класс render_device" Направление и положение камеры, характеристики экрана, программная пауза игры и др. Некоторая информация о различиях между ТЧ и ЗП в системе оконных классов и колбеков. (lekzd) Неплохо бы развить эту тему! Некоторая полезная информация о скриптовых функциях из модуля _g.script. (lekzd) Также требует развития! Полезные функции для работы с графом игры (Garry_Galler) В одном посте: Класс profile_timer Отладочные измерения скорости работы фрагментов программы Класс client_spawn_manager Колбек на выход в онлайн без использования биндера. Работа с консолью. Класс CConsole Анимации цвета. Класс color_animator Всякие моргающие элементы в окнах и пр. Управление постэффектами. Скриптовые постэффекты. Класс effector Класс sound_object. Проигрывание звуков в игре в произвольном месте, от произвольного объекта, в голове актора. (Shadows) Пост удалён автором (прим. Kirgudu) Скрытый текст Оконные классы Некоторая общая информация о создании окон Список методов, XML-тегов и событий для оконных классов (ТЧ/ЧН/ЗП) (Norman Eisenherz) Представление материала в моих статьях оптимизировано для онлайнового просмотра. Если кому не хочется лазить по спойлерам, а нужно просмотреть текст какого-либо поста "потоком", то могу рекомендовать просмотр в режиме "текстовая версия". В этом же режиме удобно сохранять содержимое темы на диск. (прим. Malandrinus) Изменено 30 Июля пользователем Kirgudu 5 5 16 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Это популярное сообщение. proper70 74 Опубликовано 13 Марта 2015 Это популярное сообщение. Поделиться Опубликовано 13 Марта 2015 (изменено) Несколько раз порывался написать этот пост, да все откладывал. Наконец нашел время. Хотя глобальное модостроение и пришло в свою завершающую фазу, но все же, напишу то, что считаю нужным, может вдруг кому и пригодится. Речь пойдет об оптимальных со всех точек зрения и построенных на правилах объектно ориентированного программирования конструкциях, как я их вижу (уверен, далеко не самый лучший вариант, но все же), которые должны были бы быть в скриптах сталкера, но которых увы, нет. Предлагаемый мной вариант организации кода позволил бы очень сильно уменьшить размер конфигов и скриптов, а также достаточно ощутимо оптимизировал бы их использование и выполнение. Жаль, что это все я понял только тогда, когда ОП-2 уже был готов и зарелизен) Можно было бы сэкономить кучу времени и нервов, отлаживая и доводя до ума все это) Да и переделывать уже имеющееся никто не будет, но эта инфа вполне может пригодиться в будущих скриптах. Начнем с класса ini_file - чтения конфигов. Огромная проблема в том, что он вылетает при каждой попытке прочесть отсутстувующую секцию или параметр. И чтобы решить эту проблему, многие мододелы, начиная с ПЫСов, нагородили разных оберток - функций, которые закрывают этот вылет, но при этом очень усложняют собственно сам процесс чтения. Тут не нужно было не городить всякие "примочки" "обертки" "проверки" и прочее, а просто сделать, например, вот так: class script_ini (ini_file)function r_string(section, line)if ini_file.section_exist(self, section) and ini_file.line_exist(self, section, line) thenreturn ini_file.r_string(self, section, line)elsereturn ""endendИ т.д. переопределить все функции, прописав в них возврат значения по умолчанию при отсутствии секции либо параметра, и все дальнейшие скрипты строить исходя из этого. И тогда не нужно было плодить всяких utils.cfg_get_string в логике, и тот ужас, который мы имеем в Солянке в виде getIniValueString. Достаточно было в _G.script написать вот это:ini = script_ini(system_ini())И далее, во всех скриптах писать просто:local var = ini:r_string(section, line)if var == нужное значение thenИ все. Никаких вылетов при отсутствии секции или параметра не будет. Конечно, при правильной организации кода эти фишки должны были быть встроены в оригинал класса ini_file изначально, но раз их нет, то их надо было просто добавить скриптово)Также, для удобочитаемости и удобоиспользования: вместоtreasure_manager.get_treasure_manager():give_treasure("mil_borov_secret")написать в опять же в _G.script:treasure = treasure_manager.CTreasure()И в любых вызовах использоватьtreasure:give("mil_borov_secret")Соответсвенно сократив имена методов класса. Ведь этот класс все равно создается единожды при лоаде и хранится в памяти всю игру. Аналогично поступить для всех глобальных классов.Следующее. Просто напрашивается всеми фибрами души вместо amk.start_timer сделать опять же в _G:timer = amk.CTimer(name, delay, parameters)B далее у этого класса методы start, g_start, has, stop, execute (при наступлении времени) и любые другие.И, наконец, самое нужное, на мой взгляд, и самое опитимизирующее практически все скрипты изменение:class CLogicИ в нем методы: net_spawn (аналог set_scheme+assign_storage_and_bind+subscribe_action_for_events), update (аналог pick_section_from_condlist+try_switch_to_another_section - все апдейты), net_destroy (аналог deactivate+reset_scheme подключенных схем)Далее, переопределяем object_binder:class "script_object_binder" (object_binder)function script_object_binder:__init(obj) super(obj)self.object.logic = CLogic() -- здесь можно добавить проверки, есть ли логика у объекта, и при каких условиях ее надо подключать.endfunction script_object_binder:net_spawn(data)object_binder.net_spawn(self, data)self.object.logic:net_spawn()endfunction script_object_binder:update(delta)object_binder.update(self, delta)self.object.logic:update(delta)endfunction script_object_binder:net_destroy()object_binder.net_destroy(self)self.object.logic:net_destroy()endИ т.д. И затем глобализируем этот переопределенный класс в _G:object_binder = script_object_binder()И тогда в биндерах объектов ничего править не нужно - все само переопределится - логика всегда будет подключаться полностью автоматически. Просто идеальный вариант, но увы, с логикой имеем только то, что имеем)) Движок при каждом старте выполняет команду ini_file("system.ini"). то есть он вычитывает и строит в памяти всю таблицу подключенных секций и параметров. Ссылка на эту таблицу возвращается функцией system_ini(). Причем все секции и параметры упорядочены по алфавиту (это лекго увидеть, выведя в лог список параметров любой секции через r_line), и, судя по всему, проиндексированы, так как получение любого параметра происходит очень быстро (можете сами проверить, запустив цикл на миллион чтений и замерив время выполнения). Другими словами - к файлу на диске движок при чтении прараметра из конфига никак не обращается - все читается один раз при старте. Следовательно, всякие дублирования данных из конфигов в таблицах, а также предубеждения, что system_ini() нельзя читать на апдейте, ибо это тормоз - абсолютно неверны. Наоборот, не только можно, но и даже нужно использовать чтение напрямую из конфигов вместо создания дублирующих таблиц. Конечно, при условии определения разовой, глобальной переменной, описаной выше:ini = system_ini()А не в каждом скрипте создавать свою копию.Исходя из вышеизложенного, наиболее оптимальный вариант работы с конфигами будет примерно следующим. Покажу на примере task_manager.CRandomTask:__init(). В ней достаточно прочитать в локальные таблицы и хранить в памяти постоянно только вот это:curr_task_info.type = self.task_ini:r_string(id, "type")curr_task_info.name = idА все остальное вычитывать на лету при активации диалога с вендором. Тогда в памяти будут храниться только реально нужные данные, по которым ведется поиск и отбор. А всё остальное - значения секций - можно прочесть "на лету". Это исключает дублирование данных движком и скриптами. Простой пример. Все монстры имеют общий базовый конфиг monster_base:[m_burer_e]:monster_baseТак вот, если в конфиге monster_base добавить параметрmonster = trueВот так:[monster_base]:common_ph_friction_params_on_npc_deathactor_hit_effect = effector_monster_hitmonster = trueто тогда таблица IAmAMonster[obj:clsid()] - становится абсолютно ненужной. Вместо нее пишем:function IAmAMonster(section)return ini:line_exist(section, "monster")endВсе. Никаких таблиц. Причем, если сделать секции stalker_base, ammo_base, wpn_base, artefact_base, medkit_base, detector_base, food_base, outfit_base и т.д., и задать там аналогичный параметр, то все эти таблицы также станут ненужными.Скажете - IAmAMonster - не такая уж и большая таблица. А как быть тогда с соляночными таблицами в protected_items? Также с различными списками вamk_mod.anom_recept_komp,news_data.ommunity_name, monster_classes, weapon_classes, различными templates,art_hit.art_hit, scient,death_manager.data_by_communityxrs_armor.excluded_npcsи с многими другими таблицами? Ведь для того, чтобы сделать, чтобы item был protected, достаточно создать секцию[protected_item]protected_item = trueИ прописывать ее в наследование в каждую секцию, которую надо защитить:[bandranen_pda]:identity_immunities, protected_itemИ все - и тогда простая проверкаini:section_exist(section, "protected_item")даст нужный результат) Конечно, в данном случае это не дает оптимизации, просто перенос с одного формата в другой. Но если этот параметр используется более чем 1 раз - то это дает экономию столько раз, сколько он используется. В частности прописывание параметраscient = trueво все броники, перечисленные в art_hit.scient полностью избавляет нас от этой таблицы.А также, если сделать вот такую секцию:[iI_ATTCH]:identity_immunitiesGroupControlSection = spawn_groupdiscovery_dependency =$spawn = "devices\quest_items\bandranen_pda";$prefetch = 32class = II_ATTCHcform = skeletonradius = 1И затем написать вместо:[bandranen_pda]:identity_immunities, protected_itemвот так:[bandranen_pda]:II_ATTCH, protected_itemТо тогда в каждой секции на классе II_ATTCH можно выкинуть все перечисленные выше строки, вынесенные в общую секцию. А это только в оригинале ТЧ более 500 ненужных и дублирующихся строк. А если посмотреть по другим классам, и добавить всё, сделанное в модах на оригинал, то количество вырастет на несколько порядков. И этот весь дубликат висит балластом в памяти всю игру, провоцируя вылеты по нехватке ресурсов. Повторюсь: жаль, что понимание этого ко мне пришло только недавно, уже после релиза ОП-2. Иначе в нем можно было еще очень и очень много чего оптимизировать и упростить) Подобного еще можно написать много, я изложил только то, что первое пришло на ум, но надеюсь суть и принципы изложенного понятны) все остальное оптимизируется по аналогии. Надеюсь этот пост окажется кому-то полезным) Изменено 13 Марта 2015 пользователем proper70 2 2 4 Ссылка на комментарий
Это популярное сообщение. Zander_driver 10 334 Опубликовано 4 Апреля 2015 Это популярное сообщение. Поделиться Опубликовано 4 Апреля 2015 (изменено) Я тут соорудил у себя такое: скриптовый элемент худа, позволяющий вести мониторинг состояния различных биндеров и др.объектов, пользующихся апдейтом. В реальном времени можно наблюдать, сколько у нас в игре таких объектов, сколько они жрут процессорного времени на свой апдейт, и как вообще поживают, не зависли ли часом. Единственный момент, из-за того что выведение на худ вызывается внутри апдейта актора, система не обнаруживает зависание его биндера. Это делается извне, другими средствами. Хотя если у кого-то биндер актора зависнет это сразу станет видно по тому, что показания этой системы обо всех категориях объектов перестанут меняться.Решил выложить - вдруг кому пригодится, потому что держать именно эту систему до выхода "Судьбы Зоны" - смысла не вижу, вряд ли ТАМ она кому-то после релиза понадобится. Собственно код: local mks_count = 1000000 --- число микросекунд в одной секунде. profile_timer работает в микросекундах, если кто забыл. local binders = {} --- таблица хранящая контроллеры биндеров по категориям. --[[ ПРИМЕР ПОДКЛЮЧЕНИЯ БИНДЕРА: (или любого объекта у которого есть апдейт) в метод __init() добавляем в конец: self.tm_id = time_monitor.register_binder("xr_motivator") -- вместо xr_motivator свое имя скрипта в метод update(delta) time_monitor.binder_update_start("xr_motivator", self.tm_id) ... ваши действия ... time_monitor.binder_update_end("xr_motivator", self.tm_id) ]] function register_binder(binder_type) local btt = binders[binder_type] if btt then local new_id = #btt + 1 binders[binder_type][new_id] = time_monitor.binder_controller() return new_id else binders[binder_type] = {} binders[binder_type][1] = time_monitor.binder_controller() return 1 end end function binder_update_start(binder_type, id) binders[binder_type][id]:start() end function binder_update_end(binder_type, id) binders[binder_type][id]:stop() end function self_update() for k, v in pairs(binders) do for i, j in pairs(v) do j:set_0() end end end function clear() for k, v in pairs(binders) do local t = {} for i, j in pairs(v) do table.insert(t, i) end local a = 1 while t[a] ~= nil do local vk = t[a] v[vk] = nil a = a + 1 end end end function get_data() local r = {} local engine_time = mks_count for k, v in pairs(binders) do local count_normal = 0 local count_broken = 0 local stime = 0 for i, j in pairs(v) do local d = j:get() if d[1] or k == "actor_binder" then count_normal = count_normal + 1 stime = stime + d[2] else count_broken = count_broken + 1 end end local R_color = round(255 * stime / 50000) if R_color > 255 then R_color = 255 end local G_color = round((200000 - stime) * 0.00127) if G_color < 0 then G_color = 0 end if G_color > 255 then G_color = 255 end local B_color = round((100000 - stime) * 0.00255) if B_color < 0 then B_color = 0 end if B_color > 255 then B_color = 255 end if count_broken ~= 0 then B_color = 0 end r[k] = { [1] = string.format("Objects online: %i; Objects broken: %i; CPU Time: %G", count_normal, count_broken, stime / mks_count), [2] = {255, R_color, G_color, B_color} } engine_time = engine_time - stime end --r["engine"] = string.format("Engine CPU Time: %G", engine_time / mks_count) return r end class "binder_controller" function binder_controller:__init() self.status = true self.time = 0 self.timer = nil end function binder_controller:__finalize() self.timer = nil end function binder_controller:start() self.timer = profile_timer() self.timer:start() self.status = false end function binder_controller:stop() self.timer:stop() self.time = self.time + self.timer:time() self.status = true self.timer = nil end function binder_controller:get() return {self.status, self.time} end function binder_controller:set_0() self.time = 0 end local hud_statics = {} local hardware_monitor_timer = 0 local hardware_time_lcnt = nil function hardware_time_monitor(delta) local bar_back = "htm_back" if hud_statics[bar_back] then if hardware_monitor_timer > 1000 then local dt = time_monitor.get_data() hardware_time_lcnt = #dt time_monitor.self_update() local a = 1 for k, v in pairs(dt) do if hud_statics["htm_line_"..tostring(a)] then local nclr = v[2] hud_statics["htm_line_"..tostring(a)]:SetTextColor(nclr[1], nclr[2], nclr[3], nclr[4]) hud_statics["htm_line_"..tostring(a)]:SetFont(GetFontLetterica16Russian()) hud_statics["htm_line_"..tostring(a)]:SetText(string.format("%s:: %s",k,v[1])) else hud_statics["htm_line_"..tostring(a)] = CUIStatic() hud_statics["htm_line_"..tostring(a)]:Init(0, a * 18, 20, 16) hud_statics["htm_line_"..tostring(a)]:InitTexture("empty_texture") hud_statics["htm_line_"..tostring(a)]:SetStretchTexture(true) hud_statics[bar_back]:AttachChild(hud_statics["htm_line_"..tostring(a)]) end a = a + 1 end else hardware_monitor_timer = hardware_monitor_timer + delta if hardware_time_lcnt then local a = 1 while a < hardware_time_lcnt do if hud_statics["htm_line_"..tostring(a)] then --- не здесь else hud_statics["htm_line_"..tostring(a)] = CUIStatic() hud_statics["htm_line_"..tostring(a)]:Init(0, a * 18, 20, 16) hud_statics["htm_line_"..tostring(a)]:InitTexture("empty_texture") hud_statics["htm_line_"..tostring(a)]:SetStretchTexture(true) hud_statics[bar_back]:AttachChild(hud_statics["htm_line_"..tostring(a)]) end a = a + 1 end end end else hud_statics[bar_back] = CUIStatic() hud_statics[bar_back]:Init(600, 20, 156, 24) hud_statics[bar_back]:InitTexture("empty_texture") hud_statics[bar_back]:SetStretchTexture(true) get_hud():AddDialogToRender(hud_statics[bar_back]) end end После этого, в апдейт актора (или в под-систему, занимающуюся апдейтами на пониженных частотах, у кого есть), добавляем вызов hud_system.hardware_time_monitor(delta) Текстуру "empty_texture" можно создать в любом xml-файле описаний текстур, описав пустой участок, или подставить свое название текстуры какое хотите. И собственно все, можно пользоваться. Как подключить биндер/любой класс объекта к системе, смотрим инструкцию в time_monitor.script: ПРИМЕР ПОДКЛЮЧЕНИЯ БИНДЕРА: (или любого объекта у которого есть апдейт) в метод __init() добавляем в конец: self.tm_id = time_monitor.register_binder("xr_motivator") -- вместо xr_motivator свое имя скрипта в метод update(delta) time_monitor.binder_update_start("xr_motivator", self.tm_id) -- в самое начало функции. вместо xr_motivator свое имя скрипта ... ваши действия ... time_monitor.binder_update_end("xr_motivator", self.tm_id) -- в самый конец функции. вместо xr_motivator свое имя скрипта Собственно скриншот как это выглядит в игре (Судьба Зоны) Значения обновляются раз в секунду, цвет строчек меняется динамически в зависимости от состояния соответствующей категории объектов. Чем больше жрет - тем ближе к красно-оранжевому цвету. Чем меньше - тем ближе к светло-голубоватому. Цвет меняется для тех объектов среди которых есть "сломанные" - объекты у которых метод update отправил начальный вызов, но не добрался до финального. т.е. возможно произошел выход из функции где-то посередине, а возможно - зависание. Изменено 4 Апреля 2015 пользователем Zander_driver 1 3 7 Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на 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. Ссылка на комментарий
Simonov50 2 Опубликовано 6 Апреля 2015 Поделиться Опубликовано 6 Апреля 2015 Решил выложить - вдруг кому пригодится Спасибо. Пригодилось и очень.Хотя бы потому, что дало ответ на множество вопросов (вообще не освещённых в разделе ХУДа). Осталась лишь одна "непонятка". В чистой версии (от 1С) шрифты Letterica16Russian (и 18Russian)переназначены на текстуры Letter_16 (18), где русские символы тоже присутствуют. Конкретнее (из fonts.ltx):[ui_font_letterica16_russian]texture = ui\ui_font_letter_16_1024и т.д.Разницу в именах вижу, пойду разбираться с "кракозябрами".Ещё раз Спасибо! Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 15 Апреля 2015 Поделиться Опубликовано 15 Апреля 2015 (изменено) Внезапный такой вопрос: от чего зависит (и где вызывается) :load() для монстров ? Ибо внезапно обнаружил, что сэйв у меня для них отрабатывает, и что-то туда пишет, а вот load почему-то отрабатывает только для торговца. Собственно монстры - reinit() и сразу net_spawn(). Upd: эффект явно связан с se_monster, и вдумчивой ревизией я, наверное, и проблему найду. Но сама суть эффекта пока что загадочна. Изменено 16 Апреля 2015 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Карлан 1 049 Опубликовано 16 Апреля 2015 Поделиться Опубликовано 16 Апреля 2015 (изменено) Каковы ограничения движка на количество сохраняемой информации? Каким образом возможно сохранять неограниченные размеры? На сколько упадет скорость загрузки если сохранять где-то порядка 5-15Мб? @Elz, я не об этом. Изменено 16 Апреля 2015 пользователем Карлан Ссылка на комментарий
Elz 343 Опубликовано 16 Апреля 2015 Поделиться Опубликовано 16 Апреля 2015 (изменено) @Карлан, упадет намного (личные наблюдения), ибо чем дальше в лес, тем толще партизаны, сохранять приходится больше. Сейв из оп-2 весит макс мега 4, а там столько всего... А ты предлагаешь по 15 метров сохранять... Ужасно, бро.Нуок, del Пусть пост висит. Сам удалю. BFG Изменено 16 Апреля 2015 пользователем BFG Первый опыт в С++ (WinAPI) - небольшой текстовый редактор.Сборник книг по C++ | DX | WinAPI | Other на ЯДе Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 16 Апреля 2015 Поделиться Опубликовано 16 Апреля 2015 2 Карлан: вообще-то вопрос скорее в тему с++. Если сохранять/читать фиксированными блоками, причем в один файл - будет практически мгновенно. Построчно/побайтно - медленно и печально. Традиционно медленными являются сами вызовы/служебные операции, действия с 1000 файлов - это очень медленно. С 10000 - невменяемо. Операция с 1 байтом - не сильно быстрее операции с 100kb. Вообще, то, что мы видим как "загрузку игры" - это чтение много разных файлов (сравни с re-load на той же локации), а все остальное (вот этот самый re-load) - вычисления и всяческие многократные рекурсивные переборы разной ереси. Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Карлан 1 049 Опубликовано 16 Апреля 2015 Поделиться Опубликовано 16 Апреля 2015 @Dennis_Chikin, в этом мой вопрос и есть. Каким образом можно нормально сохранить, т.к. на этот самый re-load я это все повесить и хочу. Если нормального варианта не найдется, то тогда буду опять с опорой на xml, откуда при старте буду считывать основной вес данных. Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 16 Апреля 2015 Поделиться Опубликовано 16 Апреля 2015 (изменено) Вопрос весьма расплывчат. Даже непонятно, относится ли он к работе с файлами, или к организации данных. Как бы в идеале, чтобы все было быстро, у тебя должен быть организован непрерывный блок, скажем, полученный через malloc() (ну или массив таки блоков), который ты пишешь/читаешь через read() или pread() / write(), а потом накладываешь структуру, и разбираешь все в один проход. При этом, да, размер сэйва тебя волновать не должен от слова совсем - ты вряд-ли в данном случае выйдешь за ту границу, где он начнет реально влиять. И, да, взятую память ни кому никогда больше не отдавать. Это я тебе как человек, писавший/правивший всякие ata* и прочие burncd с raid'ами рекомендую. И забить на "совместимость" с 49.5битным процессором неведомого производителя, работающим на троичной логике, со старшим байтом в середине слова. Но, разумеется, тебе сейчас именно xmlы генерить/парсить и насоветуют, как "идеологически правильный" подход. Изменено 16 Апреля 2015 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Malandrinus 615 Опубликовано 16 Апреля 2015 Автор Поделиться Опубликовано 16 Апреля 2015 (изменено) Каковы ограничения движка на количество сохраняемой информации?Ограничения всем известны: 1. Сохранение только данных объектов. 2. Каждый объект сохраняет только один кусок данных в виде нетпакета 8 кб, куда также входят и его собственные данные. Итого чисто теоретически можно сохранить 8 кб * 64 кб = 512 Мб, но на практике конечно в разы меньше. И разумеется всё чанками по нескольку килобайт. Каким образом возможно сохранять неограниченные размеры?Предлагаю метод сохранения во внешнем файле. Главная задача - привязать внешний файл к конкретному сейву. Если всё сохранять в файл с конкретным именем, то последний сейв затрёт внешние данные предыдущего. Для решения этой проблемы можно при сохранении генерить случайное число или даже просто счётчик, который будет добавкой к постоянной части имени, далее удостовериться, что такого счётчика в каталоге сейвов нет, затем создать файл для добавочных данных и писать уже туда с использованием Lua. Само же число сохранить в сейве любым стандартным способом. При следующем сохранении сгенерить новое число и т.д. При загрузке сперва прочитать стандартными средствами это число-добавку, далее получить имя файла внешних данных и читать оттуда средствами Lua. На сколько упадет скорость загрузки если сохранять где-то порядка 5-15Мб?Не знаю, попробуй. Думаю, что при описанном способе не очень сильно просядет. Изменено 16 Апреля 2015 пользователем Malandrinus 1 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Карлан 1 049 Опубликовано 16 Апреля 2015 Поделиться Опубликовано 16 Апреля 2015 @Malandrinus, это все хорошо, только мне это надо сделать в движке. Конечно можно с помощью луабинда это сделать как-ты говоришь, но по моему это будет не комильфо учитывая тот функционал, хотя я не знаю на самом деле, только начинаю разбираться. Ссылка на комментарий
Malandrinus 615 Опубликовано 16 Апреля 2015 Автор Поделиться Опубликовано 16 Апреля 2015 @Карлан, в движке ты этого не сделаешь, учитывая все имеющиеся ограничения. И только не luabind, а Lua. Почему плох такой вариант? Есть конкретные причины? Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Карлан 1 049 Опубликовано 16 Апреля 2015 Поделиться Опубликовано 16 Апреля 2015 @Malandrinus, да почему сразу плох? Я в целом новичок, и просто пишу проконсультироваться. Я действительно не знаю как лучше было-бы хранить такие объемы. Теперь узнал, как технически реализовать знаю, спасибо. А луабинд я сказал к тому, что мне надо будет все эти данные в движке читать, либо как-то пересматривать реализацию в сторону полного скриптового управления, пока не знаю. Ссылка на комментарий
7.9 174 Опубликовано 16 Апреля 2015 Поделиться Опубликовано 16 Апреля 2015 (изменено) Главная задача - привязать внешний файл к конкретному сейву. Если всё сохранять в файл с конкретным именем, то последний сейв затрёт внешние данные предыдущего. Если имя файла с дополнительными данными будет совпадать с именем штатного сейва с добавкой постоянного суффикса - всё будет как надо - пара: штатный сейв + файл (связанных с ним) дополнительных данных. Пример: savename1.sav savename1db.sav savenameA.sav savenameAdb.sav Изменено 16 Апреля 2015 пользователем 7.9 1 1 всё легко Ссылка на комментарий
7.9 174 Опубликовано 16 Апреля 2015 Поделиться Опубликовано 16 Апреля 2015 (изменено) Если "дополнительные данные" связанны с "текущим состоянием игры", а они связанны, этот вариант самый оптимальный. Реализовать (давно) можно с использованием расширения Lua от RvP А хранить данных надо действительно много... Изменено 16 Апреля 2015 пользователем 7.9 всё легко Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 17 Апреля 2015 Поделиться Опубликовано 17 Апреля 2015 (изменено) Нет, ну если уж трогать непосредственно движок, то почему бы и не потрогать код сохранения/загрузки ? Весь вопрос в том, что именно мы хотим сохранять, и как оно выглядит внутри игры. Сохранению контекста объектов и нетпакетам - отказать. Сделать плоскую таблицу, иметь ее в виду как последовательный кусок памяти, и тупо писать/читать поблочно. Вот прямо в новосозданный сэйв. Ничего лучшего не придумали. Скорость будет выше, чем у копирования средствами системы. Изменено 17 Апреля 2015 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 17 Апреля 2015 Поделиться Опубликовано 17 Апреля 2015 Очередной забавный вопрос: se_monster:on_death() / se_stalker:on_death() при каких-то условиях вообще вызываются, или это кто-то просто для красоты добавил ? Так, я вообще не понял этого юмора... При net_destroy()/net_spawn(), то есть, при переходе offline/online, у монстров load() тоже не вызывается. Init() -> reload() -> reinit() -> netspawn(). По крайней мере в солянке. Это значит, что все, например, сохраненное в pstor - того... А в оригинале-то оно работает ? Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
abramcumner 1 141 Опубликовано 18 Апреля 2015 Поделиться Опубликовано 18 Апреля 2015 @Dennis_Chikin, нет, в оригинале тоже не работает. При переходе оффлайн/онлайн данные биндера очищаются. Не помогает даже function se_...:keep_saved_data_anyway() return true endИ так не только у монстров 1 Ссылка на комментарий
Карлан 1 049 Опубликовано 23 Апреля 2015 Поделиться Опубликовано 23 Апреля 2015 (изменено) Я весьма обеспокоен вопросом значения тега critical_wound_weights, собственно что и для чего? Я сделал вывод, что это влияет на отыгрывание анимаций при ранении, вроде тех что мы видим иногда как сталкер за живот хватается, или на колено падает. Если так, то буду рад узнать подробнее, сам не понял.Да. Каких здесь еще подробностей не хватает ? dc Изменено 8 Августа 2015 пользователем Dennis_Chikin Ссылка на комментарий
Graff46 598 Опубликовано 29 Августа 2015 Поделиться Опубликовано 29 Августа 2015 У класса sound_object есть метод property volume; // громкость Этим методом мы задаем или получаем громкость? Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти