Добро пожаловать на Pro Pawn - Портал о PAWN-скриптинге.
Страница 1 из 3 1 2 3 ПоследняяПоследняя
Показано с 1 по 10 из 24
  1. #1
    Аватар для PawnoNoob
    Пользователь

    Статус
    Оффлайн
    Регистрация
    31.03.2016
    Сообщений
    257
    Репутация:
    3 ±

    Помогите исправить алгоритм удаления дома (всегда удаляется последний дом)

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

    есть enum с переменными:
    1. #define MAX_HOUSES (25) // для начала сделал именно 25, чтобы потом увеличивать;
    2. enum hinfo
    3. {
    4. house_ID,
    5. Float:house_X,
    6. Float:house_Y,
    7. Float:house_Z
    8. }
    9. new hInfo[MAX_HOUSES][hinfo], TOTALHOUSES;


    естественно, есть и загрузка:
    1. public LoadHouses()
    2. {
    3. new rows;
    4. cache_get_row_count(rows);
    5. if(rows)
    6. {
    7. for(new i = 1; i <= rows; i++)
    8. {
    9. TOTALHOUSES++;
    10. cache_get_value_name_int(i-1, !"id", hInfo[i][house_ID]);
    11. cache_get_value_name_float(i-1, !"x", hInfo[i][house_X]);
    12. cache_get_value_name_float(i-1, !"y", hInfo[i][house_Y]);
    13. cache_get_value_name_float(i-1, !"z", hInfo[i][house_Z]);
    14.  
    15. // здесь планировал создание пикапов и тому подобных вещей, но не об этом речь;
    16. }
    17. }
    18. return true;
    19. }


    есть команда для удаления:
    1. cmd:ahouse(playerid)
    2. {
    3. return ShowPlayerDialog(playerid, 0, DIALOG_STYLE_LIST, !"ahouse", !"1. Delete house", !"Ok", !"No");
    4. }


    и, соответственно, код в самом диалоге:
    1. ...
    2. case 0:
    3. {
    4. for(new i = 1; i <= TOTALHOUSES; i++)
    5. {
    6. // здесь показывает список домов от 1 до последнего (из TOTALHOUSES);
    7. }
    8. }


    Проблема в том, что при удалении, например, первого дома, его id остаётся в списке, но пропадает последний. В базе, соответственно, тоже удаляется (пикапы, тексты и тому подобные вещи удаляются тоже).

    Сомневаюсь в решении, но нужно ли использовать в этой ситуации итераторы? Если да, то каким образом это реализовать можно?
    Заранее благодарен за ответ!

  2. #2
    Аватар для pawnoholic
    Пользователь

    Статус
    Оффлайн
    Регистрация
    18.01.2018
    Сообщений
    128
    Репутация:
    15 ±
    Цитата Сообщение от PawnoNoob Посмотреть сообщение
    Сомневаюсь в решении, но нужно ли использовать в этой ситуации итераторы? Если да, то каким образом это реализовать можно?
    Примерно, как то так:

    1. new Iterator:House<MAX_HOUSES>;
    2.  
    3. public LoadHouses()
    4. {
    5. new
    6. idx,
    7. rows = cache_num_rows();
    8.  
    9. for (new i; i < rows; i++)
    10. {
    11. if ((idx = Iter_Free(House)) == INVALID_ITERATOR_SLOT) {
    12. break;
    13. }
    14.  
    15. cache_get_value_name_int(i, "id", hInfo[idx][house_ID]);
    16. // ...
    17.  
    18. Iter_Add(House, idx);
    19. }
    20. }

  3. Пользователь сказал cпасибо:
    PawnoNoob (09.06.2018)
  4. #3
    Аватар для PawnoNoob
    Пользователь

    Статус
    Оффлайн
    Регистрация
    31.03.2016
    Сообщений
    257
    Репутация:
    3 ±
    Цитата Сообщение от pawnoholic Посмотреть сообщение
    Примерно, как то так:

    1. new Iterator:House<MAX_HOUSES>;
    2.  
    3. public LoadHouses()
    4. {
    5. new
    6. idx,
    7. rows = cache_num_rows();
    8.  
    9. for (new i; i < rows; i++)
    10. {
    11. if ((idx = Iter_Free(House)) == INVALID_ITERATOR_SLOT) {
    12. break;
    13. }
    14.  
    15. cache_get_value_name_int(i, "id", hInfo[idx][house_ID]);
    16. // ...
    17.  
    18. Iter_Add(House, idx);
    19. }
    20. }
    А можете дать ссылку на тему, где есть урок с использованием итераторов?

    И ещё. Можете сказать, как удалить этот итератор? Ну, при удалении дома, например
    Последний раз редактировалось PawnoNoob; 09.06.2018 в 01:27.

  5. #4
    Аватар для pawnoholic
    Пользователь

    Статус
    Оффлайн
    Регистрация
    18.01.2018
    Сообщений
    128
    Репутация:
    15 ±
    Цитата Сообщение от PawnoNoob Посмотреть сообщение
    А можете дать ссылку на тему, где есть урок с использованием итераторов?
    http://forum.sa-mp.com/showthread.php?t=571159

    Цитата Сообщение от PawnoNoob Посмотреть сообщение
    И ещё. Можете сказать, как удалить этот итератор? Ну, при удалении дома, например
    1. Iter_Remove(House, id);

  6. #5
    Аватар для PawnoNoob
    Пользователь

    Статус
    Оффлайн
    Регистрация
    31.03.2016
    Сообщений
    257
    Репутация:
    3 ±
    Цитата Сообщение от pawnoholic Посмотреть сообщение
    А как их выводить? Ну, список домов в диалоговое окно

  7. #6
    Аватар для StevenH
    Пользователь

    Статус
    Оффлайн
    Регистрация
    13.10.2015
    Сообщений
    516
    Репутация:
    21 ±
    Цитата Сообщение от PawnoNoob Посмотреть сообщение
    А как их выводить? Ну, список домов в диалоговое окно
    С помощью foreach, например:

    PHP код:
    foreach(new hHouse)
    {
        
    // какой то код

    На самом деле итераторы довольно полезная и удобная штука)

  8. #7
    Аватар для DeimoS
    Модератор?

    Статус
    Оффлайн
    Регистрация
    27.01.2014
    Адрес
    Восточный Мордор
    Сообщений
    5,588
    Репутация:
    1984 ±
    Цитата Сообщение от pawnoholic Посмотреть сообщение
    Примерно, как то так:

    1. new Iterator:House<MAX_HOUSES>;
    2.  
    3. public LoadHouses()
    4. {
    5. new
    6. idx,
    7. rows = cache_num_rows();
    8.  
    9. for (new i; i < rows; i++)
    10. {
    11. if ((idx = Iter_Free(House)) == ITER_NONE) {
    12. break;
    13. }
    14.  
    15. cache_get_value_name_int(i, "id", hInfo[idx][house_ID]);
    16. // ...
    17.  
    18. Iter_Add(House, idx);
    19. }
    20. }
    Не совсем понятно зачем тут Iter_Free. У тебя ведь итератор имеет тот же размер, что и массив с домами, а значит логично просто проверить количество возвращённых строк, дабы получить тот же эффект, но без постоянного насилования Iter_Free (который, к слову, содержит в себе цикл). Да и не совсем понятен смысл поля "id", если у тебя есть итератор, который отлично сортирует данные.

    И не стоит использовать cache_num_rows, если ты записываешь значение в массив :) Этим ты вдвойне насилуешь стэк, ибо cache_num_rows является обычным stock, в котором создаётся переменная и вызывается cache_get_row_count.


    Я бы сделал так:
    Поле id оставил бы в виде "AUTO_INCREMENT" и не трогал бы его. Пусть этот столбец будет нужен исключительно MySQL. А для ID домов на сервере я создал бы ещё один столбец (например, "house_id") и контролировал бы его уже сам.
    Зачем это нужно? Во-первых, это позволит быть уверенным в том, что твой запрос на выгрузку данных вернёт ровно столько строк, сколько есть ячеек (если ты, конечно, не уменьшишь число ячеек в один момент, указав меньшее число, чем будет домов на сервере). Во-вторых, это позволит использовать этот ID в качестве индекса массива, тем самым ты сможешь обращаться к базе с домами, не обращаясь, при этом, к массиву, дабы получить ID дома, так как он будет равен индексу. Возможно, не очень понятно, так что покажу пример загрузки.


    1. new Iterator:House<MAX_HOUSES>;
    2.  
    3. public LoadHouses()
    4. {
    5. new row_count;
    6. cache_get_row_count(row_count);
    7.  
    8. if(row_count > MAX_HOUSES)// Проверка нужна как раз на случай, если ты решишь изменить значение MAX_HOUSES и укажешь его меньше, чем есть домов в базе
    9. {
    10. row_count = MAX_HOUSES;
    11. print("Warning: Тут сообщение с предупреждением о том, что часть домов не загрузилось");
    12. }
    13.  
    14. for (new i, idx; i < rows; i++)
    15. {
    16. cache_get_value_name_int(i, "house_id", idx);// Выгружаем ID дома
    17.  
    18. cache_get_value_name_float(i, "x", hInfo[idx][house_Y]);// И тут уже используем значение "idx" в качестве индекса
    19. cache_get_value_name_float(i, "y", hInfo[idx][house_Y]);
    20. cache_get_value_name_float(i, "z", hInfo[idx][house_Z]);
    21.  
    22. // ...
    23.  
    24. Iter_Add(House, idx);// + заносим индекс в итератор
    25. }
    26.  
    27. printf("Загружено %d домов", row_count);
    28. return 1;
    29. }


    А при создании дома уже используем Iter_Free, тем самым сразу проверяя лимит домов и определяя свободный ID для базы
    1. new id = Iter_Free(House);
    2. if(id == ITER_NONE)
    3. {
    4. SendClientMessage(playerid, -1, "Лимит домов исчерпан")
    5. return 1;
    6. }
    7.  
    8. format(...., "INSERT INTO house(house_id,...)VALUE(%d,....)", id);// Указываем значение Iter_Free в качестве значения "house_id"
    9. // ...
    10. Iter_Add(House, id);
    Последний раз редактировалось DeimoS; 17.06.2018 в 20:11.
    Связаться со мной в VK можно через личные сообщения этой группы
    Заказы не принимаю

    Широко известно, что идеи стоят 0.8333 цента каждая (исходя из рыночной цены 10 центов за дюжину).
    Великих идей полно, на них нет спроса.
    Воплощение идеи в законченную игру требует долгой работы,
    таланта, терпения и креативности, не говоря уж о затратах денег, времени и ресурсов.
    Предложить идею просто, воплотить – вот в чём проблема

    Steve Pavlina

  9. 2 пользователя(ей) сказали cпасибо:
    Aurelius (01.03.2020) PawnoNoob (10.06.2018)
  10. #8
    Аватар для PawnoNoob
    Пользователь

    Статус
    Оффлайн
    Регистрация
    31.03.2016
    Сообщений
    257
    Репутация:
    3 ±
    Цитата Сообщение от DeimoS Посмотреть сообщение
    Не совсем понятно зачем тут Iter_Free. У тебя ведь итератор имеет тот же размер, что и массив с домами, а значит логично просто проверить количество возвращённых строк, дабы получить тот же эффект, но без постоянного насилования Iter_Free (который, к слову, содержит в себе цикл). Да и не совсем понятен смысл поля "id", если у тебя есть итератор, который отлично сортирует данные.

    И не стоит использовать cache_num_rows, если ты записываешь значение в массив :) Этим ты вдвойне насилуешь стэк, ибо cache_num_rows является обычным stock, в котором создаётся переменная и вызывается cache_get_row_count.


    Я бы сделал так:
    Поле id оставил бы в виде "AUTO_INCREMENT" и не трогал бы его. Пусть этот столбец будет нужен исключительно MySQL. А для ID домов на сервере я создал бы ещё один столбец (например, "house_id") и контролировал бы его уже сам.
    Зачем это нужно? Во-первых, это позволит быть уверенным в том, что твой запрос на выгрузку данных вернёт ровно столько строк, сколько есть ячеек (если ты, конечно, не уменьшишь число ячеек в один момент, указав меньшее число, чем будет домов на сервере). Во-вторых, это позволит использовать этот ID в качестве индекса массива, тем самым ты сможешь обращаться к базе с домами, не обращаясь, при этом, к массиву, дабы получить ID дома, так как он будет равен индексу. Возможно, не очень понятно, так что покажу пример загрузки.


    1. new Iterator:House<MAX_HOUSES>;
    2.  
    3. public LoadHouses()
    4. {
    5. new row_count;
    6. cache_get_row_count(row_count);
    7.  
    8. if(row_count > MAX_HOUSES)// Проверка нужна как раз на случай, если ты решишь изменить значение MAX_HOUSES и укажешь его меньше, чем есть домов в базе
    9. {
    10. row_count = MAX_HOUSES;
    11. print("Warning: Тут сообщение с предупреждением о том, что часть домов не загрузилось");
    12. }
    13.  
    14. for (new i, idx; i < rows; i++)
    15. {
    16. cache_get_value_name_int(i, "house_id", idx);// Выгружаем ID дома
    17.  
    18. cache_get_value_name_float(i, "x", hInfo[idx][house_Y]);// И тут уже используем значение "idx" в качестве индекса
    19. cache_get_value_name_float(i, "y", hInfo[idx][house_Y]);
    20. cache_get_value_name_float(i, "z", hInfo[idx][house_Z]);
    21.  
    22. // ...
    23.  
    24. Iter_Add(House, idx);// + заносим индекс в итератор
    25. }
    26.  
    27. printf("Загружено %d домов", row_count);
    28. return 1;
    29. }


    А при создании дома уже используем Iter_Free, тем самым сразу проверяя лимит домов и определяя свободный ID для базы
    1. new id = Iter_Free(House);
    2. if(id == INVALID_ITERATOR_SLOT)
    3. {
    4. SendClientMessage(playerid, -1, "Лимит домов исчерпан")
    5. return 1;
    6. }
    7.  
    8. format(...., "INSERT INTO house(house_id,...)VALUE(%d,....)", id);// Указываем значение Iter_Free в качестве значения "house_id"
    9. // ...
    10. Iter_Add(House, id);
    И как потом, допустим, по номеру (id) дома посмотреть его информацию? Или присвоить значение pHouse игроку (которое равно id дома)

  11. #9
    Аватар для DeimoS
    Модератор?

    Статус
    Оффлайн
    Регистрация
    27.01.2014
    Адрес
    Восточный Мордор
    Сообщений
    5,588
    Репутация:
    1984 ±
    Цитата Сообщение от PawnoNoob Посмотреть сообщение
    И как потом, допустим, по номеру (id) дома посмотреть его информацию?
    Эмм, так во всех случаях, когда ты работаешь с домами на сервере, у тебя есть индекс этого дома в массиве hInfo. Вот точно так же, как ты получаешь индекс для массива, получай ID дома - теперь это одно и то же.

    Только теперь не забывай добавлять "LIMIT 1" ко всем запросам, где нужно изменить/получить лишь какую-то одну строку, дабы MySQL не продолжал обрабатывать все строки после нахождения нужной. В случае с выборкой по "AUTO_INCREMENT" MySQL делает это автоматически, ибо "A_I" поля не могут повторять значения и логично, что если одна строка найдена, то искать дальше нет смысла. А вот в случае с выборкой для полей без "AUTO_INCREMENT" лучше указывать "LIMIT" явно.

    Цитата Сообщение от PawnoNoob Посмотреть сообщение
    Или присвоить значение pHouse игроку (которое равно id дома)
    При авторизации делай запрос в базу с домами и ищи ID аккаунта игрока среди ID владельцев (надеюсь, ты не хранишь в базе с домами ники, а хранишь ID аккаунтов).
    Связаться со мной в VK можно через личные сообщения этой группы
    Заказы не принимаю

    Широко известно, что идеи стоят 0.8333 цента каждая (исходя из рыночной цены 10 центов за дюжину).
    Великих идей полно, на них нет спроса.
    Воплощение идеи в законченную игру требует долгой работы,
    таланта, терпения и креативности, не говоря уж о затратах денег, времени и ресурсов.
    Предложить идею просто, воплотить – вот в чём проблема

    Steve Pavlina

  12. #10
    Аватар для StevenH
    Пользователь

    Статус
    Оффлайн
    Регистрация
    13.10.2015
    Сообщений
    516
    Репутация:
    21 ±
    Дополню.. довольно правильное решение при авторизации аккаунта делать запрос в базу с домами и таким образом проверять владельца и записать в переменную, ту же pHouse (но без сохранения, и соответственно с обнулением при коннекте)..

    Почему же?

    Может быть довольно много проблем, например не раз замечал, что дом у игрока якобы есть, а в таблице с домами его нет (или наоборот). Конечно, тут косяк самой реализации, но лучше сделать удобнее и потом не мучаться!)

 

 
Страница 1 из 3 1 2 3 ПоследняяПоследняя

Информация о теме

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

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •