19.02.2017, 21:44
(
Последний раз редактировалось PowerPC603; 20.02.2017 в 10:10.
)
Every house should have it's own ID stored in the database as well to be able to identify each house separately when you want to adjust data for a house later.
You can then use that ID as the index of your array.
This is my loading function for houses in my own gamemode and works perfectly.
You'll see that it loads the ID first, and the rest uses that ID to index the array for storing the remaining data.
When creating houses using some /createhouse command, start from ID 1.
I wonder how you update certain data later on when a house gets bought, sold, upgraded, changed interior, ...
I don't see any variable to uniquely identify each house.
What do you use in your WHERE clause to update a house when it levels up for example?
If you use the hID variable, why don't you load that from the database and use it, instead of using some "i" variable and using another "j" (with a different value as well) to access the rows?
Never assume that "i" will be equal to the hID in your database.
As you might have noticed, I've built a few safe-guards in my code to prevent houseID's going outside the allowed range of the array, effectively protecting the code from array-out-of-bounds errors, even if some admin inserts an invalid ID directly inside the database.
As you can see here, it's easy when you just can use the ID variable, which is actually the index of the array.
Of course, the ID in my database isn't set to auto-increment.
Otherwise the ID will soon be larger than MAX_HOUSES and there will be gaps in the ID's when you delete houses.
I'm letting the script decide which ID the house gets when it's created.
If there is a house deleted, that gap will be filled again when I create a new house later on.
You can then use that ID as the index of your array.
PHP код:
// This function is called to load the houses from MySQL during OnGameModeInit
Houses_Load()
{
// Setup local variables
new query[256], Cache:result, rows, countsuccess, countfailed, ID;
// Send a query to load all houses from MySQL (connect the UserName from playeraccounts to the result based on the OwnerID of the house (OwnerName results in "NULL" when there is no owner))
format(query, sizeof(query), "SELECT a.*, (SELECT b.Name FROM playeraccounts b WHERE b.UserID = a.OwnerID) AS OwnerName FROM houses a");
result = mysql_query(SQL_db, query, true);
// Print some debug info to the server console
printf("*** Loading houses from MySQL");
// Get the amount of rows (houses)
cache_get_row_count(rows);
// If there are any rows (houses) loaded, load data
if (rows >= 1)
{
// Loop through all rows
for (new row; row < rows; row++)
{
// Load the ID first
cache_get_value_name_int(row, "ID", ID);
// Check if the ID is invalid (out of range)
if ((ID < 1) || (ID >= MAX_HOUSES))
{
// Count the amount of failed houses entries (invalid ID's)
countfailed++;
// Add a message to the server-console to inform the admin about the wrong ID
printf("*** ERROR: Invalid ID found in table \"houses\": %i", ID);
// Continue with the next house entry from the MySQL query
continue;
}
// Read remaining data and store it
cache_get_value_name(row, "Name", AHouses[ID][Name], 50);
cache_get_value_name_float(row, "X", AHouses[ID][X]);
cache_get_value_name_float(row, "Y", AHouses[ID][Y]);
cache_get_value_name_float(row, "Z", AHouses[ID][Z]);
cache_get_value_name_int(row, "HouseType", AHouses[ID][HouseType]);
cache_get_value_name_int(row, "Interior", AHouses[ID][Interior]);
cache_get_value_name_int(row, "Level", AHouses[ID][Level]);
cache_get_value_name_int(row, "MaxLevel", AHouses[ID][MaxLevel]);
cache_get_value_name_int(row, "BuyPrice", AHouses[ID][BuyPrice]);
cache_get_value_name_int(row, "OwnerID", AHouses[ID][OwnerID]);
cache_get_value_name(row, "OwnerName", AHouses[ID][OwnerName], 25);
cache_get_value_name_int(row, "DoorStatus", AHouses[ID][DoorStatus]);
cache_get_value_name_int(row, "HouseValue", AHouses[ID][HouseValue]);
cache_get_value_name_int(row, "MaintenanceTime", AHouses[ID][MaintenanceTime]);
cache_get_value_name_int(row, "MaintenanceFee", AHouses[ID][MaintenanceFee]);
cache_get_value_name_int(row, "AuctionEndTime", AHouses[ID][AuctionEndTime]);
cache_get_value_name_int(row, "LastBid", AHouses[ID][LastBid]);
// Create the 3DText, mapicon and pickup that appears at the house entrance
House_UpdateEntrance(ID);
// Count the succesfully loaded house entries
countsuccess++;
}
}
// Print the amount of houses entries loaded for debugging
printf("*** >>> Houses loaded: %i (successful: %i, failed: %i)", rows, countsuccess, countfailed);
printf("");
// Clear the cache to prevent memory-leaks
cache_delete(result);
return 1;
}
You'll see that it loads the ID first, and the rest uses that ID to index the array for storing the remaining data.
When creating houses using some /createhouse command, start from ID 1.
PHP код:
// Lets the player add new houses
COMMAND:createhouse(playerid, params[])
{
// Setup local variables
new buyprice, maxlevel, ID, Float:x, Float:y, Float:z, msg[128], query[160];
// If the player has an insufficient admin-level (he needs level 6), exit the command
if (APlayerData[playerid][AdminLevel] < 6) return SendClientMessage(playerid, 0xFFFFFFFF, "{FF0000}Only admins level 6 and higher can use this command");
// If the player is the driver of a vehicle, exit the command
if(GetPlayerVehicleID(playerid) != 0) return SendClientMessage(playerid, 0xFFFFFFFF, "{FF0000}You must be on foot to create a house");
// Split parameters
if (sscanf(params, "ii", buyprice, maxlevel)) return SendClientMessage(playerid, 0xFF0000AA, "Usage: \"/createhouse <price> <maxlevel (1-10)>\"");
// Exit the function if the player entered an invalid maxlevel
if ((maxlevel < 1) || (maxlevel > 10)) return SendClientMessage(playerid, 0xFFFFFFFF, "{FF0000}MaxLevel must be from 1 to 10");
// Find the first free HouseID
for (ID = 1; ID < MAX_HOUSES; ID++)
if (AHouses[ID][PickupID] == 0) // Check if an empty house-index has been found (PickupID is 0)
break; // Stop searching, the first free HouseID has been found now
// Exit the function if the maximum amount of houses has been reached
if (ID == MAX_HOUSES) return SendClientMessage(playerid, 0xFFFFFFFF, "{FF0000}The maximum amount of houses has been reached");
// Get the player's position
GetPlayerPos(playerid, x, y, z);
// Set some default data
format(AHouses[ID][Name], 50, "NoName"); // Default name of the house
AHouses[ID][X] = x;
AHouses[ID][Y] = y;
AHouses[ID][Z] = z;
AHouses[ID][HouseType] = 0; // Normal upgradable house
AHouses[ID][Interior] = 0;
AHouses[ID][Level] = 0;
AHouses[ID][MaxLevel] = maxlevel;
AHouses[ID][BuyPrice] = buyprice;
AHouses[ID][OwnerID] = 0;
AHouses[ID][OwnerName][0] = 0;
AHouses[ID][DoorStatus] = 0;
// Create the 3DText that appears above the house-pickup (displays the price of the house)
House_UpdateEntrance(ID);
// Save the house into the database
mysql_format(SQL_db, query, sizeof(query), "INSERT INTO houses (ID, X, Y, Z, MaxLevel, BuyPrice) VALUES ('%i', '%f', '%f', '%f', '%i', '%i')", ID, x, y, z, maxlevel, buyprice);
mysql_tquery(SQL_db, query, "", "");
// Inform the player that he created a new house
format(msg, sizeof(msg), "{00FF00}You've succesfully created house {FFFF00}%i", ID);
SendClientMessage(playerid, 0xFFFFFFFF, msg);
// Let the server know that this was a valid command
return 1;
}
I don't see any variable to uniquely identify each house.
What do you use in your WHERE clause to update a house when it levels up for example?
If you use the hID variable, why don't you load that from the database and use it, instead of using some "i" variable and using another "j" (with a different value as well) to access the rows?
Never assume that "i" will be equal to the hID in your database.
As you might have noticed, I've built a few safe-guards in my code to prevent houseID's going outside the allowed range of the array, effectively protecting the code from array-out-of-bounds errors, even if some admin inserts an invalid ID directly inside the database.
PHP код:
mysql_format(SQL_db, query, sizeof(query), "UPDATE houses SET Name = '%e', Interior = '1', Level = '%i', OwnerID = '%i', DoorStatus = '%i', HouseValue = '%i', MaintenanceTime = '%i', MaintenanceFee = '%i' WHERE ID = '%i'", AHouses[ID][Name], AHouses[ID][Level], AHouses[ID][OwnerID], AHouses[ID][DoorStatus], AHouses[ID][HouseValue], AHouses[ID][MaintenanceTime], AHouses[ID][MaintenanceFee], ID);
mysql_format(SQL_db, query, sizeof(query), "UPDATE houses SET Level = '%i' WHERE ID = '%i'", newlevel, houseid);
mysql_format(SQL_db, query, sizeof(query), "UPDATE houses SET Interior = '%i' WHERE ID = '%i'", AHouses[houseid][Interior], houseid);
mysql_format(SQL_db, query, sizeof(query), "UPDATE houses SET LastBid = '%i' WHERE ID = '%i'", AHouses[houseid][LastBid], houseid);
mysql_format(SQL_db, query, sizeof(query), "UPDATE houses SET Name = '%e' WHERE ID = '%i'", AHouses[houseid][Name], houseid);
mysql_format(SQL_db, query, sizeof(query), "UPDATE houses SET AuctionEndTime = '%i' WHERE ID = '%i'", AHouses[houseid][AuctionEndTime], houseid);
mysql_format(SQL_db, query, sizeof(query), "UPDATE houses SET AuctionEndTime = '0', MaintenanceTime = '%i', LastBid = '0' WHERE ID = '%i'", AHouses[houseid][MaintenanceTime], houseid);
mysql_format(SQL_db, query, sizeof(query), "UPDATE houses SET HouseValue = '%i', MaintenanceFee = '%i' WHERE ID = '%i'", AHouses[houseid][HouseValue], AHouses[houseid][MaintenanceFee], houseid);
Of course, the ID in my database isn't set to auto-increment.
Otherwise the ID will soon be larger than MAX_HOUSES and there will be gaps in the ID's when you delete houses.
I'm letting the script decide which ID the house gets when it's created.
If there is a house deleted, that gap will be filled again when I create a new house later on.