world startup/shutdown timestamps + adjust a few column names
This commit is contained in:
parent
63705942a3
commit
d92f642810
@ -16,7 +16,7 @@ make clean # remove `build` directory
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Running (SQLite)
|
## Running (SQLite)
|
||||||
The query manager becomes the database, automatically initializing and maintaining the schema, based on the files in `sqlite/` (see `sqlite/README.txt`). The default schema file won't automatically insert any initial data (see `sqlite/init.sql`), although you could put some insertions at the end to avoid having to manually run something like `sqlite/init.sql`. There are a few configuration options, and in particular `SQLite.*` options that could be adjusted in `config.cfg` but the defaults should work for most use cases.
|
The query manager becomes the database, automatically initializing and maintaining the schema, based on the files in `sqlite/` (see `sqlite/README.txt`). The default schema file won't automatically insert any initial data (see `sqlite/init.sql`), although you could put some insertions at the end to avoid having to manually run something like `sqlite/init.sql`. There are a few configuration options, and in particular `SQLite.*` options that can be adjusted in `config.cfg` but the defaults should work for most use cases.
|
||||||
|
|
||||||
## Running (PostgreSQL)
|
## Running (PostgreSQL)
|
||||||
The query manager becomes a relay to the actual database. And with PostgreSQL being a distributed database system, it makes no sense to have individual clients managing the schema, since there could be multiple, each with their own assumptions. For that reason there is a `SchemaInfo` table with a `VERSION` row that will be queried at startup and compared against `POSTGRESQL_SCHEMA_VERSION`, defined in `src/database_postgres.cc`, to make sure there is an agreement on the schema version. It is hardcoded because schema changes will usually result in query changes.
|
The query manager becomes a relay to the actual database. And with PostgreSQL being a distributed database system, it makes no sense to have individual clients managing the schema, since there could be multiple, each with their own assumptions. For that reason there is a `SchemaInfo` table with a `VERSION` row that will be queried at startup and compared against `POSTGRESQL_SCHEMA_VERSION`, defined in `src/database_postgres.cc`, to make sure there is an agreement on the schema version. It is hardcoded because schema changes will usually result in query changes.
|
||||||
|
|||||||
@ -112,6 +112,6 @@ INSERT INTO CharacterRights(CharacterID, Name)
|
|||||||
('CLEANUP_FIELDS'),
|
('CLEANUP_FIELDS'),
|
||||||
('NO_STATISTICS')
|
('NO_STATISTICS')
|
||||||
) AS R (RightName)
|
) AS R (RightName)
|
||||||
WHERE C.Name ILIKE 'Gamemaster%' COLLATE "default";
|
WHERE C.Name LIKE 'Gamemaster%' COLLATE "default";
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|||||||
@ -42,8 +42,10 @@ CREATE TABLE Worlds (
|
|||||||
PremiumPlayerBuffer SMALLINT NOT NULL,
|
PremiumPlayerBuffer SMALLINT NOT NULL,
|
||||||
MaxNewbies SMALLINT NOT NULL,
|
MaxNewbies SMALLINT NOT NULL,
|
||||||
PremiumNewbieBuffer SMALLINT NOT NULL,
|
PremiumNewbieBuffer SMALLINT NOT NULL,
|
||||||
OnlineRecord SMALLINT NOT NULL DEFAULT 0,
|
OnlinePeak SMALLINT NOT NULL DEFAULT 0,
|
||||||
OnlineRecordTimestamp TIMESTAMPTZ NOT NULL DEFAULT 'epoch',
|
OnlinePeakTimestamp TIMESTAMPTZ NOT NULL DEFAULT 'epoch',
|
||||||
|
LastStartup TIMESTAMPTZ NOT NULL DEFAULT 'epoch',
|
||||||
|
LastShutdown TIMESTAMPTZ NOT NULL DEFAULT 'epoch',
|
||||||
PRIMARY KEY (WorldID),
|
PRIMARY KEY (WorldID),
|
||||||
UNIQUE (Name)
|
UNIQUE (Name)
|
||||||
);
|
);
|
||||||
|
|||||||
@ -19,7 +19,7 @@ INSERT INTO Accounts (AccountID, Email, Auth)
|
|||||||
INSERT INTO Characters (WorldID, CharacterID, AccountID, Name, Sex)
|
INSERT INTO Characters (WorldID, CharacterID, AccountID, Name, Sex)
|
||||||
VALUES (1, 1, 111111, 'Gamemaster', 1), (1, 2, 111111, 'Player', 1);
|
VALUES (1, 1, 111111, 'Gamemaster', 1), (1, 2, 111111, 'Player', 1);
|
||||||
|
|
||||||
INSERT INTO CharacterRights (CharacterID, Right)
|
INSERT INTO CharacterRights (CharacterID, Name)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'NOTATION'),
|
(1, 'NOTATION'),
|
||||||
(1, 'NAMELOCK'),
|
(1, 'NAMELOCK'),
|
||||||
|
|||||||
@ -11,8 +11,10 @@ CREATE TABLE IF NOT EXISTS Worlds (
|
|||||||
PremiumPlayerBuffer INTEGER NOT NULL,
|
PremiumPlayerBuffer INTEGER NOT NULL,
|
||||||
MaxNewbies INTEGER NOT NULL,
|
MaxNewbies INTEGER NOT NULL,
|
||||||
PremiumNewbieBuffer INTEGER NOT NULL,
|
PremiumNewbieBuffer INTEGER NOT NULL,
|
||||||
OnlineRecord INTEGER NOT NULL DEFAULT 0,
|
OnlinePeak INTEGER NOT NULL DEFAULT 0,
|
||||||
OnlineRecordTimestamp INTEGER NOT NULL DEFAULT 0,
|
OnlinePeakTimestamp INTEGER NOT NULL DEFAULT 0,
|
||||||
|
LastStartup INTEGER NOT NULL DEFAULT 0,
|
||||||
|
LastShutdown INTEGER NOT NULL DEFAULT 0,
|
||||||
PRIMARY KEY (WorldID),
|
PRIMARY KEY (WorldID),
|
||||||
UNIQUE (Name)
|
UNIQUE (Name)
|
||||||
);
|
);
|
||||||
@ -59,15 +61,15 @@ CREATE INDEX IF NOT EXISTS CharactersGuildIndex
|
|||||||
ALTER TABLE Characters ADD GroupID INTEGER NOT NULL;
|
ALTER TABLE Characters ADD GroupID INTEGER NOT NULL;
|
||||||
CREATE TABLE IF NOT EXISTS CharacterRights (
|
CREATE TABLE IF NOT EXISTS CharacterRights (
|
||||||
GroupID INTEGER NOT NULL,
|
GroupID INTEGER NOT NULL,
|
||||||
Right TEXT NOT NULL COLLATE NOCASE,
|
Name TEXT NOT NULL COLLATE NOCASE,
|
||||||
PRIMARY KEY(GroupID, Right)
|
PRIMARY KEY(GroupID, Name)
|
||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS CharacterRights (
|
CREATE TABLE IF NOT EXISTS CharacterRights (
|
||||||
CharacterID INTEGER NOT NULL,
|
CharacterID INTEGER NOT NULL,
|
||||||
Right TEXT NOT NULL COLLATE NOCASE,
|
Name TEXT NOT NULL COLLATE NOCASE,
|
||||||
PRIMARY KEY(CharacterID, Right)
|
PRIMARY KEY(CharacterID, Name)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS CharacterDeaths (
|
CREATE TABLE IF NOT EXISTS CharacterDeaths (
|
||||||
|
|||||||
@ -1325,7 +1325,7 @@ bool GetWorlds(TDatabase *Database, DynamicArray<TWorld> *Worlds){
|
|||||||
"SELECT WorldID, COUNT(*) FROM OnlineCharacters GROUP BY WorldID"
|
"SELECT WorldID, COUNT(*) FROM OnlineCharacters GROUP BY WorldID"
|
||||||
")"
|
")"
|
||||||
" SELECT W.Name, W.Type, COALESCE(N.NumPlayers, 0), W.MaxPlayers,"
|
" SELECT W.Name, W.Type, COALESCE(N.NumPlayers, 0), W.MaxPlayers,"
|
||||||
" W.OnlineRecord, W.OnlineRecordTimestamp"
|
" W.OnlinePeak, W.OnlinePeakTimestamp, W.LastStartup, W.LastShutdown"
|
||||||
" FROM Worlds AS W"
|
" FROM Worlds AS W"
|
||||||
" LEFT JOIN N ON W.WorldID = N.WorldID");
|
" LEFT JOIN N ON W.WorldID = N.WorldID");
|
||||||
if(Stmt == NULL){
|
if(Stmt == NULL){
|
||||||
@ -1347,8 +1347,10 @@ bool GetWorlds(TDatabase *Database, DynamicArray<TWorld> *Worlds){
|
|||||||
World.Type = GetResultInt(Result, Row, 1);
|
World.Type = GetResultInt(Result, Row, 1);
|
||||||
World.NumPlayers = GetResultInt(Result, Row, 2);
|
World.NumPlayers = GetResultInt(Result, Row, 2);
|
||||||
World.MaxPlayers = GetResultInt(Result, Row, 3);
|
World.MaxPlayers = GetResultInt(Result, Row, 3);
|
||||||
World.OnlineRecord = GetResultInt(Result, Row, 4);
|
World.OnlinePeak = GetResultInt(Result, Row, 4);
|
||||||
World.OnlineRecordTimestamp = GetResultTimestamp(Result, Row, 5);
|
World.OnlinePeakTimestamp = GetResultTimestamp(Result, Row, 5);
|
||||||
|
World.LastStartup = GetResultTimestamp(Result, Row, 6);
|
||||||
|
World.LastShutdown = GetResultTimestamp(Result, Row, 7);
|
||||||
Worlds->Push(World);
|
Worlds->Push(World);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3299,12 +3301,12 @@ bool InsertOnlineCharacters(TDatabase *Database, int WorldID,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckOnlineRecord(TDatabase *Database, int WorldID, int NumCharacters, bool *NewRecord){
|
bool CheckOnlinePeak(TDatabase *Database, int WorldID, int NumCharacters, bool *NewPeak){
|
||||||
ASSERT(Database != NULL && NewRecord != NULL);
|
ASSERT(Database != NULL && NewPeak != NULL);
|
||||||
const char *Stmt = PrepareQuery(Database,
|
const char *Stmt = PrepareQuery(Database,
|
||||||
"UPDATE Worlds SET OnlineRecord = $2::INTEGER,"
|
"UPDATE Worlds SET OnlinePeak = $2::INTEGER,"
|
||||||
" OnlineRecordTimestamp = CURRENT_TIMESTAMP"
|
" OnlinePeakTimestamp = CURRENT_TIMESTAMP"
|
||||||
" WHERE WorldID = $1::INTEGER AND OnlineRecord < $2::INTEGER");
|
" WHERE WorldID = $1::INTEGER AND OnlinePeak < $2::INTEGER");
|
||||||
if(Stmt == NULL){
|
if(Stmt == NULL){
|
||||||
LOG_ERR("Failed to prepare query");
|
LOG_ERR("Failed to prepare query");
|
||||||
return false;
|
return false;
|
||||||
@ -3322,7 +3324,55 @@ bool CheckOnlineRecord(TDatabase *Database, int WorldID, int NumCharacters, bool
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*NewRecord = (ResultAffectedRows(Result) > 0);
|
*NewPeak = (ResultAffectedRows(Result) > 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckWorldStartupTime(TDatabase *Database, int WorldID){
|
||||||
|
ASSERT(Database != NULL);
|
||||||
|
const char *Stmt = PrepareQuery(Database,
|
||||||
|
"UPDATE Worlds SET LastStartup = CURRENT_TIMESTAMP"
|
||||||
|
" WHERE WorldID = $1::INTEGER AND LastStartup <= LastShutdown");
|
||||||
|
if(Stmt == NULL){
|
||||||
|
LOG_ERR("Failed to prepare query");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParamBuffer Params = {};
|
||||||
|
ParamBegin(&Params, 1, 1);
|
||||||
|
ParamInt(&Params, WorldID);
|
||||||
|
PGresult *Result = PQexecPrepared(Database->Handle, Stmt, Params.NumParams,
|
||||||
|
Params.Values, Params.Lengths, Params.Formats, 1);
|
||||||
|
AutoResultClear ResultGuard(Result);
|
||||||
|
if(PQresultStatus(Result) != PGRES_COMMAND_OK){
|
||||||
|
LOG_ERR("Failed to execute query: %s", PQerrorMessage(Database->Handle));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckWorldShutdownTime(TDatabase *Database, int WorldID){
|
||||||
|
ASSERT(Database != NULL);
|
||||||
|
const char *Stmt = PrepareQuery(Database,
|
||||||
|
"UPDATE Worlds SET LastShutdown = CURRENT_TIMESTAMP"
|
||||||
|
" WHERE WorldID = $1::INTEGER AND LastShutdown <= LastStartup");
|
||||||
|
if(Stmt == NULL){
|
||||||
|
LOG_ERR("Failed to prepare query");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParamBuffer Params = {};
|
||||||
|
ParamBegin(&Params, 1, 1);
|
||||||
|
ParamInt(&Params, WorldID);
|
||||||
|
PGresult *Result = PQexecPrepared(Database->Handle, Stmt, Params.NumParams,
|
||||||
|
Params.Values, Params.Lengths, Params.Formats, 1);
|
||||||
|
AutoResultClear ResultGuard(Result);
|
||||||
|
if(PQresultStatus(Result) != PGRES_COMMAND_OK){
|
||||||
|
LOG_ERR("Failed to execute query: %s", PQerrorMessage(Database->Handle));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -473,7 +473,7 @@ bool GetWorlds(TDatabase *Database, DynamicArray<TWorld> *Worlds){
|
|||||||
"SELECT WorldID, COUNT(*) FROM OnlineCharacters GROUP BY WorldID"
|
"SELECT WorldID, COUNT(*) FROM OnlineCharacters GROUP BY WorldID"
|
||||||
")"
|
")"
|
||||||
" SELECT W.Name, W.Type, COALESCE(N.NumPlayers, 0), W.MaxPlayers,"
|
" SELECT W.Name, W.Type, COALESCE(N.NumPlayers, 0), W.MaxPlayers,"
|
||||||
" W.OnlineRecord, W.OnlineRecordTimestamp"
|
" W.OnlinePeak, W.OnlinePeakTimestamp, W.LastStartup, W.LastShutdown"
|
||||||
" FROM Worlds AS W"
|
" FROM Worlds AS W"
|
||||||
" LEFT JOIN N ON W.WorldID = N.WorldID");
|
" LEFT JOIN N ON W.WorldID = N.WorldID");
|
||||||
if(Stmt == NULL){
|
if(Stmt == NULL){
|
||||||
@ -488,8 +488,10 @@ bool GetWorlds(TDatabase *Database, DynamicArray<TWorld> *Worlds){
|
|||||||
World.Type = sqlite3_column_int(Stmt, 1);
|
World.Type = sqlite3_column_int(Stmt, 1);
|
||||||
World.NumPlayers = sqlite3_column_int(Stmt, 2);
|
World.NumPlayers = sqlite3_column_int(Stmt, 2);
|
||||||
World.MaxPlayers = sqlite3_column_int(Stmt, 3);
|
World.MaxPlayers = sqlite3_column_int(Stmt, 3);
|
||||||
World.OnlineRecord = sqlite3_column_int(Stmt, 4);
|
World.OnlinePeak = sqlite3_column_int(Stmt, 4);
|
||||||
World.OnlineRecordTimestamp = sqlite3_column_int(Stmt, 5);
|
World.OnlinePeakTimestamp = sqlite3_column_int(Stmt, 5);
|
||||||
|
World.LastStartup = sqlite3_column_int(Stmt, 6);
|
||||||
|
World.LastShutdown = sqlite3_column_int(Stmt, 7);
|
||||||
Worlds->Push(World);
|
Worlds->Push(World);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -964,8 +966,8 @@ bool GetCharacterProfile(TDatabase *Database, const char *CharacterName, TCharac
|
|||||||
" LEFT JOIN Accounts AS A ON A.AccountID = C.AccountID"
|
" LEFT JOIN Accounts AS A ON A.AccountID = C.AccountID"
|
||||||
" LEFT JOIN CharacterRights AS R"
|
" LEFT JOIN CharacterRights AS R"
|
||||||
" ON R.CharacterID = C.CharacterID"
|
" ON R.CharacterID = C.CharacterID"
|
||||||
" AND R.Right = 'NO_STATISTICS'"
|
" AND R.Name = 'NO_STATISTICS'"
|
||||||
" WHERE C.Name = ?1 AND R.Right IS NULL");
|
" WHERE C.Name = ?1 AND R.Name IS NULL");
|
||||||
if(Stmt == NULL){
|
if(Stmt == NULL){
|
||||||
LOG_ERR("Failed to prepare query");
|
LOG_ERR("Failed to prepare query");
|
||||||
return false;
|
return false;
|
||||||
@ -1007,7 +1009,7 @@ bool GetCharacterRight(TDatabase *Database, int CharacterID, const char *Right,
|
|||||||
ASSERT(Database != NULL && Right != NULL && HasRight != NULL);
|
ASSERT(Database != NULL && Right != NULL && HasRight != NULL);
|
||||||
sqlite3_stmt *Stmt = PrepareQuery(Database,
|
sqlite3_stmt *Stmt = PrepareQuery(Database,
|
||||||
"SELECT 1 FROM CharacterRights"
|
"SELECT 1 FROM CharacterRights"
|
||||||
" WHERE CharacterID = ?1 AND Right = ?2");
|
" WHERE CharacterID = ?1 AND Name = ?2");
|
||||||
if(Stmt == NULL){
|
if(Stmt == NULL){
|
||||||
LOG_ERR("Failed to prepare query");
|
LOG_ERR("Failed to prepare query");
|
||||||
return false;
|
return false;
|
||||||
@ -1033,7 +1035,7 @@ bool GetCharacterRight(TDatabase *Database, int CharacterID, const char *Right,
|
|||||||
bool GetCharacterRights(TDatabase *Database, int CharacterID, DynamicArray<TCharacterRight> *Rights){
|
bool GetCharacterRights(TDatabase *Database, int CharacterID, DynamicArray<TCharacterRight> *Rights){
|
||||||
ASSERT(Database != NULL && Rights != NULL);
|
ASSERT(Database != NULL && Rights != NULL);
|
||||||
sqlite3_stmt *Stmt = PrepareQuery(Database,
|
sqlite3_stmt *Stmt = PrepareQuery(Database,
|
||||||
"SELECT Right FROM CharacterRights WHERE CharacterID = ?1");
|
"SELECT Name FROM CharacterRights WHERE CharacterID = ?1");
|
||||||
if(Stmt == NULL){
|
if(Stmt == NULL){
|
||||||
LOG_ERR("Failed to prepare query");
|
LOG_ERR("Failed to prepare query");
|
||||||
return false;
|
return false;
|
||||||
@ -2464,12 +2466,12 @@ bool InsertOnlineCharacters(TDatabase *Database, int WorldID,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckOnlineRecord(TDatabase *Database, int WorldID, int NumCharacters, bool *NewRecord){
|
bool CheckOnlinePeak(TDatabase *Database, int WorldID, int NumCharacters, bool *NewPeak){
|
||||||
ASSERT(Database != NULL && NewRecord != NULL);
|
ASSERT(Database != NULL && NewPeak != NULL);
|
||||||
sqlite3_stmt *Stmt = PrepareQuery(Database,
|
sqlite3_stmt *Stmt = PrepareQuery(Database,
|
||||||
"UPDATE Worlds SET OnlineRecord = ?2,"
|
"UPDATE Worlds SET OnlinePeak = ?2,"
|
||||||
" OnlineRecordTimestamp = UNIXEPOCH()"
|
" OnlinePeakTimestamp = UNIXEPOCH()"
|
||||||
" WHERE WorldID = ?1 AND OnlineRecord < ?2");
|
" WHERE WorldID = ?1 AND OnlinePeak < ?2");
|
||||||
if(Stmt == NULL){
|
if(Stmt == NULL){
|
||||||
LOG_ERR("Failed to prepare query");
|
LOG_ERR("Failed to prepare query");
|
||||||
return false;
|
return false;
|
||||||
@ -2487,7 +2489,55 @@ bool CheckOnlineRecord(TDatabase *Database, int WorldID, int NumCharacters, bool
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*NewRecord = (sqlite3_changes(Database->Handle) > 0);
|
*NewPeak = (sqlite3_changes(Database->Handle) > 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckWorldStartupTime(TDatabase *Database, int WorldID){
|
||||||
|
ASSERT(Database != NULL);
|
||||||
|
sqlite3_stmt *Stmt = PrepareQuery(Database,
|
||||||
|
"UPDATE Worlds SET LastStartup = UNIXEPOCH()"
|
||||||
|
" WHERE WorldID = ?1 AND LastStartup <= LastShutdown");
|
||||||
|
if(Stmt == NULL){
|
||||||
|
LOG_ERR("Failed to prepare query");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoStmtReset StmtReset(Stmt);
|
||||||
|
if(sqlite3_bind_int(Stmt, 1, WorldID) != SQLITE_OK){
|
||||||
|
LOG_ERR("Failed to bind WorldID: %s", sqlite3_errmsg(Database->Handle));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sqlite3_step(Stmt) != SQLITE_DONE){
|
||||||
|
LOG_ERR("Failed to execute query: %s", sqlite3_errmsg(Database->Handle));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckWorldShutdownTime(TDatabase *Database, int WorldID){
|
||||||
|
ASSERT(Database != NULL);
|
||||||
|
sqlite3_stmt *Stmt = PrepareQuery(Database,
|
||||||
|
"UPDATE Worlds SET LastShutdown = UNIXEPOCH()"
|
||||||
|
" WHERE WorldID = ?1 AND LastShutdown <= LastStartup");
|
||||||
|
if(Stmt == NULL){
|
||||||
|
LOG_ERR("Failed to prepare query");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoStmtReset StmtReset(Stmt);
|
||||||
|
if(sqlite3_bind_int(Stmt, 1, WorldID) != SQLITE_OK){
|
||||||
|
LOG_ERR("Failed to bind WorldID: %s", sqlite3_errmsg(Database->Handle));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sqlite3_step(Stmt) != SQLITE_DONE){
|
||||||
|
LOG_ERR("Failed to execute query: %s", sqlite3_errmsg(Database->Handle));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
26
src/query.cc
26
src/query.cc
@ -29,7 +29,7 @@ static int g_NumWorkers;
|
|||||||
static TWorker *g_Workers;
|
static TWorker *g_Workers;
|
||||||
static TQueryQueue *g_QueryQueue;
|
static TQueryQueue *g_QueryQueue;
|
||||||
|
|
||||||
// Query Name
|
// Query Queue and Workers
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
const char *QueryName(int QueryType){
|
const char *QueryName(int QueryType){
|
||||||
const char *Name = "";
|
const char *Name = "";
|
||||||
@ -81,8 +81,6 @@ const char *QueryName(int QueryType){
|
|||||||
return Name;
|
return Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query Queue and Workers
|
|
||||||
//==============================================================================
|
|
||||||
TQuery *QueryNew(void){
|
TQuery *QueryNew(void){
|
||||||
TQuery *Query = (TQuery*)calloc(1, sizeof(TQuery));
|
TQuery *Query = (TQuery*)calloc(1, sizeof(TQuery));
|
||||||
AtomicStore(&Query->RefCount, 1);
|
AtomicStore(&Query->RefCount, 1);
|
||||||
@ -1251,11 +1249,7 @@ void ProcessCreatePlayerlist(TDatabase *Database, TQuery *Query){
|
|||||||
QUERY_STOP_IF(!Tx.Begin(Database));
|
QUERY_STOP_IF(!Tx.Begin(Database));
|
||||||
QUERY_STOP_IF(!DeleteOnlineCharacters(Database, Query->WorldID));
|
QUERY_STOP_IF(!DeleteOnlineCharacters(Database, Query->WorldID));
|
||||||
|
|
||||||
// TODO(fusion): I think `NumCharacters` may be used to signal that the
|
bool NewPeak = false;
|
||||||
// server is going OFFLINE, in which case we'd have to add an `Online`
|
|
||||||
// column to `Worlds` and update it here.
|
|
||||||
|
|
||||||
bool NewRecord = false;
|
|
||||||
int NumCharacters = (int)Request.Read16();
|
int NumCharacters = (int)Request.Read16();
|
||||||
if(NumCharacters != 0xFFFF && NumCharacters > 0){
|
if(NumCharacters != 0xFFFF && NumCharacters > 0){
|
||||||
TOnlineCharacter *Characters = (TOnlineCharacter*)alloca(NumCharacters * sizeof(TOnlineCharacter));
|
TOnlineCharacter *Characters = (TOnlineCharacter*)alloca(NumCharacters * sizeof(TOnlineCharacter));
|
||||||
@ -1266,13 +1260,19 @@ void ProcessCreatePlayerlist(TDatabase *Database, TQuery *Query){
|
|||||||
}
|
}
|
||||||
|
|
||||||
QUERY_STOP_IF(!InsertOnlineCharacters(Database, Query->WorldID, NumCharacters, Characters));
|
QUERY_STOP_IF(!InsertOnlineCharacters(Database, Query->WorldID, NumCharacters, Characters));
|
||||||
QUERY_STOP_IF(!CheckOnlineRecord(Database, Query->WorldID, NumCharacters, &NewRecord));
|
QUERY_STOP_IF(!CheckOnlinePeak(Database, Query->WorldID, NumCharacters, &NewPeak));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(NumCharacters == 0xFFFF){
|
||||||
|
QUERY_STOP_IF(!CheckWorldShutdownTime(Database, Query->WorldID));
|
||||||
|
}else{
|
||||||
|
QUERY_STOP_IF(!CheckWorldStartupTime(Database, Query->WorldID));
|
||||||
}
|
}
|
||||||
|
|
||||||
QUERY_STOP_IF(!Tx.Commit());
|
QUERY_STOP_IF(!Tx.Commit());
|
||||||
|
|
||||||
TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
|
TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
|
||||||
Response->WriteFlag(NewRecord);
|
Response->WriteFlag(NewPeak);
|
||||||
QueryFinishResponse(Query);
|
QueryFinishResponse(Query);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1509,8 +1509,10 @@ void ProcessGetWorlds(TDatabase *Database, TQuery *Query){
|
|||||||
Response->Write8((uint8)Worlds[i].Type);
|
Response->Write8((uint8)Worlds[i].Type);
|
||||||
Response->Write16((uint16)Worlds[i].NumPlayers);
|
Response->Write16((uint16)Worlds[i].NumPlayers);
|
||||||
Response->Write16((uint16)Worlds[i].MaxPlayers);
|
Response->Write16((uint16)Worlds[i].MaxPlayers);
|
||||||
Response->Write16((uint16)Worlds[i].OnlineRecord);
|
Response->Write16((uint16)Worlds[i].OnlinePeak);
|
||||||
Response->Write32((uint32)Worlds[i].OnlineRecordTimestamp);
|
Response->Write32((uint32)Worlds[i].OnlinePeakTimestamp);
|
||||||
|
Response->Write32((uint32)Worlds[i].LastStartup);
|
||||||
|
Response->Write32((uint32)Worlds[i].LastShutdown);
|
||||||
}
|
}
|
||||||
QueryFinishResponse(Query);
|
QueryFinishResponse(Query);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -825,8 +825,10 @@ struct TWorld{
|
|||||||
int Type;
|
int Type;
|
||||||
int NumPlayers;
|
int NumPlayers;
|
||||||
int MaxPlayers;
|
int MaxPlayers;
|
||||||
int OnlineRecord;
|
int OnlinePeak;
|
||||||
int OnlineRecordTimestamp;
|
int OnlinePeakTimestamp;
|
||||||
|
int LastStartup;
|
||||||
|
int LastShutdown;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TWorldConfig{
|
struct TWorldConfig{
|
||||||
@ -1083,7 +1085,9 @@ bool GetOnlineCharacters(TDatabase *Database, int WorldID, DynamicArray<TOnlineC
|
|||||||
bool DeleteOnlineCharacters(TDatabase *Database, int WorldID);
|
bool DeleteOnlineCharacters(TDatabase *Database, int WorldID);
|
||||||
bool InsertOnlineCharacters(TDatabase *Database, int WorldID,
|
bool InsertOnlineCharacters(TDatabase *Database, int WorldID,
|
||||||
int NumCharacters, TOnlineCharacter *Characters);
|
int NumCharacters, TOnlineCharacter *Characters);
|
||||||
bool CheckOnlineRecord(TDatabase *Database, int WorldID, int NumCharacters, bool *NewRecord);
|
bool CheckOnlinePeak(TDatabase *Database, int WorldID, int NumCharacters, bool *NewPeak);
|
||||||
|
bool CheckWorldStartupTime(TDatabase *Database, int WorldID);
|
||||||
|
bool CheckWorldShutdownTime(TDatabase *Database, int WorldID);
|
||||||
|
|
||||||
// query.cc
|
// query.cc
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user