1
0
mirror of https://github.com/p2r3/bareiron.git synced 2025-10-02 07:35:08 +02:00

implement basic support for mobs

This commit is contained in:
p2r3
2025-08-22 02:29:59 +03:00
parent 5a0f8fd376
commit ca9edce43a
9 changed files with 205 additions and 41 deletions

View File

@@ -6,9 +6,14 @@
#ifdef ESP_PLATFORM
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "esp_timer.h"
#else
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC 1
#endif
#endif
#include "globals.h"
@@ -184,6 +189,14 @@ uint64_t splitmix64 (uint64_t state) {
return z ^ (z >> 31);
}
#ifndef ESP_PLATFORM
int64_t get_program_time () {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (int64_t)ts.tv_sec * 1000000LL + ts.tv_nsec / 1000LL;
}
#endif
int client_states[MAX_PLAYERS * 2];
void setClientState (int client_fd, int new_state) {
@@ -379,11 +392,7 @@ void spawnPlayer (PlayerData *player) {
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;
spawn_y = getHeightAt(8, 8) + 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;
@@ -663,3 +672,110 @@ void handlePlayerAction (PlayerData *player, int action, short x, short y, short
}
}
void spawnMob (uint8_t type, short x, uint8_t y, short z) {
for (int i = 0; i < MAX_MOBS; i ++) {
// Look for type 0 (unallocated)
if (mob_data[i].type != 0) continue;
// Assign it the input parameters
mob_data[i].type = type;
mob_data[i].x = x;
mob_data[i].y = y;
mob_data[i].z = z;
// Broadcast entity creation to all players
for (int j = 0; j < MAX_PLAYERS; j ++) {
if (player_data[j].client_fd == -1) continue;
sc_spawnEntity(
player_data[j].client_fd,
65536 + i, // Try to avoid conflict with client file descriptors
recv_buffer, // The UUID doesn't matter, feed it garbage
type, x, y, z,
// Face opposite of the player, as if looking at them when spawning
(player_data[j].yaw + 127) & 255, 0
);
}
break;
}
}
// Simulates events scheduled for regular intervals
// Takes the time since the last tick in microseconds as the only arguemnt
void handleServerTick (int64_t time_since_last_tick) {
// Send Keep Alive and Update Time packets to all in-game clients
world_time += 20 * time_since_last_tick / 1000000;
for (int i = 0; i < MAX_PLAYERS; i ++) {
if (player_data[i].client_fd == -1) continue;
sc_keepAlive(player_data[i].client_fd);
sc_updateTime(player_data[i].client_fd, world_time);
}
/**
* If the RNG seed ever hits 0, it'll never generate anything
* else. This is because the fast_rand function uses a simple
* XORshift. This isn't a common concern, so we only check for
* this periodically. If it does become zero, we reset it to
* the world seed as a good-enough fallback.
*/
if (rng_seed == 0) rng_seed = world_seed;
// Tick mob behavior
for (int i = 0; i < MAX_MOBS; i ++) {
if (mob_data[i].type == 0) continue;
uint32_t r = fast_rand();
// Skip 50% of ticks randomly
if (r & 1) continue;
// Move by one block on the X or Z axis
// Yaw is set to face in the direction of motion
short new_x = mob_data[i].x, new_z = mob_data[i].z;
uint8_t yaw;
if ((r >> 2) & 1) {
if ((r >> 1) & 1) { new_x += 1; yaw = 192; }
else { new_x -= 1; yaw = 64; }
} else {
if ((r >> 1) & 1) { new_z += 1; yaw = 0; }
else { new_z -= 1; yaw = 128; }
}
// Vary the yaw angle to look just a little less robotic
yaw += ((r >> 6) & 15) - 8;
// Check if the block we're moving into is passable:
// if yes, and the block below is solid, keep the same Y level;
// if yes, but the block below isn't solid, drop down one block;
// if not, go up by up to one block;
// if going up isn't possible, skip this iteration.
uint8_t new_y = mob_data[i].y;
uint8_t block = getBlockAt(new_x, new_y, new_z);
if (block != B_air) {
if (getBlockAt(new_x, new_y + 1, new_z) == B_air) new_y += 1;
else continue;
} else if (getBlockAt(new_x, new_y - 1, new_z) == B_air) new_y -= 1;
// Store new mob position
mob_data[i].x = new_x;
mob_data[i].y = new_y;
mob_data[i].z = new_z;
// Broadcast relevant entity movement packets
for (int j = 0; j < MAX_PLAYERS; j ++) {
if (player_data[j].client_fd == -1) continue;
int entity_id = 65536 + i;
sc_teleportEntity (
player_data[j].client_fd, entity_id,
(double)new_x + 0.5, new_y, (double)new_z + 0.5,
yaw * 360 / 256, 0
);
sc_setHeadRotation(player_data[j].client_fd, entity_id, yaw);
}
}
}