pxl8/server/src/main.rs

143 lines
4.4 KiB
Rust
Raw Normal View History

#![no_std]
#![no_main]
extern crate alloc;
mod allocator;
use core::panic::PanicInfo;
use pxl8_server::*;
#[global_allocator]
static ALLOCATOR: allocator::Allocator = allocator::Allocator;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
const TICK_RATE: u64 = 30;
const TICK_NS: u64 = 1_000_000_000 / TICK_RATE;
#[cfg(unix)]
fn get_time_ns() -> u64 {
let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 };
unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts) };
(ts.tv_sec as u64) * 1_000_000_000 + (ts.tv_nsec as u64)
}
#[cfg(windows)]
fn get_time_ns() -> u64 {
use windows_sys::Win32::System::Performance::*;
static mut FREQ: i64 = 0;
unsafe {
if FREQ == 0 {
QueryPerformanceFrequency(&mut FREQ);
}
let mut count: i64 = 0;
QueryPerformanceCounter(&mut count);
((count as u128 * 1_000_000_000) / FREQ as u128) as u64
}
}
#[cfg(unix)]
fn sleep_ms(ms: u64) {
let ts = libc::timespec {
tv_sec: (ms / 1000) as i64,
tv_nsec: ((ms % 1000) * 1_000_000) as i64,
};
unsafe { libc::nanosleep(&ts, core::ptr::null_mut()) };
}
#[cfg(windows)]
fn sleep_ms(ms: u64) {
use windows_sys::Win32::System::Threading::Sleep;
unsafe { Sleep(ms as u32) };
}
fn extract_spawn_position(payload: &[u8]) -> (f32, f32, f32, f32, f32) {
let x = f32::from_be_bytes([payload[0], payload[1], payload[2], payload[3]]);
let y = f32::from_be_bytes([payload[4], payload[5], payload[6], payload[7]]);
let z = f32::from_be_bytes([payload[8], payload[9], payload[10], payload[11]]);
let yaw = f32::from_be_bytes([payload[12], payload[13], payload[14], payload[15]]);
let pitch = f32::from_be_bytes([payload[16], payload[17], payload[18], payload[19]]);
(x, y, z, yaw, pitch)
}
#[unsafe(no_mangle)]
pub extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 {
let mut transport = match transport::Transport::bind(transport::DEFAULT_PORT) {
Some(t) => t,
None => return 1,
};
let mut sim = Simulation::new();
let mut player_id: u64 = 0;
let mut last_client_tick: u64 = 0;
let mut sequence: u32 = 0;
let mut last_tick = get_time_ns();
let mut entities_buf = [protocol::pxl8_entity_state {
entity_id: 0,
userdata: [0u8; 56],
}; 64];
let mut inputs_buf: [protocol::pxl8_input_msg; 16] = unsafe { core::mem::zeroed() };
loop {
let now = get_time_ns();
let elapsed = now.saturating_sub(last_tick);
if elapsed >= TICK_NS {
last_tick = now;
let dt = (elapsed as f32) / 1_000_000_000.0;
let mut latest_input: Option<protocol::pxl8_input_msg> = None;
while let Some(msg_type) = transport.recv() {
match msg_type {
x if x == protocol::pxl8_msg_type::PXL8_MSG_INPUT as u8 => {
latest_input = Some(transport.get_input());
}
x if x == protocol::pxl8_msg_type::PXL8_MSG_COMMAND as u8 => {
let cmd = transport.get_command();
if cmd.cmd_type == protocol::pxl8_cmd_type::PXL8_CMD_SPAWN_ENTITY as u16 {
let (x, y, z, _yaw, _pitch) = extract_spawn_position(&cmd.payload);
let player = sim.spawn_player(x, y, z);
player_id = player.to_bits();
}
}
_ => {}
}
}
if let Some(input) = latest_input {
last_client_tick = input.tick;
inputs_buf[0] = input;
sim.step(&inputs_buf[..1], dt);
} else {
sim.step(&[], dt);
}
let mut count = 0;
sim.generate_snapshot(player_id, |state| {
if count < entities_buf.len() {
entities_buf[count] = *state;
count += 1;
}
});
let header = protocol::pxl8_snapshot_header {
entity_count: count as u16,
event_count: 0,
player_id,
tick: last_client_tick,
time: sim.time,
};
transport.send_snapshot(&header, &entities_buf[..count], sequence);
sequence = sequence.wrapping_add(1);
}
sleep_ms(1);
}
}