From d66175d91f63d0644e2b2cdb67521ad5ab406378 Mon Sep 17 00:00:00 2001 From: p2r3 Date: Sun, 17 Aug 2025 17:28:42 +0300 Subject: [PATCH] optimize chunk transmission --- src/globals.h | 6 ++++ src/main.c | 88 +++++++++++++++++++++++++++++++-------------------- src/packets.c | 2 +- 3 files changed, 61 insertions(+), 35 deletions(-) diff --git a/src/globals.h b/src/globals.h index b5f8bb9..27405ac 100644 --- a/src/globals.h +++ b/src/globals.h @@ -20,6 +20,10 @@ #define PORT 25565 #define MAX_PLAYERS 16 #define GAMEMODE 0 +#define VIEW_DISTANCE 2 +// How many visited chunks to "remember" +// The server will not re-send chunks that the player has recently been in +#define VISITED_HISTORY 4 #define STATE_NONE 0 #define STATE_STATUS 1 @@ -49,6 +53,8 @@ typedef struct { short x; short y; short z; + short visited_x[VISITED_HISTORY]; + short visited_z[VISITED_HISTORY]; int8_t yaw; int8_t pitch; uint8_t hotbar; diff --git a/src/main.c b/src/main.c index 932806b..63a1faf 100644 --- a/src/main.c +++ b/src/main.c @@ -153,49 +153,22 @@ void handlePacket (int client_fd, int length, int packet_id) { double x, y, z; float yaw, pitch; + // Read player position (and rotation) if (packet_id == 0x1D) cs_setPlayerPosition(client_fd, &x, &y, &z); else cs_setPlayerPositionAndRotation(client_fd, &x, &y, &z, &yaw, &pitch); + // Cast the values to short to get integer position short cx = x, cy = y, cz = z; PlayerData *player; if (getPlayerData(client_fd, &player)) break; + // Determine the player's chunk coordinates short _x = (cx < 0 ? cx - 16 : cx) / 16, _z = (cz < 0 ? cz - 16 : cz) / 16; - short dx = _x - (player->x < 0 ? player->x - 16 : player->x) / 16, dz = _z - (player->z < 0 ? player->z - 16 : player->z) / 16; - - if (dx != 0 || dz != 0) { - - printf("sending new chunks (%d, %d)\n", _x, _z); - sc_setCenterChunk(client_fd, _x, _z); - - clock_t start, end; - int count = 0; - start = clock(); - - if (dx != 0 && dz != 0) { - sc_chunkDataAndUpdateLight(client_fd, _x + dx * 2, _z - dx); - sc_chunkDataAndUpdateLight(client_fd, _x + dx * 2, _z); - sc_chunkDataAndUpdateLight(client_fd, _x + dx * 2, _z + dz); - sc_chunkDataAndUpdateLight(client_fd, _x + dx * 2, _z + dz * 2); - sc_chunkDataAndUpdateLight(client_fd, _x + dx, _z + dz * 2); - sc_chunkDataAndUpdateLight(client_fd, _x, _z + dz * 2); - sc_chunkDataAndUpdateLight(client_fd, _x - dz, _z + dz * 2); - count += 5; - } else { - for (int i = -2; i <= 2; i ++) { - count ++; - sc_chunkDataAndUpdateLight(client_fd, _x + dx * 2 + i * dz, _z + dz * 2 + i * dx); - printf("(%d, %d) ", _x + dx * 2 + i * dz, _z + dz * 2 + i * dx); - } - printf("\n"); - } - - end = clock(); - double total_ms = (double)(end - start) / CLOCKS_PER_SEC * 1000; - printf("generated %d chunks in %.0f ms (%.2f ms per chunk)\n", count, total_ms, total_ms / count); - - } + // Calculate distance between previous and current chunk coordinates + short dx = _x - (player->x < 0 ? player->x - 16 : player->x) / 16; + short dz = _z - (player->z < 0 ? player->z - 16 : player->z) / 16; + // Update position (and rotation) in player data player->x = cx; player->y = cy; player->z = cz; @@ -204,6 +177,53 @@ void handlePacket (int client_fd, int length, int packet_id) { player->pitch = pitch / 90.0f * 127.0f; } + // Exit early if no chunk borders were crossed + if (dx == 0 && dz == 0) return; + + // Check if the player has recently been in this chunk + int found = false; + for (int i = 0; i < VISITED_HISTORY; i ++) { + if (player->visited_x[i] == _x && player->visited_z[i] == _z) { + found = true; + break; + } + } + if (found) return; + + // Update player's recently visited chunks + for (int i = 0; i < VISITED_HISTORY; i ++) { + player->visited_x[i] = player->visited_x[i + 1]; + player->visited_z[i] = player->visited_z[i + 1]; + } + player->visited_x[VISITED_HISTORY - 1] = _x; + player->visited_z[VISITED_HISTORY - 1] = _z; + + printf("sending new chunks (%d, %d)\n", _x, _z); + sc_setCenterChunk(client_fd, _x, _z); + + clock_t start, end; + start = clock(); + + if (dx != 0 && dz != 0) { + sc_chunkDataAndUpdateLight(client_fd, _x + dx * 2, _z - dx); + sc_chunkDataAndUpdateLight(client_fd, _x + dx * 2, _z); + sc_chunkDataAndUpdateLight(client_fd, _x + dx * 2, _z + dz); + sc_chunkDataAndUpdateLight(client_fd, _x + dx * 2, _z + dz * 2); + sc_chunkDataAndUpdateLight(client_fd, _x + dx, _z + dz * 2); + sc_chunkDataAndUpdateLight(client_fd, _x, _z + dz * 2); + sc_chunkDataAndUpdateLight(client_fd, _x - dz, _z + dz * 2); + } else { + sc_chunkDataAndUpdateLight(client_fd, _x + dx * 2, _z + dz * 2); + sc_chunkDataAndUpdateLight(client_fd, _x + dx * 2 + dz, _z + dz * 2 + dx); + sc_chunkDataAndUpdateLight(client_fd, _x + dx * 2 - dz, _z + dz * 2 - dx); + sc_chunkDataAndUpdateLight(client_fd, _x + dx * 2 + dz * 2, _z + dz * 2 + dx * 2); + sc_chunkDataAndUpdateLight(client_fd, _x + dx * 2 - dz * 2, _z + dz * 2 - dx * 2); + } + + end = clock(); + double total_ms = (double)(end - start) / CLOCKS_PER_SEC * 1000; + printf("generated 5 chunks in %.0f ms (%.2f ms per chunk)\n", total_ms, total_ms / 5.0f); + return; } break; diff --git a/src/packets.c b/src/packets.c index b2d63c7..f52c901 100644 --- a/src/packets.c +++ b/src/packets.c @@ -158,7 +158,7 @@ int sc_loginPlay (int client_fd) { // maxplayers writeVarInt(client_fd, MAX_PLAYERS); // view distance - writeVarInt(client_fd, 2); + writeVarInt(client_fd, VIEW_DISTANCE); // sim distance writeVarInt(client_fd, 2); // reduced debug info