C Minecraft'om дел не имел, честно говоря. Но, ассинхронное выполнение кода можна замутить, используя магию из PawnPlus под названием потоки. threaded(sync_explicit) и всё, что идёт внутри этого блока, будет выполняться ассинхронно. Тестировал на собственном примере, выполняя увесистый код прямиком в ином потоке(если точнее, то речь была о создании динамических объектов на рандомной позиции ежесекундно, причём, координаты основывались не на тех, что в массиве, а генерировались рандомным образом) и, по итогу, если выполнять всё это дело синхронно, то будет либо краш, либо бешенные пролаги, но ассинхронная же методика избавляет нас от этого и можно спокойно выполнять себе другие цели. Хотя, есть некие моменты, когда может быть достигнут эффект "гонки" и, исходя из этого, некоторые функции могут выполняться не последовательно, а хаотично. Хотя, будем честны, о ассинхронном программировании в Pawn я читал давно и потому, кое какие моменты, всё же стоило освежить в памяти. К тому же, threaded(sync_explicit) всего лишь макрос, работающий если определено соответствующее поведение(то бишь, определена директива поведения непосредственно), в ином же случае приходится использовать: thread_detach, чтобы отвязать весь последующий код от основного потока и потом, по завершении ассинхронного кода, нужно обратно его привязать к основному потоку, используя thread_attach.
Теперь, давай ближе к делу, ибо, учитывая мой заряд на ноуте, не знаю смогу ли я доделать это сейчас или, непосредственно, после зарядки. В любом случае, это будет сегодня.
Начнём, пожалуй, с начала, разобрав массив и элементы перечисления, отвечающие за метаданные для мебели.
Сам по себе масссив, как я тебе говорил, лучше всего сделать не двумерным(MAX_FURNITURES и структура), а непосредственно, трёхмерным, если известен лимит мебели на дом конечно. И, в конечном итоге, мы будем иметь такую картину:
Естественно, если лимит нам не известен и такой мебели, допустим, может быть тысяч десять условных, то загрузка в массив и последующее обращение к нему, может быть далеко не производительным. Единственный выход привязывать эти все метаданные непосредственно к созданному объекту мебели. Собственно, об этом далее и, к тому же, я слегка переделал структуру с метаданными, убрав кое какие элементы и также, саму архитектуру основной таблицы, распределив систему по нескольким таблицам.
#define MAX_FURNITURE_LOAD_DATA (9)
#define MAX_FURNITURE_ITEMS (55)
#define MAX_FURNITURE_ITEM_NAME_LEN (28)
#define MAX_FURNITURE_ON_PAGE (20)
enum E_FURNITURE_STRUCT
{
F_HOUSE_ID, /* идентификатор дома из базы данных, которому принадлежит мебель */
F_SLOT, /* слот(позиция) среди остальной мебели */
F_ID, /* ID мебели, для получения неких метаданных(её имени, модели объекта) о ней из массива. */
Float: F_POS_X, /* Координата X */
Float: F_POS_Y, /* Координата Y */
Float: F_POS_Z, /* Координата Z */
Float: F_POS_RX, /* Координата оси rX */
Float: F_POS_RY, /* Координата оси rY */
Float: F_POS_RZ /* Координата оси rZ */
}
enum E_FURNITURE_ITEM_STRUCT
{
FI_MODELID,
FI_NAME[MAX_FURNITURE_ITEM_NAME_LEN]
}
enum
{
FURNITURE_LOAD_TYPE_HOUSE,
FURNITURE_LOAD_TYPE_SLOT,
FURNITURE_LOAD_TYPE_ID,
FURNITURE_LOAD_TYPE_POS,
FURNITURE_LOAD_TYPE_ROT_POS = 6
}
enum E_HOUSE_FURN_OBJ_STRUCT
{
HFO_MIN,
HFO_MAX
}
enum E_PLAYER_FURN_STRUCT
{
PF_PAGE,
PF_COUNT_LISTED
}
new g_house_furn_obj[MAX_HOUSES][E_HOUSE_FURN_OBJ_STRUCT];
new g_player_furniture[MAX_PLAYERS][E_PLAYER_FURN_STRUCT];
new g_player_furniture_list[MAX_PLAYERS][MAX_FURNITURE_ON_PAGE];
new g_furniture_items[MAX_FURNITURE_ITEMS][E_FURNITURE_ITEM_STRUCT] =
{
// Бытовая техника
{1208, "Стиральная машина"},
{1518, "Телевизор, Чёрный"},
{1719, "DVD-Проигрыватель"},
{2099, "Музыкальный центр"},
{2149, "Микроволновка"},
{11743, "Кофеварка"},
{19786, "Телевизор [Плазма]"},
{19893, "Ноутбук"},
{19808, "Клавиатура"},
{2226, "BoomBox"},
// Ванная комната
{2514, "Унитаз"},
{2515, "Туалетная раковина"},
{2518, "Кухонная раковина"},
{2517, "Душевая кабинка"},
{2526, "Ванна"},
// Декорации
{1738, "Чугунная батарея"},
{1808, "Куллер с водой"},
{1829, "Открытый сейф"},
{2254, "Картина №-1"},
{2267, "Картина с титаником"},
{2275, "Картина с фруктами"},
{2332, "Закрытый сейф"},
{2737, "Доска"},
{2817, "Ковёр голубой с узорами"},
{2824, "Книги"},
{2826, "Журналы"},
{3077, "Стенд"},
{11728, "Навесной телефон"},
// Диваны/кровати
{1701, "Кровать №-1"},
{1712, "Диван"},
{1767, "Кресло"},
{14866, "Кровать №-2 (Элитная)"},
// Кухонная мебель
{2013, "Кухонная мебель №-1"},
{2014, "Кухонная мебель №-2"},
{2015, "Кухонная мебель №-3"},
{2016, "Кухонная мебель №-4"},
{2017, "Кухонная мебель №-5 (Плита)"},
{11706, "Мусорное ведро"},
// Освещение
{1734, "Круглая лампа"},
{2023, "Настольная лампа"},
{19806, "Люстра"},
// Столы, Стулья
{1433, "Стол №-1"},
{1516, "Стол №-2"},
{1663, "Кабинетное кресло"},
{1720, "Стул кухонный"},
{1827, "Стеклянный стол"},
{2086, "Стеклянный стол №-2"},
{2125, "Барный стул"},
{2086, "Стеклянный стол №-2"},
// Шкафы, Тумбы
{912, "Тумбочка"},
{2025, "Шкаф"},
{2091, "Шкаф с телевизором"},
{2161, "Книжная полка"},
{2608, "Книжная полка №-2"},
// Прочее
{2919, "Мешок"}
};
stock IsFurnitureIDValid(furnitureid)
return (0 <= furnitureid <= (sizeof g_furniture_items - 1));
stock GetFurnitureItemModelID(furnitureid)
{
if(!IsFurnitureIDValid(furnitureid))
return 0;
return g_furniture_items[furnitureid][FI_MODELID];
}
stock GetFurnitureItemName(furnitureid, const buffer[])
{
if(!IsFurnitureIDValid(furnitureid))
return 0;
return format
(
buffer, MAX_FURNITURE_ITEM_NAME_LEN,
"%s",
g_furniture_items[furnitureid][FI_NAME]
);
}
stock IsHouseFirstFurnObject(houseid)
return (g_house_furn_obj[houseid] == 0);
stock SetHouseMinFurnObjectID(houseid, objectid)
return g_house_furn_obj[houseid][HFO_MIN] = objectid;
stock SetHouseMaxFurnObjectID(houseid, objectid)
return g_house_furn_obj[houseid][HFO_MAX] = objectid;
stock CreateHouseFurniture(houseid, slot, furnitureid, Float: pos_x, Float: pos_y, Float: pos_z,
Float: pos_rx, Float: pos_ry, Float: pos_rz, is_furniture_last)
{
new objectid = CreateDynamicObject
(
GetFurnitureItemModelID(furnitureid),
pos_x,
pos_y,
pos_z,
pos_rx,
pos_ry,
pos_rz,
.worldid = houseid
);
if(!IsValidDynamicObject(objectid))
return 0;
if(IsHouseFirstFurnObject(houseid))
SetHouseMinFurnObjectID(houseid, objectid);
if(is_furniture_last)
SetHouseMaxFurnObjectID(houseid, objectid);
new fmt_str[] = "%d %d %d %.4f %.4f %.4f %.4f %.4f %.4f",
result_str[sizeof fmt_str +
(- 4 + 20) +
(- 2 + 5) +
(- 24 + 54)];
format
(
result_str, sizeof result_str,
fmt_str,
houseid,
slot,
furnitureid,
pos_x,
pos_y,
pos_z,
pos_rx,
pos_ry,
pos_rz
);
return Streamer_SetArrayData
(
STREAMER_TYPE_OBJECT,
objectid,
E_STREAMER_EXTRA_ID,
result_str
);
}
stock GetPlayerFurniturePage(playerid)
return g_player_furniture[playerid][PF_PAGE];
stock ClearPlayerFurnData(playerid)
{
new player_furn_empty_data[E_PLAYER_FURN_STRUCT];
return g_player_furniture[playerid] = player_furn_empty_data;
}
stock ClearPlayerFurnListData(playerid)
{
for(new idx; idx < sizeof g_player_furniture_list[]; idx ++)
g_player_furniture_list[playerid][idx] = 0;
return 1;
}
stock IsFurnitureListIndexValid(index)
return (0 <= index <= (sizeof g_player_furniture_list[] - 1));
stock GetPlayerFurnitureListIndex(playerid, index)
{
if(!IsFurnitureListIndexValid(index))
return 0;
return g_player_furniture_list[playerid][index];
}
stock SetPlayerFurnitureListIndex(playerid, index, value)
{
if(!IsFurnitureListIndexValid(index))
return 0;
return g_player_furniture_list[playerid][index] = value;
}
stock GetPlayerFurnListFirstIndex(playerid)
return GetPlayerFurnitureListIndex(playerid, 0);
stock GetPlayerFurnitureListLastIndex(playerid)
return GetPlayerFurnitureListIndex(playerid, (sizeof g_player_furniture_list[] - 1));
stock AddPlayerCountListedFurniture(playerid, count)
return g_player_furniture[playerid][PF_COUNT_LISTED] += count;
stock DivPlayerCountListedFurniture(playerid, count)
return g_player_furniture[playerid][PF_COUNT_LISTED] -= count;
stock GetPlayerCountListedFurniture(playerid)
return g_player_furniture[playerid][PF_COUNT_LISTED];
stock IncrementPlayerFurniturePage(playerid)
return g_player_furniture[playerid][PF_PAGE] ++;
stock DecrementPlayerFurniturePage(playerid)
return g_player_furniture[playerid][PF_PAGE] --;
/* Почему именно цикл, а не разницу между наибольшим и наименьшим? Ответ прост: а что, если мы, допустим,
решим продать(хотя, у тебя пока нет этой системы) какую то мебель из диапазона и тем, самым объект удалится
и допустим, возлагая бы мы надежды на разницу между числами, мы бы получили не то число, что нам нужно.
К тому же, стоит не забывать после каких-либо действий, уничтожающих минимальный/максимальный из объектов
мебели, присваивать на его место либо следующий, если это минимальный объект, иначе предыдущий. */
stock GetHouseCountOfFurniture(houseid)
{
new count,
furn_data[E_FURNITURE_STRUCT],
fmt_buffer[] = "%d %d %d %.4f %.4f %.4f %.4f %.4f %.4f",
buffer[sizeof fmt_buffer +
(- 4 + 20) +
(- 2 + 5) +
(- 24 + 54)];
for(new idx = GetHouseMinFurnObjectID(houseid), size = GetHouseMaxFurnObjectID(houseid); idx < size; idx ++)
{
Streamer_GetArrayData(STREAMER_TYPE_OBJECT, idx, E_STREAMER_EXTRA_ID, buffer);
sscanf(buffer, "e<dddffffff>", furn_data[F_HOUSE_ID], furn_data[F_SLOT], furn_data[F_ID], furn_data[F_POS_X], furn_data[F_POS_Y], furn_data[F_POS_Z], furn_data[F_POS_RX], furn_data[F_POS_RY], furn_data[F_POS_RZ]);
if(furn_data[F_HOUSE_ID] != houseid)
continue;
count ++;
}
return count;
}
stock ShowPlayerInfoAboutFurnDialog(playerid, index)
{
new fmt_str[] =
{
"ID дома: %d\n"\
"Слот мебели: %d\n"\
"Модель мебели: %d\n"\
"Название мебели: %s\n"\
"Позиция по X: %.4f\n"\
"Позиция по Y: %.4f\n"\
"Позиция по Z: %.4f\n"\
"Позиция по rX: %.4f\n"\
"Позиция по rY: %.4f\n"\
"Позиция по rZ: %.4f"
},
result_str[sizeof fmt_str +
(- 4 + 20) +
(- 2 + 5) +
(- 2 + (MAX_FURNITURE_ITEM_NAME_LEN - 1)) +
(- 24 + 54)],
objectid = GetPlayerFurnitureListIndex(playerid, index),
furn_data[E_FURNITURE_STRUCT],
fmt_buffer[] = "%d %d %d %.4f %.4f %.4f %.4f %.4f %.4f",
buffer[sizeof fmt_buffer +
(- 4 + 20) +
(- 2 + 5) +
(- 24 + 54)];
Streamer_GetArrayData(STREAMER_TYPE_OBJECT, objectid, E_STREAMER_EXTRA_ID, buffer);
sscanf(buffer, "e<dddffffff>", furn_data[F_HOUSE_ID], furn_data[F_SLOT], furn_data[F_ID], furn_data[F_POS_X], furn_data[F_POS_Y], furn_data[F_POS_Z], furn_data[F_POS_RX], furn_data[F_POS_RY], furn_data[F_POS_RZ]);
new modelid = GetFurnitureItemModelID(furn_data[F_ID]),
name[MAX_FURNITURE_ITEM_NAME_LEN];
GetFurnitureItemName(furn_data[F_ID], name);
format
(
result_str, sizeof result_str,
fmt_str,
furn_data[F_HOUSE_ID],
furn_data[F_SLOT],
modelid,
name,
furn_data[F_POS_X], furn_data[F_POS_Y], furn_data[F_POS_Z],
furn_data[F_POS_RX], furn_data[F_POS_RY], furn_data[F_POS_RZ]
);
return ShowPlayerDialog
(
playerid, DIALOG_INFO_FURNITURE, DIALOG_STYLE_LIST,
"{FFFFFF}Информация о мебели",
result_str,
"{bcbcbc}Закрыть", ""
);
}
stock ShowPlayerFurnitureListDialog(playerid, bool: is_first_page = true, bool: is_page_prev = false)
{
if(IsHouseFirstFurnObject(/* тут ид дома игрока */))
return SendClientMessage(playerid, -1, "У вашего дома нет мебели");
new fmt_str[] = "{ffd966}%d",
result_str[sizeof fmt_str + (- 2 + 10)],
dest[sizeof result_str * MAX_FURNITURE_ON_PAGE] =
idx = -1,
page = GetPlayerBusinessPage(playerid),
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
if(is_page_prev == false)
{
if(is_first_page == false)
{
IncrementPlayerBusinessPage(playerid);
page = GetPlayerBusinessPage(playerid);
}
for(new i = GetHouseMinFurnObjectID(/* ид дома игрока */, end = GetHouseMaxFurnObjectID(/* ид дома игрока */); i <= end; i ++)
{
if(idx == (sizeof g_player_furniture_list[] - 1))
break;
if(i < GetPlayerFurnitureListLastIndex(playerid))
continue;
SetPlayerFurnitureListIndex(playerid, ++ idx, i);
format(result_str, sizeof result_str, fmt_str, i);
strcat(dest, result_str);
}
if(!idx)
return SendClientMessage(playerid, -1, "У Вашего дома нет мебели");
AddPlayerCountListedFurniture(playerid, idx + 1);
}
else
{
idx = MAX_FURNITURE_ON_PAGE;
new count_of_furn;
for(new end = GetHouseMaxFurnObjectID(/* ид дома игрока */); end >= GetHouseMinFurnObjectID(/* ид дома игрока */; end --)
{
if(end > GetPlayerFurnListFirstIndex(playerid))
continue;
if(!idx)
break;
SetPlayerFurnitureListIndex(playerid, -- idx, end);
count_of_furn ++;
}
for(new j; j < count_of_furn; j ++)
{
format(result_str, sizeof result_str, fmt_str, GetPlayerFurnitureListIndex(playerid, j));
strcat(dest, result_str);
}
DivPlayerCountListedFurniture(playerid, count_of_furn);
}
new count = GetHouseCountOfFurniture(/* ид дома игрока */);
if(GetPlayerCountListedFurniture(playerid) != count)
strcat(dest, "\n{93c47d}>>>\t\t");
if(page)
strcat(dest, "\n{f44336}<<<\t\t");
new fmt_buffer[] = "Список мебели вашего дома [%d/%d]",
buffer[sizeof fmt_buffer + (- 4 + 6)],
result = (count % MAX_BUSINESS_ON_PAGE != 0 ? 1 : 0);
format
(
buffer, sizeof buffer,
fmt_buffer,
page + 1,
((count / MAX_BUSINESS_ON_PAGE) + result)
);
return ShowPlayerDialog
(
playerid, DIALOG_FURNITURE_MAIN, DIALOG_STYLE_LIST,
buffer,
dest,
"Выбрать", "Закрыть"
);
}
/* В OnGameModeInit */
@__OnLoadFurniture();
@__OnLoadFurniture()
{
new Cache: query_result = mysql_query
(
/* ид соединения */,
"SELECT COUNT(*) AS count_furniture FROM houses_furniture"
),
count_furniture;
cache_get_value_name_int(0, "count_furniture", count_furniture);
cache_delete(query_result);
new furn_data[E_FURNITURE_STRUCT],
fmt_str[] =
{
"(SELECT hf.house_id AS object1,NULL AS object2,NULL AS object3,NULL AS object4,NULL AS object5"\
" FROM houses_furniture hf LEFT JOIN houses h ON hf.house_id=h.house_id"\
" WHERE hf.house_id > %d LIMIT 1)"\
" UNION ALL"\
" (SELECT hfs.house_id,hfs.slot,NULL,NULL,NULL FROM houses_furniture_slots hfs"\
" LEFT JOIN houses h ON hfs.house_id=h.house_id"\
" WHERE hfs.house_id > %d LIMIT 1)"\
" UNION ALL"\
" (SELECT hfi.house_id,hfi.slot,hfi.furniture_id,NULL,NULL FROM houses_furniture_ids hfi"\
" LEFT JOIN houses_furniture_slots hfs ON hfi.house_id=hfs.house_id AND hfi.slot=hfs.slot"\
" WHERE hfi.house_id > %d AND hfi.slot > %d LIMIT 1)"\
" UNION ALL"\
" (SELECT hfp.house_id,hfp.slot,hfp.pos_x,hfp.pos_y,hfp.pos_z FROM houses_furniture_positions hfp"\
" LEFT JOIN houses_furniture_slots hfs ON hfp.house_id=hfs.house_id AND hfp.slot=hfs.slot"\
" WHERE hfp.house_id > %d AND hfp.slot > %d LIMIT 1)"\
" UNION ALL"\
" (SELECT hfrp.house_id,hfrp.slot,hfrp.r_pos_x,hfrp.r_pos_y,"\
"hfrp.r_pos_z FROM houses_furniture_rot_positions hfrp"\
" LEFT JOIN houses_furniture_slots hfs ON hfrp.house_id=hfs.house_id AND hfrp.slot=hfs.slot"\
" WHERE hfrp.house_id > %d AND hfrp.slot > %d LIMIT 1)"
},
result_str[sizeof fmt_str + (- 10 + 50) + (- 6 + 30)];
for(new idx; idx < count_furniture; idx ++)
{
format
(
result_str, sizeof result_str,
fmt_str,
furn_data[F_HOUSE_ID],
furn_data[F_HOUSE_ID],
furn_data[F_HOUSE_ID],
furn_data[F_SLOT],
furn_data[F_HOUSE_ID],
furn_data[F_SLOT],
furn_data[F_HOUSE_ID],
furn_data[F_SLOT]
);
query_result = mysql_query(/* ид соединения */, result_str);
for(new j; j < MAX_FURNITURE_LOAD_DATA; j ++)
{
if(FURNITURE_LOAD_TYPE_POS <= j <= (FURNITURE_LOAD_TYPE_POS + 2))
{
cache_get_value_name_float(j, "object3", furn_data[F_POS_X]);
cache_get_value_name_float(j, "object4", furn_data[F_POS_Y]);
cache_get_value_name_float(j, "object5", furn_data[F_POS_Z]);
}
if(FURNITURE_LOAD_TYPE_ROT_POS <= j <= (FURNITURE_LOAD_TYPE_ROT_POS + 2))
{
cache_get_value_name_float(j, "object3", furn_data[F_POS_RX]);
cache_get_value_name_float(j, "object4", furn_data[F_POS_RY]);
cache_get_value_name_float(j, "object5", furn_data[F_POS_RZ]);
}
switch(j)
{
case FURNITURE_LOAD_TYPE_HOUSE:
cache_get_value_name_int(j, "object1", furn_data[F_HOUSE_ID]);
case FURNITURE_LOAD_TYPE_SLOT:
cache_get_value_name_int(j, "object2", furn_data[F_SLOT]);
case FURNITURE_LOAD_TYPE_ID:
cache_get_value_name_int(j, "object3", furn_data[F_ID]);
}
CreateHouseFurniture
(
furn_data[F_HOUSE_ID],
furn_data[F_SLOT],
furn_data[F_ID],
furn_data[F_POS_X], furn_data[F_POS_Y], furn_data[F_POS_Z],
furn_data[F_POS_RX], furn_data[F_POS_RY], furn_data[F_POS_RZ],
(idx == (count_furniture - 1))
);
}
}
return printf("<МЕБЕЛИ ЗАГРУЖЕНО>: [%d]", count_furniture);
}
public OnDialogResponse(playerid, dialogid, response, listitem, const inputtext[])
{
switch(dialogid)
{
case DIALOG_FURNITURE_MAIN:
{
if(response)
{
if(!strcmp(inputtext, ">>>", true))
return ShowPlayerBusinessListDialog(playerid, false);
if(!strcmp(inputtext, "<<<", true))
return ShowPlayerBusinessListDialog(playerid, false, true);
return ShowPlayerInfoAboutBusinDialog(playerid, listitem);
}
ClearPlayerFurnData(playerid);
return ClearPlayerFurnList(playerid);
}
}
return 1;
}
Собственно, тебе остаётся лишь создать диалоги с соответствующим именем. Думаю, суть запроса объяснять не нужно, ибо ты более-менее разбираешься в MYSQL. По логике вещей, код должен работать. Так, как я не знал лимита мебели для дома, то решил привязать данные непосредственно к объекту. Сегодня у меня уже не осталось сил объяснять, если честно, возможно завтра. Хотя, тут нечего объяснять, ибо это, по сути дела, идентичный код. Вопрос, скорее, в работоспособности, ибо я его не тестировал и, в целом, делал, не имея базовой идеи. Архитектура таблиц, думаю, ясна. Если, по традиции, будут нюансы, то можешь писать, ибо повторяю: я его не тестировал