PDA

Просмотр полной версии : [Вопрос] Взаимодействие с активным списком массива.



execution
20.09.2020, 17:35
Здравствуйте.

Существует массив, который может изменять значения прямо тогда, когда его перебирает какой-то игрок. То есть, игрок нажмёт клавишу вперёд - ему покажет последующие 5 валидных значений, нажмёт назад - покажет предыдущие.
Например:


new
array_list[100] = {5, 6, 7, ...};

Показали игроку первые пять значений списка (array_list[0], array_list[1], ...)
Затем изменили значение для 6-й ячейки на невалидное (-1) и следующие пять будут браться не array_list[5], а array_list[6], array_list[7] ...
Так-же может сложиться ситуации, что показали значения 0-4 ячейки массива и в это время данные в какой-то из этих значений может измениться и как это учесть - без понятия.

С перебором неизменяемых и последовательных значений есть опыт, а в таких, нет.
Если есть хоть какие-либо предположения/мысля - рад буду выслушать все)

DeimoS
20.09.2020, 18:20
Я бы сказал, что если у тебя допускается возможность изменять данные, с которыми в данный момент работают и, при этом, актуальность данных важна, то, вероятнее всего, в реализованной тобой логике системы что-то не так.

Ну а вообще единственный вариант, который я вижу - при изменении данных проверять, показываются ли они кому-то и если показываются - сообщать об изменения и/или по новой показывать данные, но уже пропуская изменённые (если они стали невалидными). Либо если игрок пытается взаимодействовать с уже изменёнными данными - сообщать ему об ошибке и показывать уже актуальные данные.

Вообще было бы лучше, если бы ты более конкретизировал пример, рассказав что ты пытаешься сделать, что вообще за данные и почему/когда они могут изменяться (а так же почему важно, чтоб у просматривающего данные игрока, список показанных данных всегда был актуальным).

execution
20.09.2020, 18:36
Я бы сказал, что если у тебя допускается возможность изменять данные, с которыми в данный момент работают и, при этом, актуальность данных важна, то, вероятнее всего, в реализованной тобой логике системы что-то не так.

Ну а вообще единственный вариант, который я вижу - при изменении данных проверять, показываются ли они кому-то и если показываются - сообщать об изменения и/или по новой показывать данные, но уже пропуская изменённые (если они стали невалидными). Либо если игрок пытается взаимодействовать с уже изменёнными данными - сообщать ему об ошибке и показывать уже актуальные данные.

Вообще было бы лучше, если бы ты более конкретизировал пример, рассказав что ты пытаешься сделать, что вообще за данные и почему/когда они могут изменяться (а так же почему важно, чтоб у просматривающего данные игрока, список показанных данных всегда был актуальным).

Система управлением автосалонов.
Есть возможность добавлять/удалять автомобили прямо из игры. Показ автомобилей на выбор не больше, чем 5 шт за раз

DeimoS
20.09.2020, 18:46
Система управлением автосалонов.
Есть возможность добавлять/удалять автомобили прямо из игры. Показ автомобилей на выбор не больше, чем 5 шт за раз

А кто их может добавлять/удалять? И насколько часто это может быть?

Пока что не вижу ни одной причины, которая мешала бы сделать так, что даже если, во время открытия списка авто, удалили то авто, которое игрок выбрал, то игрок всё равно мог бы его купить. Либо наоборот не мог и видел сообщение, а-ля: "Данный автомобиль более недоступен".
Тут отталкиваться нужно исключительно от того, чего ты хочешь добиться и для чего.

execution
20.09.2020, 19:11
А кто их может добавлять/удалять? И насколько часто это может быть?

Пока что не вижу ни одной причины, которая мешала бы сделать так, что даже если, во время открытия списка авто, удалили то авто, которое игрок выбрал, то игрок всё равно мог бы его купить. Либо наоборот не мог и видел сообщение, а-ля: "Данный автомобиль более недоступен".
Тут отталкиваться нужно исключительно от того, чего ты хочешь добиться и для чего.

Управлять могут администраторы, возможно в будущем будут изменения.
На счёт проверки наличия во время покупки - согласен, спасибо :hi:

А что на счёт перебора авто группами?
Допустим я буду сохранять индексы пяти показываемых авто, соответственно буду сохранять и номер страницы. Удалили в автосалоне 3 автомобиля, и я нажимаю далее -> по формуле номер_страницы*кол-во_показа_за_раз я получу якобы последний индекс, но уже это будет не последний и как в этом случае быть?

DeimoS
20.09.2020, 19:28
Тебе нужно решить, настолько ли важно не давать игроку покупать автомобиль, который удалил администратор.

Если не так важно - при первом открытии списка автомобилей выгружай не 5 автомобилей, а сразу все и сохраняй пришедший кэш. Далее уже работай с этим кэшем и тогда тебе будет совершенно всё равно на то, что происходит с самой таблицей. Собственно, это, как по мне, самый правильный вариант, ибо ситуация, при которой администратор удаляет автомобиль прямо во время игры - это не очень нормально. Лучше уж тогда просто помечать их для удаления, выделив под это столбец, и при следующем запуске мода уже непосредственно удалить их, не мешая , тем самым, игровому процессу.

Но даже если важно - всё равно нужно грузить все автомобили и работать с кэшем, а не мучить БД постоянными запросами. Собственно, по переменной, которая будет хранить кэш, можно будет определять то, какому игроку показывается список, и, при удалении одного из авто, по новой загружать данные для всех игроков с открытыми списками, сообщая в чате, что в таблице были совершены изменения.


Вот, если что, пример того, как можно работать с кэшем в подобном случае:

new pVar__BanLog_Cache[] = "pVar__BanLog_Cache";
new pVar__BanLog_Page[] = "pVar__BanLog_Page";
new pVar__BanLog_BannedName[] = "pVar__BanLog_BannedName";

const MAX_ROW_IN_BANLOG_DIALOG_PAGE = 30;
const dBanLogList = 666;

CMD:checkban(playerid, params[])
{
if(pl[playerid][pAdmin]<4)return 1;
if(isnull(params)) return send(playerid, COLOR_GRAD1, "/checkban Nick_Name");

ShowPlayerBanLogForPlayer(playerid, params);
return 1;
}

stock ShowPlayerBanLogForPlayer(playerid, const banned_player_name[])
{
if(GetPVarType(playerid, pVar__BanLog_Cache))
{
new Cache:cache_id = Cache:GetPVarInt(playerid, pVar__BanLog_Cache);

if(cache_is_valid(cache_id))
cache_delete(cache_id);

DeletePVar(playerid, pVar__BanLog_Cache);
DeletePVar(playerid, pVar__BanLog_Page);
DeletePVar(playerid, pVar__BanLog_BannedName);
}

new query_string[78+MAX_PLAYER_NAME+1];
mysql_format(mysql_connect_ID, query_string, sizeof(query_string),
"SELECT Nick, BanDate, AdmNick, Reason FROM banhistory WHERE Nick='%e' ORDER BY BanDate", banned_player_name);
mysql_tquery(mysql_connect_ID, query_string, "@MySQL__PlayerBanLog", "i", playerid);
SetPVarString(playerid, pVar__BanLog_BannedName, banned_player_name);
}


@MySQL__PlayerBanLog(playerid);
@MySQL__PlayerBanLog(playerid)
{
new rows;
cache_get_row_count(rows);
if(!rows)
{
SendClientMessage(playerid, 0xFFFFFFFF, "Ошибка: Указанный игрок не найден или не был забанен.");
return;
}

if(rows > MAX_ROW_IN_BANLOG_DIALOG_PAGE)
{
SetPVarInt(playerid, pVar__BanLog_Cache, _:cache_save());
}

ShowPlayerBanLogCache(playerid);
}

stock ShowPlayerBanLogCache(playerid)
{
if(!GetPVarType(playerid, pVar__BanLog_Cache))
{
SendClientMessage(playerid, 0xFFFFFFFF,
"При отображении списка блокировок произошла ошибка [#001]. Повторите попытку.");
return;
}

new Cache:cache_id = Cache:GetPVarInt(playerid, pVar__BanLog_Cache);

if(!cache_is_valid(cache_id))
{
DeletePVar(playerid, pVar__BanLog_Cache);
DeletePVar(playerid, pVar__BanLog_Page);
DeletePVar(playerid, pVar__BanLog_BannedName);
SendClientMessage(playerid, 0xFFFFFFFF,
"При отображении списка блокировок произошла ошибка [#002]. Повторите попытку.");
return;
}

if(cache_is_any_active())
cache_unset_active();

cache_set_active(cache_id);

new rows;
cache_get_row_count(rows);

new page = GetPVarInt(playerid, pVar__BanLog_Page);

new i = page*MAX_ROW_IN_BANLOG_DIALOG_PAGE;
new max_i = i + MAX_ROW_IN_BANLOG_DIALOG_PAGE;
if(max_i > rows)
max_i = rows;

new ban_date[22];
new admin_name[MAX_PLAYER_NAME - 3];
new reason[20];

new dialog_string[(2+5+sizeof(ban_date)+sizeof(admin_name)+sizeof(reason))*MAX_ROW_IN_BANLOG_DIALOG_PAGE+1];
dialog_string = "№. Админ.\tДата блокировки\tПричина\n";

for(; i < max_i; i++)
{
cache_get_value_name(i, "BanDate", ban_date);
cache_get_value_name(i, "AdmNick", admin_name);
cache_get_value_name(i, "Reason", reason);

format(dialog_string, sizeof(dialog_string), "%s%i. %s\t%s\t%s\n", dialog_string, i + 1, admin_name, ban_date, reason);
}

if(rows > MAX_ROW_IN_BANLOG_DIALOG_PAGE)
{
if(max_i < rows)
{
strcat(dialog_string, "»» Далее\n");
}
if(page > 0)
{
strcat(dialog_string, "«« Назад\n");
}
}

new banned_player_name[MAX_PLAYER_NAME];
GetPVarString(playerid, pVar__BanLog_BannedName, banned_player_name, MAX_PLAYER_NAME);
ShowPlayerDialog(playerid, dBanLogList, DIALOG_STYLE_TABLIST_HEADERS, banned_player_name, dialog_string, "Выбрать", "Закрыть");
}


public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
switch(dialogid)
{
case dBanLogList:
{
if(!GetPVarType(playerid, pVar__BanLog_Cache))
{
SendClientMessage(playerid, 0xFFFFFFFF,
"При отображении списка использований промокода произошла ошибка [#003]. Повторите попытку.");
return 1;
}
new Cache:cache_id = Cache:GetPVarInt(playerid, pVar__BanLog_Cache);

if(!cache_is_valid(cache_id))
{
DeletePVar(playerid, pVar__BanLog_Cache);
DeletePVar(playerid, pVar__BanLog_Page);
DeletePVar(playerid, pVar__BanLog_BannedName);
SendClientMessage(playerid, 0xFFFFFFFF,
"При отображении списка использований промокода произошла ошибка [#004]. Повторите попытку.");
return 1;
}

if(!response)
{
cache_delete(cache_id);
DeletePVar(playerid, pVar__BanLog_Cache);
DeletePVar(playerid, pVar__BanLog_Page);
DeletePVar(playerid, pVar__BanLog_BannedName);
return 1;
}

if(!strcmp(inputtext, "»» Далее"))
{
SetPVarInt(playerid, pVar__BanLog_Page, GetPVarInt(playerid, pVar__BanLog_Page)+1);
ShowPlayerBanLogCache(playerid);
}
else if(!strcmp(inputtext, "«« Назад"))
{
SetPVarInt(playerid, pVar__BanLog_Page, GetPVarInt(playerid, pVar__BanLog_Page)-1);
if(GetPVarInt(playerid, pVar__BanLog_Page) < 1)
DeletePVar(playerid, pVar__BanLog_Page);
ShowPlayerBanLogCache(playerid);
}
else
{
ShowPlayerBanLogCache(playerid);
}
return 1;
}
}
return 1;
}


public OnPlayerDisconnect(playerid, reason)
{
if(GetPVarType(playerid, pVar__BanLog_Cache))
{
new Cache:cache_id = Cache:GetPVarInt(playerid, pVar__BanLog_Cache);

if(cache_is_valid(cache_id))
cache_delete(cache_id);
}
return 1;
}