PDA

Просмотр полной версии : [Вопрос] Нерабочий /lock



SteveStage
08.12.2019, 21:57
Помнится, раньше я спрашивал, как создать /lock. Позже я наткнулся на такую функцию нахождения транспорта поблизости:

stock GetSearchVehicle(playerid, Float:distance)
{
new
Float:veh_x,
Float:veh_y,
Float:veh_z,
Float:pos_veh,
search_vehicle = INVALID_VEHICLE_ID;

foreach(Vehicle, vehicle)
{
GetVehiclePos(vehicle, veh_x, veh_y, veh_z);
pos_veh = GetPlayerDistanceFromPoint(playerid, veh_x, veh_y, veh_z);
if(pos_veh <= distance)
{
search_vehicle = vehicle,
distance = pos_veh;
}
}
return search_vehicle;
}

Но в этой комманде ты можешь открыть любое авто независимо от владельца:

CMD:lock(playerid, params[])
{
if(login_check{playerid} == false)
return true;
new vehicleid = GetPlayerVehicleID(playerid);
if(vehicleid == 0)
vehicleid = GetSearchVehicle(playerid, 5.0);
if(vehicleid == INVALID_VEHICLE_ID || strcmp(veh[vehicleid][v_owner], GetName(playerid)))
return SCM(playerid, COLOR_YELLOW, !"Вы должны находиться рядом со своим личным т/с, чтобы открыть его дверь!");
new
string[144+1];
if(lock_car{vehicleid} == false)
{
format(string, sizeof(string), "*%s закрыл дверь т/с", GetName(playerid));
ProxDetector(playerid, 20.0, COLOR_ACTION, string);
GetVehicleParamsEx(vehicleid, engine, lights, alarm, doors, bonnet, boot, objective);
SetVehicleParamsEx(vehicleid, engine, lights, alarm, VEHICLE_PARAMS_ON, bonnet, boot, objective);
lock_car{vehicleid} = true;
return true;
}
if(lock_car{vehicleid} == true)
{
format(string, sizeof(string), "*%s открыл дверь т/с", GetName(playerid));
ProxDetector(playerid, 20.0, COLOR_ACTION, string);
GetVehicleParamsEx(vehicleid, engine, lights, alarm, doors, bonnet, boot, objective);
SetVehicleParamsEx(vehicleid, engine, lights, alarm, VEHICLE_PARAMS_OFF, bonnet, boot, objective);
lock_car{vehicleid} = false;
return true;
}
return true;
}

Что я делаю не так?

DeimoS
08.12.2019, 22:28
Во-первых, зачем ты после
if(lock_car{vehicleid} == false)
делаешь проверку
if(lock_car{vehicleid} == true)
если и так понятно, что переменная имеет значение "true"? Заменяешь вторую проверку на "else" и избавляешься от лишнего обращения к переменной lock_car

Во-вторых, логируй содержимое v_owner и GetName. Как вариант, либо переменная содержит пустую строку, либо функция возвращает оную, из-за чего проверка и проходит (так как в strcmp есть баг (http://wiki.pro-pawn.ru/wiki/Strcmp)).

Вообще зачем делать проверку на ник? Автомобиль игрока есть смысл грузить только при авторизации этого самого игрока на сервере (точнее, лучше грузить только когда игрок сам запрашивает его), ибо если ты собрался грузить все личные авто при запуске сервера, то лимит в 2000 автомобилей на сервере быстро обломает тебя, когда ты запустишь сервер и нагонишь онлайна.
А если данные грузятся только при авторизации игрока, то и для определения владельца можно просто сохранить ID игрока (а игроку - ID автомобиля, чтоб не тратить время на перебор всех авто циклом). Сверять строки тут вообще ни к чему.

SteveStage
08.12.2019, 23:03
Автомобиль игрока есть смысл грузить только при авторизации этого самого игрока на сервере (точнее, лучше грузить только когда игрок сам запрашивает его), ибо если ты собрался грузить все личные авто при запуске сервера, то лимит в 2000 автомобилей на сервере быстро обломает тебя, когда ты запустишь сервер и нагонишь онлайна.

(100*3)+(16*5) = 390 < 2000

SteveStage
08.12.2019, 23:41
А если данные грузятся только при авторизации игрока, то и для определения владельца можно просто сохранить ID игрока (а игроку - ID автомобиля, чтоб не тратить время на перебор всех авто циклом). Сверять строки тут вообще ни к чему.

Немного не понял сути, а как тогда делать запросы на ник игрока по его айди, если его айди = айди авто? И что ты вообще подразумевал, когда писал эти строки?

DeimoS
09.12.2019, 02:24
Немного не понял сути, а как тогда делать запросы на ник игрока по его айди, если его айди = айди авто? И что ты вообще подразумевал, когда писал эти строки?

Какие запросы на ник игрока? В таблице с автомобилями у тебя вообще ников быть не должно. Там должен быть ID аккаунта владельца.
При авторизации получаешь ID аккаунта вместе со всеми данными из таблицы "account" и делаешь запрос в таблицу с автомобилями, выгружая данные по этому самому ID. И уже дальнейшую работу с таблицей для игрока (обновление/чтение данных) производишь либо опять по ID аккаунта владельца, либо по номеру строки автомобиля из таблицы с автомобилями, который так же можешь выгрузить в отдельную переменную.

ID игрока - это его ID в игре. По этому ID ты можешь напрямую обращаться к массиву игрока, получая любые данные.
А у игрока будет хранится ID автомобиля, который сразу будет равен и индексу в ячейке массива с автомобилями, и ID автомобиля на сервере.
Грубо говоря, так:
enum e_PLAYER_INFO
{
/*...*/
pVehID,// Тут будет хранится значение vehicleid, которое ты получишь, когда создашь автомобиль при загрузке данных
/*...*/
};
new pInfo[MAX_PLAYERS][e_PLAYER_INFO];
enum e_PLAYER_VEHICLE_INFO
{
/*...*/
pTableRowID,// Тут будет хранится значение поля 'id'
pOwnerID,// Тут будет хранится значение playerid для владельца
pOwnerTableID,// Тут будет хранится значение поля 'owner_id', содержащее номер строки поля 'id' из таблицы с аккаунтами
/*...*/
};
new pVehInfo[MAX_VEHICLES][e_PLAYER_VEHICLE_INFO];

//Соответственно, чтоб проверить, есть ли у автомобиля владелец, достаточно будет сделать так:
if(pVehInfo[vehicleid][pOwnerTableID] == 0))// Владельца нет.
if(pVehInfo[vehicleid][pOwnerID] != playerid))// Владелец не игрок.
// И т.п.

//А для взаимодействия напрямую с транспортом игрока можно сделать так:
new vehicleid = pInfo[playerid][pVeh];
// И уже после проверки vehicleid на валидность (существует ли у игрока автомобиль), можно напрямую обращаться к pVehInfo
pVehInfo[vehicleid][/*Нужная константа*/]

SteveStage
09.12.2019, 21:20
Вот так синтаксически и логически правильно?

case DLG_ID_CAR_BUY:
{
if(response)
{
new
i = GetPVarInt(playerid, "BuyCarID");
if(player[playerid][p_money] < veh[i][v_price])
{
SCM(playerid, COLOR_RED, !"[SERVER] У вас недостаточно денег, чтобы купить этот транспорт!");
return RemovePlayerFromVehicle(playerid);
}
else
{
player[playerid][p_money]-=veh[i][v_price];
SavePlayer(playerid, "Money", player[playerid][p_money], "d");
new
string[128+1];
format(string, sizeof(string), "UPDATE `vehicles` SET `ownerid` = '%d' WHERE `id` = '%d'", playerid, veh[i][v_id]);
mysql_function_query(connect_mysql, string, false, "", "");

format(string, sizeof(string), "UPDATE `accounts` SET `vehid` = '%d' WHERE `id` = '%d'", veh[i][v_id], player[playerid][p_id]);
mysql_function_query(connect_mysql, string, false, "", "");
}
}
else
return RemovePlayerFromVehicle(playerid);
}

При загрузке аккаунта

format(string, sizeof(string), "SELECT * FROM `vehicles` WHERE `id` = '%d'", player[playerid][p_vehid]);
mysql_function_query(connect_mysql, string, true, "@_LoadVehs", "dd", playerid, player[playerid][p_vehid]);

@_LoadVehs(playerid, vehicleid);
@_LoadVehs(playerid, vehicleid)
{
new
rows,
fields;
cache_get_data(rows, fields);
if(rows)
{
new
veh_id,
veh_model,
Float:veh_x,
Float:veh_y,
Float:veh_z,
Float:veh_a,
Float:veh_hp,
veh_color1,
veh_color2,
veh_dmg1,
veh_dmg2,
veh_dmg3,
veh_dmg4,
veh_paintjob;

veh_model = cache_get_field_content_int(0, "model");
veh_x = cache_get_field_content_float(0, "x");
veh_y = cache_get_field_content_float(0, "y");
veh_z = cache_get_field_content_float(0, "z");
veh_a = cache_get_field_content_float(0, "a");
veh_hp = cache_get_field_content_float(0, "hp");
veh_color1 = cache_get_field_content_int(0, "color1");
veh_color2 = cache_get_field_content_int(0, "color2");
veh_dmg1 = cache_get_field_content_int(0, "dmg1");
veh_dmg2 = cache_get_field_content_int(0, "dmg2");
veh_dmg3 = cache_get_field_content_int(0, "dmg3");
veh_dmg4 = cache_get_field_content_int(0, "dmg4");
veh_paintjob = cache_get_field_content_int(0, "paintjob");

veh_id = CreateVehicle(veh_model, veh_x, veh_y, veh_z, veh_a, veh_color1, veh_color2, 0);
if(veh_id != INVALID_VEHICLE_ID) return true;
UpdateVehicleDamageStatus(veh_id, veh_dmg1, veh_dmg2, veh_dmg3, veh_dmg4);
SetVehicleHealth(veh_id, veh_hp);
if(veh_paintjob > 0)
ChangeVehiclePaintjob(veh_id, veh_paintjob-1); // 1, 2, 3 - нумерация винилов по порядку, 4 - отсутствие винил
allvehs++;
veh[veh_id][v_price] = ModelPrice[veh_model-400];
veh[veh_id][v_model] = veh_model;
veh[veh_id][v_x] = veh_x;
veh[veh_id][v_y] = veh_y;
veh[veh_id][v_z] = veh_z;
veh[veh_id][v_a] = veh_a;
veh[veh_id][v_hp] = veh_hp;
veh[veh_id][v_color1] = veh_color1;
veh[veh_id][v_color2] = veh_color2;
veh[veh_id][v_dmg1] = veh_dmg1;
veh[veh_id][v_dmg2] = veh_dmg2;
veh[veh_id][v_dmg3] = veh_dmg3;
veh[veh_id][v_dmg4] = veh_dmg4;
veh[veh_id][v_paintjob] = veh_paintjob;
veh[veh_id][v_class] = cache_get_field_content_int(0, "class");
veh[veh_id][v_ownerid] = playerid;
veh[veh_id][v_id] = vehicleid;
static
fmt_str[] = "UPDATE `vehicles` SET `ownerid` = '%d' WHERE `id` = '%d'";
new
string[sizeof(fmt_str)-4+4*2+1];
format(string, sizeof(string), fmt_str, playerid, vehicleid);
mysql_function_query(connect_mysql, string, false, "", "");
}
return true;
}

UPD: Проверил, но машины не загружаются
Честно уже не знаю, правильно ли логически построена эта система, голова раскалывается, мог написать полнейший бред :)

DeimoS
10.12.2019, 04:04
Сильно не вчитывался в код, но почему ты, например, вот тут

format(string, sizeof(string), "UPDATE `vehicles` SET `ownerid` = '%d' WHERE `id` = '%d'", playerid, veh[i][v_id]);
в ownerid записываешь playerid?
Отдохни немного и вернись к коду на свежую голову :)

SteveStage
10.12.2019, 15:24
Сильно не вчитывался в код, но почему ты, например, вот тут

format(string, sizeof(string), "UPDATE `vehicles` SET `ownerid` = '%d' WHERE `id` = '%d'", playerid, veh[i][v_id]);
в ownerid записываешь playerid?

ownerid - айди владельца в таблице `vehicles`, тоесть playerid

DeimoS
10.12.2019, 15:29
ownerid - айди владельца в таблице `vehicles`, тоесть playerid

Эмм, а зачем он тебе в таблице? В таблице должен хранится ID аккаунта, а не ID игрока.

SteveStage
10.12.2019, 15:48
Эмм, а зачем он тебе в таблице? В таблице должен хранится ID аккаунта, а не ID игрока.

Я же говорю - полнейший бред мог написать, сори)

Правильней будет вот так:

format(string, sizeof(string), "UPDATE `vehicles` SET `ownerid` = '%d' WHERE `id` = '%d'", player[playerid][p_id], veh[i][v_id]);

Кстати, я понял, почему машина не загрузилась - я забыл в таблице `accounts` своему акку присвоить айди авто из `vehicles`

DeimoS
10.12.2019, 16:06
Правильней будет вот так:

format(string, sizeof(string), "UPDATE `vehicles` SET `ownerid` = '%d' WHERE `id` = '%d'", player[playerid][p_id], veh[i][v_id]);

Ага. Только этот запрос не нужен при загрузке транспорта. Только при покупке или перепродаже.

SteveStage
10.12.2019, 17:21
Ага. Только этот запрос не нужен при загрузке транспорта. Только при покупке или перепродаже.

Получилось как-то так:

case DLG_ID_VEH_BUY:
{
if(response)
{
new
i = GetPVarInt(playerid, "BuyVehID");
if(player[playerid][p_money] < veh[i][v_price])
{
SCM(playerid, COLOR_RED, !"[SERVER] У вас недостаточно денег, чтобы купить этот транспорт!");
return RemovePlayerFromVehicle(playerid);
}
else
{
player[playerid][p_money]-=veh[i][v_price];
SavePlayer(playerid, "Money", player[playerid][p_money], "d");
new
string[128+1];
format(string, sizeof(string), "UPDATE `vehicles` SET `ownerid` = '%d' WHERE `id` = '%d'", player[playerid][p_id], veh[i][v_id]);
mysql_function_query(connect_mysql, string, false, "", "");

format(string, sizeof(string), "UPDATE `accounts` SET `vehid` = '%d' WHERE `id` = '%d'", veh[i][v_id], player[playerid][p_id]);
mysql_function_query(connect_mysql, string, false, "", "");
}
}
else
return RemovePlayerFromVehicle(playerid);
}

@_LoadVehs(playerid, vehicleid);
@_LoadVehs(playerid, vehicleid)
{
new
rows,
fields;
cache_get_data(rows, fields);
if(rows)
{
new
veh_id,
veh_model,
Float:veh_x,
Float:veh_y,
Float:veh_z,
Float:veh_a,
Float:veh_hp,
veh_color1,
veh_color2,
veh_dmg1,
veh_dmg2,
veh_dmg3,
veh_dmg4,
veh_paintjob;

veh_model = cache_get_field_content_int(0, "model");
veh_x = cache_get_field_content_float(0, "x");
veh_y = cache_get_field_content_float(0, "y");
veh_z = cache_get_field_content_float(0, "z");
veh_a = cache_get_field_content_float(0, "a");
veh_hp = cache_get_field_content_float(0, "hp");
veh_color1 = cache_get_field_content_int(0, "color1");
veh_color2 = cache_get_field_content_int(0, "color2");
veh_dmg1 = cache_get_field_content_int(0, "dmg1");
veh_dmg2 = cache_get_field_content_int(0, "dmg2");
veh_dmg3 = cache_get_field_content_int(0, "dmg3");
veh_dmg4 = cache_get_field_content_int(0, "dmg4");
veh_paintjob = cache_get_field_content_int(0, "paintjob");

veh_id = CreateVehicle(veh_model, veh_x, veh_y, veh_z, veh_a, veh_color1, veh_color2, 0);
if(veh_id != INVALID_VEHICLE_ID) return true;
UpdateVehicleDamageStatus(veh_id, veh_dmg1, veh_dmg2, veh_dmg3, veh_dmg4);
SetVehicleHealth(veh_id, veh_hp);
if(veh_paintjob > 0)
ChangeVehiclePaintjob(veh_id, veh_paintjob-1); // 1, 2, 3 - нумерация винилов по порядку, 4 - отсутствие винил
allvehs++;
veh[veh_id][v_price] = ModelPrice[veh_model-400];
veh[veh_id][v_model] = veh_model;
veh[veh_id][v_x] = veh_x;
veh[veh_id][v_y] = veh_y;
veh[veh_id][v_z] = veh_z;
veh[veh_id][v_a] = veh_a;
veh[veh_id][v_hp] = veh_hp;
veh[veh_id][v_color1] = veh_color1;
veh[veh_id][v_color2] = veh_color2;
veh[veh_id][v_dmg1] = veh_dmg1;
veh[veh_id][v_dmg2] = veh_dmg2;
veh[veh_id][v_dmg3] = veh_dmg3;
veh[veh_id][v_dmg4] = veh_dmg4;
veh[veh_id][v_paintjob] = veh_paintjob;
veh[veh_id][v_class] = cache_get_field_content_int(0, "class");
veh[veh_id][v_ownerid] = playerid;
veh[veh_id][v_id] = vehicleid;
}
return true;
}

public OnPlayerStateChange(playerid, newstate, oldstate)
{
if(newstate == PLAYER_STATE_DRIVER)
{
new
vehicleid = GetPlayerVehicleID(playerid);
if(IsABicycle(vehicleid) || IsAHelicopter(vehicleid))
{
GetVehicleParamsEx(vehicleid, engine, lights, alarm, doors, bonnet, boot, objective);
SetVehicleParamsEx(vehicleid, VEHICLE_PARAMS_ON, lights, alarm, doors, bonnet, boot, objective);
}
for(new i; i < allvehs; i++)
{
if(vehicleid < i) continue;
if(veh[vehicleid][v_id] == SALE_VEHICLE_ID)
{
static
fmt_str[] =
"{00C0FF}Желаете ли вы купить данный транспорт?\
\n\
\n{00C0FF}Модель:\t\t{F81414}%s\
\n{00C0FF}ID:\t\t{F81414}%d";
new
string[sizeof(fmt_str)-4+4+20+1];
format(string, sizeof(string), fmt_str, ModelName[veh[vehicleid][v_model]-400], vehicleid);
SetPVarInt(playerid, "BuyVehID", vehicleid);
SPD(playerid, DLG_ID_VEH_BUY, DSM, !"{00C0FF}Покупка транспорта", string, !"{00C0FF}Да", !"{00C0FF}Нет");
}
else
{
if(veh[vehicleid][v_ownerid] != playerid)
RemovePlayerFromVehicle(playerid);
}
}
}
return true;
}

DeimoS
10.12.2019, 17:47
Опять же, не вчитывался в код особо (то есть, могут быть и другие проблемы, помимо перечисленных).

Два запроса можно объединить в один:
new string[90+10+10+1];
format(string, sizeof(string),
"UPDATE vehicles AS v, accounts AS a SET a.vehid=v.id, v.ownerid=a.id WHERE v.id=%d AND a.id=%d",
veh[i][v_id], player[playerid][p_id]);
mysql_function_query(connect_mysql, string, false, "", "");
Для MySQL это будут всё те же 2 запроса, но сервер, при этом, меньше действий совершать будет.


И зачем в OnPlayerStateChange цикл?

SteveStage
10.12.2019, 18:53
Два запроса можно объединить в один:
new string[90+10+10+1];
format(string, sizeof(string),
"UPDATE vehicles AS v, accounts AS a SET a.vehid=v.id, v.ownerid=a.id WHERE v.id=%d AND a.id=%d",
veh[i][v_id], player[playerid][p_id]);
mysql_function_query(connect_mysql, string, false, "", "");
Для MySQL это будут всё те же 2 запроса, но сервер, при этом, меньше действий совершать будет.

Не мог бы ты объяснить смысл этого запроса? Как и где использовать "AS, v" и точки в запросах?


И зачем в OnPlayerStateChange цикл?

Когда писал сам не знал, а сейчас не обратил на это внимания
Вот так будет правильнее:

public OnPlayerStateChange(playerid, newstate, oldstate)
{
if(newstate == PLAYER_STATE_DRIVER)
{
new
vehicleid = GetPlayerVehicleID(playerid);
if(IsABicycle(vehicleid) || IsAHelicopter(vehicleid))
{
engine_veh{vehicleid} = true;
GetVehicleParamsEx(vehicleid, engine, lights, alarm, doors, bonnet, boot, objective);
SetVehicleParamsEx(vehicleid, VEHICLE_PARAMS_ON, lights, alarm, doors, bonnet, boot, objective);
}
if(veh[vehicleid][v_id] == SALE_VEHICLE_ID)
{
static
fmt_str[] =
"{00C0FF}Желаете ли вы купить данный транспорт?\
\n\
\n{00C0FF}Модель:\t\t{F81414}%s\
\n{00C0FF}ID:\t\t{F81414}%d";
new
string[sizeof(fmt_str)-4+4+20+1];
format(string, sizeof(string), fmt_str, ModelName[veh[vehicleid][v_model]-400], vehicleid);
SetPVarInt(playerid, "BuyVehID", vehicleid);
SPD(playerid, DLG_ID_VEH_BUY, DSM, !"{00C0FF}Покупка транспорта", string, !"{00C0FF}Да", !"{00C0FF}Нет");
}
else
{
if(veh[vehicleid][v_ownerid] != playerid)
RemovePlayerFromVehicle(playerid);
}
}
return true;
}

DeimoS
10.12.2019, 19:10
https://forum.sa-mp.com/showpost.php?p=2878737&postcount=3

SteveStage
10.12.2019, 20:34
https://forum.sa-mp.com/showpost.php?p=2878737&postcount=3

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