Вопросы

phizlfs
Освоившийся

Привет! Решил добавить себе в мод систему инвентаря, взятую с одного из форумов. Всё работает хорошо, но не могу понять как всё это дело сохранять.
Тема: *клик* (Не реклама)

Очень надеюсь на помощь, заранее огромное спасибо!

Поделиться сообщением


Ссылка на сообщение

21 ответ на этот вопрос

  • 0
Sleash
Завсегдатый

@phizlfs 

Вот код загрузки и сохранения инвентаря через БД с комментариями и разъяснениями:
 

Спойлер

#define DB_TABLE_ACCOUNTS       "Accounts"      // Таблица с данными игроков    // Заменить на свою
#define DB_COLUMN_INVENTORY     "Inventory"     // Столбец с данными инвентаря  // Заменить на свой
#define DB_COLUMN_NICKNAME      "Name"          // Столбец с ником игрока       // Заменить на свой

stock GN(playerid) { // Функция для получения ника игрока
    new funcNN[MAX_PLAYER_NAME]; // Создаём переменную для временого хранения ника
    GetPlayerName(playerid,funcNN,MAX_PLAYER_NAME); // Получаем ник игрока
    return funcNN; // Возвращаем ник игрока
}
stock SaveInventory(playerid) { // Функция для сохранения инвентаря игрока
    new str_inv[INVENTORY_MAX_SLOT*(4+4+1+1)+1]; // Создаём строку с данными инвентаря
    // 4 - макс. значение ID предмета (если кол-во предметов дойдёт до 1000+)
    // 4 - макс. значение кол-ва предмета (если можно будет стаковать до 1000+)
    // 1 - выделение ячейки на запятую между ID и кол-вом предмета
    // 1 - выделение ячейки на вертикальную черту для разметки ID слотов
    // 1 - выделение ячейки на символ завершения строки - '\0'
    for(new i = 0; i < INVENTORY_MAX_SLOT; i++) { // перебираем все слоты игрока
        format(str_inv, sizeof(str_inv), "%s|%d,%d", str_inv, pInventoryData[playerid][idItem][i], pInventoryData[playerid][idAmount][i]);
        // Инвентарь будет храниться так: id_предмета,кол-во_предмета|след.слот...
    } strdel(str_inv,0,1); // убираем ненужный первый знак '|'. Как по мне это лучше чем проверка на номер элемента при переборе
    new str_query[sizeof(str_inv) + 100]; // создаём строку для запроса в БД. 100 - примерная доп. длина запроса
    // Форматируем запрос для дальнейшего обращения в БД:
    format(str_query, sizeof(str_query), "UPDATE `%s` SET `%s` = '%s' WHERE `%s` = '%s'", DB_TABLE_ACCOUNTS, DB_COLUMN_INVENTORY, str_inv, DB_COLUMN_NICKNAME, GN(playerid));
    mysql_query(1, str_query, false); // отправляем данные в БД без использование кэша
    return 1;
}
stock strsub(text[], sub_char, new_char = ' ') { // Функция для замены символов в строке
    // Если новый символ не указан, то он будет пробелом
    new subed = 0; // Создаём переменную для подсчёта заменённых символов
    for(new i = 0; i < strlen(text); i++) { // перебираем все символы текста
        if(text[i] == sub_char) ++subed, text[i] = new_char; // Если символ тот, который надо заменить, заменяем на нужный
    }
    return subed; // Возвращаем кол-во заменённых символов
}
stock LoadInventory(playerid) { // Функция для загрузки инвентаря игрока
    new str_inv[INVENTORY_MAX_SLOT*(4+4+1+1)+1]; // Создаём строку с данными инвентаря
    // Заодно её можно и использовать для запроса
    // Форматируем запрос для дальнейшего обращения в БД:
    format(str_inv, sizeof(str_inv), "SELECT `%s` FROM `%s` WHERE `%s` = '%s' LIMIT 1", DB_TABLE_ACCOUNTS, DB_COLUMN_INVENTORY, DB_COLUMN_NICKNAME, GN(playerid));
    new Cache:inv_cache = mysql_query(1, str_inv, true); // отправляем данные в БД с использованием кэша
    if(!cache_get_row_count(1)) return false; // Запрос не дал результата
    cache_get_row(0, 0, str_inv); // Получаем строку с данными инвентаря в str_inv
    cache_delete(inv_cache); // Можем удалять кеш за ненадобностью
    strsub(str_inv, '|'); // Заменяем все вертикальные черточки на пробел (т. к. он стоит по умолчанию)
    new str_inv_slots[INVENTORY_MAX_SLOT][4+4+1+1]; // Создаём переменную для записи каждого слота инвентаря
    // 4 - на максимаольный ID предмета (если дойдёт до 1000+)
    // 4 - на максимаольное кол-во предмета (если будет стакаться до 1000+)
    // 1 - на запятую между кол-вом и ID
    // 1 - на символ окончания строки - '\0'
    new str_for_sscanf[10+2+2+1]; // создание строки для sscanf
    format(str_for_sscanf, sizeof(str_for_sscanf), "a<s[%d]>[%d]", sizeof(str_inv_slots[]), sizeof(str_inv_slots));
    sscanf(str_inv, str_for_sscanf, str_inv_slots); // получаем данные слотов в str_inv_slots
    for(new i = 0; i < INVENTORY_MAX_SLOT; i++) { // Переьираем все слоты
        // Получаем данные предметов инвентаря в переменные игрока:
        sscanf(str_inv_slots[i], "p<,>ii", pInventoryData[playerid][idItem][i], pInventoryData[playerid][idAmount][i]);
    }
}

 

вот же код без комментариев, который сразу можно внедрять в мод:
 

Спойлер

#define DB_TABLE_ACCOUNTS       "Accounts"
#define DB_COLUMN_INVENTORY     "Inventory"
#define DB_COLUMN_NICKNAME      "Name"
stock GN(playerid){new funcNN[MAX_PLAYER_NAME];GetPlayerName(playerid,funcNN,MAX_PLAYER_NAME);return funcNN;}
stock SaveInventory(playerid) { 
    new str_inv[INVENTORY_MAX_SLOT*(4+4+1+1)+1];
    for(new i = 0; i < INVENTORY_MAX_SLOT; i++) format(str_inv, sizeof(str_inv), "%s|%d,%d", str_inv, pInventoryData[playerid][idItem][i], pInventoryData[playerid][idAmount][i]);
    strdel(str_inv,0,1); new str_query[sizeof(str_inv) + 100];
    format(str_query, sizeof(str_query), "UPDATE `%s` SET `%s` = '%s' WHERE `%s` = '%s'", DB_TABLE_ACCOUNTS, DB_COLUMN_INVENTORY, str_inv, DB_COLUMN_NICKNAME, GN(playerid));
    mysql_query(1, str_query, false);
    return 1;
}
stock strsub(text[], sub_char, new_char = ' ') {
    new subed = 0;
    for(new i = 0; i < strlen(text); i++){if(text[i]==sub_char){++subed,text[i]=new_char;}}
    return subed;
}
stock LoadInventory(playerid) { 
    new str_inv[INVENTORY_MAX_SLOT*(4+4+1+1)+1];
    format(str_inv, sizeof(str_inv), "SELECT `%s` FROM `%s` WHERE `%s` = '%s' LIMIT 1", DB_TABLE_ACCOUNTS, DB_COLUMN_INVENTORY, DB_COLUMN_NICKNAME, GN(playerid));
    new Cache:inv_cache = mysql_query(1, str_inv, true);
    if(!cache_get_row_count(1)) return false;
    cache_get_row(0, 0, str_inv),cache_delete(inv_cache),strsub(str_inv, '|');
    new str_inv_slots[INVENTORY_MAX_SLOT][4+4+1+1], str_for_sscanf[10+2+2+1]; 
    format(str_for_sscanf, sizeof(str_for_sscanf), "a<s[%d]>[%d]", sizeof(str_inv_slots[]), sizeof(str_inv_slots));
    sscanf(str_inv, str_for_sscanf, str_inv_slots); 
    for(new i = 0; i < INVENTORY_MAX_SLOT; i++) sscanf(str_inv_slots[i], "p<,>ii", pInventoryData[playerid][idItem][i], pInventoryData[playerid][idAmount][i]);
}

 

Не забудьте изменить название ячеек базы данных на своё, а так же создать слобец для хранения информации инвентаря
Если что его можно сделать таким запросом в базе данных:

ALTER TABLE `Таблица с акк-ами` ADD `Столбец с данными инвентаря` TEXT NOT NULL;
-- Пример:
ALTER TABLE `Accounts` ADD `Inventory` TEXT NOT NULL;

 

Поделиться сообщением


Ссылка на сообщение
  • 0
phizlfs
Освоившийся

Огромное Вам спасибо!

 ADD `Inventory` TEXT NOT NULL; создавать любое имя, или такое, какое прописано в теме на другом форуме? (если это там есть, может я что-то не понял)

Поделиться сообщением


Ссылка на сообщение
  • 0
phizlfs
Освоившийся

Добавил всё в точности как написали вы, сохранение не работало. Попробовал добавить в /additem сток SaveInventory(playerid). Начало выдавать эти огибки:
 

C:\Users\phuzl\Desktop\INV\gamemodes\edit.pwn(29004) : error 012: invalid function call, not a valid address
C:\Users\phuzl\Desktop\INV\gamemodes\edit.pwn(29004) : warning 215: expression has no effect
C:\Users\phuzl\Desktop\INV\gamemodes\edit.pwn(29004) : warning 215: expression has no effect
C:\Users\phuzl\Desktop\INV\gamemodes\edit.pwn(29004) : warning 215: expression has no effect
C:\Users\phuzl\Desktop\INV\gamemodes\edit.pwn(29004) : error 001: expected token: ";", but found ")"
C:\Users\phuzl\Desktop\INV\gamemodes\edit.pwn(29004) : error 029: invalid expression, assumed zero
C:\Users\phuzl\Desktop\INV\gamemodes\edit.pwn(29004) : fatal error 107: too many error messages on one line

 

Жалуется на паблик SaveInventory(playerid). 
 

строка 29004: mysql_query(1, str_query, false);

Поделиться сообщением


Ссылка на сообщение
  • 0
phizlfs
Освоившийся
stock SaveInventory(playerid)
{
    new mysql_query[128];
    new str_inv[INVENTORY_MAX_SLOT*(4+4+1+1)+1];
    for(new i = 0; i < INVENTORY_MAX_SLOT; i++) format(str_inv, sizeof(str_inv), "%s|%d,%d", str_inv, pInventoryData[playerid][idItem][i], pInventoryData[playerid][idAmount][i]);
    strdel(str_inv,0,1); new str_query[sizeof(str_inv) + 100];
    format(str_query, sizeof(str_query), "UPDATE `%s` SET `%s` = '%s' WHERE `%s` = '%s'", DB_TABLE_ACCOUNTS, DB_COLUMN_INVENTORY, str_inv, DB_COLUMN_NICKNAME, GN(playerid));

 

ниже:

return 1;
}
stock strsub(text[], sub_char, new_char = ' ')
{
    new subed = 0;

@Sleash

Отредактировано пользователем phizlfs

Поделиться сообщением


Ссылка на сообщение
  • 0
Sleash
Завсегдатый

@phizlfs Значит у вас не новая версия MySQL, попробуйте так:
 

Спойлер

#define DB_TABLE_ACCOUNTS       "Accounts"
#define DB_COLUMN_INVENTORY     "Inventory"
#define DB_COLUMN_NICKNAME      "Name"
stock GN(playerid){new funcNN[MAX_PLAYER_NAME];GetPlayerName(playerid,funcNN,MAX_PLAYER_NAME);return funcNN;}
stock SaveInventory(playerid) { 
    new str_inv[INVENTORY_MAX_SLOT*(4+4+1+1)+1];
    for(new i = 0; i < INVENTORY_MAX_SLOT; i++) format(str_inv, sizeof(str_inv), "%s|%d,%d", str_inv, pInventoryData[playerid][idItem][i], pInventoryData[playerid][idAmount][i]);
    strdel(str_inv,0,1); new str_query[sizeof(str_inv) + 100];
    format(str_query, sizeof(str_query), "UPDATE `%s` SET `%s` = '%s' WHERE `%s` = '%s'", DB_TABLE_ACCOUNTS, DB_COLUMN_INVENTORY, str_inv, DB_COLUMN_NICKNAME, GN(playerid));
    mysql_tquery(1, str_query, "", "");
    return 1;
}
stock strsub(text[], sub_char, new_char = ' ') {
    new subed = 0;
    for(new i = 0; i < strlen(text); i++){if(text[i]==sub_char){++subed,text[i]=new_char;}}
    return subed;
}
stock LoadInventory(playerid) { 
    new sql_str[64];
    format(sql_str, sizeof(sql_str), "SELECT `%s` FROM `%s` WHERE `%s` = '%s' LIMIT 1", DB_TABLE_ACCOUNTS, DB_COLUMN_INVENTORY, DB_COLUMN_NICKNAME, GN(playerid));
    mysql_tquery(1, sql_str, "SQLLoadInv", "i", playerid);
}
forward SQLLoadInv(playerid);
public SQLLoadInv(playerid) {
    new str_inv[INVENTORY_MAX_SLOT*(4+4+1+1)+1];
    cache_get_row(0, 0, str_inv),strsub(str_inv, '|');
    new str_inv_slots[INVENTORY_MAX_SLOT][4+4+1+1], str_for_sscanf[10+2+2+1]; 
    format(str_for_sscanf, sizeof(str_for_sscanf), "a<s[%d]>[%d]", sizeof(str_inv_slots[]), sizeof(str_inv_slots));
    sscanf(str_inv, str_for_sscanf, str_inv_slots); 
    for(new i = 0; i < INVENTORY_MAX_SLOT; i++) sscanf(str_inv_slots[i], "p<,>ii", pInventoryData[playerid][idItem][i], pInventoryData[playerid][idAmount][i]);
}

 

 

Поделиться сообщением


Ссылка на сообщение
  • 0
phizlfs
Освоившийся

Код скомпилировался. В логах выдаёт этот текст:
1064, You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''Christopher_' at line 1, SQLLoadInv, SELECT `Accounts` FROM `Inventory` WHERE `Name` = 'Christopher_, 1

в базе 'inventory' начало появляться: 2,3|3,3|4,3|1,3|0,0|0,0|0,0|0,0|0,0|0,0|0,0|0,0|0,0|0,0|0,0|0,0|0,0|0,0|0,0|0,0

 

Но при коннекте этих вещей в инвентаре нет

@Sleash

 И еще при коннекте это появляется в логах: 1146, Table 'gs219520.Inventory' doesn't exist, SQLLoadInv, SELECT `Accounts` FROM `Inventory` WHERE `Name` = 'Christopher_Bryte' LIMIT 1, 1

Отредактировано пользователем phizlfs

Поделиться сообщением


Ссылка на сообщение
  • 0
Sleash
Завсегдатый

@phizlfs 
1) Я чуть просчитался с размером строки для запроса, попробуйте так:

stock LoadInventory(playerid) { 
    new sql_str[128];
    format(sql_str, sizeof(sql_str), "SELECT `%s` FROM `%s` WHERE `%s` = '%s' LIMIT 1", DB_TABLE_ACCOUNTS, DB_COLUMN_INVENTORY, DB_COLUMN_NICKNAME, GN(playerid));
    mysql_tquery(1, sql_str, "SQLLoadInv", "i", playerid);
}

2) Table 'gs219520.Inventory' doesn't exis
Тут всё и так понятно, столбца `Inventory` не существует
Если вы не добавляли его, добавьте по примеру из первого сообщения
Если вы помните, что добавляли его, то проверьте его название
P.S. Учитывая данные из логов ваш запрос в базу должен выглядеть так:

ALTER TABLE `Accounts` ADD `Inventory` TEXT NOT NULL;

 

Поделиться сообщением


Ссылка на сообщение
  • 0
phizlfs
Освоившийся

По прежнему не загружает инвентарь. При коннекте выдаёт это:

1146, Table 'gs219520.Inventory' doesn't exist, SQLLoadInv, SELECT `Accounts` FROM `Inventory` WHERE `Name` = 'Christopher_Bryte' LIMIT 1, 1

p.s: в коннекте у меня и прописана загрузка инвентаря, а так же при спавне (пробовал вписывать всё это по отдельности, все равно не работает)
@Sleash

Поделиться сообщением


Ссылка на сообщение
  • 0
Sleash
Завсегдатый

@phizlfs 
Ошибка была моя, так как я переметал местами таблицу и столбец, код ниже должен работать

stock LoadInventory(playerid) { 
    new sql_str[128];
    format(sql_str, sizeof(sql_str), "SELECT `%s` FROM `%s` WHERE `%s` = '%s' LIMIT 1", DB_COLUMN_INVENTORY, DB_TABLE_ACCOUNTS, DB_COLUMN_NICKNAME, GN(playerid));
    mysql_tquery(1, sql_str, "SQLLoadInv", "i", playerid);
}

 

Поделиться сообщением


Ссылка на сообщение
  • 0
phizlfs
Освоившийся

Вроде как всё работает, щас подетальнее потестирую, спасибо большое!

Поделиться сообщением


Ссылка на сообщение
  • 0
phizlfs
Освоившийся

Чтоб добавить в инвентарь другие предметы, к примеру аксы. Нужно так сделать? @Sleash

stock UseInventoryItem(playerid, slot, itemid, type) 
{
    switch(type) 
    {
        case ITEM_TYPE_SKIN: // единственная функция, которая была в теме по стандарту.
        { 
            if(GetPlayerSkin(playerid) == itemid)
                return 1;

            SetPlayerSkin(playerid, itemid);
        } 
        case ITEM_TYPE_ACS: // То, что я хотел бы добавить
        { 
            if(IsPlayerAttachedObjectSlotUsed(playerid, 5)) RemovePlayerAttachedObject(playerid, 5); // ГИТАРА КРАСНАЯ
            SetPlayerAttachedObject(playerid, 5, 19317, 1, 0.114000,-0.122000,-0.052999, 4.199994,119.299995,-4.700001, 0.688000,1.000000,0.696000);
        }
    } 

 

А то я в подобных системах плохо понимаю

Отредактировано пользователем phizlfs

Поделиться сообщением


Ссылка на сообщение
  • 0
Sleash
Завсегдатый

@phizlfs 
В gInventoryItem у вас должна быть такая запись:

{19317, "НАДЕТЬ", "Красная гитара",    "Описание", ITEM_TYPE_ACS, 0.0, 0.0, 0.0, 1.0}

А проверку лучше сделать такой:
 

stock UseInventoryItem(playerid, slot, itemid, type) 
{
    switch(type) 
    {
        case ITEM_TYPE_SKIN: // единственная функция, которая была в теме по стандарту.
        { 
            if(GetPlayerSkin(playerid) == itemid)
                return 1;

            SetPlayerSkin(playerid, itemid);
        } 
        case ITEM_TYPE_ACS: // То, что я хотел бы добавить
        { 
            switch(itemid) {
                case 19317: {
                    if(IsPlayerAttachedObjectSlotUsed(playerid, 5)) RemovePlayerAttachedObject(playerid, 5); // ГИТАРА КРАСНАЯ
                    SetPlayerAttachedObject(playerid, 5, 19317, 1, 0.114000,-0.122000,-0.052999, 4.199994,119.299995,-4.700001, 0.688000,1.000000,0.696000);
                }
            }
        }
    }

Ну или вместо switch использовать if, решать уже вам

Ещё лучше создать массив, который будет запоминать какие акс-ы на игроке надеты
И желательно это тоже с save + load БД
Это позволит проверять и надевать на игроков акс-ы при входе, а так же при надевании, допустим чёрно гитары, проверить надет ли на игроки другой акс. на спину (к примеру та же чёрная гитара)

Отредактировано пользователем Sleash

Поделиться сообщением


Ссылка на сообщение
  • 0
phizlfs
Освоившийся
enum {
    ITEM_TYPE_ACS = 0,     // гитара

    __DUMMY_ELEMENT_,
    ITEM_TYPE_COUNT = __DUMMY_ELEMENT_
}

Тут создать такой же enum? или же как-то приписать это к enum со скином?

@Sleash

Отредактировано пользователем phizlfs

Поделиться сообщением


Ссылка на сообщение
  • 0
Sleash
Завсегдатый

@phizlfs 
 

enum {
    ITEM_TYPE_SKIN = 0,     // скины

    ITEM_TYPE_ACS = 1,     // аксессуары

    __DUMMY_ELEMENT_,
    ITEM_TYPE_COUNT = __DUMMY_ELEMENT_
}

 

Поделиться сообщением


Ссылка на сообщение
  • 0
phizlfs
Освоившийся

Добавил гитару и RC игрушку, начало почему-то выбивать это:
C:\Users\phuzl\Desktop\INV\gamemodes\edit.pwn(423) : warning 228: length of initialler exceeds size of the enum field
C:\Users\phuzl\Desktop\INV\gamemodes\edit.pwn(423) : error 018: initialization data exceeds declared size

new gInventoryItem[][e_InventoryItems] = {
    {0, " ", " ", " ", __DUMMY_ELEMENT_, 0.0, 0.0, 0.0, 1.0},
    {1, "НАДЕТЬ", "Одежда Truth №1",     "Можно приобрести в магазине одежды", ITEM_TYPE_SKIN, 0.0, 0.0, 0.0, 1.0},
    {2, "НАДЕТЬ", "Одежда Maccer №2",    "Можно приобрести в магазине одежды", ITEM_TYPE_SKIN, 0.0, 0.0, 0.0, 1.0},
    {3, "НАДЕТЬ", "Одежда Andre №3",     "Можно приобрести в магазине одежды", ITEM_TYPE_SKIN, 0.0, 0.0, 0.0, 1.0},
    {4, "НАДЕТЬ", "Одежда Bbthin №4",    "Можно приобрести в магазине одежды", ITEM_TYPE_SKIN, 0.0, 0.0, 0.0, 1.0},
    {19317, "НАДЕТЬ", "Красная гитара",  "Купить можно в /mm - 9", ITEM_TYPE_ACS, 0.0, 0.0, 0.0, 1.0},
    {564, "ИСПОЛЬЗОВАТЬ", "RC",          "Купить можно в /mm - 9", ITEM_TYPE_RC, 0.0, 0.0, 0.0, 1.0}
};

как раз на последний пункт ругается 
@Sleash

p.s: после добавления гитары всё работало отлично, гитара надевалась и появлялась

Поделиться сообщением


Ссылка на сообщение
  • 0
Sleash
Завсегдатый

@phizlfs Взглянем на enum с данными предметов:

enum e_InventoryItems {
    /*
        Enum, содержащий информацию о предметах Инвентаря
    */
    iItemID,
    iUse[10], // Вот тут длина слова не может быть более 10 символов
    iName[30],
    iDesc[110],
    iType,

    Float: iItemPosX,
    Float: iItemPosY,
    Float: iItemPosZ,
    Float: iItemPosC
};

А у вас стоит слово "Использовать" - это 12 символов, надо просто увеличить размер с 10 до, к примеру, 15-и символов:
iUse[10], -> iUse[15],

Поделиться сообщением


Ссылка на сообщение
  • 0
phizlfs
Освоившийся

Все отлично работает, спасибо вам)


Я тут столкнулся с небольшой проблемой, а именно загрузкой последний надетых аксессуаров на персонаже при спавне/смерти.
У меня есть предположение как это сделать, но всё накладывается друг на друга или удаляется в занятом слоте до тех пор, пока не дойдёт до последнего пункта в коде. Как это можно реализовать? @Sleash
 

Отредактировано пользователем phizlfs

Поделиться сообщением


Ссылка на сообщение
  • 0
Sleash
Завсегдатый

@phizlfs 
1) Я написал +- примитивный код, постарайтесь изучить его, что бы понять как это работает
2) Если появятся ещё вопросы - прошу создавать новую тему на форуме.
3) Код на работоспособность не проверял, но он компилируется:
 

Спойлер

// Для начала надо бы раставить index`ы на прикрепления объектов к игроку,
// что бы в дальнейшем было проще, к примеру:
enum {
    ATTACH_IDX_NONE = -1, // Несуществующий индекс
    ATTACH_IDX_HEAD = 0, // index для акс-ов на голову
    ATTACH_IDX_BACK = 1, // index для акс-ов на спину
    ATTACH_IDX_RARM = 2, // index для акс-ов на правую руку
    ATTACH_IDX_LARM = 3 // index для акс-ов на левую руку
    // И так далее, но, если я не ошибасю у них есть ограничение от 0 до 9-и
    // Точно не помню действует ли оно в SA:MP 0.3.7
};
#define MAX_ATTACHS 3 // Тут пишем последне число, котороые было в enum выше
#define DB_TABLE_ACCOUNTS       "Accounts"
#define DB_COLUMN_USEDACS       "UsedAcs"
#define DB_COLUMN_NICKNAME      "Name"
// Дальше неплохо было бы докинуть к переменным надетые акс-ы игрока:
new pUsedAcs[MAX_PLAYERS][MAX_ATTACHS+1];

public OnPlayerSpawn(playerid) {
    new str_sql[128];
    format(str_sql, 128, "SELECT `%s` FROM `%s` WHERE `%s` = '%s'", DB_COLUMN_USEDACS, DB_TABLE_ACCOUNTS, DB_COLUMN_NICKNAME, GN(playerid));
    SetPVarInt(playerid, "SpawnLoadUsedAcs", 1);
    mysql_tquery(1, str_sql, "LoadUsedAcs", "i", playerid);
    // ...
}

// Теперь создадим функцию дял получения типа индекса:
stock GetAttachIDX(itemID) {
    switch(itemID) {
        case 19317: return ATTACH_IDX_BACK; // Если это гитара, то возвращает спину
        default: return ATTACH_IDX_NONE; // Если акс-а нет в перечни case, то возвращаем несуществующий id
    }
    return ATTACH_IDX_NONE;
}
// Далее рассмотрим надевание акс-са
stock UseInventoryItem(playerid, slot, itemid, type) 
{
    switch(type) 
    {
        case ITEM_TYPE_ACS: return UseAcs(plaeyrid, itemid); // перенаправляем на нашу функцию
        //...
    }
    //...
}
// Теперь распишем полную функцию использования акс-а:
stock UseAcs(playerid, itemid, onspawn = 0) {
    new index = GetAttachIDX(itemid); // Получаем индекс акс-а
    if(index == ATTACH_IDX_NONE && onspawn) return false; // Если индекс неверный при спавне
    if(index == ATTACH_IDX_NONE && !onspawn) return SendClientMessage(playerid, -1, "Неизвестный аксессуар"); // Если индекс неверный при попытке надеть
    if(pUsedAcs[playerid][index]) RemovePlayerAttachedObject(playerid, index); // если на этот индекс уже надет акс. - снимаем
    pUsedAcs[playerid][index] = itemid; // Обновляем переменную по нашему индексу на новый акс.
    // Плюсом для удобства я бы добавил себе define
    #define AcsAttach(%0) SetPlayerAttachedObject(playerid,index,itemid,%0)
    // Далее перебор акс-ов
    switch(itemid) {
        // Нам остаётся ввести просто кость и координаты:
        case 19317: AcsAttach(1, 0.114000,-0.122000,-0.052999, 4.199994,119.299995,-4.700001, 0.688000,1.000000,0.696000);
    }
    return 1; // Можно на этом и заканчивать цепочку действий надевания акс-а
}
// Созданение функций загрузки и разгрузки использованных акс-ов:
// Сначала загрузка акс-ов:
forward LoadUsedAcs(playerid);
public LoadUsedAcs(playerid) {
    new sql_usedacs[(MAX_ATTACHS+1)*(5+1)]; // создаём массив для получения данных
    if(GetPVarInt(playerid, "SpawnLoadUsedAcs")) { //Если сток вызван по случаю входа игрока
        cache_get_row(0, 0, sql_usedacs); // получаем данные
        new f_sscanf[15]; // создаём массив для форматирование строки для sscanf
        format(f_sscanf, 15, "p<,>a<d>[%d]", MAX_ATTACHS+1);
        // Мы удаляя из строки запятые получаем числа в кол-ве MAX_ATTACHS+1
        sscanf(sql_usedacs, f_sscanf, pUsedAcs[playerid]); // Получил числа отдельно в массив pUsedAcs
        DeletePVar(playerid, "SpawnLoadUsedAcs");
    } // Дальше простая загрузка
    // GetPVarInt(playerid, "SpawnLoadUsedAcs") был добавлен, что бы мы не получали пустую строку, если хотим обновить акс-ы игркоа в середине игры без запроса
    // Это сожно будет делать просто вызываю функцию: LoadUsedAcs(playerid);
    // Как раз для тех моментов, когада надо обновить акс-ы игрока при, допустим, смерти (как вы и указывали на форуме)
    for(new i = 0; i <= MAX_ATTACHS+1; i++) UseAcs(playerid, pUsedAcs[playerid][i], true); // пытаемся надеть все акс-ы
}
// Теперь сохранение акс-ов:
stock SaveUsedAcs(playerid) {
    new sql_usedacs[(MAX_ATTACHS+1)*(5+1)+1]; // создаём массив для сохранения данных данных
    for(new i = 0; i <= MAX_ATTACHS+1; i++)
        format(sql_usedacs, sizeof(sql_usedacs), "%s,%d",sql_usedacs, pUsedAcs[playerid][i]); // перебираем все акс-ы
    strdel(sql_usedacs,0,1); // Убираем лишнюю запятую в начале
    new str_sql[128+sizeof(sql_usedacs)]; // Переменная для запроса
    //UPDATE `Qelksekm` SET `OldIP` = '%s',`onl_status`='1001',`Lastlogin` = CURDATE() WHERE `ID` = '%i'
    format(str_sql, 128, "UPDATE `%s` SET `%s` = '%s' WHERE `%s` = '%s'", DB_TABLE_ACCOUNTS, DB_COLUMN_USEDACS, sql_usedacs, DB_COLUMN_NICKNAME, GN(playerid));
    mysql_tquery(1, str_sql, "", "");
}

 

 

Поделиться сообщением


Ссылка на сообщение
Гость
Эта тема закрыта для публикации ответов.
  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

  • Похожий контент

    • patrickk
      От patrickk
      Всем привет, решил написать dm сервер и довольно хорошим получился, даже на голову выше Goat dm. Оставил не решенную проблему тем что  у меня есть 4 локации с rp run и cj run ну а как добавить cj бег на те локации не знаю и как эта система работает. Надеюсь мне помогут знающие люди
    • Samolet
      От Samolet
      Здраствуйте, cоздаю копию Arizona на ОМП, опен мультиплеер, загрузил и подключил бд, но сервер не хочет вот лог :[2026-10-20T21:03:32+0300] [Info] Log file reloaded. Starting open.mp server (1.5.8.3079) from commit c6759bd8d265171ae3d86598895a23d5a8d92a3b Loading component $CAPI.so Successfully loaded component C-API (1.5.8.3079) with UID 10467dd8d4c56fc6 Loading component LegacyConfig.so Successfully loaded component LegacyConfig (1.5.8.3079) with UID 24ef6216838f9ffc Loading component NPCs.so Successfully loaded component NPCs (1.5.8.3079) with UID 3d0e59e87f4e90bc Loading component Recordings.so Successfully loaded component Recordings (1.5.8.3079) with UID 871144d399f5f613 Loading component Checkpoints.so Successfully loaded component Checkpoints (1.5.8.3079) with UID 44a937350d611dde Loading component TextDraws.so Successfully loaded component TextDraws (1.5.8.3079) with UID 9b5dc2b1d15c992a Loading component Pawn.so Successfully loaded component Pawn (1.5.8.3079) with UID 78906cd9f19c36a6 Loading component GangZones.so Successfully loaded component GangZones (1.5.8.3079) with UID b3351d11ee8d8056 Loading component Actors.so Successfully loaded component Actors (1.5.8.3079) with UID c81ca021eae2ad5c Loading component Pickups.so Successfully loaded component Pickups (1.5.8.3079) with UID cf304faa363dd971 Loading component Dialogs.so Successfully loaded component Dialogs (1.5.8.3079) with UID 44a111350d611dde Loading component Objects.so Successfully loaded component Objects (1.5.8.3079) with UID 59f8415f72da6160 Loading component Console.so Successfully loaded component Console (1.5.8.3079) with UID bfa24e49d0c95ee4 Loading component TextLabels.so Successfully loaded component TextLabels (1.5.8.3079) with UID a0c57ea80a009742 Loading component Variables.so Successfully loaded component Variables (1.5.8.3079) with UID 75e121848bc01fa2 Loading component Databases.so Successfully loaded component Databases (1.5.8.3079) with UID 80092e7eb5821a96 Loading component LegacyNetwork.so Successfully loaded component RakNetLegacyNetwork (1.5.8.3079) with UID ea9799fd79cf8442 Loading component CustomModels.so Successfully loaded component CustomModels (1.5.8.3079) with UID 15e3cb1e7c77ffff Loading component Menus.so Successfully loaded component Menus (1.5.8.3079) with UID 621e219eb97ee0b2 Loading component Vehicles.so Successfully loaded component Vehicles (1.5.8.3079) with UID 3f1f62ee9e22ab19 Loading component Classes.so Successfully loaded component Classes (1.5.8.3079) with UID 8cfb3183976da208 Loading component Timers.so Successfully loaded component Timers (1.5.8.3079) with UID 2ad8124c5ea257a3 Loaded 22 component(s) from /home/gs113492/components Executing Server Config... [2026-10-20T21:03:33+0300] [Info] Loading plugin: crashdetect.so [2026-10-20T21:03:33+0300] [Info] CrashDetect plugin 4.19 [2026-10-20T21:03:33+0300] [Info] Loading plugin: mapandreas.so [2026-10-20T21:03:33+0300] [Info] Loading plugin: streamer.so [2026-10-20T21:03:33+0300] [Info] *** Streamer Plugin v2.9.4 by Incognito loaded *** [2026-10-20T21:03:33+0300] [Info] Loading plugin: sscanf.so [2026-10-20T21:03:33+0300] [Info] [2026-10-20T21:03:33+0300] [Info] =============================== [2026-10-20T21:03:33+0300] [Info] sscanf plugin loaded. [2026-10-20T21:03:33+0300] [Info] Version: 2.8.3 [2026-10-20T21:03:33+0300] [Info] (c) 2018 Alex "Y_Less" Cole [2026-10-20T21:03:33+0300] [Info] =============================== [2026-10-20T21:03:33+0300] [Info] Loading plugin: TOTP.so [2026-10-20T21:03:33+0300] [Info] TOTP plugin v1.0.1 by Games loaded. [2026-10-20T21:03:33+0300] [Info] Loading plugin: mysql_static.so [2026-10-20T21:03:33+0300] [Info] >> plugin.mysql: R39-6 successfully loaded. [2026-10-20T21:03:33+0300] [Info] Loading plugin: libpawn_json.so [2026-10-20T21:03:34+0300] [Error] Function not registered: YSF_SetTickRate [2026-10-20T21:03:34+0300] [Error] Function not registered: PC_Init [2026-10-20T21:03:34+0300] [Info] [debug] Run time error 19: "File or function is not found" [2026-10-20T21:03:34+0300] [Info] [debug] PC_Init [2026-10-20T21:03:34+0300] [Info] [debug] YSF_SetTickRate [2026-10-20T21:03:34+0300] [Error] File or function is not found [2026-10-20T21:03:34+0300] [Error] Function not registered: PC_RegAlias [2026-10-20T21:03:34+0300] [Error] Function not registered: BS_GetWriteOffset [2026-10-20T21:03:34+0300] [Error] Function not registered: BS_Reset [2026-10-20T21:03:34+0300] [Error] Function not registered: PR_RegHandler [2026-10-20T21:03:34+0300] [Error] Function not registered: BS_Delete [2026-10-20T21:03:34+0300] [Error] Function not registered: BS_New [2026-10-20T21:03:34+0300] [Error] Function not registered: BS_ResetReadPointer [2026-10-20T21:03:34+0300] [Error] Function not registered: BS_SetWriteOffset [2026-10-20T21:03:34+0300] [Error] Function not registered: BS_IgnoreBits [2026-10-20T21:03:34+0300] [Error] Function not registered: PR_Init [2026-10-20T21:03:34+0300] [Error] Function not registered: PR_SendRPC [2026-10-20T21:03:34+0300] [Error] Function not registered: PR_SendPacket [2026-10-20T21:03:34+0300] [Error] Function not registered: BS_WriteValue [2026-10-20T21:03:34+0300] [Error] Function not registered: BS_GetNumberOfBytesUsed [2026-10-20T21:03:34+0300] [Error] Function not registered: BS_ReadValue [2026-10-20T21:03:34+0300] [Error] Function not registered: PC_Init [2026-10-20T21:03:34+0300] [Info] [debug] Run time error 19: "File or function is not found" [2026-10-20T21:03:34+0300] [Info] [debug] PC_Init [2026-10-20T21:03:34+0300] [Info] [debug] BS_ReadValue [2026-10-20T21:03:34+0300] [Info] [debug] BS_GetNumberOfBytesUsed [2026-10-20T21:03:34+0300] [Info] [debug] BS_WriteValue [2026-10-20T21:03:34+0300] [Info] [debug] PR_SendPacket [2026-10-20T21:03:34+0300] [Info] [debug] PR_SendRPC [2026-10-20T21:03:34+0300] [Info] [debug] PR_Init [2026-10-20T21:03:34+0300] [Info] [debug] BS_IgnoreBits [2026-10-20T21:03:34+0300] [Info] [debug] BS_SetWriteOffset [2026-10-20T21:03:34+0300] [Info] [debug] BS_ResetReadPointer [2026-10-20T21:03:34+0300] [Info] [debug] BS_New [2026-10-20T21:03:34+0300] [Info] [debug] BS_Delete [2026-10-20T21:03:34+0300] [Info] [debug] PR_RegHandler [2026-10-20T21:03:34+0300] [Info] [debug] BS_Reset [2026-10-20T21:03:34+0300] [Info] [debug] BS_GetWriteOffset [2026-10-20T21:03:34+0300] [Info] [debug] PC_RegAlias [2026-10-20T21:03:34+0300] [Error] File or function is not found [2026-10-20T21:03:34+0300] [Info] [debug] Run time error 19: "File or function is not found" [2026-10-20T21:03:34+0300] [Info] [debug] PC_Init [2026-10-20T21:03:34+0300] [Info] [debug] YSF_SetTickRate [2026-10-20T21:03:34+0300] [Error] File or function is not found [2026-10-20T21:03:34+0300] [Info] [debug] Run time error 19: "File or function is not found" [2026-10-20T21:03:34+0300] [Info] [debug] PC_Init [2026-10-20T21:03:34+0300] [Info] [debug] BS_ReadValue [2026-10-20T21:03:34+0300] [Info] [debug] BS_GetNumberOfBytesUsed [2026-10-20T21:03:34+0300] [Info] [debug] BS_WriteValue [2026-10-20T21:03:34+0300] [Info] [debug] PR_SendPacket [2026-10-20T21:03:34+0300] [Info] [debug] PR_SendRPC [2026-10-20T21:03:34+0300] [Info] [debug] PR_Init [2026-10-20T21:03:34+0300] [Info] [debug] BS_IgnoreBits [2026-10-20T21:03:34+0300] [Info] [debug] BS_SetWriteOffset [2026-10-20T21:03:34+0300] [Info] [debug] BS_ResetReadPointer [2026-10-20T21:03:34+0300] [Info] [debug] BS_New [2026-10-20T21:03:34+0300] [Info] [debug] BS_Delete [2026-10-20T21:03:34+0300] [Info] [debug] PR_RegHandler [2026-10-20T21:03:34+0300] [Info] [debug] BS_Reset [2026-10-20T21:03:34+0300] [Info] [debug] BS_GetWriteOffset [2026-10-20T21:03:34+0300] [Info] [debug] PC_RegAlias [2026-10-20T21:03:34+0300] [Info] Legacy Network started on ***.**.**.***:2717. Помогите пожалуйста