![]() |
Здравствуйте, гость ( Вход | Регистрация )
![]() |
![]()
Сообщение
#1
|
|
Level 9 ![]() Класс: Волшебник Характер: Chaotic Good Раса: Дракон NWN: Скриптинг [PW] ![]() |
Вопрос для обсуждения - как сделать крафтовый движок, достаточно гибкий, удобный в обновлении и, самое главное, не приводящий к лагам.
Самый распространенный вариант - делать все рецепты для крафта через .2da файлы. И обновлять удобно (достаточно на сервер выложить новую версию файлов и )желательно) перегрузить модуль). Но есть и проблемы. 2да таблицы хороши, пока число строк в ней невелико. С ростом файла задержки становяться просто недопустимыми и нужно придумывать что-то другое. Хороший вариант - использовать внешнюю БД (mySQL например) и делать через нее. Будет быстрее и довольно гибко (обновлять рецепты можно даже через веб-интерфейс, не перегружая модуль). Только есть свои "если". Если хостер прикрутит поддержку mySQL и поставит саму mySQL. Хочу предложить другой вариант, в чем-то менее удобный, но заметно более быстрый. Идея простая. Пусть все рецепты хранятся в тех-же 2да файлах (не важно в чем соб-но). Пишется простой скрипт (программа) (я использовал perl), который преобразует таблицу в .nss скрипт, готовый для компиляции. Его можно вставить в модуль, а для обновления можно просто класть новую версию в папку override на сервере, не меняя сам модуль. Что должен делать такой скрипт, на примере. Вот кусок реальной 2da-таблицы (список ресурсов-спавнов, с Мидгарда) Код 2DA V2.0 Name FullName FullName2 ResRef Price Spawn TTL Radius Search Spot MaxValue MaxCount DC Desc 0 min020 "Торф" "торфа" "_res_min020" 1 2 6000 5 6 **** 5 48 8 "Торф._Применяется_для_выплавки_слитков_и_сплавов_из_руды." 1 min022 "Уголь" "угля" "_res_min022" 15 1 6000 4 12 **** 7 25 12 "Каменный_уголь._Применяется_для_выплавки_слитков_и_сплавов_из_руды." 2 min013 "Болотное_железо" "железа" "_res_min013" 1 2 6000 2 10 **** 8 30 10 "Железная_руда_невысокого_качества" [...skip...] Описывается имя резурса, русское имя, имя в падеже, ресреф, шансы на спавн, место спаван (поверхность\подземелье\везде), время жизни спавна, радиус обнаружения ресурса, DC на search, spot, на добычу, максимальное качество и количество ресурса в спавне и описание. После работы скрипта получаем вот такой скрипт Код string _res_i() { object oI = GetWaypointByTag("mg_wp_i"); if (GetIsObjectValid(oI)) return GetName(oI); else return "Я"; } //return count of resources int _cra_GetMaxRes(); struct stRes { string Name,FullName,FullName2,ResRef, Desc; int Price, Spawn, TTL, Radius, Search, Spot, MaxValue, MaxCount, DC, Result; }; struct stRes _cra_GetRes(int nNumber) { struct stRes stResult; if (!nNumber || nNumber > _cra_GetMaxRes()) { stResult.Result = 0; return stResult; } switch (nNumber) { case 1: stResult.Name = "min020"; stResult.FullName = "Торф"; stResult.FullName2 = "торфа"; stResult.ResRef = "_res_min020"; stResult.Price = 1; stResult.Spawn = 2; stResult.TTL = 6000; stResult.Radius = 5; stResult.Search = 6; stResult.Spot = 0; stResult.MaxValue = 5; stResult.MaxCount = 48; stResult.DC = 8; stResult.Desc = "Торф. Примен"+_res_i()+"етс"+_res_i()+" дл"+_res_i()+" выплавки слитков и сплавов из руды."; stResult.Result = 1; break; case 2: stResult.Name = "min022"; stResult.FullName = "Уголь"; stResult.FullName2 = "угл"+_res_i()+""; stResult.ResRef = "_res_min022"; stResult.Price = 15; stResult.Spawn = 1; stResult.TTL = 6000; stResult.Radius = 4; stResult.Search = 12; stResult.Spot = 0; stResult.MaxValue = 7; stResult.MaxCount = 25; stResult.DC = 12; stResult.Desc = "Каменный уголь. Примен"+_res_i()+"етс"+_res_i()+" дл"+_res_i()+" выплавки слитков и сплавов из руды."; stResult.Result = 1; break; case 3: stResult.Name = "min013"; stResult.FullName = "Болотное железо"; stResult.FullName2 = "железа"; stResult.ResRef = "_res_min013"; stResult.Price = 1; stResult.Spawn = 2; stResult.TTL = 6000; stResult.Radius = 2; stResult.Search = 10; stResult.Spot = 0; stResult.MaxValue = 8; stResult.MaxCount = 30; stResult.DC = 10; stResult.Desc = "Железна"+_res_i()+" руда невысокого качества"; stResult.Result = 1; break; [...skip...] return stResult; } int _cra_GetMaxRes() { return 3; } Данный вариант - инклуд (можно делать и вызываемый скрипт), возвращает структуру по номеру и количество ресурсов. Вставляем этот файл в папку с открытым модулем, компилим. Скорость работы - выше сложнее придумать, ведь мегабайтные файлы с АИ мобов выполняются шустро, а тут объемы гораздо меньше и все данные статичны. Аналогично можно поступить с любой 2да-таблицей. Как уже говорил - не обязаетельно делать вариант с инклудом полученного скрипта в другой, можно создавать полноценный скрипт с main() функцией и передавать в него параметры через SetLocalInt(GetModule()...), ExecuteScript("..",) и потом так-же получать результат - GetLocalInt(GetModule()...) В моем случае все скрипты писались под определенные 2да-таблицы, но легко можно сделать унифицированный скрипт, который будет работать очень похоже на функцию чтения данных из 2да-файла. Что в итоге: минусы: * дополнительный этап при сборке модуля, если изменились таблицы - компиляция 2да-таблиц в скрипты. * меньшая гибкость по сравнению с mySQL -вариантом в плане обновления плюсы: * скорость. выше - сложнее придумать, а для шарда это очень важно * не нужны спец. условия для хостинга * простота и универсальность (хоть и проигрывает в этом простому варианту с 2да-файлами) Предлагаю обсудить другие варианты и отвечу на вопросы - если будут (IMG:style_emoticons/kolobok_light/smile.gif) Сообщение отредактировал _kaa_ - Jun 17 2004, 11:07 |
![]() ![]() |
Текстовая версия | Сейчас: 27th April 2025 - 15:47 |