Skip to content

Commit

Permalink
now it works
Browse files Browse the repository at this point in the history
  • Loading branch information
flafmg committed Jul 30, 2024
1 parent 9dbdbfe commit 131a297
Show file tree
Hide file tree
Showing 16 changed files with 773 additions and 327 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ edition = "2021"
tokio = { version = "1.39", features = ["full"] }
reqwest = { version = "0.12", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
serde_yaml = { version = "0.9" }
serde_yaml = "0.9"
async-trait = "0.1"
flate2 = "1.0.30"
rand = "0.8"
noise = "0.9"
dashmap = "6.0"
2 changes: 1 addition & 1 deletion server-config.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
addr: 0.0.0.0
port: 25565
heartbeat_url: https://www.classicube.net/server/heartbeat
name: Dandelion dev server
name: dandelion dev [github.com/flafmg/dandelion-classic]
motd: wtf are you doing here, get out
public: true
do_user_auth: true
Expand Down
3 changes: 2 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ mod server;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let server = Arc::new(Server::new().await?); // i fucking hate arcs
let server = Arc::new(Server::new().await?);
server.start().await?;

Ok(())
}
22 changes: 20 additions & 2 deletions src/server/game/dmf_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::{
const HEADER_INDENTIFIER: &str = "DANDELION MAP FORMAT";
const HEADER_VERSION: u8 = 0x00;

#[derive(Debug, Clone)]
pub struct DmfMap {
pub x_spawn: i16,
pub y_spawn: i16,
Expand Down Expand Up @@ -40,7 +41,20 @@ impl DmfMap {
blocks: vec![0x00; total_blocks],
};
}

pub fn get_block(&self, x: i16, y: i16, z: i16) -> u8 {
if x < self.x_size && y < self.y_size && z < self.z_size {
let index = (y as usize * self.z_size as usize * self.x_size as usize)
+ (z as usize * self.x_size as usize)
+ x as usize;
self.blocks[index]
} else {
println!(
"Error: attempted to get block outside world ({}, {}, {})",
x, y, z
);
0x00
}
}
pub fn set_block(&mut self, x: i16, y: i16, z: i16, block: u8) {
if x < self.x_size && y < self.y_size && z < self.z_size {
let index = (y as usize * self.z_size as usize * self.x_size as usize)
Expand All @@ -54,7 +68,11 @@ impl DmfMap {
);
}
}

pub fn set_spawn_point(&mut self, x: i16, y: i16, z: i16) {
self.x_spawn = x;
self.y_spawn = y;
self.z_spawn = z;
}
pub fn save_file(&self, path: &str) -> io::Result<()> {
let mut file = File::create(path)?;
print!("saving file to {}", path);
Expand Down
91 changes: 81 additions & 10 deletions src/server/game/player.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,42 @@
use crate::server::game::dmf_map::DmfMap;
use crate::server::network::packets::clientbound::{
SendMessagePacket, SetPositionAndOrientationPacket,
};
use crate::server::network::{
packet::PacketTrait,
packet_stream::packet_writer::PacketWriter,
packets::clientbound::{LevelDataChunkPacket, LevelFinalizePacket, LevelInitializePacket},
};
use flate2::write::GzEncoder;
use flate2::Compression;
use std::io::prelude::*;
use std::sync::Arc;

use tokio::{io::WriteHalf, net::TcpStream, sync::Mutex};

use crate::server::network::packet::PacketTrait;
use tokio::{io::WriteHalf, net::TcpStream, sync::RwLock};

#[derive(Clone, Debug)]
pub struct Player {
id: i8,
name: String,
current_world: String,
pub current_map: String,
pub x: i16,
pub y: i16,
pub z: i16,
pub yaw: u8,
pub pitch: u8,
pub socket: Arc<Mutex<WriteHalf<TcpStream>>>,
pub socket: Arc<RwLock<WriteHalf<TcpStream>>>,
}

impl Player {
pub fn new(
id: i8,
name: String,
current_world: String,
socket: Arc<Mutex<WriteHalf<TcpStream>>>,
current_map: String,
socket: Arc<RwLock<WriteHalf<TcpStream>>>,
) -> Self {
Self {
id,
name,
current_world,
current_map,
x: 0,
y: 0,
z: 0,
Expand All @@ -46,7 +55,7 @@ impl Player {
}

pub fn get_current_world(&self) -> &str {
&self.current_world
&self.current_map
}

pub fn set_pos(&mut self, x: i16, y: i16, z: i16, pitch: u8, yaw: u8) {
Expand All @@ -56,4 +65,66 @@ impl Player {
self.pitch = pitch;
self.yaw = yaw;
}
pub async fn teleport(&mut self, x: i16, y: i16, z: i16, pitch: u8, yaw: u8) {
self.set_pos(x, y, z, pitch, yaw);
let mut set_position = SetPositionAndOrientationPacket::new(-1, x, y, z, pitch, yaw);
set_position.write(&mut PacketWriter::new());
let mut socket = self.socket.write().await;
set_position.resolve(&mut socket).await;
}
pub async fn send_message(&self, msg: &str) {
let mut message_packet = SendMessagePacket::new(-1, msg.to_string());
message_packet.write(&mut PacketWriter::new());
let mut socket = self.socket.write().await;
message_packet.resolve(&mut socket).await;
}
pub async fn send_to_level(&self, map: &DmfMap) {
let block_data = &map.blocks;

let mut socket_guard = self.socket.write().await;

let mut resolve_packet_response = LevelInitializePacket::new();
let mut packet_writer = PacketWriter::new();
resolve_packet_response.write(&mut packet_writer);
resolve_packet_response
.resolve(&mut *socket_guard)
.await
.unwrap();

let total_length = block_data.len();
let mut prefixed_data = Vec::with_capacity(4 + total_length);
prefixed_data.extend_from_slice(&(total_length as u32).to_be_bytes());
prefixed_data.extend_from_slice(&block_data);

let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
encoder.write_all(&prefixed_data).unwrap();
let compressed_data = encoder.finish().unwrap();

let chunk_size = 1024;
for (i, chunk) in compressed_data.chunks(chunk_size).enumerate() {
let chunk_length = chunk.len() as i16;
let percent_complete = ((i * chunk_size + chunk_length as usize) as f32
/ compressed_data.len() as f32
* 100.0) as u8;

let mut chunk_data = chunk.to_vec();
if chunk_data.len() < chunk_size {
chunk_data.resize(chunk_size, 0x00);
}

let mut packet = LevelDataChunkPacket::new(chunk_length, chunk_data, percent_complete);
let mut packet_writer = PacketWriter::new();
packet.write(&mut packet_writer);

if let Err(e) = packet.resolve(&mut *socket_guard).await {
eprintln!("Error sending chunk {}: {}", i, e);
break;
}
}

let mut level_finalize = LevelFinalizePacket::new(map.x_size, map.y_size, map.z_size);
let mut packet_writer = PacketWriter::new();
level_finalize.write(&mut packet_writer);
level_finalize.resolve(&mut *socket_guard).await.unwrap();
}
}
179 changes: 179 additions & 0 deletions src/server/map_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// shitty map generation thingy slow as hell
// flat = flat duh
// noise = plain noise
// classic = water in 31 and sand on 33 and bellow

use noise::{NoiseFn, Perlin};

use super::game::dmf_map::DmfMap;

pub struct MapBuilder;

impl MapBuilder {
pub async fn create_map(preset: &str, params: Option<PresetParams>) -> DmfMap {
match preset {
"flat" => Self::create_flat_map(
params.clone().unwrap().flat_ground_level,
params.clone().unwrap().dimensions,
),
"noise" => Self::create_noise_map(
params.clone().unwrap().noise_layers,
params.clone().unwrap().dimensions,
),
"island" => Self::create_classic_map(
params.clone().unwrap().noise_layers,
params.unwrap().dimensions,
),
_ => panic!("Unknown preset"),
}
}

fn create_flat_map(ground_level: u32, dimensions: Dimensions) -> DmfMap {
let mut map = DmfMap::new(
0,
ground_level as i16 + 4,
0,
dimensions.x,
dimensions.y,
dimensions.z,
);

for x in 0..dimensions.x {
for z in 0..dimensions.z {
for y in 0..ground_level {
map.set_block(x as i16, y as i16, z as i16, 0x01); // stone
}
for y in ground_level..(ground_level + 3) {
map.set_block(x as i16, y as i16, z as i16, 0x03); // dirt
}
map.set_block(x as i16, ground_level as i16 + 3, z as i16, 0x02);
// grass
}
}

map
}

fn create_noise_map(layers: Vec<NoiseLayer>, dimensions: Dimensions) -> DmfMap {
let mut map = DmfMap::new(0, 64, 0, dimensions.x, dimensions.y, dimensions.z);

for x in 0..dimensions.x {
for z in 0..dimensions.z {
let mut height = 0.0;
for layer in &layers {
let perlin = Perlin::new(50);
height +=
perlin.get([x as f64 / layer.scale, z as f64 / layer.scale]) * layer.weight;
}
let height = (height + dimensions.y as f64 / 2.0).min(dimensions.y as f64) as u32;

for y in 0..height {
map.set_block(x as i16, y as i16, z as i16, 0x01); // stone
}
for y in height..(height + 3) {
map.set_block(x as i16, y as i16, z as i16, 0x03); // dirt
}
map.set_block(x as i16, height as i16 + 3, z as i16, 0x02); // grass
}
}

map
}

fn create_classic_map(layers: Vec<NoiseLayer>, dimensions: Dimensions) -> DmfMap {
const SHORE_FACTOR: f64 = 0.25;
const SHORE_AFFECTED_DISTANCE: f64 = 25.0; // Distance in blocks that affects the shore

let water_level = 31;
let mut map = DmfMap::new(
0,
water_level + 1,
0,
dimensions.x,
dimensions.y,
dimensions.z,
);

for x in 0..dimensions.x {
for z in 0..dimensions.z {
let mut height = 0.0;
for layer in &layers {
let perlin = Perlin::new(70);
height +=
perlin.get([x as f64 / layer.scale, z as f64 / layer.scale]) * layer.weight;
}

let distance_from_edge_x = (x as f64).min((dimensions.x - x) as f64);
let distance_from_edge_z = (z as f64).min((dimensions.z - z) as f64);
let distance_from_edge = distance_from_edge_x.min(distance_from_edge_z);
let shore_adjustment = if distance_from_edge <= SHORE_AFFECTED_DISTANCE {
(1.0 - distance_from_edge / SHORE_AFFECTED_DISTANCE) * SHORE_FACTOR
} else {
0.0
};

let height = ((height + dimensions.y as f64 / 2.0) * (1.0 - shore_adjustment))
.min(dimensions.y as f64) as u32;

for y in 0..height {
map.set_block(x as i16, y as i16, z as i16, 0x01);
}
}
}

for x in 0..dimensions.x {
for z in 0..dimensions.z {
for y in 0..=water_level {
if map.get_block(x as i16, y as i16, z as i16) == 0x00 {
map.set_block(x as i16, y as i16, z as i16, 0x08);
}
}
}
}

for x in 0..dimensions.x {
for z in 0..dimensions.z {
for y in (0..dimensions.y).rev() {
let block = map.get_block(x as i16, y as i16, z as i16);

if block == 0x01 {
if map.get_block(x as i16, y as i16 + 1, z as i16) == 0x00
|| map.get_block(x as i16, y as i16 + 1, z as i16) == 0x08
{
if y as u32 <= water_level as u32 + 2 {
map.set_block(x as i16, y as i16, z as i16, 0x0c);
} else {
map.set_block(x as i16, y as i16, z as i16, 0x02);
for i in 1..=3 {
map.set_block(x as i16, y as i16 - i, z as i16, 0x03);
}
}
}
}
}
}
}

map
}
}

#[derive(Clone)]
pub struct PresetParams {
pub flat_ground_level: u32,
pub noise_layers: Vec<NoiseLayer>,
pub dimensions: Dimensions,
}

#[derive(Clone)]
pub struct NoiseLayer {
pub scale: f64,
pub weight: f64,
}

#[derive(Clone)]
pub struct Dimensions {
pub x: i16,
pub y: i16,
pub z: i16,
}
Loading

0 comments on commit 131a297

Please sign in to comment.