~comcloudway/little_town

6a13111872fa899d1c8c007edae0948740bead73 — Jakob Meier 1 year, 3 months ago 95026a3
Migrated from nightly channel to stable channel
M Cargo.lock => Cargo.lock +16 -15
@@ 281,13 281,13 @@ checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae"

[[package]]
name = "async-trait"
version = "0.1.68"
version = "0.1.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.22",
 "syn 2.0.28",
]

[[package]]


@@ 698,7 698,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.22",
 "syn 2.0.28",
]

[[package]]


@@ 906,7 906,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.22",
 "syn 2.0.28",
]

[[package]]


@@ 1604,6 1604,7 @@ name = "little_town"
version = "0.2.3"
dependencies = [
 "async-std",
 "async-trait",
 "directories-next",
 "futures",
 "libp2p",


@@ 2111,7 2112,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.22",
 "syn 2.0.28",
]

[[package]]


@@ 2352,9 2353,9 @@ dependencies = [

[[package]]
name = "quote"
version = "1.0.28"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
checksum = "5907a1b7c277254a8b15170f6e7c97cfa60ee7872a3217663bb81151e48184bb"
dependencies = [
 "proc-macro2",
]


@@ 2787,9 2788,9 @@ dependencies = [

[[package]]
name = "syn"
version = "2.0.22"
version = "2.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
dependencies = [
 "proc-macro2",
 "quote",


@@ 2846,7 2847,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.22",
 "syn 2.0.28",
]

[[package]]


@@ 2936,7 2937,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.22",
 "syn 2.0.28",
]

[[package]]


@@ 3138,7 3139,7 @@ dependencies = [
 "once_cell",
 "proc-macro2",
 "quote",
 "syn 2.0.22",
 "syn 2.0.28",
 "wasm-bindgen-shared",
]



@@ 3172,7 3173,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.22",
 "syn 2.0.28",
 "wasm-bindgen-backend",
 "wasm-bindgen-shared",
]


@@ 3420,5 3421,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.22",
 "syn 2.0.28",
]

M Cargo.toml => Cargo.toml +1 -0
@@ 29,3 29,4 @@ futures = { version = "0.3.26", optional = true }
async-std = { version = "1.12.0", optional = true }
quad-rand = { version = "0.2.1", optional = true }
quad-snd = "0.2.7"
async-trait = "0.1.73"

M README.md => README.md +4 -4
@@ 97,9 97,9 @@ or you don't want to use the default features,
you can follow this guide to build the binary yourself.

### Dependencies
- [rustup](https://www.rust-lang.org/tools/install), `cargo` and `rust` nightly
- `alsa-lib-dev` (or `libasound` depending on your distro) on linux
- `protoc` on linux, with `multiplayer` feature enabled
- [rustup](https://www.rust-lang.org/tools/install), `cargo` and `rust`
- `alsa-lib-dev` (or `libasound` depending on your distro) on Linux
- `protoc` on Linux, with `multiplayer` feature enabled
### Steps
1. Clone this repo:
    ```bash


@@ 129,6 129,6 @@ See below or a detailed list:

The Background music has been obtained from [pixabay](https://pixabay.com/music/solo-piano-raining-ambient-calm-piano-music-loop-111521/).
The song is called *Raining - Ambient Calm Piano Music*,
and has been comosed by *HarumachiMusic*.
and has been composed by *HarumachiMusic*.
According to the [pixabey license](https://pixabay.com/service/license/),
it may be used for personal and commercial use.

M src/game/mod.rs => src/game/mod.rs +3 -0
@@ 4,6 4,8 @@ pub mod inventory;
pub mod types;
pub mod world;

use async_trait::async_trait;

use crate::screens::Screen;
use crate::textures::AssetStore;



@@ 12,6 14,7 @@ use crate::textures::AssetStore;
/// and has a handler for the event loop
/// NOTE: draw and `ev_loop` are tehcnically the same,
/// but the serve different purposes
#[async_trait]
pub trait GameComponent {
    /// Callback used to redraw the component
    async fn draw(&self, _assets: &AssetStore) {}

M src/game/world.rs => src/game/world.rs +19 -18
@@ 101,13 101,14 @@ impl World {
                let mut builder = Vec::new();

                for entry in rd.by_ref().flatten() {
                    if let Ok(ftype) = entry.file_type() && ftype.is_file() {
                        if let Some(name) = entry.file_name().to_str() {
                            builder.push(name.to_string());
                    if let Ok(ftype) = entry.file_type() {
                        if ftype.is_file() {
                            if let Some(name) = entry.file_name().to_str() {
                                builder.push(name.to_string());
                            }
                        }
                    }
                }

                return builder;
            }
        }


@@ 117,24 118,24 @@ impl World {
    /// tries loading the world from a file
    pub fn from_disk(name: &str) -> Option<Self> {
        let existing_maps = Self::get_list();
        if let Some(dir) = get_data_dir() && existing_maps.contains(&name.to_string()) {
            if let Ok(file) = File::open(Path::new(&dir).join(name)) {
                let mut buf_reader = BufReader::new(file);
                let mut contents = String::new();
                if buf_reader.read_to_string(&mut contents).is_ok() {
                    match Self::deserialize_json(&contents) {
                        Ok(bscr) => return Some(bscr),
                        Err(e) => println!("{e:?}")
        if let Some(dir) = get_data_dir() {
            if existing_maps.contains(&name.to_string()) {
                if let Ok(file) = File::open(Path::new(&dir).join(name)) {
                    let mut buf_reader = BufReader::new(file);
                    let mut contents = String::new();
                    if buf_reader.read_to_string(&mut contents).is_ok() {
                        match Self::deserialize_json(&contents) {
                            Ok(bscr) => return Some(bscr),
                            Err(e) => {
                                println!("{e:?}");
                                return None;
                            }
                        }
                    }
                } else {
                    println!("Faield to read file");
                }
            } else {
                println!("Failed to open file");
            }
        } else {
            println!("World not found");
        }
        println!("Unable to open world");

        None
    }

M src/main.rs => src/main.rs +0 -6
@@ 1,9 1,3 @@
#![feature(int_roundings)]
#![feature(let_chains)]
#![feature(async_fn_in_trait)]
#![feature(associated_type_defaults)]
#![feature(inherent_associated_types)]

use macroquad::prelude::*;

mod screens;

M src/screens/build.rs => src/screens/build.rs +14 -4
@@ 8,6 8,7 @@ use crate::game::{
};
use crate::textures::AssetStore;
use crate::ui::{ButtonEvent, CenteredText, ItemFrame, TextButton, Widget};
use async_trait::async_trait;
use macroquad::prelude::*;

#[cfg(feature = "multiplayer")]


@@ 95,7 96,9 @@ impl InventoryWidgets {
        let title = inv.category.get_name();
        self.widget_categories.set_text(title);
        let list = inv.category.get_blocks();
        let page_count = list.len().div_ceil(9);
        let page_count = (list.len() + 9 - 1) / 9;
        // NOTE: once div_ceil is stable, we can use
        // let page_count = list.len().div_ceil(9);
        self.widget_page_indicator
            .set_text(&format!("{}/{}", self.page + 1, page_count));
        self.widget_categories.set_text(title);


@@ 106,7 109,9 @@ impl InventoryWidgets {
    fn load_page(&mut self, page: usize, inv: &Inventory) {
        self.page = page;
        let list = inv.category.get_blocks();
        let max_page = list.len().div_ceil(9);
        let max_page = (list.len() + 9 - 1) / 9;
        // NOTE: once div_ceil is stable, we can use
        //let max_page = list.len().div_ceil(9);
        for (i, slot) in self.widgets_slots.iter_mut().enumerate() {
            if let Some(block) = list.get(i + page * 9) {
                let amount = inv.contents.get(block).copied();


@@ 125,7 130,9 @@ impl InventoryWidgets {
        if page > 0 {
            page -= 1;
        } else {
            page = list.len().div_ceil(9) - 1;
            page = (list.len() + 9 - 1) / 9 - 1;
            // NOTE: once div_ceil is stable, we can use
            // page = list.len().div_ceil(9) - 1;
        }
        self.load_page(page, inv);
    }


@@ 133,7 140,9 @@ impl InventoryWidgets {
    fn page_up(&mut self, inv: &Inventory) {
        let list = inv.category.get_blocks();
        let mut page = self.page;
        let max_page = list.len().div_ceil(9);
        let max_page = (list.len() + 9 - 1) / 9;
        // NOTE: once div_ceil is stable, we can use
        //let max_page = list.len().div_ceil(9);
        if page + 1 >= max_page {
            page = 0;
        } else {


@@ 216,6 225,7 @@ impl BuildScreen {
        }
    }
}
#[async_trait]
impl GameComponent for BuildScreen {
    async fn draw(&self, assets: &AssetStore) {
        if let Some(world) = &self.world {

M src/screens/map_creator.rs => src/screens/map_creator.rs +2 -0
@@ 3,6 3,7 @@ use super::map_select::SelectScreen;
use super::Screen;
use crate::game::{world::World, GameComponent, GameEvent};
use crate::textures::AssetStore;
use async_trait::async_trait;
use macroquad::prelude::*;

use crate::ui::{ButtonEvent, SelectableText, TextButton, Widget};


@@ 33,6 34,7 @@ impl MapCreatorScreen {
        }
    }
}
#[async_trait]
impl GameComponent for MapCreatorScreen {
    async fn draw(&self, assets: &AssetStore) {
        {

M src/screens/map_select.rs => src/screens/map_select.rs +11 -4
@@ 2,6 2,7 @@ use super::{build::BuildScreen, map_creator::MapCreatorScreen, Screen};
use crate::game::{world::World, GameComponent, GameEvent};
use crate::textures::AssetStore;
use crate::ui::{ButtonEvent, SelectableText, TextButton, Widget};
use async_trait::async_trait;
use macroquad::prelude::*;

/// The map select screen


@@ 55,6 56,7 @@ impl SelectScreen {
        }
    }
}
#[async_trait]
impl GameComponent for SelectScreen {
    async fn draw(&self, assets: &AssetStore) {
        {


@@ 124,10 126,15 @@ impl GameComponent for SelectScreen {
        for slot in &mut self.level_select_widgets {
            slot.set_selected(false);
            if let ButtonEvent::LeftClick = slot.ev_loop() {
                if let Some(sel) = &self.selected && sel == slot.get_text() {
                    // already selected
                    // deselect
                    self.selected = None;
                if let Some(sel) = &self.selected {
                    if sel == slot.get_text() {
                        // already selected
                        // deselect
                        self.selected = None;
                    } else {
                        // user selected this item
                        self.selected = Some(slot.get_text().to_string());
                    }
                } else {
                    // user selected this item
                    self.selected = Some(slot.get_text().to_string());

M src/screens/mod.rs => src/screens/mod.rs +2 -0
@@ 5,6 5,7 @@ mod welcome;

use crate::game::{GameComponent, GameEvent};
use crate::textures::AssetStore;
use async_trait::async_trait;
use build::BuildScreen;
use map_creator::MapCreatorScreen;
use map_select::SelectScreen;


@@ 22,6 23,7 @@ pub enum Screen {
    /// Map creation screen
    Create(MapCreatorScreen),
}
#[async_trait]
impl GameComponent for Screen {
    async fn draw(&self, assets: &AssetStore) {
        match self {

M src/screens/welcome.rs => src/screens/welcome.rs +2 -0
@@ 5,6 5,7 @@ use super::Screen;
use crate::game::{GameComponent, GameEvent};
use crate::textures::AssetStore;
use crate::ui::{ButtonEvent, CenteredText, TextButton, Widget};
use async_trait::async_trait;
use macroquad::prelude::*;

/// The welcome screen


@@ 32,6 33,7 @@ impl WelcomeScreen {
        }
    }
}
#[async_trait]
impl GameComponent for WelcomeScreen {
    async fn draw(&self, assets: &AssetStore) {
        {

M src/ui/centered_text.rs => src/ui/centered_text.rs +3 -0
@@ 1,5 1,6 @@
use super::Widget;
use crate::textures::AssetStore;
use async_trait::async_trait;
use macroquad::prelude::*;

/// UI Widget


@@ 65,6 66,8 @@ impl CenteredText {
        self.text = text.to_string();
    }
}

#[async_trait]
impl Widget for CenteredText {
    type Event = bool;
    async fn draw(&self, _assets: &AssetStore) {

M src/ui/item_frame.rs => src/ui/item_frame.rs +2 -0
@@ 2,6 2,7 @@ use super::{ButtonEvent, CenteredText, Widget};
use crate::game::blocks::Block;
use crate::game::types::Direction;
use crate::textures::AssetStore;
use async_trait::async_trait;
use macroquad::prelude::*;

pub struct ItemFrame {


@@ 103,6 104,7 @@ impl ItemFrame {
        self.direction = direction.clone();
    }
}
#[async_trait]
impl Widget for ItemFrame {
    type Event = ButtonEvent;
    fn get_dimensions(&self) -> (f32, f32) {

M src/ui/mod.rs => src/ui/mod.rs +2 -0
@@ 1,4 1,5 @@
use crate::textures::AssetStore;
use async_trait::async_trait;
use macroquad::prelude::*;

mod centered_text;


@@ 23,6 24,7 @@ pub enum ButtonEvent {
}

/// A UI item that can be rendered
#[async_trait]
pub trait Widget {
    /// Message types returned from the event loop
    type Event;

M src/ui/selectable_text.rs => src/ui/selectable_text.rs +2 -0
@@ 1,5 1,6 @@
use super::{ButtonEvent, Widget};
use crate::textures::AssetStore;
use async_trait::async_trait;
use macroquad::prelude::*;

/// A widget similar to a button,


@@ 93,6 94,7 @@ impl SelectableText {
        &self.text
    }
}
#[async_trait]
impl Widget for SelectableText {
    type Event = ButtonEvent;
    fn get_dimensions(&self) -> (f32, f32) {

M src/ui/text_button.rs => src/ui/text_button.rs +2 -0
@@ 1,5 1,6 @@
use super::{ButtonEvent, Widget};
use crate::textures::AssetStore;
use async_trait::async_trait;
use macroquad::prelude::*;

/// UI Widget


@@ 65,6 66,7 @@ impl TextButton {
        self.text = text.to_string();
    }
}
#[async_trait]
impl Widget for TextButton {
    type Event = ButtonEvent;
    fn get_dimensions(&self) -> (f32, f32) {