Skip to content

Commit 3a7c10d

Browse files
fixed sqlite threaded access
1 parent ed84dc9 commit 3a7c10d

5 files changed

Lines changed: 157 additions & 18 deletions

File tree

include/game/GameLogic.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class GameLogic : public LogicCore
8484
// World message handlers
8585
void HandleWorldChunkRequest(uint64_t sessionId, const nlohmann::json& data);
8686
void HandleWorldChunkRequestJson(uint64_t sessionId, const nlohmann::json& data);
87+
void HandleWorldChunkHMapRequest(uint64_t sessionId, const nlohmann::json& data);
8788
void HandlePlayerPositionUpdate(uint64_t sessionId, const nlohmann::json& data);
8889
void HandleNPCInteraction(uint64_t sessionId, const nlohmann::json& data);
8990
void HandleCollisionCheck(uint64_t sessionId, const nlohmann::json& data);

include/game/WorldChunk.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class WorldChunk {
9999
// Serialization
100100
virtual nlohmann::json Serialize() const;
101101
virtual void Deserialize(const nlohmann::json& data);
102+
virtual nlohmann::json SerializeHeightmap() const;
102103

103104
// Geometry generation
104105
virtual void GenerateGeometry() { GenerateLowPolyGeometry(); }

src/database/SQLiteClient.cpp

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,16 @@ bool SQLiteClient::Connect() {
4848
return false;
4949
}
5050

51+
// --- New: Set busy timeout to 5 seconds ---
52+
sqlite3_busy_timeout(db_, 5000);
53+
5154
char* errMsg = nullptr;
55+
rc = sqlite3_exec(db_, "PRAGMA journal_mode=WAL;", nullptr, nullptr, &errMsg);
56+
if (rc != SQLITE_OK) {
57+
Logger::Warn("Failed to enable WAL mode: {}", errMsg ? errMsg : "unknown error");
58+
sqlite3_free(errMsg);
59+
}
60+
5261
rc = sqlite3_exec(db_, "PRAGMA foreign_keys = ON;", nullptr, nullptr, &errMsg);
5362
if (rc != SQLITE_OK) {
5463
Logger::Warn("Failed to enable foreign keys: {}", errMsg ? errMsg : "unknown error");
@@ -541,11 +550,73 @@ std::vector<std::string> SQLiteClient::ListGameStates() {
541550

542551
// =============== World Data Operations ===============
543552
bool SQLiteClient::SaveChunkData(int chunkX, int chunkZ, const nlohmann::json& chunkData) {
553+
std::lock_guard<std::mutex> lock(dbMutex_);
554+
if (!db_) {
555+
Logger::Error("SaveChunkData: database not connected");
556+
return false;
557+
}
558+
544559
std::string sql = sqlProvider_.GetQuery("save_chunk_data");
545560
if (sql.empty()) {
546561
sql = "INSERT OR REPLACE INTO world_chunks (chunk_x, chunk_z, biome, data, last_updated) VALUES (?, ?, ?, ?, datetime('now'));";
547562
}
548-
return ExecuteWithParams(sql, { std::to_string(chunkX), std::to_string(chunkZ), "0", chunkData.dump() });
563+
564+
// Begin immediate transaction
565+
char* errMsg = nullptr;
566+
int rc = sqlite3_exec(db_, "BEGIN IMMEDIATE;", nullptr, nullptr, &errMsg);
567+
if (rc != SQLITE_OK) {
568+
Logger::Error("Failed to begin transaction: {}", errMsg ? errMsg : "unknown");
569+
sqlite3_free(errMsg);
570+
return false;
571+
}
572+
573+
// Prepare and execute the INSERT statement
574+
sqlite3_stmt* stmt = nullptr;
575+
rc = sqlite3_prepare_v2(db_, sql.c_str(), -1, &stmt, nullptr);
576+
if (rc != SQLITE_OK) {
577+
Logger::Error("Failed to prepare chunk save statement: {}", sqlite3_errmsg(db_));
578+
sqlite3_exec(db_, "ROLLBACK;", nullptr, nullptr, nullptr);
579+
return false;
580+
}
581+
582+
std::string chunkXStr = std::to_string(chunkX);
583+
std::string chunkZStr = std::to_string(chunkZ);
584+
std::string dataStr = chunkData.dump();
585+
586+
sqlite3_bind_text(stmt, 1, chunkXStr.c_str(), -1, SQLITE_TRANSIENT);
587+
sqlite3_bind_text(stmt, 2, chunkZStr.c_str(), -1, SQLITE_TRANSIENT);
588+
sqlite3_bind_int(stmt, 3, 0); // biome default
589+
sqlite3_bind_text(stmt, 4, dataStr.c_str(), -1, SQLITE_TRANSIENT);
590+
591+
rc = sqlite3_step(stmt);
592+
bool success = (rc == SQLITE_DONE);
593+
if (!success) {
594+
Logger::Error("Failed to execute chunk save: {}", sqlite3_errmsg(db_));
595+
}
596+
597+
sqlite3_finalize(stmt);
598+
599+
// Commit or rollback
600+
if (success) {
601+
rc = sqlite3_exec(db_, "COMMIT;", nullptr, nullptr, &errMsg);
602+
if (rc != SQLITE_OK) {
603+
Logger::Error("Failed to commit chunk save: {}", errMsg ? errMsg : "unknown");
604+
sqlite3_free(errMsg);
605+
success = false;
606+
}
607+
} else {
608+
sqlite3_exec(db_, "ROLLBACK;", nullptr, nullptr, nullptr);
609+
}
610+
611+
if (success) {
612+
lastInsertId_ = sqlite3_last_insert_rowid(db_);
613+
affectedRows_ = sqlite3_changes(db_);
614+
stats_.totalQueries++;
615+
} else {
616+
stats_.failedQueries++;
617+
}
618+
619+
return success;
549620
}
550621

551622
nlohmann::json SQLiteClient::LoadChunkData(int chunkX, int chunkZ) {

src/game/GameLogic.cpp

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -563,17 +563,53 @@ void GameLogic::HandleWorldChunkRequest(uint64_t sessionId, const nlohmann::json
563563
}
564564

565565
void GameLogic::HandleWorldChunkRequestJson(uint64_t sessionId, const nlohmann::json& data) {
566-
Logger::Debug("HandleWorldChunkRequestJson called for session {}", sessionId);
567-
Logger::Debug("Request data: {}", data.dump());
568566
try {
569567
int chunkX = data.value("chunkX", 0);
570568
int chunkZ = data.value("chunkZ", 0);
571569
int lod = data.value("lod", 0);
572-
Logger::Debug("JSON world chunk request: [{}, {}] LOD: {}", chunkX, chunkZ, lod);
573570
auto start = std::chrono::steady_clock::now();
574571
auto chunk = GetOrCreateChunk(chunkX, chunkZ);
575572
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
576-
Logger::Debug("GetOrCreateChunk took {} ms", elapsed.count());
573+
if (!chunk) {
574+
Logger::Error("Failed to get or create chunk ({},{})", chunkX, chunkZ);
575+
SendError(sessionId, "Failed to generate chunk", 404);
576+
return;
577+
}
578+
chunk->GenerateLowPolyGeometry();
579+
nlohmann::json response = {
580+
{"type", "world_chunk"},
581+
{"chunkX", chunkX},
582+
{"chunkZ", chunkZ},
583+
{"lod", lod},
584+
{"data", chunk->Serialize()},
585+
{"timestamp", GetCurrentTimestamp()}
586+
};
587+
SendToSession(sessionId, response);
588+
} catch (const std::exception& err) {
589+
Logger::Error("Exception in HandleWorldChunkRequestJson: {}", err.what());
590+
try {
591+
SendError(sessionId, "Internal server error", 500);
592+
} catch (...) {
593+
Logger::Error("Failed to send error response to session {}", sessionId);
594+
}
595+
} catch (...) {
596+
Logger::Error("Unknown exception in HandleWorldChunkRequestJson");
597+
try {
598+
SendError(sessionId, "Internal server error", 500);
599+
} catch (...) {
600+
Logger::Error("Failed to send error response to session {}", sessionId);
601+
}
602+
}
603+
}
604+
605+
void GameLogic::HandleWorldChunkHMapRequest(uint64_t sessionId, const nlohmann::json& data) {
606+
try {
607+
int chunkX = data.value("chunkX", 0);
608+
int chunkZ = data.value("chunkZ", 0);
609+
int lod = data.value("lod", 0);
610+
auto start = std::chrono::steady_clock::now();
611+
auto chunk = GetOrCreateChunk(chunkX, chunkZ);
612+
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
577613
if (!chunk) {
578614
Logger::Error("Failed to get or create chunk ({},{})", chunkX, chunkZ);
579615
SendError(sessionId, "Failed to generate chunk", 404);
@@ -587,9 +623,7 @@ void GameLogic::HandleWorldChunkRequestJson(uint64_t sessionId, const nlohmann::
587623
{"data", chunk->Serialize()},
588624
{"timestamp", GetCurrentTimestamp()}
589625
};
590-
Logger::Debug("Sending chunk response: {}", response.dump());
591626
SendToSession(sessionId, response);
592-
Logger::Debug("Chunk response sent for ({},{})", chunkX, chunkZ);
593627
} catch (const std::exception& err) {
594628
Logger::Error("Exception in HandleWorldChunkRequestJson: {}", err.what());
595629
try {

src/game/WorldChunk.cpp

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -208,19 +208,26 @@ nlohmann::json WorldChunk::Serialize() const {
208208
data["lod"] = static_cast<int>(lod_);
209209
data["biome"] = static_cast<int>(biome_);
210210

211-
// Serialize heightmap
212-
nlohmann::json heightmapArray = nlohmann::json::array();
213-
for (float height : heightmap_) {
214-
heightmapArray.push_back(height);
211+
// Serialize vertices (position + normal as flat float array)
212+
nlohmann::json verticesArray = nlohmann::json::array();
213+
for (const auto& v : vertices_) {
214+
verticesArray.push_back(v.position.x);
215+
verticesArray.push_back(v.position.y);
216+
verticesArray.push_back(v.position.z);
217+
verticesArray.push_back(v.normal.x);
218+
verticesArray.push_back(v.normal.y);
219+
verticesArray.push_back(v.normal.z);
215220
}
216-
data["heightmap"] = heightmapArray;
217-
218-
// Serialize blocks (simplified)
219-
nlohmann::json blocksArray = nlohmann::json::array();
220-
for (BlockType block : blocks_) {
221-
blocksArray.push_back(static_cast<int>(block));
221+
data["vertices"] = verticesArray;
222+
223+
// Serialize indices (using v0, v1, v2)
224+
nlohmann::json indicesArray = nlohmann::json::array();
225+
for (const auto& tri : triangles_) {
226+
indicesArray.push_back(tri.v0);
227+
indicesArray.push_back(tri.v1);
228+
indicesArray.push_back(tri.v2);
222229
}
223-
data["blocks"] = blocksArray;
230+
data["indices"] = indicesArray;
224231

225232
return data;
226233
}
@@ -252,3 +259,28 @@ void WorldChunk::Deserialize(const nlohmann::json& data) {
252259
// Regenerate geometry
253260
GenerateGeometry();
254261
}
262+
263+
nlohmann::json WorldChunk::SerializeHeightmap() const {
264+
nlohmann::json data;
265+
266+
data["chunkX"] = chunkX_;
267+
data["chunkZ"] = chunkZ_;
268+
data["lod"] = static_cast<int>(lod_);
269+
data["biome"] = static_cast<int>(biome_);
270+
271+
// Serialize heightmap
272+
nlohmann::json heightmapArray = nlohmann::json::array();
273+
for (float height : heightmap_) {
274+
heightmapArray.push_back(height);
275+
}
276+
data["heightmap"] = heightmapArray;
277+
278+
// Serialize blocks (simplified)
279+
nlohmann::json blocksArray = nlohmann::json::array();
280+
for (BlockType block : blocks_) {
281+
blocksArray.push_back(static_cast<int>(block));
282+
}
283+
data["blocks"] = blocksArray;
284+
285+
return data;
286+
}

0 commit comments

Comments
 (0)