I'm having a huge problem and I can't fix it. -
adamslj - 02.09.2017
In my script, there are two vehicle types: player; and faction. This is the enum:
PHP код:
enum carData {
carID, // This is the SQL ID.
carExists,
carModel,
carOwner,
Float:carPos[4],
carColor1,
carColor2,
carPlate[11],
carLocked,
carParked,
carWorld,
carRank,
carFaction,
carVehicle
Player Vehicles
Player vehicles only spawn when the player is logged in, and they disappear when the player logs out. The player vehicles are created, saved, loaded and unloaded like so --
Created:
PHP код:
CMD:createpcar(playerid, params[])
{
static
userid,
model[32];
if (PlayerData[playerid][pAdmin] < 4)
return SendErrorMessage(playerid, "You don't have permission to use this command.");
if (sscanf(params, "us[32]", userid, model))
return SendSyntaxMessage(playerid, "/createpcar [playerid/name] [modelid/name]");
if (Car_GetCount(userid) >= MAX_OWNABLE_CARS)
return SendErrorMessage(playerid, "This player already owns the maximum amount of cars.");
if ((model[0] = GetVehicleModelByName(model)) == 0)
return SendErrorMessage(playerid, "Invalid model ID.");
static
Float:x,
Float:y,
Float:z,
Float:angle,
id = -1;
GetPlayerPos(userid, x, y, z);
GetPlayerFacingAngle(userid, angle);
id = PlayerCar_Create(PlayerData[userid][pID], model[0], x, y + 2, z + 1, angle, random(127), random(127));
if (id == -1)
return SendErrorMessage(playerid, "The server has reached the limit for dynamic vehicles.");
SendServerMessage(playerid, "You have created vehicle ID: %d for %s.", CarData[id][carVehicle], ReturnName(userid, 0));
return 1;
}
PlayerCar_Create(ownerid, modelid, Float:x, Float:y, Float:z, Float:angle, color1, color2)
{
for (new i = 0; i != MAX_DYNAMIC_CARS; i ++)
{
if (!CarData[i][carExists])
{
if (color1 == -1)
color1 = random(127);
if (color2 == -1)
color2 = random(127);
CarData[i][carExists] = true;
CarData[i][carModel] = modelid;
CarData[i][carOwner] = ownerid;
CarData[i][carPos][0] = x;
CarData[i][carPos][1] = y;
CarData[i][carPos][2] = z;
CarData[i][carPos][3] = angle;
CarData[i][carColor1] = color1;
CarData[i][carColor2] = color2;
new str[8], query[400];
format(str, sizeof(str), "%s%s%d%d%s%s%s", LetterList[random(sizeof(LetterList))], LetterList[random(sizeof(LetterList))], random(9), random(9), LetterList[random(sizeof(LetterList))], LetterList[random(sizeof(LetterList))], LetterList[random(sizeof(LetterList))]);
SetVehicleNumberPlate(i, str);
format(CarData[i][carPlate], 11, "%s", str);
CarData[i][carPaintjob] = -1;
CarData[i][carLocked] = false;
CarData[i][carParked] = 0;
CarData[i][carWorld] = 0;
CarData[i][carImpounded] = -1;
CarData[i][carImpoundPrice] = 0;
for (new j = 0; j < 14; j ++)
{
if (j < 5)
{
CarData[i][carWeapons][j] = 0;
CarData[i][carAmmo][j] = 0;
}
CarData[i][carMods][j] = 0;
}
CarData[i][carVehicle] = CreateVehicle(modelid, x, y, z, angle, color1, color2, -1);
if (CarData[i][carVehicle] != INVALID_VEHICLE_ID) {
ResetVehicle(CarData[i][carVehicle]);
}
mysql_format(g_iHandle, query, sizeof(query), "INSERT INTO `playercars` (carModel, carOwner, carPosX, carPosY, carPosZ, carPosR, carColor1, carColor2, carPlate, carPaintjob, carParked, carWorld) VALUES(%d, %d, %f, %f, %f, %f, %d, %d, '%s', -1, 0, 0)",
CarData[i][carModel],
CarData[i][carOwner],
CarData[i][carPos][0],
CarData[i][carPos][1],
CarData[i][carPos][2],
CarData[i][carPos][3],
CarData[i][carColor1],
CarData[i][carColor2],
CarData[i][carPlate],
CarData[i][carPaintjob],
CarData[i][carParked],
CarData[i][carWorld]);
mysql_tquery(g_iHandle, query, "OnplayerCarCreated", "i", i);
return 1;
}
}
return -1;
}
forward OnPlayerCarCreated(carid);
public OnPlayerCarCreated(carid)
{
if (carid == -1 || !CarData[carid][carExists])
return 0;
CarData[carid][carID] = mysql_insert_id();
PlayerCar_Save(carid);
return 1;
}
Saved:
PHP код:
PlayerCar_Save(carid)
{
static
query[900];
if (CarData[carid][carVehicle] != INVALID_VEHICLE_ID)
{
for (new i = 0; i < 14; i ++) {
CarData[carid][carMods][i] = GetVehicleComponentInSlot(CarData[carid][carVehicle], i);
}
}
format(query, sizeof(query), "UPDATE `playercars` SET `carModel` = '%d', `carOwner` = '%d', `carPosX` = '%.4f', `carPosY` = '%.4f', `carPosZ` = '%.4f', `carPosR` = '%.4f', `carColor1` = '%d', `carColor2` = '%d', `carPlate` = '%s', `carLocked` = '%d', `carParked` = '%d', `carWorld` ='%d'",
CarData[carid][carModel],
CarData[carid][carOwner],
CarData[carid][carPos][0],
CarData[carid][carPos][1],
CarData[carid][carPos][2],
CarData[carid][carPos][3],
CarData[carid][carColor1],
CarData[carid][carColor2],
CarData[carid][carPlate],
CarData[carid][carLocked],
CarData[carid][carParked],
CarData[carid][carWorld]
);
return mysql_function_query(g_iHandle, query, false, "", "");
}
Loaded:
PHP код:
public OnPlayerSpawn(playerid)
{
new query[300];
mysql_format(g_iHandle, query, sizeof(query), "SELECT * FROM `playercars` WHERE carOwner = %d LIMIT 3", PlayerData[playerid][pID]);
mysql_tquery(g_iHandle, query,"PlayerCar_Load", "i", playerid);
return 1;
}
forward PlayerCar_Load(playerid);
public PlayerCar_Load(playerid)
{
static
rows,
fields,
str[128];
cache_get_data(rows, fields, g_iHandle);
for (new i = 0; i < rows; i ++) if (i < MAX_DYNAMIC_CARS)
{
CarData[i][carExists] = true;
CarData[i][carID] = cache_get_field_int(i, "carID");
CarData[i][carModel] = cache_get_field_int(i, "carModel");
CarData[i][carOwner] = cache_get_field_int(i, "carOwner");
CarData[i][carPos][0] = cache_get_field_float(i, "carPosX");
CarData[i][carPos][1] = cache_get_field_float(i, "carPosY");
CarData[i][carPos][2] = cache_get_field_float(i, "carPosZ");
CarData[i][carPos][3] = cache_get_field_float(i, "carPosR");
CarData[i][carColor1] = cache_get_field_int(i, "carColor1");
CarData[i][carColor2] = cache_get_field_int(i, "carColor2");
cache_get_field_content(i, "carPlate", CarData[i][carPlate], g_iHandle, 12);
CarData[i][carLocked] = cache_get_field_int(i, "carLocked");
CarData[i][carParked] = cache_get_field_int(i, "carParked");
CarData[i][carWorld] = cache_get_field_int(i, "carWorld");
CarData[i][carImpounded] = cache_get_field_int(i, "carImpounded");
CarData[i][carImpoundPrice] = cache_get_field_int(i, "carImpoundPrice");
for (new j = 0; j < 14; j ++)
{
if (j < 5)
{
format(str, sizeof(str), "carWeapon%d", j + 1);
CarData[i][carWeapons][j] = cache_get_field_int(i, str);
format(str, sizeof(str), "carAmmo%d", j + 1);
CarData[i][carAmmo][j] = cache_get_field_int(i, str);
}
format(str, sizeof(str), "carMod%d", j + 1);
CarData[i][carMods][j] = cache_get_field_int(i, str);
}
Car_Spawn(i);
}
for (new i = 0; i < MAX_DYNAMIC_CARS; i ++) if (CarData[i][carExists]) {
format(str, sizeof(str), "SELECT * FROM `carstorage` WHERE `ID` = '%d'", CarData[i][carID]);
mysql_function_query(g_iHandle, str, true, "OnLoadCarStorage", "d", i);
}
return 1;
}
Unloaded:
PHP код:
public OnPlayerDisconnect(playerid, reason)
{
PlayerCar_Unload(playerid);
return 1;
}
stock PlayerCar_Unload(playerid)
{
for(new id; id < MAX_DYNAMIC_CARS; id++)
{
if (IsVehicleSpawned(id))
{
if (PlayerData[playerid][pID] == CarData[id][carOwner])
{
PlayerCar_Save(id);
DestroyVehicle(id);
CarData[id][carExists] = false;
}
}
}
return 1;
}
Faction Vehicles
Faction vehicles load when the server starts, and remain there permanently. They are created and loaded like so --
PHP код:
CMD:createfcar(playerid, params[])
{
static
model[32],
color1,
color2,
factionid;
if (PlayerData[playerid][pAdmin] < 4)
return SendErrorMessage(playerid, "You don't have permission to use this command.");
if (sscanf(params, "s[32]I(-1)I(-1)I(0)", model, color1, color2, factionid))
return SendSyntaxMessage(playerid, "/createfcar [modelid/name] [color1] [color2] [faction ID]");
if ((model[0] = GetVehicleModelByName(model)) == 0)
return SendErrorMessage(playerid, "Invalid model ID.");
static
Float:x,
Float:y,
Float:z,
Float:angle,
id = -1;
GetPlayerPos(playerid, x, y, z);
GetPlayerFacingAngle(playerid, angle);
id = FactionCar_Create(model[0], x, y, z + 1, angle, color1, color2, factionid, GetPlayerVirtualWorld(playerid));
if (id == -1)
return SendErrorMessage(playerid, "The server has reached the limit for dynamic vehicles.");
return 1;
}
FactionCar_Create(modelid, Float:x, Float:y, Float:z, Float:angle, color1, color2, faction, world)
{
for (new i = 0; i != MAX_DYNAMIC_CARS; i ++)
{
if (!CarData[i][carExists])
{
if (color1 == -1)
color1 = random(127);
if (color2 == -1)
color2 = random(127);
CarData[i][carExists] = true;
CarData[i][carModel] = modelid;
CarData[i][carPos][0] = x;
CarData[i][carPos][1] = y;
CarData[i][carPos][2] = z;
CarData[i][carPos][3] = angle;
CarData[i][carColor1] = color1;
CarData[i][carColor2] = color2;
new str[8], query[400];
format(str, sizeof(str), "%s%s%d%d%s%s%s", LetterList[random(sizeof(LetterList))], LetterList[random(sizeof(LetterList))], random(9), random(9), LetterList[random(sizeof(LetterList))], LetterList[random(sizeof(LetterList))], LetterList[random(sizeof(LetterList))]);
SetVehicleNumberPlate(i, str);
format(CarData[i][carPlate], 11, "%s", str);
CarData[i][carWorld] = world;
CarData[i][carFaction] = faction;
CarData[i][carRank] = 1;
CarData[i][carVehicle] = CreateVehicle(modelid, x, y, z, angle, color1, color2, -1);
if (CarData[i][carVehicle] != INVALID_VEHICLE_ID) {
ResetVehicle(CarData[i][carVehicle]);
}
mysql_format(g_iHandle, query, sizeof(query), "INSERT INTO `factioncars` (carModel, carPosX, carPosY, carPosZ, carPosR, carColor1, carColor2, carPlate, carFaction, carWorld, carRank) VALUES(%d, %f, %f, %f, %f, %d, %d, '%s', %d, %d, %d)",
CarData[i][carModel],
CarData[i][carPos][0],
CarData[i][carPos][1],
CarData[i][carPos][2],
CarData[i][carPos][3],
CarData[i][carColor1],
CarData[i][carColor2],
CarData[i][carPlate],
CarData[i][carFaction],
CarData[i][carWorld],
CarData[i][carRank]
);
mysql_tquery(g_iHandle, query, "OnFactionCarCreated", "i", i);
return 1;
}
}
return -1;
}
forward OnFactionCarCreated(carid);
public OnFactionCarCreated(carid)
{
if (carid == -1 || !CarData[carid][carExists])
return 0;
CarData[carid][carID] = mysql_insert_id();
FactionCar_Save(carid);
return 1;
}
FactionCar_Save(carid)
{
static
query[900];
if (CarData[carid][carVehicle] != INVALID_VEHICLE_ID)
{
for (new i = 0; i < 14; i ++) {
CarData[carid][carMods][i] = GetVehicleComponentInSlot(CarData[carid][carVehicle], i);
}
}
format(query, sizeof(query), "UPDATE `factioncars` SET `carModel` = '%d', `carPosX` = '%.4f', `carPosY` = '%.4f', `carPosZ` = '%.4f', `carPosR` = '%.4f', `carColor1` = '%d', `carColor2` = '%d', `carPlate` = '%s', `carFaction` = '%d', `carWorld` = '%d', `carRank` ='%d' WHERE `carID` = '%d'",
CarData[carid][carModel],
CarData[carid][carPos][0],
CarData[carid][carPos][1],
CarData[carid][carPos][2],
CarData[carid][carPos][3],
CarData[carid][carColor1],
CarData[carid][carColor2],
CarData[carid][carPlate],
CarData[carid][carFaction],
CarData[carid][carWorld],
CarData[carid][carRank],
CarData[carid][carID]
);
return mysql_function_query(g_iHandle, query, false, "", "");
}
forward FactionCar_Load();
public FactionCar_Load()
{
static
rows,
fields;
cache_get_data(rows, fields, g_iHandle);
for (new i = 0; i < rows; i ++) if (i < MAX_DYNAMIC_CARS)
{
CarData[i][carExists] = true;
CarData[i][carID] = cache_get_field_int(i, "carID");
CarData[i][carModel] = cache_get_field_int(i, "carModel");
CarData[i][carPos][0] = cache_get_field_float(i, "carPosX");
CarData[i][carPos][1] = cache_get_field_float(i, "carPosY");
CarData[i][carPos][2] = cache_get_field_float(i, "carPosZ");
CarData[i][carPos][3] = cache_get_field_float(i, "carPosR");
CarData[i][carColor1] = cache_get_field_int(i, "carColor1");
CarData[i][carColor2] = cache_get_field_int(i, "carColor2");
cache_get_field_content(i, "carPlate", CarData[i][carPlate], g_iHandle, 12);
CarData[i][carParked] = cache_get_field_int(i, "carFaction");
CarData[i][carWorld] = cache_get_field_int(i, "carWorld");
CarData[i][carImpounded] = cache_get_field_int(i, "carRank");
if(CarData[i][carModel] > 399 && CarData[i][carModel] < 612)
{
new FCar = CreateVehicle(CarData[i][carModel], CarData[i][carPos][0], CarData[i][carPos][1], CarData[i][carPos][2], CarData[i][carPos][3], CarData[i][carColor1], CarData[i][carColor2], -1);
SetVehicleNumberPlate(FCar, CarData[i][carPlate]);
SetVehicleToRespawn(FCar);
CarData[FCar][carID] = CarData[i][carID];
CarData[FCar][carModel] = CarData[i][carModel];
CarData[FCar][carPos][0] = CarData[i][carPos][0];
CarData[FCar][carPos][1] = CarData[i][carPos][1];
CarData[FCar][carPos][2] = CarData[i][carPos][2];
CarData[FCar][carPos][3] = CarData[i][carPos][3];
CarData[FCar][carColor1] = CarData[i][carColor1];
CarData[FCar][carColor2] = CarData[i][carColor2];
CarData[FCar][carFaction] = CarData[i][carFaction];
CarData[FCar][carWorld] = CarData[i][carWorld];
CarData[FCar][carRank] = CarData[i][carRank];
}
else printf("[MYSQL] ERROR LOADING FACTION VEHICLE SQLID: %d",CarData[i][carID]);
}
return 1;
}
Now, BOTH of these work
in isolation.
If I create a player car for myself it creates and saves, and then when I logout it disappears, and re-appears on logging back in.
If I create faction cars, they save and load successfully, and re-appear on server restart.
HOWEVER, if I create a faction car AND a player car and then logout, it all goes tits up. It's so random, sometimes both cars will disappear, sometimes the player car will disappear, sometimes the faction car will. Then, when I relog, they will both appear. Sometimes the car will duplicate itself (but not save to the database). If there are two players in-game both with player cars, if ONE of us logs out, BOTH cars will disappear and the random screw ups will start again, with the cars disappearing and respawning at random when someone re-connects or leaves.
I have no idea wtf is causing this, I've tried to fix it and I just can't. Player cars and faction cars save to separate tables in the database. Should I use two separate enums? Are the SQL IDs conflicting? I'm so confused.
Re: I'm having a huge problem and I can't fix it. -
Misiur - 02.09.2017
This might be your problem, as FactionCar_Create returns only either 1 or -1.
#e: Nevermind, I see you only check for -1 and not use it anywhere
Re: I'm having a huge problem and I can't fix it. -
adamslj - 02.09.2017
Yeah, it can't be that. It's just so weird, can SQL ids conflict with the actual vehicle ID? Or are they not static? Surely if a player logs in one day and the logs in the next day, the DL vehicle ID would be different?
I just don't see why this is happening... everything is coded fine, as far as I can see. They work absolutely great independently, but when there are other players or a mix of player and faction vehicles it just fucks up.
So irritated.
Re: I'm having a huge problem and I can't fix it. -
Misiur - 02.09.2017
Alright, I know what's the issue: you use CarData for both player cars and faction cars.
Player cars:
pawn Код:
for (new i = 0; i < rows; i ++) if (i < MAX_DYNAMIC_CARS)
{
CarData[i][carExists] = true;
Faction cars
pawn Код:
for (new i = 0; i < rows; i ++) if (i < MAX_DYNAMIC_CARS)
{
CarData[i][carExists] = true;
As you can see, you are overwriting the same indexes. I'd suggest y_iterate/foreach custom iterators, but we'll keep things simple: change the above loops to something like:
pawn Код:
new row = 0;
for (new i = 0; i < MAX_VEHICLES; i++)
{
if (CarData[i][carExists]) continue;
if (row++ >= MAX_DYNAMIC_CARS) { // handle too much cars error }
CarData[i][carExists] = true;
// All of your logic
Re: I'm having a huge problem and I can't fix it. -
adamslj - 02.09.2017
Thanks for the suggestion. What difference does that make? They're still both going to be using CarData, I'm not familiar with y_iterate
Re: I'm having a huge problem and I can't fix it. -
Misiur - 02.09.2017
Yes, but they won't be overriding themselves. My loop checks if CarData[index] is taken, if so, it skips the current index and goes forward until it finds empty slot (with CarData[i][carExists] equal to false)
Re: I'm having a huge problem and I can't fix it. -
adamslj - 02.09.2017
I see, so in my code if I create a player car, then a faction car, both are created with index 1, and the faction car overwrites the player car because it doesn't check if the index is used? This is making sense now.
Please can you implement your fix into my player car function so I can see how it all pieces together?
I appreciate your help; this issue has had me stumped for hours!
Re: I'm having a huge problem and I can't fix it. -
Misiur - 02.09.2017
pawn Код:
public PlayerCar_Load(playerid)
{
static
rows,
fields,
str[128];
new
row = 0
;
cache_get_data(rows, fields, g_iHandle);
for (new i = 0; i < rows; i ++)
{
// Skip current CarData index if it's taken
if (CarData[i][carExists]) continue;
if (row++ >= MAX_DYNAMIC_CARS) {
printf("Exceeded MAX_DYNAMIC_CARS (%d), breaking", MAX_DYNAMIC_CARS);
break;
}
CarData[i][carExists] = true;
CarData[i][carID] = cache_get_field_int(i, "carID");
CarData[i][carModel] = cache_get_field_int(i, "carModel");
CarData[i][carOwner] = cache_get_field_int(i, "carOwner");
CarData[i][carPos][0] = cache_get_field_float(i, "carPosX");
CarData[i][carPos][1] = cache_get_field_float(i, "carPosY");
CarData[i][carPos][2] = cache_get_field_float(i, "carPosZ");
CarData[i][carPos][3] = cache_get_field_float(i, "carPosR");
CarData[i][carColor1] = cache_get_field_int(i, "carColor1");
CarData[i][carColor2] = cache_get_field_int(i, "carColor2");
cache_get_field_content(i, "carPlate", CarData[i][carPlate], g_iHandle, 12);
CarData[i][carLocked] = cache_get_field_int(i, "carLocked");
CarData[i][carParked] = cache_get_field_int(i, "carParked");
CarData[i][carWorld] = cache_get_field_int(i, "carWorld");
CarData[i][carImpounded] = cache_get_field_int(i, "carImpounded");
CarData[i][carImpoundPrice] = cache_get_field_int(i, "carImpoundPrice");
for (new j = 0; j < 14; j ++)
{
if (j < 5)
{
format(str, sizeof(str), "carWeapon%d", j + 1);
CarData[i][carWeapons][j] = cache_get_field_int(i, str);
format(str, sizeof(str), "carAmmo%d", j + 1);
CarData[i][carAmmo][j] = cache_get_field_int(i, str);
}
format(str, sizeof(str), "carMod%d", j + 1);
CarData[i][carMods][j] = cache_get_field_int(i, str);
}
Car_Spawn(i);
}
for (new i = 0; i < MAX_DYNAMIC_CARS; i ++) if (CarData[i][carExists]) {
format(str, sizeof(str), "SELECT * FROM `carstorage` WHERE `ID` = '%d'", CarData[i][carID]);
mysql_function_query(g_iHandle, str, true, "OnLoadCarStorage", "d", i);
}
return 1;
}
Do the same for faction cars. Also, if you ever see a SELECT query in a loop, you did the wrong thing. Database/file access is the slowest part of the code. Select all rows you need at once, then sort it out in your code.
Re: I'm having a huge problem and I can't fix it. -
adamslj - 02.09.2017
Thank you for your help, I'll test this out tomorrow! Would the index issue have also been causing the problem where if two different players each have a car, it would despawn both of them?
Re: I'm having a huge problem and I can't fix it. -
Misiur - 02.09.2017
From quick glance it should not, I can't test your code as I don't have your database and declarations of variables, sorry.