Самый распространенный вариант - делать все рецепты для крафта через .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да-файлами)
Предлагаю обсудить другие варианты и отвечу на вопросы - если будут
