Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!
Иконка ресурса

PawnMap - плагин для создания мап в pawn v1.0.0

Версия мультиплеера
  1. SA:MP 0.3.7
  2. open.mp
PawnMap - плагин для создания мап в pawn​

Основная задача была: сделать максимально понятную и производительную мапу для Pawn, насколько это было возможно.
Чтобы её можно было использовать в обычных системах, при этом чтобы она сильно не уступала сырым массивам pawn, а там, где нужна какая-то операция с данными (поиск, сортировка), была и вовсе быстрее.

Вся подробная документация с примерами находится в моем репозитории>> https://github.com/i-Saibot/PawnMap/wiki

Тут я только вкратце покажу список функций и пару примеров:

Pawn:
// Функции

Map_Create- Создает новый экземпляр мапы.
Map_Destroy - Удаляет экземпляр мапы.
Map_IsValid - Проверяет, существует ли мапы в памяти.
Map_Clear - Полностью очищает мапу.
Map_Clone - Создает полную копию существующей мапы.
Map_Merge - Объединяет две мапы.
Map_Set - Устанавливает набор значений для указанного ключа.
Map_Get - Извлекает все данные, хранящиеся под указанным ключом.
Map_RemoveKey - Удаляет указанный ключ.
Map_SafeRemoveKey - Безопасно удаляет указанный ключ в цикле.
Map_RenameKey - Изменяет идентификатор существующего ключа на новый.
Map_Swap - Меняет местами данные двух указанных ключей.
Map_ContainsKey - Проверяет наличие указанного ключа в мапе.
Map_GetKeyByIndex - Позволяет получить значение ключа по его индексу.
Map_GetKeyCount - Позволяет получить кол-во ключей в мапе.
Map_FindKeyByField - Поиск ключа по значению.
Map_SortByKey- Сортирует все ключи в мапе в зависимости от выбранного порядка.
Map_SortByField - Сортирует записи в мапе на основе значений поля из enum.
Map_SetString- Вспомогательная функция для безопасной записи строки в массив.
mapfor - Цикл для перебора ключей в мапе.
Map_StringKeyToIntor - Преобразует строковый ключ в int для мапы.
Map_GetIdByStringKey - Находит и возвращает целочисленный (ID) существующего строкового ключа в мапе.
Map_ContainsStringKey - Проверяет, существует ли в мапе запись с указанным строковым ключом.
Map_GetStringById - Получает строковое имя ключа по его числовому идентификатору (ID).

Pawn:
//Dm Zone

// Представим, что нам нужно сделать ДМ арену, на которой мы будем записывать количество убийств, смертей и урона.
// В конце раунда нам нужно отсортировать список, вывести данные и очистить мапу для следующего раунда.

В данной мапе мы используем playerid как ключ.

enum e_dm_zone
{
    Kills,
    Death,
    Float:Damage

}
new PawnMap:MapDmZone;


public OnGameModeInit()
{
    // Создаем мапу при старте мода
    MapDmZone = Map_Create();
    return 1;

}

public OnGameModeExit()
{
    // Удаляем мапу
    Map_Destroy(MapDmZone);
    return 1;
}

public OnPlayerTakeDamage(playerid, issuerid, Float:amount, weaponid, bodypart)
{
    // Проверка находится ли игрок на дм зоне

    static data[e_dm_zone];

    // Получаем текущие данные игрока, чтобы обновить их

    Map_Get(MapDmZone, playerid, data);

    data[Damage] += amount;

    // Обновляем только урон
    Map_Set(MapDmZone, playerid, data);

    return 1;
}


public OnPlayerDeath(playerid, killerid, reason)
{
    // Проверка находится ли игрок на дм зоне

    static data[e_dm_zone];

    // Обновляем смерти (Death)

    Map_Get(MapDmZone, playerid, data);

    data[Death] += 1;

    Map_Set(MapDmZone, playerid, data);

    // Обновляем убийства (Kill)

    if(killerid != INVALID_PLAYER_ID)
    {
        Map_Get(MapDmZone, killerid, data);

        data[Kills] += 1;

        Map_Set(MapDmZone, killerid, data);
    }
    return 1;
}

stock DmZoneRoundFinish()
{
    // Сортировка по убыванию (сначала те, у кого больше киллов)

    Map_SortByField(MapDmZone, e_dm_zone:Kills, MAP_SORT_DESC);

    static data[e_dm_zone];

    new string[144];

    mapfor(MapDmZone, i)
    {
        Map_Get(MapDmZone, i, data);

        format(string, sizeof(string),
            "[DM ZONE] playerid %d | kills %d | death %d | damage %.2f",
            i,
            data[Kills],
            data[Death],
            data[Damage]
        );
        SendClientMessageToAll(-1, string);
    }

    // Очищаем данные для следующего раунда

    Map_Clear(MapDmZone);
    return 1;

}


Pawn:
// Inventory

// Представим, что нам необходимо реализовать простой инвентарь с базовым набором функций.
// В данной архитектуре мы используем ID слота в качестве уникального ключа (Key), а структуру предмета - в качестве значения (Value).
// Это позволяет эффективно управлять ячейками, перемещать предметы и быстро проверять заполненность сумки.

В данной системе мы используем ID слота как ключ (Key), а структуру предмета — как значение (Value).

const INVENTORY_MAX_SLOTS = 15;

enum e_inventory
{
    Item,
    Amount,
    Name[24]

}

new PawnMap:MapInventory[MAX_PLAYERS] = {INVALID_MAP_ID, ...};

public OnPlayerConnect(playerid)
{
    // Создаем мапу для каждого игрока при подключении
    MapInventory[playerid] = Map_Create();
    return 1;
}

public OnPlayerDisconnect(playerid, reason)
{
    new PawnMap:mapid = MapInventory[playerid];

    // Проверяем на валидность перед удалением

    if (Map_IsValid(mapid))
    {
        // Полностью удаляем мапу и освобождаем память в плагине
        Map_Destroy(mapid);

        // Сбрасываем переменную в исходное состояние
        MapInventory[playerid] = INVALID_MAP_ID;
    }
    return 1;
}

stock GiveInventoryItems(playerid, itemid, amount, const name[])
{
    new PawnMap:mapid = MapInventory[playerid];

    // Ищем, есть ли уже такой предмет в инвентаре (по полю Item)
    new slotid = Map_FindKeyByField(mapid, e_inventory:Item, MAP_TYPE_INT, itemid);
    static data[e_inventory];

    if (slotid != INVALID_MAP_KEY_ID)
    {
        // Если предмет найден - увеличиваем количество
        Map_Get(mapid, slotid, data);

        data[Amount] += amount;

        Map_Set(mapid, slotid, data);
    }
    else
    {
        // Если предмет новый - проверяем лимит слотов
        if (Map_GetKeyCount(mapid) >= INVENTORY_MAX_SLOTS)
        {
            SendClientMessage(playerid, -1, "Нет свободного слота для предмета.");
            return 0;
        }
        new free_slotid = Map_GetFreeKey(mapid);

        if (free_slotid == INVALID_MAP_KEY_ID)
        {
            SendClientMessage(playerid, -1, "Ошибка при поиске свободного слота.");
            return 0;
        }
        data[Item] = itemid;
        data[Amount] = amount;
        Map_SetString(data[Name], name);

        Map_Set(mapid, free_slotid, data);
    }
    SendClientMessage(playerid, -1, "Инвентарь обновлен.");
    return 1;
}

stock RemoveInventoryItems(playerid, itemid)
{
    new PawnMap:mapid = MapInventory[playerid];
    new slotid = Map_FindKeyByField(mapid, e_inventory:Item, MAP_TYPE_INT, itemid);

    if (slotid == INVALID_MAP_KEY_ID)
    {
        SendClientMessage(playerid, -1, "Ошибка: предмет не найден.");
        return 0;
    }
    Map_RemoveKey(mapid, slotid);
    SendClientMessage(playerid, -1, "Предмет удален.");
    return 1;
}

stock UseInventoryItems(playerid, itemid, amount)
{
    new PawnMap:mapid = MapInventory[playerid];
    new slotid = Map_FindKeyByField(mapid, e_inventory:Item, MAP_TYPE_INT, itemid);

    if (slotid == INVALID_MAP_KEY_ID)
    {
        SendClientMessage(playerid, -1, "Ошибка: предмет не найден.");
        return 0;
    }
    static data[e_inventory];
    Map_Get(mapid, slotid, data);

    data[Amount] -= amount;

    if (data[Amount] <= 0)
    {
        Map_RemoveKey(mapid, slotid);
    }
    else
    {
        Map_Set(mapid, slotid, data);
    }
    return 1;
}

stock SwapInventoryItems(playerid, slot_1, slot_2)
{
    new PawnMap:mapid = MapInventory[playerid];

    if (Map_Swap(mapid, slot_1, slot_2))
    {

        SendClientMessage(playerid, -1, "Предметы успешно перемещены.");
    }
    else
    {
        SendClientMessage(playerid, -1, "Ошибка перемещения.");
    }
    return 1;
}

stock ShowInventory(playerid)
{
    new PawnMap:mapid = MapInventory[playerid];
    new string[1024];

    mapfor(mapid, slotid)
    {
        static data[e_inventory];
        Map_Get(mapid, slotid, data);

        format(string, sizeof(string),
            "%s№%d\t%s\tКол-во: %d\n",
            string,
            slotid,
            data[Name],
            data[Amount]
        );
    }
    ShowPlayerDialog(playerid, 1000, DIALOG_STYLE_LIST, "Инвентарь", string, "Выбрать", "Закрыть");
    return 1;
}


public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
    if (dialogid == 1000)
    {
        if (!response) return 0;

        new slotid = listitem;
        new PawnMap:mapid = MapInventory[playerid];
        static data[e_inventory];
      
        if (Map_Get(mapid, slotid, data))
        {
            new string[144];
            format(string, sizeof(string),

                "Вы выбрали - Название: %s | ID: %d | Кол-во: %d",
                data[Name], data[Item], data[Amount]
            );
            SendClientMessage(playerid, -1, string);
        }
    }
    return 1;

}

Это тест, просто показывает, что мапа не медленная, а в некоторых местах даже быстрее.
Код теста >> https://github.com/i-Saibot/PawnMap

PawnMap.png

Код:
На данный момент ключом может быть только целое число (int).
За четыре года работы над проектами мне лишь однажды понадобился строковый идентификатор для системы, других случаев, где это было бы необходимо, я не припомню.
Чтобы не загромождать API дублирующими функциями с постфиксом _Str (которые пришлось бы добавлять практически для каждой функции) и не снижать производительность мапы, я решил не внедрять поддержку строковых ключей.
Вместо этого я реализовал возможность конвертации строки в целочисленный ключ.


Pawn:
// Пример

enum inventory_struct
{
    Itemid,
    Amount
}

public OnGameModeInit()
{
    new PawnMap:mapid = Map_Create();

    // 1. Преобразуем строку "Deagle" в числовой ID и записываем данные
    new keyid = Map_StringKeyToInt(mapid, "Deagle");

    if (keyid != INVALID_MAP_KEY_ID)
    {

        new data[inventory_struct];

        data[Itemid] = 24;
        data[Amount] = 100;

        // Сохраняем массив данных под этим ID
        Map_Set(mapid, keyid, data);

        printf("Строка 'Deagle' успешно преобразована в ID: %d", keyid);
    }
    // 2. Получаем ID по строке (используем уже созданную переменную без 'new')
    keyid = Map_GetIdByStringKey(mapid, "Deagle");

    if (keyid != INVALID_MAP_KEY_ID)
    {
        printf("ID для ключа 'Deagle' найден: %d", keyid);
    }
    else
    {
        printf("Этот строковый ключ не существует в мапе.");
    }
    // 3. Проверяем наличие ключа напрямую
    if (Map_ContainsStringKey(mapid, "Deagle"))
    {
        printf("Ключ 'Deagle' существует в этой мапе.");
    }
    else
    {
        printf("Ключ 'Deagle' не найден.");
    }
    // 4. Конвертируем числовой ID обратно в строку
    new buffer[32];

    if (Map_GetStringById(mapid, keyid, buffer))
    {
        printf("Имя ключа под ID %d - '%s'", keyid, buffer);
    }
    return 1;

}

Скачать: https://github.com/i-Saibot/PawnMap/releases
Нет прав для скачивания
Автор
Saibot
Скачивания
0
Просмотры
49
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху