Pumpkin/crates/pumpkin/src/world/map.rs
2026-08-06 12:56:40 +02:00

133 lines
3.6 KiB
Rust

use crate::entity::player::Player;
use dashmap::DashMap;
use pumpkin_data::dimension::Dimension;
use pumpkin_util::math::{position::BlockPos, vector2::Vector2};
use std::sync::Arc;
use tokio::sync::Mutex;
pub struct MapManager {
pub maps: DashMap<i32, Arc<Mutex<MapData>>>,
}
impl Default for MapManager {
fn default() -> Self {
Self::new()
}
}
impl MapManager {
#[must_use]
pub fn new() -> Self {
Self {
maps: DashMap::new(),
}
}
#[must_use]
pub fn get_map(&self, id: i32) -> Option<Arc<Mutex<MapData>>> {
self.maps.get(&id).map(|m| m.clone())
}
#[must_use]
pub fn create_map(
&self,
id: i32,
dimension: Dimension,
x: i32,
z: i32,
scale: i8,
) -> Arc<Mutex<MapData>> {
let map = Arc::new(Mutex::new(MapData::new(dimension, x, z, scale)));
self.maps.insert(id, map.clone());
map
}
}
pub struct MapData {
pub scale: i8,
pub locked: bool,
pub dimension: Dimension,
pub center_x: i32,
pub center_z: i32,
pub colors: Box<[u8; 128 * 128]>,
pub dirty: bool,
pub fully_updated: bool,
}
impl MapData {
#[must_use]
pub fn new(dimension: Dimension, x: i32, z: i32, scale: i8) -> Self {
Self {
scale,
locked: false,
dimension,
center_x: x,
center_z: z,
colors: Box::new([0; 128 * 128]),
dirty: true,
fully_updated: false,
}
}
pub fn set_color(&mut self, x: usize, z: usize, color: u8) {
if x < 128 && z < 128 {
let idx = z * 128 + x;
if self.colors[idx] != color {
self.colors[idx] = color;
self.dirty = true;
}
}
}
pub fn update(&mut self, player: &Player) {
let world = player.world();
let scale = 1 << self.scale;
let center_x = self.center_x;
let center_z = self.center_z;
let player_pos = player.position();
let player_x = player_pos.x as i32;
let player_z = player_pos.z as i32;
let start_img_x = ((player_x - center_x) / scale + 64).clamp(0, 127) as usize;
let start_img_z = ((player_z - center_z) / scale + 64).clamp(0, 127) as usize;
let radius = 16;
let (range_x, range_z) = if self.fully_updated {
(
(start_img_x.saturating_sub(radius))..(start_img_x + radius).min(128),
(start_img_z.saturating_sub(radius))..(start_img_z + radius).min(128),
)
} else {
self.fully_updated = true;
(0..128, 0..128)
};
for img_x in range_x {
let mut prev_y = -1;
for img_z in range_z.clone() {
let world_x = (img_x as i32 - 64) * scale + center_x;
let world_z = (img_z as i32 - 64) * scale + center_z;
let top_y = world.get_top_block(Vector2::new(world_x, world_z));
let block = world.get_block(&BlockPos::new(world_x, top_y, world_z));
let color_base = block.map_color;
let mut brightness = 2; // Normal
if prev_y != -1 {
if top_y > prev_y {
brightness = 3; // High
} else if top_y < prev_y {
brightness = 1; // Low
}
}
prev_y = top_y;
let color = color_base * 4 + brightness;
self.set_color(img_x, img_z, color);
}
}
}
}