mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-14 07:47:13 +00:00
Live kept the total before the running session in <char time> and the session's seconds in <char stime>; both changed at a login, together with llog (time 262486 and stime 7344 became time 269830 at the next login). The client reads both (LWOCharacterComponent::LoadFromSaveData 0x00ca4910) and shows their sum (SendMessage 0x00d34330, GetTimePlayed). The server wrote everything into time and no stime. Now time + stime is read (a missing stime is 0, so a save from before keeps its total) and time and stime are written as live had them. A session starts when the character is picked on the character list: charinfo.last_login is loaded with the character, a save whose llog is another login has its stime moved into time, and llog is written as the session's login. Without a known login the session goes on. GetTotalTimePlayed is still every second played. The dashboard's save check knows stime as a number. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
115 lines
4.4 KiB
C++
115 lines
4.4 KiB
C++
#include "SQLiteDatabase.h"
|
|
#include "json.hpp"
|
|
|
|
std::vector<std::string> SQLiteDatabase::GetApprovedCharacterNames() {
|
|
auto [_, result] = ExecuteSelect("SELECT name FROM charinfo;");
|
|
|
|
std::vector<std::string> toReturn;
|
|
|
|
while (!result.eof()) {
|
|
toReturn.push_back(result.getStringField("name"));
|
|
result.nextRow();
|
|
}
|
|
|
|
return toReturn;
|
|
}
|
|
|
|
std::optional<ICharInfo::Info> CharInfoFromQueryResult(CppSQLite3Query stmt) {
|
|
if (stmt.eof()) {
|
|
return std::nullopt;
|
|
}
|
|
|
|
ICharInfo::Info toReturn;
|
|
|
|
toReturn.id = stmt.getInt64Field("id");
|
|
toReturn.name = stmt.getStringField("name");
|
|
toReturn.pendingName = stmt.getStringField("pending_name");
|
|
toReturn.needsRename = stmt.getIntField("needs_rename");
|
|
toReturn.cloneId = stmt.getInt64Field("prop_clone_id");
|
|
toReturn.accountId = stmt.getIntField("account_id");
|
|
toReturn.permissionMap = static_cast<ePermissionMap>(stmt.getIntField("permission_map"));
|
|
toReturn.lastLogin = static_cast<uint64_t>(stmt.getInt64Field("last_login"));
|
|
|
|
return toReturn;
|
|
}
|
|
|
|
std::optional<ICharInfo::Info> SQLiteDatabase::GetCharacterInfo(const LWOOBJID charId) {
|
|
return CharInfoFromQueryResult(
|
|
ExecuteSelect("SELECT name, pending_name, needs_rename, prop_clone_id, permission_map, id, account_id, last_login FROM charinfo WHERE id = ? LIMIT 1;", charId).second
|
|
);
|
|
}
|
|
|
|
std::optional<ICharInfo::Info> SQLiteDatabase::GetCharacterInfo(const std::string_view name) {
|
|
return CharInfoFromQueryResult(
|
|
ExecuteSelect("SELECT name, pending_name, needs_rename, prop_clone_id, permission_map, id, account_id, last_login FROM charinfo WHERE name = ? LIMIT 1;", name).second
|
|
);
|
|
}
|
|
|
|
std::vector<LWOOBJID> SQLiteDatabase::GetAccountCharacterIds(const LWOOBJID accountId) {
|
|
auto [_, result] = ExecuteSelect("SELECT id FROM charinfo WHERE account_id = ? ORDER BY last_login DESC LIMIT 4;", accountId);
|
|
|
|
std::vector<LWOOBJID> toReturn;
|
|
while (!result.eof()) {
|
|
toReturn.push_back(result.getInt64Field("id"));
|
|
result.nextRow();
|
|
}
|
|
|
|
return toReturn;
|
|
}
|
|
|
|
uint32_t SQLiteDatabase::GetCharacterCount() {
|
|
auto [_, res] = ExecuteSelect("SELECT COUNT(*) as count FROM charinfo;");
|
|
if (res.eof()) return 0;
|
|
|
|
return res.getIntField("count");
|
|
}
|
|
|
|
void SQLiteDatabase::InsertNewCharacter(const ICharInfo::Info info) {
|
|
ExecuteInsert(
|
|
"INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`, `prop_clone_id`) VALUES (?,?,?,?,?,?,(SELECT IFNULL(MAX(`prop_clone_id`), 0) + 1 FROM `charinfo`))",
|
|
info.id,
|
|
info.accountId,
|
|
info.name,
|
|
info.pendingName,
|
|
false,
|
|
static_cast<uint32_t>(time(NULL)));
|
|
}
|
|
|
|
void SQLiteDatabase::SetCharacterName(const LWOOBJID characterId, const std::string_view name) {
|
|
ExecuteUpdate("UPDATE charinfo SET name = ?, pending_name = '', needs_rename = 0, last_login = ? WHERE id = ?;", name, static_cast<uint32_t>(time(NULL)), characterId);
|
|
}
|
|
|
|
void SQLiteDatabase::SetPendingCharacterName(const LWOOBJID characterId, const std::string_view name) {
|
|
ExecuteUpdate("UPDATE charinfo SET pending_name = ?, needs_rename = 0, last_login = ? WHERE id = ?;", name, static_cast<uint32_t>(time(NULL)), characterId);
|
|
}
|
|
|
|
void SQLiteDatabase::UpdateLastLoggedInCharacter(const LWOOBJID characterId) {
|
|
ExecuteUpdate("UPDATE charinfo SET last_login = ? WHERE id = ?;", static_cast<uint32_t>(time(NULL)), characterId);
|
|
}
|
|
|
|
bool SQLiteDatabase::IsNameInUse(const std::string_view name) {
|
|
auto [_, result] = ExecuteSelect("SELECT name FROM charinfo WHERE name = ? or pending_name = ? LIMIT 1;", name, name);
|
|
|
|
return !result.eof();
|
|
}
|
|
|
|
nlohmann::json SQLiteDatabase::GetCharacterById(const LWOOBJID charId) {
|
|
auto [_, result] = ExecuteSelect(
|
|
"SELECT c.id, c.name, c.pending_name, c.needs_rename, c.account_id, c.last_login, c.prop_clone_id, c.permission_map, a.name as account_name "
|
|
"FROM charinfo c LEFT JOIN accounts a ON c.account_id = a.id WHERE c.id = ? LIMIT 1;", charId);
|
|
if (result.eof()) {
|
|
return nlohmann::json({{"error", "Character not found"}});
|
|
}
|
|
return nlohmann::json({
|
|
{"id", std::to_string(result.getInt64Field("id"))},
|
|
{"name", result.getStringField("name")},
|
|
{"pending_name", result.getStringField("pending_name")},
|
|
{"needs_rename", result.getIntField("needs_rename") != 0},
|
|
{"account_id", result.getIntField("account_id")},
|
|
{"account_name", result.getStringField("account_name")},
|
|
{"last_login", result.getInt64Field("last_login")},
|
|
{"prop_clone_id", result.getInt64Field("prop_clone_id")},
|
|
{"permission_map", result.getIntField("permission_map")}
|
|
});
|
|
}
|