From 98dd54f1f2dbe480bb61261e2868872ae201c77e Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Mon, 17 Apr 2023 19:35:19 +0200 Subject: [PATCH] =?UTF-8?q?l=C3=B6=C3=B6p?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.rs | 341 ++----------------------------- src/bitmanip.rs | 54 +---- src/cmdline.rs | 27 +-- src/debug.rs | 200 ++++++++---------- src/game.rs | 174 +--------------- src/graphics.rs | 30 +-- src/input.rs | 57 +----- src/inventory.rs | 104 +--------- src/math.rs | 76 +------ src/player.rs | 34 +-- src/res.rs | 9 +- src/stringfmt.rs | 16 +- src/texture_atlas.rs | 88 +------- src/tiles/tiledb_edit_ui.rs | 81 +------- src/world.rs | 188 +++-------------- src/world/reg_chunk_existence.rs | 26 +-- src/world/serialization.rs | 79 +------ src/worldgen.rs | 57 +----- 18 files changed, 196 insertions(+), 1445 deletions(-) diff --git a/src/app.rs b/src/app.rs index d5f17dd..896f660 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,5 +1,4 @@ use std::fmt::Write; - use anyhow::Context; use directories::ProjectDirs; use egui_sfml::SfEgui; @@ -7,26 +6,21 @@ use gamedebug_core::{imm, imm_dbg}; use sfml::{ audio::SoundSource, graphics::{ - BlendMode, Color, Rect, RectangleShape, RenderStates, RenderTarget, RenderTexture, - RenderWindow, Shape, Sprite, Transformable, View, + BlendMode, Color, Rect, RectangleShape, RenderStates, RenderTarget, + RenderTexture, RenderWindow, Shape, Sprite, Transformable, View, }, system::{Vector2, Vector2u}, window::{Event, Key}, }; - use crate::{ command::{Cmd, CmdVec}, debug::{self, DebugState}, game::{for_each_tile_on_screen, Biome, GameState}, graphics::{self, ScreenSc, ScreenVec}, - input::Input, - inventory::{ItemId, Slot, TileLayer, UseAction}, + input::Input, inventory::{ItemId, Slot, TileLayer, UseAction}, math::{center_offset, TILE_SIZE}, - res::Res, - tiles::TileId, - CliArgs, + res::Res, tiles::TileId, CliArgs, }; - /// Application level state (includes game and ui state, etc.) pub struct App { pub rw: RenderWindow, @@ -45,39 +39,10 @@ pub struct App { pub project_dirs: ProjectDirs, pub cmdvec: CmdVec, } - impl App { pub fn new(args: CliArgs) -> anyhow::Result { - let rw = graphics::make_window(); - let sf_egui = SfEgui::new(&rw); - let mut res = Res::load()?; - res.surf_music.set_looping(true); - res.surf_music.set_volume(10.0); - res.surf_music.play(); - let rw_size = rw.size(); - let rt = - RenderTexture::new(rw_size.x, rw_size.y).context("Failed to create render texture")?; - let light_map = RenderTexture::new(rw_size.x, rw_size.y) - .context("Failed to create lightmap texture")?; - let project_dirs = ProjectDirs::from("", "", "mantle-diver").unwrap(); - let worlds_dir = project_dirs.data_dir().join("worlds"); - let path = worlds_dir.join(&args.world_name); - Ok(Self { - rw, - should_quit: false, - game: GameState::new(args.world_name, path, &res), - res, - sf_egui, - input: Input::default(), - debug: DebugState::default(), - scale: 1, - rt, - light_map, - project_dirs, - cmdvec: CmdVec::default(), - }) + loop {} } - pub fn do_game_loop(&mut self) { while !self.should_quit { self.do_event_handling(); @@ -89,252 +54,15 @@ impl App { self.game.tile_db.try_save(); self.game.world.save(); } - fn do_event_handling(&mut self) { - while let Some(ev) = self.rw.poll_event() { - self.sf_egui.add_event(&ev); - { - let ctx = self.sf_egui.context(); - self.input.update_from_event( - &ev, - ctx.wants_keyboard_input(), - ctx.wants_pointer_input(), - ); - } - match ev { - Event::Closed => self.should_quit = true, - Event::Resized { width, height } => { - self.rt = - RenderTexture::new(width / self.scale as u32, height / self.scale as u32) - .unwrap(); - self.light_map = - RenderTexture::new(width / self.scale as u32, height / self.scale as u32) - .unwrap(); - let view = View::from_rect(Rect::new(0., 0., width as f32, height as f32)); - self.rw.set_view(&view); - } - Event::KeyPressed { code, .. } => match code { - Key::F11 => { - self.debug.console.show ^= true; - self.debug.console.just_opened = true; - } - Key::F12 => self.debug.panel ^= true, - _ => {} - }, - _ => {} - } - } + loop {} } - fn do_update(&mut self) { - let rt_size = self.rt.size(); - if self.debug.freecam { - self.do_freecam(); - } else { - let spd = if self.input.down(Key::LShift) { - 8.0 - } else if self.input.down(Key::LControl) { - 128.0 - } else { - 3.0 - }; - self.game.world.player.hspeed = 0.; - if self.input.down(Key::A) { - self.game.world.player.hspeed = -spd; - } - if self.input.down(Key::D) { - self.game.world.player.hspeed = spd; - } - if self.input.down(Key::W) && self.game.world.player.can_jump() { - self.game.world.player.vspeed = -10.0; - self.game.world.player.jumps_left = 0; - } - self.game.world.player.down_intent = self.input.down(Key::S); - let terminal_velocity = 60.0; - self.game.world.player.vspeed = self - .game - .world - .player - .vspeed - .clamp(-terminal_velocity, terminal_velocity); - let mut on_screen_tile_ents = Vec::new(); - for_each_tile_on_screen(self.game.camera_offset, self.rt.size(), |tp, _sp| { - let tile = self.game.world.tile_at_mut(tp, &self.game.worldgen).mid; - if tile.empty() { - return; - } - let tdef = &self.game.tile_db[tile]; - let Some(bb) = tdef.layer.bb else { - return; - }; - let x = tp.x as i32 * TILE_SIZE as i32; - let y = tp.y as i32 * TILE_SIZE as i32; - let en = s2dc::Entity::from_rect_corners( - x + bb.x as i32, - y + bb.y as i32, - x + bb.w as i32, - y + bb.h as i32, - ); - on_screen_tile_ents.push(TileColEn { - col: en, - platform: tdef.layer.platform, - }); - }); - imm_dbg!(on_screen_tile_ents.len()); - self.game.world.player.col_en.move_y( - self.game.world.player.vspeed, - |player_en, off| { - let mut col = false; - for en in &on_screen_tile_ents { - if player_en.would_collide(&en.col, off) { - if en.platform { - if self.game.world.player.vspeed < 0. { - continue; - } - // If the player's feet are below the top of the platform, - // collision shouldn't happen - let player_feet = player_en.pos.y + player_en.bb.y; - if player_feet > en.col.pos.y || self.game.world.player.down_intent - { - continue; - } - } - col = true; - if self.game.world.player.vspeed > 0. { - self.game.world.player.jumps_left = 1; - } - self.game.world.player.vspeed = 0.; - } - } - col - }, - ); - self.game.world.player.col_en.move_x( - self.game.world.player.hspeed, - |player_en, off| { - let mut col = false; - for en in &on_screen_tile_ents { - if en.platform { - continue; - } - if player_en.would_collide(&en.col, off) { - col = true; - self.game.world.player.hspeed = 0.; - } - } - col - }, - ); - self.game.world.player.vspeed += self.game.gravity; - let (x, y, _w, _h) = self.game.world.player.col_en.en.xywh(); - self.game.camera_offset.x = (x - rt_size.x as i32 / 2).try_into().unwrap_or(0); - self.game.camera_offset.y = (y - rt_size.y as i32 / 2).try_into().unwrap_or(0); - } - let mut loc = self.input.mouse_down_loc; - let vco = viewport_center_offset(self.rw.size(), rt_size, self.scale); - loc.x -= vco.x; - loc.y -= vco.y; - loc.x /= self.scale as ScreenSc; - loc.y /= self.scale as ScreenSc; - let mut wpos = self.game.camera_offset; - wpos.x = wpos.x.saturating_add_signed(loc.x.into()); - wpos.y = wpos.y.saturating_add_signed(loc.y.into()); - let mouse_tpos = wpos.tile_pos(); - imm!( - "Mouse @ tile {}, {} ({:?})", - mouse_tpos.x, - mouse_tpos.y, - self.game.world.tile_at_mut(mouse_tpos, &self.game.worldgen) - ); - let m_chk = mouse_tpos.to_chunk(); - imm!("@ chunk {}, {}", m_chk.x, m_chk.y); - let (m_chk_x, m_chk_y) = m_chk.region(); - imm!("@ region {m_chk_x}, {m_chk_y}"); - if self.debug.freecam && self.input.pressed(Key::P) { - self.game.world.player.col_en.en.pos.x = wpos.x as i32; - self.game.world.player.col_en.en.pos.y = wpos.y as i32; - } - 'item_use: { - if !self.input.lmb_down { - break 'item_use; - } - let Some(active_slot) = self.game.inventory.slots.get(self.game.selected_inv_slot) else { - log::error!("Selected slot {} out of bounds", self.game.selected_inv_slot); - break 'item_use; - }; - if active_slot.qty == 0 { - break 'item_use; - } - let def = &self.game.itemdb.db[active_slot.id as usize]; - let t = self.game.world.tile_at_mut(mouse_tpos, &self.game.worldgen); - match &def.use_action { - UseAction::PlaceBgTile { id } => { - if t.bg.empty() { - t.bg = *id - } - } - UseAction::PlaceMidTile { id } => { - if t.mid.empty() { - t.mid = *id - } - } - UseAction::PlaceFgTile { id } => { - if t.fg.empty() { - t.fg = *id - } - } - UseAction::RemoveTile { layer } => match layer { - TileLayer::Bg => t.bg = TileId::EMPTY, - TileLayer::Mid => t.mid = TileId::EMPTY, - TileLayer::Fg => t.fg = TileId::EMPTY, - }, - } - } - if self.game.camera_offset.y > 643_000 { - self.game.current_biome = Biome::Underground; - } else { - self.game.current_biome = Biome::Surface; - } - if self.game.current_biome != self.game.prev_biome { - self.game.prev_biome = self.game.current_biome; - match self.game.current_biome { - Biome::Surface => { - self.res.und_music.stop(); - self.res.surf_music.play(); - } - Biome::Underground => { - self.res.surf_music.stop(); - self.res.und_music.set_volume(self.res.surf_music.volume()); - self.res.und_music.set_looping(true); - self.res.und_music.play(); - } - } - } - self.game.update(&self.input); + loop {} } - fn do_freecam(&mut self) { - let spd = if self.input.down(Key::LShift) { - 100 - } else if self.input.down(Key::LControl) { - 1000 - } else { - 2 - }; - if self.input.down(Key::A) { - self.game.camera_offset.x = self.game.camera_offset.x.saturating_sub(spd); - } - if self.input.down(Key::D) { - self.game.camera_offset.x = self.game.camera_offset.x.saturating_add(spd); - } - if self.input.down(Key::W) { - self.game.camera_offset.y = self.game.camera_offset.y.saturating_sub(spd); - } - if self.input.down(Key::S) { - self.game.camera_offset.y = self.game.camera_offset.y.saturating_add(spd); - } + loop {} } - fn do_rendering(&mut self) { self.game.light_pass(&mut self.light_map, &self.res); self.rt.clear(Color::rgb(55, 221, 231)); @@ -347,14 +75,12 @@ impl App { spr.set_position((vco.x as f32, vco.y as f32)); self.rw.clear(Color::rgb(40, 10, 70)); self.rw.draw(&spr); - // Draw light overlay with multiply blending let mut rst = RenderStates::default(); rst.blend_mode = BlendMode::MULTIPLY; self.light_map.display(); spr.set_texture(self.light_map.texture(), false); self.rw.draw_with_renderstates(&spr, &rst); drop(spr); - // Draw ui on top of in-game scene self.rt.clear(Color::TRANSPARENT); let ui_dims = Vector2 { x: (self.rw.size().x / self.scale as u32) as f32, @@ -380,7 +106,9 @@ impl App { if self.debug.show_atlas { let atlas = &self.res.atlas.tex; let size = atlas.size(); - let mut rs = RectangleShape::from_rect(Rect::new(0., 0., size.x as f32, size.y as f32)); + let mut rs = RectangleShape::from_rect( + Rect::new(0., 0., size.x as f32, size.y as f32), + ); rs.set_fill_color(Color::MAGENTA); self.rw.draw(&rs); self.rw.draw(&Sprite::with_texture(atlas)); @@ -390,58 +118,15 @@ impl App { drop(spr); self.execute_commands(); } - fn execute_commands(&mut self) { - for cmd in self.cmdvec.drain(..) { - match cmd { - Cmd::QuitApp => self.should_quit = true, - Cmd::ToggleFreecam => self.debug.freecam ^= true, - Cmd::TeleportPlayer { pos, relative } => { - if relative { - let s2dc = pos.to_s2dc(); - self.game.world.player.col_en.en.pos.x += s2dc.x; - self.game.world.player.col_en.en.pos.y += s2dc.y; - } else { - self.game.world.player.col_en.en.pos = pos.to_s2dc() - } - } - Cmd::TeleportPlayerSpawn => { - self.game.world.player.col_en.en.pos = self.game.spawn_point.to_s2dc() - } - Cmd::GiveItemByName(name) => { - for (i, item) in self.game.itemdb.db.iter().enumerate() { - if item.name == name { - self.game.inventory.slots.push(Slot { - id: i as ItemId, - qty: 1, - }); - return; - } - } - writeln!( - &mut self.debug.console.log, - "Item with name '{name}' not found" - ) - .unwrap(); - } - } - } + loop {} } } - /// Tile collision entity for doing physics struct TileColEn { col: s2dc::Entity, platform: bool, } - fn viewport_center_offset(rw_size: Vector2u, rt_size: Vector2u, scale: u8) -> ScreenVec { - let rw_size = rw_size; - let rt_size = rt_size * scale as u32; - let x = center_offset(rt_size.x as i32, rw_size.x as i32); - let y = center_offset(rt_size.y as i32, rw_size.y as i32); - ScreenVec { - x: x as ScreenSc, - y: y as ScreenSc, - } + loop {} } diff --git a/src/bitmanip.rs b/src/bitmanip.rs index f36e80b..49e7098 100644 --- a/src/bitmanip.rs +++ b/src/bitmanip.rs @@ -1,58 +1,22 @@ use std::ops::{BitAndAssign, BitOrAssign}; - use num_traits::PrimInt; - pub fn nth_bit_set(number: N, n: usize) -> bool { - (number & (N::one() << n)) != N::zero() + loop {} } - -pub fn set_nth_bit(number: &mut N, n: usize, set: bool) { - let mask = N::one() << n; - if set { - *number |= mask; - } else { - *number &= !mask; - } +pub fn set_nth_bit( + number: &mut N, + n: usize, + set: bool, +) { + loop {} } - #[test] #[allow(clippy::bool_assert_comparison)] fn test_nth_bit_set() { - let number: u8 = 0b0100_0100; - assert_eq!(nth_bit_set(number, 0), false); - assert_eq!(nth_bit_set(number, 1), false); - assert_eq!(nth_bit_set(number, 2), true); - assert_eq!(nth_bit_set(number, 3), false); - assert_eq!(nth_bit_set(number, 4), false); - assert_eq!(nth_bit_set(number, 5), false); - assert_eq!(nth_bit_set(number, 6), true); - assert_eq!(nth_bit_set(number, 7), false); - assert_eq!(nth_bit_set(0u64, 0), false); - assert_eq!(nth_bit_set(u64::MAX, 63), true); + loop {} } - #[test] #[allow(clippy::bool_assert_comparison)] fn test_set_nth_bit() { - let mut number: u8 = 0b0000_0000; - set_nth_bit(&mut number, 0, true); - assert_eq!(number, 0b0000_0001); - set_nth_bit(&mut number, 1, true); - assert_eq!(number, 0b0000_0011); - set_nth_bit(&mut number, 2, true); - assert_eq!(number, 0b0000_0111); - set_nth_bit(&mut number, 0, false); - assert_eq!(number, 0b0000_0110); - - let mut all_bits_set: u64 = 0; - for i in 0..64 { - set_nth_bit(&mut all_bits_set, i, true); - assert_eq!(nth_bit_set(all_bits_set, i), true); - } - - let mut no_bits_set: u64 = u64::MAX; - for i in 0..64 { - set_nth_bit(&mut no_bits_set, i, false); - assert_eq!(nth_bit_set(no_bits_set, i), false); - } + loop {} } diff --git a/src/cmdline.rs b/src/cmdline.rs index 6661e76..08c9c7b 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -1,7 +1,5 @@ use clap::Parser; - use crate::{command::Cmd, math::WorldPos}; - #[derive(Parser)] pub enum CmdLine { Quit, @@ -11,7 +9,6 @@ pub enum CmdLine { Spawn, Give(Give), } - #[derive(Parser)] pub struct Tp { x: u32, @@ -22,40 +19,22 @@ pub struct Tp { } impl Tp { fn to_world_pos(&self) -> WorldPos { - WorldPos { - x: self.x, - y: self.y, - } + loop {} } } - #[derive(Parser)] pub struct Give { name: String, } - pub enum Dispatch { Cmd(Cmd), ClearConsole, } - impl CmdLine { pub fn parse_cmdline(cmdline: &str) -> anyhow::Result { - let words = std::iter::once(" ").chain(cmdline.split_whitespace()); - Ok(Self::try_parse_from(words)?) + loop {} } - pub(crate) fn dispatch(self) -> Dispatch { - match self { - CmdLine::Quit => Dispatch::Cmd(Cmd::QuitApp), - CmdLine::Freecam => Dispatch::Cmd(Cmd::ToggleFreecam), - CmdLine::Clear => Dispatch::ClearConsole, - CmdLine::Tp(tp) => Dispatch::Cmd(Cmd::TeleportPlayer { - pos: tp.to_world_pos(), - relative: tp.rel, - }), - CmdLine::Spawn => Dispatch::Cmd(Cmd::TeleportPlayerSpawn), - CmdLine::Give(give) => Dispatch::Cmd(Cmd::GiveItemByName(give.name)), - } + loop {} } } diff --git a/src/debug.rs b/src/debug.rs index 0ce352f..3cc5023 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,20 +1,13 @@ use std::fmt::Write; - use egui::TextBuffer; use egui_inspect::{derive::Inspect, inspect}; use sfml::audio::SoundSource; - use crate::{ - cmdline::CmdLine, - command::CmdVec, - game::GameState, + cmdline::CmdLine, command::CmdVec, game::GameState, math::{px_per_frame_to_km_h, WorldPos}, - res::Res, - stringfmt::LengthDisp, - texture_atlas::AtlasBundle, + res::Res, stringfmt::LengthDisp, texture_atlas::AtlasBundle, tiles::tiledb_edit_ui::TileDbEdit, }; - #[derive(Default, Debug, Inspect)] pub struct DebugState { pub panel: bool, @@ -23,7 +16,6 @@ pub struct DebugState { pub show_atlas: bool, pub console: Console, } - #[derive(Default, Debug, Inspect)] pub struct Console { pub show: bool, @@ -32,7 +24,6 @@ pub struct Console { pub just_opened: bool, pub history: Vec, } - fn debug_panel_ui( mut debug: &mut DebugState, mut game: &mut GameState, @@ -40,75 +31,92 @@ fn debug_panel_ui( res: &mut Res, mut scale: &mut u8, ) { - egui::Window::new("Debug (F12)").show(ctx, |ui| { - if debug.freecam { - ui.label("Cam x"); - ui.add(egui::DragValue::new(&mut game.camera_offset.x)); - ui.label("Cam y"); - ui.add(egui::DragValue::new(&mut game.camera_offset.y)); - let co = game.camera_offset; - ui.label(format!( - "Cam Depth: {}", - LengthDisp(co.y as f32 - WorldPos::SURFACE as f32) - )); - ui.label(format!( - "Cam offset from center: {}", - LengthDisp(co.x as f32 - WorldPos::CENTER as f32) - )); - } else { - ui.label(format!( - "Player Depth: {}", - LengthDisp(game.world.player.feet_y() as f32 - WorldPos::SURFACE as f32) - )); - ui.label(format!( - "Player offset from center: {}", - LengthDisp(game.world.player.col_en.en.pos.x as f32 - WorldPos::CENTER as f32) - )); - ui.label(format!( - "Hspeed: {} ({} km/h)", - game.world.player.hspeed, - px_per_frame_to_km_h(game.world.player.hspeed) - )); - ui.label(format!( - "Vspeed: {} ({} km/h)", - game.world.player.vspeed, - px_per_frame_to_km_h(game.world.player.vspeed) - )); - } - ui.label("Music volume"); - let mut vol = res.surf_music.volume(); - ui.add(egui::DragValue::new(&mut vol)); - res.surf_music.set_volume(vol); - ui.separator(); - egui::ScrollArea::both() - .id_source("insp_scroll") - .max_height(240.) - .max_width(340.0) - .show(ui, |ui| { - inspect! { - ui, - scale, - game, - debug + egui::Window::new("Debug (F12)") + .show( + ctx, + |ui| { + if debug.freecam { + ui.label("Cam x"); + ui.add(egui::DragValue::new(&mut game.camera_offset.x)); + ui.label("Cam y"); + ui.add(egui::DragValue::new(&mut game.camera_offset.y)); + let co = game.camera_offset; + ui.label( + format!( + "Cam Depth: {}", LengthDisp(co.y as f32 - WorldPos::SURFACE + as f32) + ), + ); + ui.label( + format!( + "Cam offset from center: {}", LengthDisp(co.x as f32 - + WorldPos::CENTER as f32) + ), + ); + } else { + ui.label( + format!( + "Player Depth: {}", LengthDisp(game.world.player.feet_y() as + f32 - WorldPos::SURFACE as f32) + ), + ); + ui.label( + format!( + "Player offset from center: {}", LengthDisp(game.world.player + .col_en.en.pos.x as f32 - WorldPos::CENTER as f32) + ), + ); + ui.label( + format!( + "Hspeed: {} ({} km/h)", game.world.player.hspeed, + px_per_frame_to_km_h(game.world.player.hspeed) + ), + ); + ui.label( + format!( + "Vspeed: {} ({} km/h)", game.world.player.vspeed, + px_per_frame_to_km_h(game.world.player.vspeed) + ), + ); } - }); - if ui.button("Reload graphics").clicked() { - res.atlas = AtlasBundle::new().unwrap(); - game.tile_db.update_rects(&res.atlas.rects); - } - ui.separator(); - egui::ScrollArea::vertical().show(ui, |ui| { - gamedebug_core::for_each_imm(|info| match info { - gamedebug_core::Info::Msg(msg) => { - ui.label(msg); + ui.label("Music volume"); + let mut vol = res.surf_music.volume(); + ui.add(egui::DragValue::new(&mut vol)); + res.surf_music.set_volume(vol); + ui.separator(); + egui::ScrollArea::both() + .id_source("insp_scroll") + .max_height(240.) + .max_width(340.0) + .show( + ui, + |ui| { + inspect! { + ui, scale, game, debug + } + }, + ); + if ui.button("Reload graphics").clicked() { + res.atlas = AtlasBundle::new().unwrap(); + game.tile_db.update_rects(&res.atlas.rects); } - gamedebug_core::Info::Rect(_, _, _, _, _) => todo!(), - }); - }); - gamedebug_core::clear_immediates(); - }); + ui.separator(); + egui::ScrollArea::vertical() + .show( + ui, + |ui| { + gamedebug_core::for_each_imm(|info| match info { + gamedebug_core::Info::Msg(msg) => { + ui.label(msg); + } + gamedebug_core::Info::Rect(_, _, _, _, _) => todo!(), + }); + }, + ); + gamedebug_core::clear_immediates(); + }, + ); } - pub(crate) fn do_debug_ui( ctx: &egui::Context, debug: &mut DebugState, @@ -125,42 +133,6 @@ pub(crate) fn do_debug_ui( console_ui(ctx, debug, cmd); } } - fn console_ui(ctx: &egui::Context, debug: &mut DebugState, cmd: &mut CmdVec) { - egui::Window::new("Console (F11)").show(ctx, |ui| { - let up_arrow = - ui.input_mut(|inp| inp.consume_key(egui::Modifiers::default(), egui::Key::ArrowUp)); - let re = - ui.add(egui::TextEdit::singleline(&mut debug.console.cmdline).hint_text("Command")); - if debug.console.just_opened { - re.request_focus(); - } - if re.lost_focus() && ui.input(|inp| inp.key_pressed(egui::Key::Enter)) { - re.request_focus(); - let cmdline = match CmdLine::parse_cmdline(&debug.console.cmdline) { - Ok(cmd) => cmd, - Err(e) => { - writeln!(&mut debug.console.log, "{e}").unwrap(); - debug.console.history.push(debug.console.cmdline.take()); - return; - } - }; - debug.console.history.push(debug.console.cmdline.take()); - match cmdline.dispatch() { - crate::cmdline::Dispatch::Cmd(command) => cmd.push(command), - crate::cmdline::Dispatch::ClearConsole => debug.console.log.clear(), - } - } - if up_arrow { - if let Some(line) = debug.console.history.pop() { - debug.console.cmdline = line; - } - } - egui::ScrollArea::vertical() - .stick_to_bottom(true) - .show(ui, |ui| { - ui.add(egui::TextEdit::multiline(&mut &debug.console.log[..])); - }); - }); - debug.console.just_opened = false; + loop {} } diff --git a/src/game.rs b/src/game.rs index 756dc40..16a145f 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,26 +1,21 @@ use std::path::PathBuf; - use derivative::Derivative; use egui_inspect::derive::Inspect; use sfml::{ graphics::{ - Color, Rect, RectangleShape, RenderTarget, RenderTexture, Shape, Sprite, Transformable, + Color, Rect, RectangleShape, RenderTarget, RenderTexture, Shape, Sprite, + Transformable, }, system::{Vector2f, Vector2u}, window::Key, }; - use crate::{ graphics::{ScreenSc, ScreenVec}, - input::Input, - inventory::{Inventory, ItemDb}, + input::Input, inventory::{Inventory, ItemDb}, math::{smoothwave, wp_to_tp, WorldPos}, - res::Res, - tiles::TileDb, - world::{TilePos, World}, + res::Res, tiles::TileDb, world::{TilePos, World}, worldgen::Worldgen, }; - #[derive(Derivative, Inspect)] #[derivative(Debug)] pub struct GameState { @@ -40,186 +35,39 @@ pub struct GameState { pub selected_inv_slot: usize, pub spawn_point: WorldPos, } - #[derive(Debug, Inspect)] pub struct LightSource { pub pos: ScreenVec, } - #[derive(PartialEq, Eq, Clone, Copy, Debug, Inspect)] pub enum Biome { Surface, Underground, } - impl GameState { pub fn update(&mut self, input: &Input) { - if input.pressed(Key::Num1) { - self.selected_inv_slot = 0; - } - if input.pressed(Key::Num2) { - self.selected_inv_slot = 1; - } - if input.pressed(Key::Num3) { - self.selected_inv_slot = 2; - } - if input.pressed(Key::Num4) { - self.selected_inv_slot = 3; - } - if input.pressed(Key::Num5) { - self.selected_inv_slot = 4; - } - if input.pressed(Key::Num6) { - self.selected_inv_slot = 5; - } - if input.pressed(Key::Num7) { - self.selected_inv_slot = 6; - } - if input.pressed(Key::Num8) { - self.selected_inv_slot = 7; - } - if input.pressed(Key::Num9) { - self.selected_inv_slot = 8; - } - if input.pressed(Key::Num0) { - self.selected_inv_slot = 9; - } - self.world.ticks += 1; + loop {} } pub(crate) fn draw_world(&mut self, rt: &mut RenderTexture, res: &mut Res) { - self.light_sources.clear(); - let mut s = Sprite::with_texture(&res.atlas.tex); - for_each_tile_on_screen(self.camera_offset, rt.size(), |tp, sp| { - let tile = self.world.tile_at_mut(tp, &self.worldgen); - s.set_position(sp.to_sf_vec()); - if !tile.bg.empty() { - s.set_texture_rect(self.tile_db[tile.bg].tex_rect.to_sf()); - rt.draw(&s); - } - if !tile.mid.empty() { - s.set_texture_rect(self.tile_db[tile.mid].tex_rect.to_sf()); - if let Some(light) = self.tile_db[tile.mid].light { - let pos = ScreenVec { - x: sp.x + light.x, - y: sp.y + light.y, - }; - self.light_sources.push(LightSource { pos }); - } - rt.draw(&s); - } - if !tile.fg.empty() { - s.set_texture_rect(self.tile_db[tile.fg].tex_rect.to_sf()); - rt.draw(&s); - } - }); + loop {} } pub fn draw_entities(&mut self, rt: &mut RenderTexture) { - let (x, y, w, h) = self.world.player.col_en.en.xywh(); - let mut rect_sh = RectangleShape::new(); - rect_sh.set_position(( - (x - self.camera_offset.x as i32) as f32, - (y - self.camera_offset.y as i32) as f32, - )); - rect_sh.set_size((w as f32, h as f32)); - rt.draw(&rect_sh); - rect_sh.set_size((2., 2.)); - rect_sh.set_fill_color(Color::RED); - rect_sh.set_position(( - (self.world.player.col_en.en.pos.x - self.camera_offset.x as i32) as f32, - (self.world.player.col_en.en.pos.y - self.camera_offset.y as i32) as f32, - )); - rt.draw(&rect_sh); + loop {} } - pub fn draw_ui(&mut self, rt: &mut RenderTexture, res: &Res, ui_dims: Vector2f) { - let mut s = Sprite::with_texture(&res.atlas.tex); - let mut rs = RectangleShape::from_rect(Rect::new(0., 0., 32., 32.)); - rs.set_outline_color(Color::YELLOW); - rs.set_outline_thickness(1.0); - rs.set_fill_color(Color::TRANSPARENT); - for (i, slot) in self.inventory.slots.iter().enumerate() { - s.set_texture_rect(res.atlas.rects["ui/invframe"].to_sf()); - let pos = ((i * 38) as f32 + 8.0, (ui_dims.y - 38.)); - s.set_position(pos); - rt.draw(&s); - let item_def = &self.itemdb.db[slot.id as usize]; - if let Some(rect) = res.atlas.rects.get(&item_def.graphic_name) { - s.set_texture_rect(rect.to_sf()); - rt.draw(&s); - } else { - log::error!("Missing rect for item {}", item_def.name); - } - if i == self.selected_inv_slot { - rs.set_position(pos); - rt.draw(&rs); - } - } + loop {} } - pub(crate) fn light_pass(&mut self, lightmap: &mut RenderTexture, res: &Res) { - let how_much_below_surface = self.camera_offset.y.saturating_sub(WorldPos::SURFACE); - let light_dropoff = (how_much_below_surface / 8).min(255) as u8; - let daylight = 255u8; - self.ambient_light = daylight.saturating_sub(light_dropoff); - // Clear light map - // You can clear to a brighter color to increase ambient light level - lightmap.clear(Color::rgba( - self.ambient_light, - self.ambient_light, - self.ambient_light, - 255, - )); - let mut s = Sprite::with_texture(&res.atlas.tex); - s.set_texture_rect(res.atlas.rects["light/1"].to_sf()); - for ls in &self.light_sources { - let flicker = smoothwave(self.world.ticks, 40) as f32 / 64.0; - s.set_scale((4. + flicker, 4. + flicker)); - s.set_origin((128., 128.)); - s.set_position((ls.pos.x.into(), ls.pos.y.into())); - lightmap.draw(&s); - } + loop {} } - pub(crate) fn new(world_name: String, path: PathBuf, res: &Res) -> GameState { - let mut spawn_point = WorldPos::SURFACE_CENTER; - spawn_point.y -= 1104; - let mut tile_db = TileDb::load_or_default(); - tile_db.update_rects(&res.atlas.rects); - Self { - camera_offset: spawn_point, - world: World::new(spawn_point, &world_name, path), - gravity: 0.55, - current_biome: Biome::Surface, - prev_biome: Biome::Surface, - worldgen: Worldgen::from_seed(0), - ambient_light: 0, - light_sources: Vec::new(), - tile_db, - inventory: Inventory::new_debug(), - itemdb: ItemDb::default(), - selected_inv_slot: 0, - spawn_point, - } + loop {} } } - pub fn for_each_tile_on_screen( camera_offset: WorldPos, rt_size: Vector2u, mut f: impl FnMut(TilePos, ScreenVec), ) { - for y in (-32..(rt_size.y as i16) + 32).step_by(32) { - for x in (-32..(rt_size.x as i16) + 32).step_by(32) { - f( - TilePos { - x: wp_to_tp(camera_offset.x.saturating_add(x.try_into().unwrap_or(0))), - y: wp_to_tp(camera_offset.y.saturating_add(y.try_into().unwrap_or(0))), - }, - ScreenVec { - x: ((x as i64) - ((camera_offset.x as i64) % 32)) as ScreenSc, - y: ((y as i64) - ((camera_offset.y as i64) % 32)) as ScreenSc, - }, - ) - } - } + loop {} } diff --git a/src/graphics.rs b/src/graphics.rs index 331b962..da4c300 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -1,55 +1,33 @@ use egui_inspect::derive::Inspect; use serde::{Deserialize, Serialize}; use sfml::{ - graphics::RenderWindow, - system::Vector2f, - window::{ContextSettings, Style, VideoMode}, + graphics::RenderWindow, system::Vector2f, window::{ContextSettings, Style, VideoMode}, }; use sfml_xt::graphics::RenderWindowExt; - use crate::math::FPS_TARGET; - pub struct ScreenRes { pub w: u16, pub h: u16, } - impl ScreenRes { fn to_sf(&self) -> VideoMode { - VideoMode { - width: self.w as _, - height: self.h as _, - bits_per_pixel: 32, - } + loop {} } } - #[derive(Default, Clone, Copy, Debug, Inspect, Serialize, Deserialize)] pub struct ScreenVec { pub x: ScreenSc, pub y: ScreenSc, } - /// Screen position/offset scalar /// We assume this game won't be played above 32767*32767 resolution pub type ScreenSc = i16; - impl ScreenVec { pub fn to_sf_vec(self) -> Vector2f { - Vector2f::new(self.x.into(), self.y.into()) + loop {} } } - const DEFAULT_RES: ScreenRes = ScreenRes { w: 960, h: 540 }; - pub fn make_window() -> RenderWindow { - let mut rw = RenderWindow::new( - DEFAULT_RES.to_sf(), - "Mantle Diver", - Style::DEFAULT, - &ContextSettings::default(), - ); - rw.set_framerate_limit(FPS_TARGET.into()); - rw.center(); - rw + loop {} } diff --git a/src/input.rs b/src/input.rs index c2bf7c1..14856a0 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,8 +1,6 @@ use fnv::FnvHashSet; use sfml::window::{mouse, Event, Key}; - use crate::graphics::ScreenVec; - #[derive(Default, Debug)] pub struct Input { down: FnvHashSet, @@ -12,65 +10,18 @@ pub struct Input { pub mouse_down_loc: ScreenVec, pub mid_pressed: bool, } - impl Input { pub fn update_from_event(&mut self, ev: &Event, egui_kbd: bool, egui_ptr: bool) { - match ev { - &Event::KeyPressed { code, .. } => { - self.pressed.insert(code); - self.down.insert(code); - } - Event::KeyReleased { code, .. } => { - self.down.remove(code); - } - &Event::MouseButtonPressed { button, x, y } => { - self.mouse_down_loc = ScreenVec { - x: x as i16, - y: y as i16, - }; - if button == mouse::Button::Left { - self.lmb_down = true; - } - if button == mouse::Button::Right { - self.rmb_down = true; - } - if button == mouse::Button::Middle { - self.mid_pressed = true; - } - } - &Event::MouseButtonReleased { button, .. } => { - if button == mouse::Button::Left { - self.lmb_down = false; - } - if button == mouse::Button::Right { - self.rmb_down = false; - } - } - &Event::MouseMoved { x, y } => { - self.mouse_down_loc.x = x as i16; - self.mouse_down_loc.y = y as i16; - } - _ => {} - } - if egui_kbd { - self.pressed.clear(); - self.down.clear(); - } - if egui_ptr { - self.lmb_down = false; - self.rmb_down = false; - self.mid_pressed = false; - } + loop {} } /// Pressed event should be cleared every frame pub fn clear_pressed(&mut self) { - self.mid_pressed = false; - self.pressed.clear(); + loop {} } pub fn down(&self, key: Key) -> bool { - self.down.contains(&key) + loop {} } pub fn pressed(&self, key: Key) -> bool { - self.pressed.contains(&key) + loop {} } } diff --git a/src/inventory.rs b/src/inventory.rs index 00cd56b..c62cf5b 100644 --- a/src/inventory.rs +++ b/src/inventory.rs @@ -1,22 +1,15 @@ use egui_inspect::derive::Inspect; - -use crate::{ - math::IntRect, - tiles::{BgTileId, FgTileId, MidTileId}, -}; - +use crate::{math::IntRect, tiles::{BgTileId, FgTileId, MidTileId}}; /// We won't have more than 65535 different items pub type ItemId = u16; /// We won't have more than 65535 item quantity in a single slot pub type ItemQty = u16; - /// Inventory slot #[derive(Debug, Inspect)] pub struct Slot { pub id: ItemId, pub qty: ItemQty, } - #[derive(Debug, Inspect)] pub struct Inventory { pub slots: Vec, @@ -24,37 +17,9 @@ pub struct Inventory { impl Inventory { /// A new inventory filled with some debug items pub(crate) fn new_debug() -> Inventory { - Self { - slots: vec![ - Slot { - id: items::WOOD_PICK, - qty: 1, - }, - Slot { - id: items::DIRT_BLOCK, - qty: 100, - }, - Slot { - id: items::TORCH, - qty: 100, - }, - Slot { - id: items::PLATFORM, - qty: 100, - }, - Slot { - id: items::STONE_WALL, - qty: 100, - }, - Slot { - id: items::PANZERIUM, - qty: 100, - }, - ], - } + loop {} } } - #[derive(Debug, Inspect)] pub struct ItemDef { pub name: String, @@ -64,14 +29,12 @@ pub struct ItemDef { pub use_action: UseAction, pub consumable: bool, } - #[derive(Debug, Inspect, PartialEq)] pub enum TileLayer { Bg, Mid, Fg, } - #[derive(Debug)] pub enum UseAction { PlaceBgTile { id: BgTileId }, @@ -79,78 +42,17 @@ pub enum UseAction { PlaceFgTile { id: FgTileId }, RemoveTile { layer: TileLayer }, } - #[derive(Debug, Inspect)] pub struct ItemDb { pub db: Vec, } - impl Default for ItemDb { fn default() -> Self { - Self { - db: vec![ - ItemDef { - name: String::from("Dirt Block"), - graphic_name: String::from("tiles/dirt"), - tex_rect: IntRect::default(), - use_action: UseAction::PlaceMidTile { - id: MidTileId::DIRT, - }, - consumable: true, - }, - ItemDef { - name: String::from("Torch"), - graphic_name: String::from("tiles/torch"), - tex_rect: IntRect::default(), - use_action: UseAction::PlaceMidTile { - id: MidTileId::TORCH, - }, - consumable: true, - }, - ItemDef { - name: String::from("Platform"), - graphic_name: String::from("tiles/platform"), - tex_rect: IntRect::default(), - use_action: UseAction::PlaceMidTile { - id: MidTileId::PLATFORM, - }, - consumable: true, - }, - ItemDef { - name: String::from("Wood Pick"), - graphic_name: String::from("items/woodpick"), - tex_rect: IntRect::default(), - use_action: UseAction::RemoveTile { - layer: TileLayer::Mid, - }, - consumable: true, - }, - ItemDef { - name: String::from("Panzerium"), - graphic_name: String::from("tiles/panzerium"), - tex_rect: IntRect::default(), - use_action: UseAction::PlaceMidTile { - id: MidTileId::PANZERIUM, - }, - consumable: true, - }, - ItemDef { - name: String::from("Stone wall"), - graphic_name: String::from("tiles/stoneback"), - tex_rect: IntRect::default(), - use_action: UseAction::PlaceBgTile { - id: BgTileId::STONE, - }, - consumable: true, - }, - ], - } + loop {} } } - pub mod items { use super::ItemId; - pub const DIRT_BLOCK: ItemId = 0; pub const TORCH: ItemId = 1; pub const PLATFORM: ItemId = 2; diff --git a/src/math.rs b/src/math.rs index 2f9edd4..68e4f05 100644 --- a/src/math.rs +++ b/src/math.rs @@ -1,19 +1,14 @@ use std::fmt::Debug; - use egui_inspect::derive::Inspect; use num_traits::{Num, Signed}; use serde::{Deserialize, Serialize}; - use crate::world::{TPosSc, TilePos}; - pub type WPosSc = u32; - #[derive(Clone, Copy, Debug, Inspect)] pub struct WorldPos { pub x: WPosSc, pub y: WPosSc, } - /// Tile size in pixels pub const TILE_SIZE: u8 = 32; /// Pixels per meter. @@ -21,25 +16,17 @@ pub const PX_PER_M: f32 = TILE_SIZE as f32 * 2.; /// Meters per pixel pub const M_PER_PX: f32 = 1. / PX_PER_M; pub const FPS_TARGET: u8 = 60; - pub fn px_per_frame_to_m_per_s(px_per_frame: f32) -> f32 { - let m_per_frame = px_per_frame / PX_PER_M; - m_per_frame * FPS_TARGET as f32 + loop {} } - pub fn px_per_frame_to_km_h(px_per_frame: f32) -> f32 { - px_per_frame_to_m_per_s(px_per_frame) * 3.6 + loop {} } - /// World extent in tiles. Roughly 50km*50km. pub const WORLD_EXTENT: TPosSc = 100_000; - impl WorldPos { pub fn tile_pos(&self) -> TilePos { - TilePos { - x: wp_to_tp(self.x), - y: wp_to_tp(self.y), - } + loop {} } /// Horizontal center of the world pub const CENTER: WPosSc = (WORLD_EXTENT / 2) * TILE_SIZE as WPosSc; @@ -50,47 +37,20 @@ impl WorldPos { x: Self::CENTER, y: Self::SURFACE, }; - pub(crate) fn to_s2dc(self) -> s2dc::Vec2 { - s2dc::Vec2 { - x: self.x as i32, - y: self.y as i32, - } + loop {} } } - pub fn wp_to_tp(wp: WPosSc) -> TPosSc { - (wp / TILE_SIZE as WPosSc) as TPosSc + loop {} } - -// Get the offset required to center an object of `xw` width inside an object of `yw` width. -// -// For example, let's say `xw` (+) is 10 and we want to center it inside `yw` (-), which is 20 -// -// ++++++++++ (x uncentered) -// -------------------- (y) -// ++++++++++ (x centered) -// -// In this case, we needed to add 5 to x to achieve centering. -// This is the offset that this function calculates. -// -// We can calulate it by subtracting `xw` from `yw` (10), and dividing it by 2. pub fn center_offset + Copy + Signed>(xw: N, yw: N) -> N { - let diff = yw - xw; - diff / N::from(2) + loop {} } - /// A smooth triangle-wave like transform of the input value, oscillating between 0 and the ceiling. pub fn smoothwave + PartialOrd + Copy>(input: T, max: T) -> T { - let period = max * T::from(2); - let value = input % period; - if value < max { - value - } else { - period - value - } + loop {} } - #[derive(Serialize, Deserialize, Debug, Inspect, Default, Clone, Copy)] pub struct IntRect { pub x: i32, @@ -100,30 +60,14 @@ pub struct IntRect { } impl IntRect { pub(crate) fn to_sf(self) -> sfml::graphics::Rect { - sfml::graphics::Rect:: { - left: self.x, - top: self.y, - width: self.w, - height: self.h, - } + loop {} } } - #[test] fn test_smooth_wave() { - assert_eq!(smoothwave(0, 100), 0); - assert_eq!(smoothwave(50, 100), 50); - assert_eq!(smoothwave(125, 100), 75); - assert_eq!(smoothwave(150, 100), 50); - assert_eq!(smoothwave(175, 100), 25); - assert_eq!(smoothwave(199, 100), 1); - assert_eq!(smoothwave(200, 100), 0); - assert_eq!(smoothwave(201, 100), 1); + loop {} } - #[test] fn test_wp_to_tp() { - assert_eq!(wp_to_tp(0), 0); - assert_eq!(wp_to_tp(1), 0); - assert_eq!(wp_to_tp(33), 1); + loop {} } diff --git a/src/player.rs b/src/player.rs index 8d8fca1..3d6ccf0 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,14 +1,11 @@ use std::path::Path; - use egui_inspect::{derive::Inspect, inspect}; use s2dc::{vec2, MobileEntity}; use serde::{Deserialize, Serialize}; - use crate::{ math::{WorldPos, TILE_SIZE}, world::{TPosSc, TilePos}, }; - #[derive(Debug, Inspect, Serialize, Deserialize)] pub struct Player { #[inspect_with(inspect_mobile_entity)] @@ -19,43 +16,24 @@ pub struct Player { /// true if the player wants to jump down from a platform pub down_intent: bool, } - fn inspect_mobile_entity(en: &mut MobileEntity, ui: &mut egui::Ui, _id_src: u64) { - inspect! { - ui, - en.en.pos.x, - en.en.pos.y, - en.en.bb.x, - en.en.bb.y - } + loop {} } - impl Player { pub fn new_at(pos: WorldPos) -> Self { - Self { - col_en: MobileEntity::from_pos_and_bb(vec2(pos.x as i32, pos.y as i32), vec2(20, 46)), - vspeed: 0.0, - hspeed: 0.0, - jumps_left: 0, - down_intent: false, - } + loop {} } #[allow(dead_code)] pub fn center_tp(&self) -> TilePos { - TilePos { - x: (self.col_en.en.pos.x / TILE_SIZE as i32) as TPosSc, - y: (self.col_en.en.pos.y / TILE_SIZE as i32) as TPosSc, - } + loop {} } pub fn can_jump(&self) -> bool { - self.jumps_left > 0 + loop {} } pub fn feet_y(&self) -> i32 { - self.col_en.en.pos.y + self.col_en.en.bb.y + loop {} } - pub(crate) fn save(&self, path: &Path) { - let result = std::fs::write(path.join("player.dat"), rmp_serde::to_vec(self).unwrap()); - log::info!("{result:?}"); + loop {} } } diff --git a/src/res.rs b/src/res.rs index be8a15f..4fb8439 100644 --- a/src/res.rs +++ b/src/res.rs @@ -1,20 +1,13 @@ use sfml::audio::Music; - use crate::texture_atlas::AtlasBundle; - #[derive(Debug)] pub struct Res { pub atlas: AtlasBundle, pub surf_music: Music<'static>, pub und_music: Music<'static>, } - impl Res { pub fn load() -> anyhow::Result { - Ok(Self { - atlas: AtlasBundle::new()?, - surf_music: Music::from_file("res/music/music.ogg").unwrap(), - und_music: Music::from_file("res/music/cave2.ogg").unwrap(), - }) + loop {} } } diff --git a/src/stringfmt.rs b/src/stringfmt.rs index d67b5bb..897d837 100644 --- a/src/stringfmt.rs +++ b/src/stringfmt.rs @@ -1,22 +1,8 @@ use std::fmt; - use crate::math::M_PER_PX; - pub struct LengthDisp(pub f32); - impl fmt::Display for LengthDisp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let meters = self.0 * M_PER_PX; - if meters.abs() > 1000. { - let km = if meters.is_sign_negative() { - (meters / 1000.).ceil() - } else { - (meters / 1000.).floor() - }; - let m = meters % 1000.; - write!(f, "{km} km, {m} m") - } else { - write!(f, "{meters} m") - } + loop {} } } diff --git a/src/texture_atlas.rs b/src/texture_atlas.rs index 514c94b..e1e6580 100644 --- a/src/texture_atlas.rs +++ b/src/texture_atlas.rs @@ -1,106 +1,28 @@ use std::{collections::HashMap, path::Path}; - use crate::math::IntRect; use sfml::{graphics::Texture, SfBox}; use texture_packer::{texture::Texture as _, TexturePacker, TexturePackerConfig}; - pub type RectMap = HashMap; - #[derive(Debug)] pub struct AtlasBundle { pub tex: SfBox, - // Key could be `tiles/dirt` for example, derived from folder+filename without extension pub rects: RectMap, } - impl AtlasBundle { pub fn new() -> anyhow::Result { - let cfg = TexturePackerConfig { - max_width: 512, - max_height: 512, - allow_rotation: false, - border_padding: 0, - texture_padding: 0, - texture_extrusion: 0, - trim: true, - texture_outlines: false, - }; - let mut packer = TexturePacker::new_skyline(cfg); - walk_graphics(|path| { - let img = image::open(path).unwrap(); - let key = path_img_key(path); - packer.pack_own(key, img).unwrap(); - dbg!(path); - }); - let mut rects = HashMap::new(); - let mut tex = Texture::new().unwrap(); - log::info!( - "Texture atlas size is: {}x{}", - packer.width(), - packer.height() - ); - if !tex.create(packer.width(), packer.height()) { - panic!("Failed to create texture"); - } - let pixbuf = make_pix_buf(&packer); - unsafe { - tex.update_from_pixels(&pixbuf, packer.width(), packer.height(), 0, 0); - } - for (k, frame) in packer.get_frames() { - rects.insert( - k.clone(), - IntRect { - x: frame.frame.x as i32, - y: frame.frame.y as i32, - w: frame.frame.w as i32, - h: frame.frame.h as i32, - }, - ); - } - Ok(AtlasBundle { tex, rects }) + loop {} } } - fn make_pix_buf(packer: &TexturePacker) -> Vec { - let (w, h) = (packer.width(), packer.height()); - let px_size = 4; - let mut vec = vec![0; w as usize * h as usize * px_size as usize]; - for y in 0..h { - for x in 0..w { - let idx = ((y * w + x) * px_size) as usize; - if let Some(px) = packer.get(x, y) { - vec[idx..idx + px_size as usize].copy_from_slice(&px.0); - } - } - } - vec + loop {} } - fn path_img_key(path: &Path) -> String { - let mut rev_iter = path.components().rev(); - let fname = rev_iter.next().unwrap(); - let folder = rev_iter.next().unwrap(); - let fname: &Path = fname.as_ref(); - let folder: &Path = folder.as_ref(); - folder - .join(fname.file_stem().unwrap()) - .display() - .to_string() + loop {} } - #[test] fn test_path_img_key() { - assert_eq!( - &path_img_key("/home/person/res/graphics/tiles/foo.png".as_ref()), - "tiles/foo" - ); + loop {} } - fn walk_graphics(mut f: impl FnMut(&Path)) { - for en in walkdir::WalkDir::new("res/graphics") { - let en = en.unwrap(); - if en.file_type().is_file() { - f(en.path()); - } - } + loop {} } diff --git a/src/tiles/tiledb_edit_ui.rs b/src/tiles/tiledb_edit_ui.rs index 4f4d52f..d1b2368 100644 --- a/src/tiles/tiledb_edit_ui.rs +++ b/src/tiles/tiledb_edit_ui.rs @@ -1,12 +1,9 @@ use std::fmt::Debug; - use egui_inspect::{derive::Inspect, Inspect}; - use crate::{ graphics::{ScreenSc, ScreenVec}, math::TILE_SIZE, }; - #[derive(Debug, Default, Inspect)] pub struct TileDbEdit { open: bool, @@ -15,109 +12,39 @@ pub struct TileDbEdit { } impl TileDbEdit { pub(crate) fn ui(&mut self, ctx: &egui::Context, tile_db: &mut TileDb) { - if !self.open { - return; - } - egui::Window::new("Tiledb editor").show(ctx, |ui| { - ui.horizontal(|ui| { - ui.selectable_value(&mut self.layer, Layer::Bg, "Bg"); - ui.selectable_value(&mut self.layer, Layer::Mid, "Mid"); - ui.selectable_value(&mut self.layer, Layer::Fg, "Fg"); - }); - ui.separator(); - egui::ScrollArea::vertical() - .max_height(400.0) - .show(ui, |ui| match self.layer { - Layer::Bg => db_ui(&mut tile_db.bg, ui), - Layer::Fg => db_ui(&mut tile_db.fg, ui), - Layer::Mid => db_ui(&mut tile_db.mid, ui), - }); - }); + loop {} } } - #[derive(Debug, PartialEq, Eq)] enum Layer { Bg, Fg, Mid, } - impl Default for Layer { fn default() -> Self { - Self::Bg + loop {} } } - use super::{Bg, Fg, Mid, TileDb, TileDef, TileLayer, DEFAULT_TILE_BB}; - trait SpecialUi { fn special_ui(&mut self, ui: &mut egui::Ui); } - impl SpecialUi for TileDef { fn special_ui(&mut self, ui: &mut egui::Ui) { - match &mut self.layer.bb { - Some(bb) => { - ui.horizontal(|ui| { - ui.label("x"); - ui.add(egui::DragValue::new(&mut bb.x)); - ui.label("y"); - ui.add(egui::DragValue::new(&mut bb.y)); - ui.label("w"); - ui.add(egui::DragValue::new(&mut bb.w)); - ui.label("h"); - ui.add(egui::DragValue::new(&mut bb.h)); - }); - } - None => { - if ui.button("Insert bb").clicked() { - self.layer.bb = Some(DEFAULT_TILE_BB); - } - } - } - ui.checkbox(&mut self.layer.platform, "platform"); + loop {} } } - impl SpecialUi for TileDef { fn special_ui(&mut self, _ui: &mut egui::Ui) {} } - impl SpecialUi for TileDef { fn special_ui(&mut self, _ui: &mut egui::Ui) {} } - fn db_ui(db: &mut Vec>, ui: &mut egui::Ui) where ::SpecificDef: Debug + Default + Inspect, TileDef: SpecialUi, { - for (i, def) in db.iter_mut().enumerate() { - ui.label(i.to_string()); - ui.text_edit_singleline(&mut def.graphic_name); - match &mut def.light { - Some(light) => { - ui.horizontal(|ui| { - ui.label("x"); - ui.add(egui::DragValue::new(&mut light.x)); - ui.label("y"); - ui.add(egui::DragValue::new(&mut light.y)); - }); - } - None => { - if ui.button("Insert light emit").clicked() { - def.light = Some(ScreenVec { - x: TILE_SIZE as ScreenSc / 2, - y: TILE_SIZE as ScreenSc / 2, - }); - } - } - } - def.special_ui(ui); - ui.separator(); - } - if ui.button("Add new default").clicked() { - db.push(Default::default()); - } + loop {} } diff --git a/src/world.rs b/src/world.rs index 9077106..1d35fbc 100644 --- a/src/world.rs +++ b/src/world.rs @@ -1,52 +1,30 @@ mod reg_chunk_existence; mod serialization; - -use std::{ - fmt::Debug, - fs::File, - io::Seek, - path::{Path, PathBuf}, -}; - +use std::{fmt::Debug, fs::File, io::Seek, path::{Path, PathBuf}}; use egui_inspect::derive::Inspect; use fnv::FnvHashMap; use serde::{Deserialize, Serialize}; - use crate::{ - math::WorldPos, - player::Player, - tiles::{BgTileId, FgTileId, MidTileId, TileId}, - world::reg_chunk_existence::ExistenceBitset, - worldgen::Worldgen, + math::WorldPos, player::Player, tiles::{BgTileId, FgTileId, MidTileId, TileId}, + world::reg_chunk_existence::ExistenceBitset, worldgen::Worldgen, }; - use self::serialization::save_chunk; - pub type ChkPosSc = u16; - #[derive(Hash, PartialEq, Eq, Debug, Clone, Copy, Inspect)] pub struct ChunkPos { pub x: ChkPosSc, pub y: ChkPosSc, } - impl ChunkPos { /// Returns the region this chunk position belongs to pub fn region(&self) -> (u8, u8) { - ( - (self.x / REGION_CHUNK_EXTENT as ChkPosSc) as u8, - (self.y / REGION_CHUNK_EXTENT as ChkPosSc) as u8, - ) + loop {} } /// Returns the local position in the region (0-7) pub fn local(&self) -> (u8, u8) { - ( - (self.x % REGION_CHUNK_EXTENT as ChkPosSc) as u8, - (self.y % REGION_CHUNK_EXTENT as ChkPosSc) as u8, - ) + loop {} } } - #[derive(Debug, Inspect)] pub struct World { /// The currently loaded chunks @@ -59,220 +37,108 @@ pub struct World { #[opaque] pub path: PathBuf, } - impl World { pub fn new(spawn_point: WorldPos, name: &str, path: PathBuf) -> Self { - Self { - chunks: Default::default(), - ticks: Default::default(), - player: Player::new_at(spawn_point), - name: name.to_string(), - path, - } + loop {} } /// Get mutable access to the tile at `pos`. /// /// Loads or generates the containing chunk if necessary. pub fn tile_at_mut(&mut self, pos: TilePos, worldgen: &Worldgen) -> &mut Tile { - let (chk, local) = pos.to_chunk_and_local(); - let chk = self - .chunks - .entry(chk) - .or_insert_with(|| Chunk::load_or_gen(chk, worldgen, &self.path)); - chk.at_mut(local) + loop {} } pub fn save(&self) { - let result = std::fs::create_dir_all(&self.path); - log::info!("{result:?}"); - self.save_meta(); - self.player.save(&self.path); - self.save_chunks(); + loop {} } pub fn save_meta(&self) { - let meta = WorldMetaSave { - name: self.name.clone(), - ticks: self.ticks, - }; - let result = std::fs::write( - self.path.join("world.dat"), - rmp_serde::to_vec(&meta).unwrap(), - ); - log::info!("{result:?}"); + loop {} } pub fn save_chunks(&self) { - for (pos, chk) in self.chunks.iter() { - save_chunk(pos, chk, &self.path); - } + loop {} } } - fn loc_byte_idx_xy(x: u8, y: u8) -> usize { - loc_byte_idx(loc_idx(y, x)) + loop {} } - fn loc_byte_idx(loc_idx: u8) -> usize { - loc_idx as usize * CHUNK_BYTES + loop {} } - fn loc_idx(loc_y: u8, loc_x: u8) -> u8 { - (loc_y * REGION_CHUNK_EXTENT) + loc_x + loop {} } - fn format_reg_file_name((x, y): (u8, u8)) -> String { - format!("{x}.{y}.rgn") + loop {} } - const CHUNK_BYTES: usize = CHUNK_N_TILES * TILE_BYTES; const TILE_BYTES: usize = 3 * 2; - #[derive(Serialize, Deserialize)] struct WorldMetaSave { name: String, ticks: u64, } - #[derive(Debug, Clone, Copy)] pub struct TilePos { pub x: TPosSc, pub y: TPosSc, } - #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct ChunkLocalTilePos { pub x: ChkLocalTPosSc, pub y: ChkLocalTPosSc, } - /// Chunk-local tile position scalar. Supports up to 256 tiles per chunk. type ChkLocalTPosSc = u8; - impl TilePos { pub fn to_chunk_and_local(self) -> (ChunkPos, ChunkLocalTilePos) { - let chk = ChunkPos { - x: chk_pos(self.x), - y: chk_pos(self.y), - }; - let local = ChunkLocalTilePos { - x: chunk_local(self.x), - y: chunk_local(self.y), - }; - (chk, local) + loop {} } - pub(crate) fn to_chunk(self) -> ChunkPos { - self.to_chunk_and_local().0 + loop {} } } - fn chk_pos(tile: TPosSc) -> ChkPosSc { - (tile / CHUNK_EXTENT as TPosSc) as ChkPosSc + loop {} } - #[test] fn test_chk_pos() { - assert_eq!(chk_pos(0), 0); - assert_eq!(chk_pos(1), 0); - assert_eq!(chk_pos(127), 0); - assert_eq!(chk_pos(128), 1); + loop {} } - fn chunk_local(global: TPosSc) -> ChkLocalTPosSc { - (global % CHUNK_EXTENT as TPosSc) as ChkLocalTPosSc + loop {} } - #[test] fn test_chunk_local() { - assert_eq!(chunk_local(0), 0); + loop {} } - #[test] fn test_to_chunk_and_local() { - assert_eq!( - TilePos { x: 0, y: 0 }.to_chunk_and_local(), - (ChunkPos { x: 0, y: 0 }, ChunkLocalTilePos { x: 0, y: 0 }) - ); - assert_eq!( - TilePos { x: 1, y: 1 }.to_chunk_and_local(), - (ChunkPos { x: 0, y: 0 }, ChunkLocalTilePos { x: 1, y: 1 }) - ); + loop {} } - -// Need to support at least 4 million tiles long pub type TPosSc = u32; - pub const CHUNK_EXTENT: u16 = 128; const CHUNK_N_TILES: usize = CHUNK_EXTENT as usize * CHUNK_EXTENT as usize; - type ChunkTiles = [Tile; CHUNK_N_TILES]; - fn default_chunk_tiles() -> ChunkTiles { - [Tile { - bg: TileId::EMPTY, - mid: TileId::EMPTY, - fg: TileId::EMPTY, - }; CHUNK_N_TILES] + loop {} } - #[derive(Debug, Inspect)] pub struct Chunk { tiles: ChunkTiles, } - impl Chunk { pub fn gen(pos: ChunkPos, worldgen: &Worldgen) -> Self { - let mut tiles = default_chunk_tiles(); - let noise = worldgen.chunk_noise(pos); - if pos.y >= 156 { - for (i, t) in tiles.iter_mut().enumerate() { - let x = i % CHUNK_EXTENT as usize; - let y = i / CHUNK_EXTENT as usize; - let noise = noise[x][y]; - *t = noise; - } - } - // Unbreakable layer at bottom - if pos.y > 798 { - for b in &mut tiles { - b.mid = MidTileId::UNBREAKANIUM; - } - } - Self { tiles } + loop {} } - pub fn load_or_gen(chk: ChunkPos, worldgen: &Worldgen, world_path: &Path) -> Chunk { - log::info!("Loading chunk {chk:?} (reg: {:?})", chk.region()); - let reg_filename = world_path.join(format_reg_file_name(chk.region())); - if chunk_exists(®_filename, chk) { - log::info!("Chunk exists, loading"); - let mut f = File::open(®_filename).unwrap(); - let bitset = ExistenceBitset::read_from_file(&mut f); - log::info!("Existence bitset: {bitset:?}"); - assert_eq!(f.stream_position().unwrap(), 8); - let decomp_data = zstd::decode_all(f).unwrap(); - assert_eq!(decomp_data.len(), REGION_BYTES); - let local_pos = chk.local(); - Chunk::load_from_region(&decomp_data, local_pos.0, local_pos.1) - } else { - log::warn!("Chunk at {:?} doesn't exist, generating.", chk); - Chunk::gen(chk, worldgen) - } + loop {} } - fn at_mut(&mut self, local: ChunkLocalTilePos) -> &mut Tile { - &mut self.tiles[CHUNK_EXTENT as usize * local.y as usize + local.x as usize] + loop {} } } - fn chunk_exists(reg_path: &Path, pos: ChunkPos) -> bool { - if !Path::new(®_path).exists() { - return false; - } - let bitset = ExistenceBitset::read_from_fs(reg_path); - let local = pos.local(); - let idx = loc_idx(local.1, local.0); - crate::bitmanip::nth_bit_set(bitset.0, idx as usize) + loop {} } - #[derive(Clone, Copy, Debug, Inspect)] pub struct Tile { /// Background wall behind entities @@ -282,12 +148,10 @@ pub struct Tile { /// A layer on top of the mid wall. Usually ores or decorative pieces. pub fg: FgTileId, } - pub const REGION_CHUNK_EXTENT: u8 = 8; pub const REGION_N_CHUNKS: u8 = REGION_CHUNK_EXTENT * REGION_CHUNK_EXTENT; /// This is the uncompressed byte length of a region pub const REGION_BYTES: usize = REGION_N_CHUNKS as usize * CHUNK_BYTES; - #[allow(clippy::assertions_on_constants)] const _: () = assert!( REGION_N_CHUNKS <= 64, diff --git a/src/world/reg_chunk_existence.rs b/src/world/reg_chunk_existence.rs index 20cab70..14e5c52 100644 --- a/src/world/reg_chunk_existence.rs +++ b/src/world/reg_chunk_existence.rs @@ -1,37 +1,17 @@ use std::{fs::File, io::Read, path::Path}; - #[derive(Clone, Copy)] pub struct ExistenceBitset(pub u64); - impl ExistenceBitset { pub const EMPTY: Self = Self(0); - pub fn read_from_file(f: &mut File) -> ExistenceBitset { - let mut buf = [0; 8]; - f.read_exact(&mut buf).unwrap(); - ExistenceBitset(u64::from_le_bytes(buf)) + loop {} } - pub fn read_from_fs(path: &Path) -> ExistenceBitset { - let mut f = File::open(path).unwrap(); - Self::read_from_file(&mut f) + loop {} } } - impl std::fmt::Debug for ExistenceBitset { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f)?; - for i in 0..64 { - let chr = if crate::bitmanip::nth_bit_set(self.0, i) { - 'X' - } else { - '_' - }; - write!(f, "{chr}")?; - if (i + 1) % 8 == 0 { - writeln!(f)?; - } - } - Ok(()) + loop {} } } diff --git a/src/world/serialization.rs b/src/world/serialization.rs index 065e2ed..84b3117 100644 --- a/src/world/serialization.rs +++ b/src/world/serialization.rs @@ -1,93 +1,22 @@ use std::{ - fs::OpenOptions, - io::{Seek, Write}, + fs::OpenOptions, io::{Seek, Write}, path::Path, }; - use crate::world::{ format_reg_file_name, loc_byte_idx, loc_idx, reg_chunk_existence::ExistenceBitset, REGION_BYTES, TILE_BYTES, }; - use super::{default_chunk_tiles, loc_byte_idx_xy, Chunk, ChunkPos}; - pub(super) fn save_chunk(pos: &ChunkPos, chk: &Chunk, world_dir: &Path) { - let reg_file_name = world_dir.join(format_reg_file_name(pos.region())); - let reg_file_exists = Path::new(®_file_name).exists(); - if !reg_file_exists { - log::warn!("Region file doesn't exist. Going to create one."); - } - let mut f = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .open(®_file_name) - .unwrap(); - let mut existence_bitset = if reg_file_exists { - ExistenceBitset::read_from_file(&mut f) - } else { - ExistenceBitset::EMPTY - }; - let mut region_tile_data = if reg_file_exists { - assert_eq!(f.stream_position().unwrap(), 8); - zstd::decode_all(&mut f).unwrap() - } else { - vec![0; REGION_BYTES] - }; - // Even the zstd decompressed data should be exactly REGION_BYTES size - assert_eq!(region_tile_data.len(), REGION_BYTES); - let (loc_x, loc_y) = pos.local(); - let loc_idx = loc_idx(loc_y, loc_x); - crate::bitmanip::set_nth_bit(&mut existence_bitset.0, loc_idx as usize, true); - let byte_idx = loc_byte_idx(loc_idx); - for (i, tile) in chk.tiles.iter().enumerate() { - let off = byte_idx + (i * TILE_BYTES); - region_tile_data[off..off + 2].copy_from_slice(&tile.bg.0.to_le_bytes()); - region_tile_data[off + 2..off + 4].copy_from_slice(&tile.mid.0.to_le_bytes()); - region_tile_data[off + 4..off + 6].copy_from_slice(&tile.fg.0.to_le_bytes()); - } - f.rewind().unwrap(); - f.write_all(&u64::to_le_bytes(existence_bitset.0)[..]) - .unwrap(); - assert_eq!(f.stream_position().unwrap(), 8); - assert_eq!(region_tile_data.len(), REGION_BYTES); - let result = f.write_all(&zstd::encode_all(®ion_tile_data[..], COMP_LEVEL).unwrap()); - let cursor = f.stream_position().unwrap(); - f.set_len(cursor).unwrap(); - log::info!("{result:?}"); + loop {} } - const COMP_LEVEL: i32 = 9; - impl Chunk { pub fn load_from_region(data: &[u8], x: u8, y: u8) -> Self { - let byte_idx = loc_byte_idx_xy(x, y); - let mut tiles = default_chunk_tiles(); - for (i, t) in tiles.iter_mut().enumerate() { - let off = byte_idx + (i * TILE_BYTES); - t.bg.0 = u16::from_le_bytes(data[off..off + 2].try_into().unwrap()); - t.mid.0 = u16::from_le_bytes(data[off + 2..off + 4].try_into().unwrap()); - t.fg.0 = u16::from_le_bytes(data[off + 4..off + 6].try_into().unwrap()); - } - Self { tiles } + loop {} } } - #[test] fn test_chunk_seri() { - env_logger::builder() - .filter_level(log::LevelFilter::Info) - .init(); - let _ = std::fs::create_dir("testworld"); - let mut chk = Chunk { - tiles: super::default_chunk_tiles(), - }; - for t in &mut chk.tiles { - t.bg = crate::tiles::BgTileId::DIRT; - } - save_chunk(&ChunkPos { x: 2, y: 0 }, &chk, "testworld".as_ref()); - save_chunk(&ChunkPos { x: 3, y: 0 }, &chk, "testworld".as_ref()); - let raw = std::fs::read("testworld/0.0.rgn").unwrap(); - zstd::decode_all(&raw[8..]).unwrap(); - std::fs::remove_dir_all("testworld").unwrap(); + loop {} } diff --git a/src/worldgen.rs b/src/worldgen.rs index 9ac53b3..42b0d05 100644 --- a/src/worldgen.rs +++ b/src/worldgen.rs @@ -1,74 +1,23 @@ use worldgen::{ - constraint, - noise::perlin::PerlinNoise, + constraint, noise::perlin::PerlinNoise, noisemap::{NoiseMap, NoiseMapGenerator, Seed, Step}, world::{ tile::{Constraint, ConstraintType}, Size, Tile, World, }, }; - use crate::{ tiles::{BgTileId, FgTileId, MidTileId, TileId}, world::{ChunkPos, Tile as Tl, CHUNK_EXTENT}, }; - pub struct Worldgen { world: World, } - impl Worldgen { pub fn from_seed(seed: i64) -> Self { - let noise = PerlinNoise::new(); - - let nm1 = NoiseMap::new(noise) - .set(Seed::of(seed)) - .set(Step::of(0.005, 0.005)); - - let nm2 = NoiseMap::new(noise) - .set(Seed::of(seed)) - .set(Step::of(0.05, 0.05)); - - let nm = Box::new(nm1 + nm2 * 3); - - let world = World::new() - .set(Size::of(CHUNK_EXTENT as i64, CHUNK_EXTENT as i64)) - // Dirt coal - .add( - Tile::new(Tl { - bg: BgTileId::DIRT, - mid: MidTileId::DIRT, - fg: FgTileId::COAL, - }) - .when(constraint!(nm.clone(), < -0.8)), - ) - // Dirt - .add( - Tile::new(Tl { - bg: BgTileId::DIRT, - mid: MidTileId::DIRT, - fg: TileId::EMPTY, - }) - .when(constraint!(nm.clone(), < -0.1)), - ) - // Stone - .add( - Tile::new(Tl { - bg: BgTileId::STONE, - mid: MidTileId::STONE, - fg: TileId::EMPTY, - }) - .when(constraint!(nm, < 0.45)), - ) - // Dirt wall - .add(Tile::new(Tl { - bg: BgTileId::DIRT, - mid: TileId::EMPTY, - fg: TileId::EMPTY, - })); - Self { world } + loop {} } pub fn chunk_noise(&self, pos: ChunkPos) -> Vec> { - self.world.generate(pos.x as i64, pos.y as i64).unwrap() + loop {} } }