enum PData {
dbID,
wafflez,
pancakes[32]
}
new PInfo[MAX_PLAYERS][PData];
public OnGameModeExit() {
foreach(new pid : Player) {
SavePlayer(pid);
}
}
stock SavePlayer(uid) {
mysql_format(dbhandle, q, "UPDATE `users` SET wafflez = %d, pancakes = '%e' WHERE id = %d", PInfo[pid][wafflez] + 1, PInfo[pid][pancakes], PInfo[pid][dbID]);
mysql_function_query(dbhandle, q, false, "", "");
}
UPDATE `users`
SET wafflez = CASE id
WHEN PInfo[1][dbID] THEN PInfo[1][wafflez]
WHEN PInfo[2][dbID] THEN PInfo[2][wafflez]
WHEN PInfo[3][dbID] THEN PInfo[3][wafflez]
END,
title = CASE id
WHEN PInfo[1][dbID] THEN "PInfo[1][pancakes]"
WHEN PInfo[2][dbID] THEN "PInfo[2][pancakes]"
WHEN PInfo[3][dbID] THEN "PInfo[3][pancakes]"
END
WHERE id IN (1,2,3)
static currentUser@ = 0, currentField@ = 0;
#define FIELDS_NUMBER 2
enum PData {
dbID,
wafflez,
pancakes[32],
bool:alreadySaved[FIELDS_NUMBER]
}
enum {
DB_INT,
DB_STR
}
enum dBInfo {
fname[32],
PData:pointer,
_:type
}
static const dbprops[FIELDS_NUMBER][dBInfo] = {
{ "wafflez", PData:wafflez, DB_INT },
{ "pancakes", PData:pancakes, DB_STR }
};
stock ResetPlayersStates() {
currentUser@ = 0;
currentField@ = 0;
for(new pid = 0; pid < MAX_PLAYERS; ++pid) {
if(IsPlayerConnected(pid)) {
for(new j = 0; j < FIELDS_NUMBER; ++j) {
PInfo[pid][alreadySaved][j] ^= PInfo[pid][alreadySaved][j];
}
}
}
}
Sidenote: variable ^= variable is exactly the same as variable = false, howerver this is my old asm habit |
#define MAX_SINGLE 64
stock SaveAllPlayers() {
#define MAX_QUERY 128
//Alots are awesome
#define ALOT 32
#if MAX_QUERY < ALOT || MAX_QUERY < 64
#error Dont do this, k?
#endif
static const where[] = " END WHERE id IN ";
new query[MAX_QUERY+1], first = 1, ids[ALOT+1], idlen = 0, pdbID = 0, bool:emptyRun = true, tmp[MAX_SINGLE + 1], bool:errorFlag = false;
format(query, sizeof query, "UPDATE `users` SET `%s` = CASE `id` ", dbprops[currentField@][fname]);
ids[0] = '(';
for(; currentUser@ < MAX_PLAYERS; ++currentUser@) {
if(PInfo[currentUser@][dbID]/*IsPlayerConnected(currentUser@)*/) {
if(PInfo[currentUser@][alreadySaved][currentField@]) continue;
//Database id string length
pdbID = PInfo[currentUser@][dbID];
idlen = 1;
while (pdbID > 9) {
idlen++;
pdbID /= 10;
}
//Check if we are still under ALOT magic barrier
//Current ids + current id length + comma separator + )
if(strlen(ids) + idlen + (first ? 0 : 1) + 1 > ALOT) break;
if(!first) strcat(ids, ",");
format(ids, sizeof ids, "%s%d", ids, pdbID);
tmp[0] = EOS;
strcat(tmp, BuildSet(currentUser@, dbprops[currentField@]));
//Check if we are still under MAX_QUERY barrier
//Current query + where + all ids
if(strlen(query) + strlen(where) + strlen(ids) + strlen(tmp) + (first ? 0 : 1) > MAX_QUERY) {
if(first) errorFlag = true;
break;
}
if(!first) strcat(query, ",");
strcat(query, tmp);
PInfo[currentUser@][alreadySaved][currentField@] = true;
if(first) {
first ^= first;
emptyRun ^= emptyRun;
}
}
}
if(errorFlag) {
//This shouldn't happen, but when the query isn't long enough even to fit one record, do eet
print("GODDAMNIT");
return 0;
}
if(!emptyRun) {
strcat(ids, ")");
strcat(query, where);
strcat(query, ids);
} else {
if(currentField@ < FIELDS_NUMBER) ++currentField@;
currentUser@ = 0;
query[0] = EOS;
}
mysql_function_query(dbhandle, query, false, "", "");
printf("Query: '%s'", query);
#undef MAX_QUERY
#undef ALOT
return emptyRun && currentField@ == FIELDS_NUMBER ? 1 : SaveAllPlayers();
}
stock BuildSet(pid, variable[]) {
new q[MAX_SINGLE + 1];
switch(variable[type]) {
case DB_INT:
mysql_format(dbhandle, q, "WHEN %d THEN %d", PInfo[pid][dbID], PInfo[pid][PData:variable[pointer]]);
default:
//includes str
mysql_format(dbhandle, q, "WHEN %d THEN '%e'", PInfo[pid][dbID], PInfo[pid][PData:variable[pointer]]);
}
//Add more cases for special tags, or handle it in some other way
return q;
}
#define MAX_SINGLE 64
stock SaveAllPlayers() {
#define MAX_QUERY 512
//Alots are awesome
#define ALOT 128
#if MAX_QUERY < ALOT || MAX_QUERY < 64
#error Dont do this, k?
#endif
static const where[] = " END WHERE id IN ";
new query[MAX_QUERY+1], first = 1, ids[ALOT+1], idlen = 0, pdbID = 0, bool:emptyRun = true, tmp[MAX_SINGLE + 1], bool:errorFlag = false;
format(query, sizeof query, "UPDATE `users` SET `%s` = CASE `id` ", dbprops[currentField@][fname]);
ids[0] = '(';
for(; currentUser@ < MAX_PLAYERS; ++currentUser@) {
if(IsPlayerConnected(currentUser@)) {
if(PInfo[currentUser@][alreadySaved][currentField@]) continue;
//Database id string length
pdbID = PInfo[currentUser@][dbID];
idlen = 1;
while (pdbID > 9) {
idlen++;
pdbID /= 10;
}
//Check if we are still under ALOT magic barrier
//Current ids + current id length + comma separator + )
if(strlen(ids) + idlen + (first ? 0 : 1) + 1 > ALOT) break;
if(!first) strcat(ids, ",");
format(ids, sizeof ids, "%s%d", ids, pdbID);
tmp[0] = EOS;
strcat(tmp, BuildSet(currentUser@, dbprops[currentField@]));
//Check if we are still under MAX_QUERY barrier
//Current query + where + all ids
if(strlen(query) + strlen(where) + strlen(ids) + strlen(tmp) + (first ? 0 : 1) > MAX_QUERY) {
if(first) errorFlag = true;
break;
}
if(!first) strcat(query, ",");
strcat(query, tmp);
PInfo[currentUser@][alreadySaved][currentField@] = true;
if(first) {
first ^= first;
emptyRun ^= emptyRun;
}
}
}
if(errorFlag) {
//This shouldn't happen, but when the query isn't long enough even to fit one record, do eet
print("GODDAMNIT");
return 0;
}
if(!emptyRun) {
strcat(ids, ")");
strcat(query, where);
strcat(query, ids);
mysql_function_query(dbhandle, query, false, "", "");
printf("Query: '%s'", query);
} else {
if(currentField@ < FIELDS_NUMBER) ++currentField@;
currentUser@ = 0;
printf("Empty run, next field XOR end");
}
#undef MAX_QUERY
#undef ALOT
return emptyRun && currentField@ == FIELDS_NUMBER ? 1 : SaveAllPlayers();
}
stock BuildSet(pid, variable[]) {
new q[MAX_SINGLE + 1];
switch(variable[type]) {
case DB_INT:
mysql_format(dbhandle, q, "WHEN %d THEN %d", PInfo[pid][dbID], PInfo[pid][PData:variable[pointer]]);
default:
//includes str
mysql_format(dbhandle, q, "WHEN %d THEN '%e'", PInfo[pid][dbID], PInfo[pid][PData:variable[pointer]]);
}
//Add more cases for special tags, or handle it in some other way
return q;
}
Sidenote: there are two ways you can create the query - field by field, or row by row. I don't know about internal database implementations, but I guess that row by row will be faster becuase it won't have to search for all the ids each time. Currently this function handles only one field at a time. However coding for row by row would be twice as long (at least for me), so I'll just leave this here. |
public OnGameModeExit() {
ResetPlayersStates();
SaveAllPlayers();
return 1;
}