forked from EXTERNAL/bareiron
implement respawning
This commit is contained in:
@@ -29,6 +29,8 @@ uint8_t recv_buffer[256] = {0};
|
||||
uint32_t world_seed = 0xA103DE6C;
|
||||
uint32_t rng_seed = 0xE2B9419;
|
||||
|
||||
uint64_t world_time = 0;
|
||||
|
||||
uint16_t client_count;
|
||||
|
||||
BlockChange block_changes[20000];
|
||||
|
67
src/main.c
67
src/main.c
@@ -31,8 +31,6 @@
|
||||
#include "worldgen.h"
|
||||
#include "registries.h"
|
||||
|
||||
uint64_t world_time = 0;
|
||||
|
||||
void handlePacket (int client_fd, int length, int packet_id) {
|
||||
|
||||
int state = getClientState(client_fd);
|
||||
@@ -72,66 +70,16 @@ void handlePacket (int client_fd, int length, int packet_id) {
|
||||
return;
|
||||
} else if (state == STATE_CONFIGURATION) {
|
||||
printf("Client Acknowledged Configuration\n\n");
|
||||
setClientState(client_fd, STATE_PLAY);
|
||||
|
||||
// Enter client into "play" state
|
||||
setClientState(client_fd, STATE_PLAY);
|
||||
sc_loginPlay(client_fd);
|
||||
|
||||
PlayerData *player;
|
||||
if (getPlayerData(client_fd, &player)) break;
|
||||
|
||||
float spawn_x = 8.5f, spawn_y = 80.0f, spawn_z = 8.5f;
|
||||
float spawn_yaw = 0.0f, spawn_pitch = 0.0f;
|
||||
|
||||
if (player->y == -32767) { // is this a new player?
|
||||
int _x = 8 / CHUNK_SIZE;
|
||||
int _z = 8 / CHUNK_SIZE;
|
||||
int rx = 8 % CHUNK_SIZE;
|
||||
int rz = 8 % CHUNK_SIZE;
|
||||
spawn_y = getHeightAt(rx, rz, _x, _z, getChunkHash(_x, _z), getChunkBiome(_x, _z)) + 1;
|
||||
} else {
|
||||
spawn_x = player->x > 0 ? (float)player->x + 0.5 : (float)player->x - 0.5;
|
||||
spawn_y = player->y;
|
||||
spawn_z = player->z > 0 ? (float)player->z + 0.5 : (float)player->z - 0.5;
|
||||
spawn_yaw = player->yaw * 180 / 127;
|
||||
spawn_pitch = player->pitch * 90 / 127;
|
||||
}
|
||||
|
||||
sc_synchronizePlayerPosition(client_fd, spawn_x, spawn_y, spawn_z, spawn_yaw, spawn_pitch);
|
||||
|
||||
task_yield();
|
||||
|
||||
for (uint8_t i = 0; i < 41; i ++) {
|
||||
sc_setContainerSlot(client_fd, 0, serverSlotToClientSlot(0, i), player->inventory_count[i], player->inventory_items[i]);
|
||||
}
|
||||
sc_setHeldItem(client_fd, player->hotbar);
|
||||
|
||||
sc_setHealth(client_fd, player->health, player->hunger);
|
||||
|
||||
sc_playerAbilities(client_fd, 0x01 + 0x04); // invulnerability + flight
|
||||
sc_updateTime(client_fd, world_time);
|
||||
|
||||
short _x = player->x / 16, _z = player->z / 16;
|
||||
if (player->x % 16 < 0) _x -= 1;
|
||||
if (player->z % 16 < 0) _z -= 1;
|
||||
|
||||
sc_setDefaultSpawnPosition(client_fd, 8, 80, 8);
|
||||
sc_startWaitingForChunks(client_fd);
|
||||
sc_setCenterChunk(client_fd, _x, _z);
|
||||
|
||||
task_yield();
|
||||
|
||||
// Send spawn chunk first
|
||||
sc_chunkDataAndUpdateLight(client_fd, _x, _z);
|
||||
for (int i = -VIEW_DISTANCE; i <= VIEW_DISTANCE; i ++) {
|
||||
for (int j = -VIEW_DISTANCE; j <= VIEW_DISTANCE; j ++) {
|
||||
if (i == 0 && j == 0) continue;
|
||||
sc_chunkDataAndUpdateLight(client_fd, _x + i, _z + j);
|
||||
}
|
||||
}
|
||||
// Re-synchronize player position after all chunks have been sent
|
||||
sc_synchronizePlayerPosition(client_fd, spawn_x, spawn_y, spawn_z, spawn_yaw, spawn_pitch);
|
||||
|
||||
task_yield();
|
||||
// Send full client spawn sequence
|
||||
spawnPlayer(player);
|
||||
|
||||
// Register all existing players and spawn their entities, and broadcast
|
||||
// information about the joining player to all existing players.
|
||||
@@ -156,6 +104,13 @@ void handlePacket (int client_fd, int length, int packet_id) {
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0B:
|
||||
if (state == STATE_PLAY) {
|
||||
if (cs_clientStatus(client_fd)) break;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0C:
|
||||
if (state == STATE_PLAY) {
|
||||
// client tick
|
||||
|
@@ -144,7 +144,7 @@ int sc_finishConfiguration (int client_fd) {
|
||||
// S->C Login (play)
|
||||
int sc_loginPlay (int client_fd) {
|
||||
|
||||
writeVarInt(client_fd, 69 + sizeVarInt(MAX_PLAYERS));
|
||||
writeVarInt(client_fd, 49 + sizeVarInt(MAX_PLAYERS));
|
||||
writeByte(client_fd, 0x2B);
|
||||
// entity id
|
||||
uint32_t entity_id = getClientIndex(client_fd);
|
||||
@@ -153,9 +153,9 @@ int sc_loginPlay (int client_fd) {
|
||||
writeByte(client_fd, false);
|
||||
// dimensions
|
||||
writeVarInt(client_fd, 1);
|
||||
writeVarInt(client_fd, 19);
|
||||
const char *dimension = "minecraft:overworld";
|
||||
send_all(client_fd, dimension, 19);
|
||||
writeVarInt(client_fd, 9);
|
||||
const char *dimension = "overworld";
|
||||
send_all(client_fd, dimension, 9);
|
||||
// maxplayers
|
||||
writeVarInt(client_fd, MAX_PLAYERS);
|
||||
// view distance
|
||||
@@ -171,8 +171,8 @@ int sc_loginPlay (int client_fd) {
|
||||
// dimension id
|
||||
writeVarInt(client_fd, 0);
|
||||
// dimension name
|
||||
writeVarInt(client_fd, 19);
|
||||
send_all(client_fd, dimension, 19);
|
||||
writeVarInt(client_fd, 9);
|
||||
send_all(client_fd, dimension, 9);
|
||||
// hashed seed
|
||||
writeUint64(client_fd, 0x0123456789ABCDEF);
|
||||
// gamemode
|
||||
@@ -850,6 +850,57 @@ int sc_setHealth (int client_fd, uint8_t health, uint8_t food) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// S->C Respawn
|
||||
int sc_respawn (int client_fd) {
|
||||
|
||||
writeVarInt(client_fd, 28);
|
||||
writeByte(client_fd, 0x4B);
|
||||
|
||||
// dimension id
|
||||
writeVarInt(client_fd, 0);
|
||||
// dimension name
|
||||
const char *dimension = "overworld";
|
||||
writeVarInt(client_fd, 9);
|
||||
send_all(client_fd, dimension, 9);
|
||||
// hashed seed
|
||||
writeUint64(client_fd, 0x0123456789ABCDEF);
|
||||
// gamemode
|
||||
writeByte(client_fd, GAMEMODE);
|
||||
// previous gamemode
|
||||
writeByte(client_fd, 0xFF);
|
||||
// is debug
|
||||
writeByte(client_fd, 0);
|
||||
// is flat
|
||||
writeByte(client_fd, 0);
|
||||
// has death location
|
||||
writeByte(client_fd, 0);
|
||||
// portal cooldown
|
||||
writeVarInt(client_fd, 0);
|
||||
// sea level
|
||||
writeVarInt(client_fd, 63);
|
||||
// data kept
|
||||
writeByte(client_fd, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// C->S Client Status
|
||||
int cs_clientStatus (int client_fd) {
|
||||
|
||||
uint8_t id = readByte(client_fd);
|
||||
|
||||
PlayerData *player;
|
||||
if (getPlayerData(client_fd, &player)) return 1;
|
||||
|
||||
if (id == 0) {
|
||||
sc_respawn(client_fd);
|
||||
resetPlayerData(player);
|
||||
spawnPlayer(player);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// S->C Registry Data (multiple packets) and Update Tags (configuration, multiple packets)
|
||||
int sc_registries (int client_fd) {
|
||||
|
||||
|
85
src/tools.c
85
src/tools.c
@@ -218,6 +218,21 @@ int getClientIndex (int client_fd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void resetPlayerData (PlayerData *player) {
|
||||
player->health = 20;
|
||||
player->hunger = 20;
|
||||
player->y = -32767;
|
||||
player->grounded_y = 0;
|
||||
for (int i = 0; i < 41; i ++) {
|
||||
player->inventory_items[i] = 0;
|
||||
player->inventory_count[i] = 0;
|
||||
}
|
||||
for (int i = 0; i < 9; i ++) {
|
||||
player->craft_items[i] = 0;
|
||||
player->craft_count[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int reservePlayerData (int client_fd, uint8_t *uuid, char *name) {
|
||||
|
||||
for (int i = 0; i < MAX_PLAYERS; i ++) {
|
||||
@@ -237,9 +252,7 @@ int reservePlayerData (int client_fd, uint8_t *uuid, char *name) {
|
||||
player_data[i].client_fd = client_fd;
|
||||
memcpy(player_data[i].uuid, uuid, 16);
|
||||
memcpy(player_data[i].name, name, 16);
|
||||
player_data[i].health = 20;
|
||||
player_data[i].hunger = 20;
|
||||
player_data[i].y = -32767;
|
||||
resetPlayerData(&player_data[i]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -357,6 +370,72 @@ int givePlayerItem (PlayerData *player, uint16_t item, uint8_t count) {
|
||||
|
||||
}
|
||||
|
||||
// Sends the full sequence for spawning the player to the client
|
||||
void spawnPlayer (PlayerData *player) {
|
||||
|
||||
// Player spawn coordinates, initialized to placeholders
|
||||
float spawn_x = 8.5f, spawn_y = 80.0f, spawn_z = 8.5f;
|
||||
float spawn_yaw = 0.0f, spawn_pitch = 0.0f;
|
||||
|
||||
if (player->y == -32767) { // Is this a new player?
|
||||
// Determine spawning Y coordinate based on terrain height
|
||||
int _x = 8 / CHUNK_SIZE;
|
||||
int _z = 8 / CHUNK_SIZE;
|
||||
int rx = 8 % CHUNK_SIZE;
|
||||
int rz = 8 % CHUNK_SIZE;
|
||||
spawn_y = getHeightAt(rx, rz, _x, _z, getChunkHash(_x, _z), getChunkBiome(_x, _z)) + 1;
|
||||
} else { // Not a new player
|
||||
// Calculate spawn position from player data
|
||||
spawn_x = player->x > 0 ? (float)player->x + 0.5 : (float)player->x - 0.5;
|
||||
spawn_y = player->y;
|
||||
spawn_z = player->z > 0 ? (float)player->z + 0.5 : (float)player->z - 0.5;
|
||||
spawn_yaw = player->yaw * 180 / 127;
|
||||
spawn_pitch = player->pitch * 90 / 127;
|
||||
}
|
||||
|
||||
// Teleport player to spawn coordinates (first pass)
|
||||
sc_synchronizePlayerPosition(player->client_fd, spawn_x, spawn_y, spawn_z, spawn_yaw, spawn_pitch);
|
||||
|
||||
task_yield(); // Check task timer between packets
|
||||
|
||||
// Sync client inventory and hotbar
|
||||
for (uint8_t i = 0; i < 41; i ++) {
|
||||
sc_setContainerSlot(player->client_fd, 0, serverSlotToClientSlot(0, i), player->inventory_count[i], player->inventory_items[i]);
|
||||
}
|
||||
sc_setHeldItem(player->client_fd, player->hotbar);
|
||||
// Sync client health and hunger
|
||||
sc_setHealth(player->client_fd, player->health, player->hunger);
|
||||
// Sync client clock time
|
||||
sc_updateTime(player->client_fd, world_time);
|
||||
|
||||
// Give the player flight (for testing)
|
||||
sc_playerAbilities(player->client_fd, 0x04);
|
||||
|
||||
// Calculate player's chunk coordinates
|
||||
short _x = div_floor(player->x, 16), _z = div_floor(player->z, 16);
|
||||
|
||||
// Indicate that we're about to send chunk data
|
||||
sc_setDefaultSpawnPosition(player->client_fd, 8, 80, 8);
|
||||
sc_startWaitingForChunks(player->client_fd);
|
||||
sc_setCenterChunk(player->client_fd, _x, _z);
|
||||
|
||||
task_yield(); // Check task timer between packets
|
||||
|
||||
// Send spawn chunk first
|
||||
sc_chunkDataAndUpdateLight(player->client_fd, _x, _z);
|
||||
for (int i = -VIEW_DISTANCE; i <= VIEW_DISTANCE; i ++) {
|
||||
for (int j = -VIEW_DISTANCE; j <= VIEW_DISTANCE; j ++) {
|
||||
if (i == 0 && j == 0) continue;
|
||||
sc_chunkDataAndUpdateLight(player->client_fd, _x + i, _z + j);
|
||||
}
|
||||
}
|
||||
// Re-teleport player after all chunks have been sent
|
||||
sc_synchronizePlayerPosition(player->client_fd, spawn_x, spawn_y, spawn_z, spawn_yaw, spawn_pitch);
|
||||
|
||||
task_yield(); // Check task timer between packets
|
||||
|
||||
}
|
||||
|
||||
uint8_t getBlockChange (short x, uint8_t y, short z) {
|
||||
for (int i = 0; i < block_changes_count; i ++) {
|
||||
if (block_changes[i].block == 0xFF) continue;
|
||||
|
Reference in New Issue
Block a user