Какую структуру использовать для реализации связи елементов из двух списков ?

Сообщения
260
Реакции
129
Помог
12 раз(а)
Есть массив из N (порядка 100-200) элементов , и нужно организовать связи между этими елементами и некоторыми ентитями на сервере.

1. Добавление связи. Входные данные (n,id)
По тригеру определенных событий я получаю n индекс обьекта и id ентити - и мне нужно получить связи обьекта n и если у него нету связи с id то добавить такую связь.

2. Разрушение связи. Входные данные (id)
При разрушении ентити мне нужно получить все связи ее id c обьектами n и удалить их(связи) если таковые есть.

3. Быстро проверить есть ли связи у обьекта n

Возможно кто-то уже подобное делал - поделитесь примером своей реализации или хотя бы идеями с помощью каких структур хранить связи и работать с ними было бы оптимально.

Уточнение - связи могут быть множественными то есть один обьект может быть связан с несколькими ентити и наоборот одна энтитя может иметь связи с несколькими обьектами

example.jpg
 
Сообщения
846
Реакции
525
Помог
13 раз(а)
можно ставить метки на объекты, чтобы идентифицировать их правильно (как минимум быть уверенным, что этот объект тот самый, а не зашедший на его айди левый объект) https://dev-cs.ru/threads/222/page-17#post-137814

далее открываем дин.массив и туда записываем инфу об объектах связанных с искомым

PHP:
enum eEntitiesData {
     eEntitiesData_Index,
     eEntitiesData_Key,
}

public plugin_init()
{
    
     RegisterHookChain(RH_ED_Free, "fw_Edict_Free", false);
}

stock SetEntityToList(iEntityOwner, iEntityTarget)
{
     if (pev(iEntityTarget, pev_iuser666)) {
           return false;
     }
     new Array:aEntityList = Array:pev(iEntityOwner, pev_iuser777);
     if (!aEntityList) aEntityList = ArrayCreate(eEntitiesData);

     new szData[eEntitiesData];
    
     szData[eEntitiesData_Index] = iEntityTarget;
     szData[eEntitiesData_Key] =  pev(iEntityTarget, pev_iuser4); // Ключ / уник.айди объекта лучше вытянуть из примера по ссылке выше

     ArrayPushArray(aEntityList , szData);

set_pev(iEntityOwner, pev_iuser777, aEntityList); // сохраняем дин.массив в пев объекта. В идеале использовать что-то вроде ced'ов, т.к. pev относительно других плагинов могут быть ненадежны (может произойти перезапись другими плагинами)

    set_pev(iEntityTarget, pev_iuser666,  iEntityOwner); // Ставим инфу что этот объект уже занят каким-то другим
    set_pev(iEntityTarget, pev_iuser666key, pev(iEntityOwner, pev_iuser4));
    return true;
}

public fw_Edict_Free(iEnt)
{
     // необходима доп.проверка что это наш объект, на класс например или кей.

     //чистим данные дин.массива перед удалением объекта
     new Array:aEntityList = Array:pev(iEnt, pev_iuser777);

     if (aEntityList) ArrayDestroy(aEntityList);
}

соответственно чтобы разорвать связь ищем по списку
Код:
stock RemoveDependence(iEntityTarget)
{
        // при удалении зависимого объекта из списка 
        new iEntityOwner = pev(iEntityTarget, pev_iuser666);
       
          // Удостоверимся что именно от этого объекта зависимы;
        if (!is_nullent(iEntityOwner)) {
                 if (pev(iEntityTarget, pev_iuser666key) == pev(iEntityOwner, pev_iuser4)) {

                       new Array:aEntityList = Array:pev(iEntityOwner, pev_iuser777);

                       // По идее если ключи совпали, то проверять смысла нет есть ли дин.массив или нет в pev'е
                       new szData[eEntitiesData];
                      
                       for (new i, iMax = ArraySize(aEntityList ); i<iMax; i++ ) {
                                  ArrayGetArray(aEntityList, i, szData);

                                 // Нашли в списке, почистили данные, удалили метки
                                 if (szData[eEntitiesData_Index] == iEntityTarget && szData[eEntitiesData_Key] == pev(iEntityTarget , pev_iuser4)) {
                                       ArrayDeleteItem(aEntityList, i);
                                       set_pev(iEntityTarget, pev_iuser666, 0);
                                       set_pev(iEntityTarget, pev_iuser666key, 0);
                                       return true;
                                 }
                       }
                 }
         }
      return false;
}

1712483099770.png
 
Сообщения
3,583
Реакции
1,572
Помог
138 раз(а)
BalbuR, чет как-то слишком замудрено.
Проще хранить инфу в хешмапе, создавая ключи вида %i_key_%i, вместо %i соответственно n и id. По коду проверять, существует ли ключ, если существует, значит связь есть. Когда надо разрушить связть - удаляем ключ. И всё.
 
Сообщения
846
Реакции
525
Помог
13 раз(а)
BalbuR, чет как-то слишком замудрено.
Проще хранить инфу в хешмапе, создавая ключи вида %i_key_%i, вместо %i соответственно n и id. По коду проверять, существует ли ключ, если существует, значит связь есть. Когда надо разрушить связть - удаляем ключ. И всё.
не понимаю, пример бы
 
Сообщения
3,583
Реакции
1,572
Помог
138 раз(а)
BalbuR, не совсем понятно что ТС хотел сделать, поэтому приведу свой пример. Представим, что n это предметы в кастомном магазине, а id - соответственно игроки.
Код:
#include amxmodx

new Trie:trie = TrieCreate();

add_item_to_player(id, item) {
    TrieSetCell(trie, fmt("%i_key_%i", id, item), true);
}

bool:has_player_item(id, item) {
    return TrieKeyExists(trie, fmt("%i_key_%i", id, item));
}

delete_player_item(id, item) {
    TrieDeleteKey(trie, fmt("%i_key_%i", id, item))
}
 
Сообщения
260
Реакции
129
Помог
12 раз(а)
Nordic Warrior, ты меня почти правильно понял - но если подстраиваться под твой пример мне вот что нужно :

Код:
1. add_item_to_player(id, item) {
    TrieSetCell(trie, fmt("%i_key_%i", id, item), true);
}

2. delete_player_all_items(id) {}  // (забрать все итемы у игрока) не часто вызывается
3. bool:any_player_has_item(item) {} // (есть ли у кого то из игроков конкретный item) будет часто вызываться
В принципе концепция с игроками хорошо подходит , правда размер списка у меня будет не 32, а кол-во обьектов 100-200 поэтому и думаю как - то можно ли полных обходов избежать.

Думал может два Trie использовать : в одном ключ id и в значении массив из n а во втором ключ n и в значении массив из id
 
Последнее редактирование:
Сообщения
91
Реакции
141
Помог
1 раз(а)
Для твоей задачи очень хорошо подходит данная система - https://github.com/nikolaygaus/amxx-entity-prefub, также основана на Trie. Легко передавать данные между плагинами без использования сторонних нативов, все делается благодаря данной системе, главное продумать то, какая у тебя будет иерархия ключей и айдишников, дальше дело за малым.

Там есть пару примеров плагинов как этим пользоваться, можешь посмотреть, а так, практически тоже самое что и написал Nordic Warrior, только в одной единой системе
 
Сообщения
260
Реакции
129
Помог
12 раз(а)
t3rkecorejz, блин наверное у меня таки ничего не получилось с обьяснением задачи, потому как не понимаю как этот вариант или вариант Нордика мне может помочь. Попробую вариант trie с массивами внутри покрутить, если не добьюсь результата - тогда вернусь к теме и еще раз перечитаю все может потом дойдет ...
 

Пользователи, просматривающие эту тему

Сейчас на форуме нет ни одного пользователя.
Сверху Снизу