From 90d68082ba0c1f31a1c320d5e4e64a221ad47bc5 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Mon, 14 Aug 2023 07:44:53 +0200 Subject: [PATCH] Formatted code using cargo clippy and cargo fmt --- src/game/blocks.rs | 907 +++++++++++++++++++++++++++---------- src/game/camera.rs | 4 +- src/game/inventory.rs | 11 +- src/game/mod.rs | 6 +- src/game/types.rs | 25 +- src/game/world.rs | 48 +- src/main.rs | 32 +- src/p2p.rs | 318 ++++++------- src/screens/build.rs | 481 ++++++++++---------- src/screens/map_creator.rs | 79 ++-- src/screens/map_select.rs | 127 +++--- src/screens/mod.rs | 15 +- src/screens/welcome.rs | 67 ++- src/textures.rs | 63 +-- src/ui/centered_text.rs | 25 +- src/ui/item_frame.rs | 75 +-- src/ui/mod.rs | 4 +- src/ui/selectable_text.rs | 54 +-- src/ui/text_button.rs | 60 +-- 19 files changed, 1382 insertions(+), 1019 deletions(-) diff --git a/src/game/blocks.rs b/src/game/blocks.rs index 07dfb6a..5ae8095 100644 --- a/src/game/blocks.rs +++ b/src/game/blocks.rs @@ -1,14 +1,10 @@ -use macroquad::prelude::*; +use crate::screens::build::{ + TEXTURE_DEPTH, TEXTURE_INNER_HEIGHT, TEXTURE_WIDTH, TEXTURE_Y_WHITESPACE, +}; use crate::textures::DirectionalTexture; +use macroquad::prelude::*; use nanoserde::{DeJson, SerJson}; use std::collections::HashMap; -use crate::screens::build::{ - TEXTURE_WIDTH, - TEXTURE_Y_WHITESPACE, - TEXTURE_DEPTH, - TEXTURE_INNER_HEIGHT -}; - /// A block's face /// /'\ @@ -24,14 +20,13 @@ use crate::screens::build::{ pub enum Face { Top, Left, - Right + Right, } impl Face { /// gets the face (if any) that was clicked /// coordinates have to be normalized, /// the top left should be (0,0) pub fn from_xy(x: f32, y: f32, scale: f32) -> Option { - // test A face { let ox = (TEXTURE_WIDTH * scale / 2.0 - x).abs(); @@ -40,7 +35,7 @@ impl Face { let y_max = TEXTURE_DEPTH * scale / 2.0; let x_max = TEXTURE_WIDTH * scale / 2.0; - let grow = (0.0 - y_max)/(x_max - 0.0); + let grow = (0.0 - y_max) / (x_max - 0.0); let cy = grow.mul_add(ox, y_max); if cy >= oy { @@ -58,7 +53,7 @@ impl Face { let y_max = TEXTURE_DEPTH * scale / 2.0; let x_max = TEXTURE_WIDTH * scale / 2.0; - let grow = (0.0 - y_max)/(x_max - 0.0); + let grow = (0.0 - y_max) / (x_max - 0.0); let y_top = grow.mul_add(ox_abs, y_max); let y_bottom = TEXTURE_INNER_HEIGHT.mul_add(scale, grow.mul_add(ox_abs, y_max)); @@ -100,7 +95,7 @@ pub enum Category { /// i.e bridges Wood, /// all items - All + All, } /// rust macro to autogenerate the Block enum @@ -168,225 +163,671 @@ macro_rules! auto_gen_blocks { } auto_gen_blocks!( - ( BalconyStone, "exp/Tiles/balcony_stone", [Building] ), - ( BalconyWood, "exp/Tiles/balcony_wood", [Building] ), - ( Bridge, "base/Tiles/bridge", [Wood] ), - ( BuildingCenter, "base/Tiles/building_center", [Building] ), - ( BuildingCenterBeige, "base/Tiles/building_centerBeige", [Building] ), - ( BuildingCorner, "base/Tiles/building_corner", [Building] ), - ( BuildingCornerBeige, "base/Tiles/building_cornerBeige", [Building] ), - ( BuildingDoor, "base/Tiles/building_door", [Building] ), - ( BuildingDoorBeige, "base/Tiles/building_doorBeige", [Building] ), - ( BuildingDoorWindows, "base/Tiles/building_doorWindows", [Building] ), - ( BuildingDoorWindowsBeige, "base/Tiles/building_doorWindowsBeige", [Building] ), - ( BuildingWindow, "base/Tiles/building_window", [Building] ), - ( BuildingWindowBeige, "base/Tiles/building_windowBeige", [Building] ), - ( BuildingWindows, "base/Tiles/building_windows", [Building] ), - ( BuildingWindowsBeige, "base/Tiles/building_windowsBeige", [Building] ), - ( BuildingStack, "exp/Tiles/building_stack", [Building] ), - ( BuildingStackBeige, "exp/Tiles/building_stackBeige", [Building] ), - ( BuildingStackCorner, "exp/Tiles/building_stackCorner", [Building] ), - ( BuildingStackCornerBeige, "exp/Tiles/building_stackCornerBeige", [Building] ), - - ( DesertBuilding, "desert/Tiles/building_center", [Building, Desert] ), - ( DesertBuildingSides, "desert/Tiles/building_sides", [Building, Desert] ), - ( DesertDarkBuilding, "desert/Tiles/building_dark_center", [Building, Desert] ), - ( DesertDarkBuildingDoor, "desert/Tiles/building_dark_center_door", [Building, Desert] ), - ( DesertDarkBuildingWindows, "desert/Tiles/building_dark_center_windows", [Building, Desert] ), - ( DesertDarkBuildingSides, "desert/Tiles/building_dark_sides", [Building, Desert] ), - ( DesertDarkBuildingSidesWindows, "desert/Tiles/building_dark_sides_windows", [Building, Desert] ), - - ( CastleBend, "base/Tiles/castle_bend", [Building] ), - ( CastleCenter, "base/Tiles/castle_center", [Building] ), - ( CastleCorner, "base/Tiles/castle_corner", [Building] ), - ( CastleEnd, "exp/Tiles/castle_end", [Building] ), - ( CastleEndRound, "exp/Tiles/castle_endRound", [Building] ), - ( CastleEndRuined, "exp/Tiles/castle_endRuined", [Building] ), - ( CastleGate, "base/Tiles/castle_gate", [Building] ), - ( CastleGateOpen, "base/Tiles/castle_gateOpen", [Building] ), - ( CastleSlope, "base/Tiles/castle_slope", [Building] ), - ( CastleTower, "base/Tiles/castle_tower", [Building] ), - ( CastleTowerCenter, "exp/Tiles/castle_towerCenter", [Building] ), - ( CastleTowerBeige, "base/Tiles/castle_towerBeige", [Building] ), - ( CastleTowerBeigeBase, "exp/Tiles/castle_towerBeigeBase", [Building] ), - ( CastleTowerBeigeTop, "exp/Tiles/castle_towerBeigeTop", [Building, Roof] ), - ( CastleTowerBrown, "base/Tiles/castle_towerBrown", [Building] ), - ( CastleTowerBrownBase, "exp/Tiles/castle_towerBrownBase", [Building] ), - ( CastleTowerBrownTop, "exp/Tiles/castle_towerBrownTop", [Building, Roof] ), - ( CastleTowerGreen, "base/Tiles/castle_towerGreen", [Building] ), - ( CastleTowerGreenBase, "exp/Tiles/castle_towerGreenBase", [Building] ), - ( CastleTowerGreenTop, "exp/Tiles/castle_towerGreenTop", [Building, Roof] ), - ( CastleTowerPurple, "base/Tiles/castle_towerPurple", [Building] ), - ( CastleTowerPurpleBase, "exp/Tiles/castle_towerPurpleBase", [Building] ), - ( CastleTowerPurpleTop, "exp/Tiles/castle_towerPurpleTop", [Building, Roof] ), - ( CastleWall, "base/Tiles/castle_wall", [Building] ), - ( CastleWindow, "base/Tiles/castle_window", [Building] ), - - ( Cliff, "exp/Tiles/cliff", [Block] ), - ( CliffCorner, "exp/Tiles/cliff_corner", [Block] ), - ( CliffCornerInner, "exp/Tiles/cliff_cornerInner", [Block] ), - ( CliffEntrance, "exp/Tiles/cliff_entrance", [Block] ), - ( CliffTop, "exp/Tiles/cliff_top", [Block] ), - ( CliffTopEntrance, "exp/Tiles/cliff_topEntrance", [Block] ), - ( CliffTopCorner, "exp/Tiles/cliff_topCorner", [Block] ), - ( CliffTopCornerInner, "exp/Tiles/cliff_topCornerInner", [Block] ), - - ( DirtCenter, "base/Tiles/dirt_center", [Block] ), - ( DirtCorner, "exp/Tiles/dirt_corner", [Block] ), - ( DirtLow, "base/Tiles/dirt_low", [Block] ), - - ( Fence, "exp/Tiles/fence_wood", [Wood] ), - ( FenceCorner, "exp/Tiles/fence_woodCorner", [Wood] ), - ( FenceCurve, "exp/Tiles/fence_woodCurve", [Wood] ), - ( FenceEnd, "exp/Tiles/fence_woodEnd", [Wood] ), - ( FenceDouble, "exp/Tiles/fence_woodDouble", [Wood] ), - ( FenceDoubleCorner, "exp/Tiles/fence_woodDoubleCorner", [Wood] ), - ( FenceDoubleCurve, "exp/Tiles/fence_woodDoubleCurve", [Wood] ), - ( FenceDoubleEnd, "exp/Tiles/fence_woodDoubleEnd", [Wood]), - - ( Furrow, "exp/Tiles/furrow", [Plant] ), - ( FurrowCropWheat, "exp/Tiles/furrow_cropWheat", [Plant] ), - ( FurrowCrop, "exp/Tiles/furrow_crop", [Plant] ), - ( FurrowEnd, "exp/Tiles/furrow_end", [Plant] ), - - ( Grass, "exp/Tiles/grass_block", [Block] ), - ( GrassCenter, "base/Tiles/grass_center", [Block] ), - ( GrassCorner, "base/Tiles/grass_corner", [Block] ), - ( GrassSlope, "base/Tiles/grass_slope", [Block] ), - ( GrassSlopeConcave, "base/Tiles/grass_slopeConcave", [Block] ), - ( GrassSlopeConvex, "base/Tiles/grass_slopeConvex", [Block] ), - ( GrassPath, "base/Tiles/grass_path", [Block] ), - ( GrassPathBend, "base/Tiles/grass_pathBend", [Block] ), - ( GrassPathCorner, "base/Tiles/grass_pathCorner", [Block] ), - ( GrassPathCrossing, "base/Tiles/grass_pathCrossing", [Block] ), - ( GrassPathEnd, "base/Tiles/grass_pathEnd", [Block] ), - ( GrassPathEndSquare, "base/Tiles/grass_pathEndSquare", [Block] ), - ( GrassPathSlope, "base/Tiles/grass_pathSlope", [Block] ), - ( GrassPathSplit, "base/Tiles/grass_pathSplit", [Block] ), - ( GrassRiver, "base/Tiles/grass_river", [Block, Water] ), - ( GrassRiverBend, "base/Tiles/grass_riverBend", [Block, Water] ), - ( GrassRiverBridge, "base/Tiles/grass_riverBridge", [Block, Water] ), - ( GrassRiverCorner, "base/Tiles/grass_riverCorner", [Block, Water] ), - ( GrassRiverCrossing, "base/Tiles/grass_riverCrossing", [Block, Water] ), - ( GrassRiverEnd, "base/Tiles/grass_riverEnd", [Block, Water] ), - ( GrassRiverEndSquare, "base/Tiles/grass_riverEndSquare", [Block, Water] ), - ( GrassRiverSlope, "base/Tiles/grass_riverSlope", [Block, Water] ), - ( GrassRiverSplit, "base/Tiles/grass_riverSplit", [Block, Water] ), - ( GrassWater, "base/Tiles/grass_water", [Block, Water] ), - ( GrassWaterConcave, "base/Tiles/grass_waterConcave", [Block, Water] ), - ( GrassWaterConvex, "base/Tiles/grass_waterConvex", [Block, Water] ), - ( GrassWaterRiver, "base/Tiles/grass_waterRiver", [Block, Water] ), - - ( DesertGrass, "desert/Tiles/grass_center", [Block, Desert] ), - ( DesertGrassSlope, "desert/Tiles/grass_slope", [Block, Desert] ), - ( DesertGrassSlopeConcave, "desert/Tiles/grass_slopeConcave", [Block, Desert] ), - ( DesertGrassSlopeConvex, "desert/Tiles/grass_slopeConvex", [Block, Desert] ), - ( DesertGrassCorner, "desert/Tiles/grass_corner", [Block, Desert] ), - ( DesertGrassPath, "desert/Tiles/grass_path", [Block, Desert] ), - ( DesertGrassPathBend, "desert/Tiles/grass_pathBend", [Block, Desert] ), - ( DesertGrassPathCorner, "desert/Tiles/grass_pathCorner", [Block, Desert] ), - ( DesertGrassPathCrossing, "desert/Tiles/grass_pathCrossing", [Block, Desert] ), - ( DesertGrassPathEnd, "desert/Tiles/grass_pathEnd", [Block, Desert] ), - ( DesertGrassPathEndSquare, "desert/Tiles/grass_pathEndSquare", [Block, Desert] ), - ( DesertGrassPathSlope, "desert/Tiles/grass_pathSlope", [Block, Desert] ), - ( DesertGrassPathSplit, "desert/Tiles/grass_pathSplit", [Block, Desert] ), - ( DesertGrassRiver, "desert/Tiles/grass_river", [Block, Desert, Water] ), - ( DesertGrassRiverBend, "desert/Tiles/grass_riverBend", [Block, Desert, Water] ), - ( DesertGrassRiverBridge, "desert/Tiles/grass_riverBridge", [Block, Desert, Water] ), - ( DesertGrassRiverCorner, "desert/Tiles/grass_riverCorner", [Block, Desert, Water] ), - ( DesertGrassRiverCrossing, "desert/Tiles/grass_riverCrossing", [Block, Desert, Water] ), - ( DesertGrassRiverEnd, "desert/Tiles/grass_riverEnd", [Block, Desert, Water] ), - ( DesertGrassRiverEndSquare, "desert/Tiles/grass_riverEndSquare", [Block, Desert, Water] ), - ( DesertGrassRiverSlope, "desert/Tiles/grass_riverSlope", [Block, Desert, Water] ), - ( DesertGrassRiverSplit, "desert/Tiles/grass_riverSplit", [Block, Desert, Water] ), - ( DesertGrassWater, "desert/Tiles/grass_water", [Block, Desert, Water] ), - ( DesertGrassWaterConcave, "desert/Tiles/grass_waterConcave", [Block, Desert, Water] ), - ( DesertGrassWaterConvex, "desert/Tiles/grass_waterConvex", [Block, Desert, Water] ), - ( DesertGrassWaterRiver, "desert/Tiles/grass_waterRiver", [Block, Desert, Water] ), - - ( RocksDirt, "base/Tiles/rocks_dirt", [Plant] ), - ( RocksGrass, "base/Tiles/rocks_grass", [Plant] ), - ( RocksDesert, "desert/Tiles/rocks", [Plant, Desert] ), - - ( DesertOverhang, "desert/Tiles/overhang", [Building, Desert] ), - ( DesertOverhangSmall, "desert/Tiles/overhang_small", [Building, Desert] ), - - ( RoofChurchBeige, "base/Tiles/roof_churchBeige", [Building, Roof] ), - ( RoofChuchBrown, "base/Tiles/roof_churchBrown", [Building, Roof] ), - ( RoofChurchGreen, "base/Tiles/roof_churchGreen", [Building, Roof] ), - ( RoofChurchPurple, "base/Tiles/roof_churchPurple", [Building, Roof] ), - ( RoofGableBeige, "base/Tiles/roof_gableBeige", [Building, Roof] ), - ( RoofGableCornerBeige, "exp/Tiles/roof_gableCornerBeige", [Building, Roof] ), - ( RoofGableBrown, "base/Tiles/roof_gableBrown", [Building, Roof] ), - ( RoofGableCornerBrown, "exp/Tiles/roof_gableCornerBrown", [Building, Roof] ), - ( RoofGableGreen, "base/Tiles/roof_gableGreen", [Building, Roof] ), - ( RoofGableCornerGreen, "exp/Tiles/roof_gableCornerGreen", [Building, Roof] ), - ( RoofGablePurple, "base/Tiles/roof_gablePurple", [Building, Roof] ), - ( RoofGableCornerPurple, "exp/Tiles/roof_gableCornerPurple", [Building, Roof] ), - ( RoofPointBeige, "base/Tiles/roof_pointBeige", [Building, Roof] ), - ( RoofPointBrown, "base/Tiles/roof_pointBrown", [Building, Roof] ), - ( RoofPointGreen, "base/Tiles/roof_pointGreen", [Building, Roof] ), - ( RoofPointPurple, "base/Tiles/roof_pointPurple", [Building, Roof] ), - ( RoofRoundBeige, "base/Tiles/roof_roundBeige", [Building, Roof] ), - ( RoofRoundCornerBeige, "exp/Tiles/roof_roundCornerBeige", [Building, Roof] ), - ( RoofRoundBrown, "base/Tiles/roof_roundBrown", [Building, Roof] ), - ( RoofRoundCornerBrown, "exp/Tiles/roof_roundCornerBrown", [Building, Roof] ), - ( RoofRoundGreen, "base/Tiles/roof_roundGreen", [Building, Roof] ), - ( RoofRoundCornerGreen, "exp/Tiles/roof_roundCornerGreen", [Building, Roof] ), - ( RoofRoundPurple, "base/Tiles/roof_roundPurple", [Building, Roof] ), - ( RoofRoundCornerPurple, "exp/Tiles/roof_roundCornerPurple", [Building, Roof] ), - ( RoofRoundedBeige, "base/Tiles/roof_roundedBeige", [Building, Roof] ), - ( RoofRoundedBrown, "base/Tiles/roof_roundedBrown", [Building, Roof] ), - ( RoofRoundedGreen, "base/Tiles/roof_roundedGreen", [Building, Roof] ), - ( RoofRoundedPurple, "base/Tiles/roof_roundedPurple", [Building, Roof] ), - ( RoofSlantBeige, "base/Tiles/roof_slantBeige", [Building, Roof] ), - ( RoofSlantCornerBeige, "exp/Tiles/roof_slantCornerBeige", [Building, Roof] ), - ( RoofSlantCornerInnerBeige, "exp/Tiles/roof_slantCornerInnerBeige", [Building, Roof] ), - ( RoofSlantBrown, "base/Tiles/roof_slantBrown", [Building, Roof] ), - ( RoofSlantCornerBrown, "exp/Tiles/roof_slantCornerBrown", [Building, Roof] ), - ( RoofSlantCornerInnerBrown, "exp/Tiles/roof_slantCornerInnerBrown", [Building, Roof] ), - ( RoofSlantGreen, "base/Tiles/roof_slantGreen", [Building, Roof] ), - ( RoofSlantCornerGreen, "exp/Tiles/roof_slantCornerGreen", [Building, Roof] ), - ( RoofSlantCornerInnerGreen, "exp/Tiles/roof_slantCornerInnerGreen", [Building, Roof] ), - ( RoofSlantPurple, "base/Tiles/roof_slantPurple", [Building, Roof] ), - ( RoofSlantCornerPurple, "exp/Tiles/roof_slantCornerPurple", [Building, Roof] ), - ( RoofSlantCornerInnerPurple, "exp/Tiles/roof_slantCornerInnerPurple", [Building, Roof] ), - - ( DesertDome, "desert/Tiles/dome", [Building, Desert, Roof] ), - ( DesertDomeSmall, "desert/Tiles/dome_small", [Building, Desert, Roof] ), - - ( DesertStairs, "desert/Tiles/stairs_full", [Building, Desert] ), - ( DesertStairsLeft, "desert/Tiles/stairs_left", [Building, Desert] ), - ( DesertStairsRight, "desert/Tiles/stairs_right", [Building, Desert] ), - - ( StructureArch, "base/Tiles/structure_arch", [Wood] ), - ( StructureHigh, "base/Tiles/structure_high", [Wood] ), - ( StructureLow, "base/Tiles/structure_low", [Wood] ), - ( StructureTent, "desert/Tiles/structure_tent", [Building, Wood, Desert] ), - ( StructureTentSlant, "desert/Tiles/structure_tentSlant", [Building, Wood, Desert] ), - - ( DesertTiles, "desert/Tiles/tiles", [Block, Desert] ), - ( DesertTilesCrumbled, "desert/Tiles/tiles_crumbled", [Block, Desert] ), - ( DesertTilesDecorated, "desert/Tiles/tiles_decorated", [Block, Desert] ), - ( DesertTilesSteps, "desert/Tiles/tiles_steps", [Block, Desert] ), - - ( Trees, "base/Tiles/tree_multiple", [Plant] ), - ( Tree, "base/Tiles/tree_single", [Plant] ), - ( Pine, "exp/Tiles/tree_pine", [Plant] ), - ( PineLarge, "exp/Tiles/tree_pineLarge", [Plant] ), - ( PalmTree, "desert/Tiles/tree", [Plant, Desert] ), - ( PalmTrees, "desert/Tiles/trees", [Plant, Desert] ), - - ( DesertWalls, "desert/Tiles/walls_square", [Desert, Building] ), - ( DesertWallsBroken, "desert/Tiles/walls_broken", [Desert, Building] ), - ( DesertWallsCorner, "desert/Tiles/walls_corner", [Desert, Building] ), - ( DesertWallsEnd, "desert/Tiles/walls_end", [Desert, Building] ), - ( DesertWallsLeft, "desert/Tiles/walls_left", [Desert, Building] ), - ( DesertWallsRight, "desert/Tiles/walls_right", [Desert, Building] ), - - ( WaterCenter, "base/Tiles/water_center", [Block, Water] ), - ( WaterFall, "base/Tiles/water_fall", [Block, Water] ), - ( Well, "exp/Tiles/well", [Water] ) + (BalconyStone, "exp/Tiles/balcony_stone", [Building]), + (BalconyWood, "exp/Tiles/balcony_wood", [Building]), + (Bridge, "base/Tiles/bridge", [Wood]), + (BuildingCenter, "base/Tiles/building_center", [Building]), + ( + BuildingCenterBeige, + "base/Tiles/building_centerBeige", + [Building] + ), + (BuildingCorner, "base/Tiles/building_corner", [Building]), + ( + BuildingCornerBeige, + "base/Tiles/building_cornerBeige", + [Building] + ), + (BuildingDoor, "base/Tiles/building_door", [Building]), + ( + BuildingDoorBeige, + "base/Tiles/building_doorBeige", + [Building] + ), + ( + BuildingDoorWindows, + "base/Tiles/building_doorWindows", + [Building] + ), + ( + BuildingDoorWindowsBeige, + "base/Tiles/building_doorWindowsBeige", + [Building] + ), + (BuildingWindow, "base/Tiles/building_window", [Building]), + ( + BuildingWindowBeige, + "base/Tiles/building_windowBeige", + [Building] + ), + (BuildingWindows, "base/Tiles/building_windows", [Building]), + ( + BuildingWindowsBeige, + "base/Tiles/building_windowsBeige", + [Building] + ), + (BuildingStack, "exp/Tiles/building_stack", [Building]), + ( + BuildingStackBeige, + "exp/Tiles/building_stackBeige", + [Building] + ), + ( + BuildingStackCorner, + "exp/Tiles/building_stackCorner", + [Building] + ), + ( + BuildingStackCornerBeige, + "exp/Tiles/building_stackCornerBeige", + [Building] + ), + ( + DesertBuilding, + "desert/Tiles/building_center", + [Building, Desert] + ), + ( + DesertBuildingSides, + "desert/Tiles/building_sides", + [Building, Desert] + ), + ( + DesertDarkBuilding, + "desert/Tiles/building_dark_center", + [Building, Desert] + ), + ( + DesertDarkBuildingDoor, + "desert/Tiles/building_dark_center_door", + [Building, Desert] + ), + ( + DesertDarkBuildingWindows, + "desert/Tiles/building_dark_center_windows", + [Building, Desert] + ), + ( + DesertDarkBuildingSides, + "desert/Tiles/building_dark_sides", + [Building, Desert] + ), + ( + DesertDarkBuildingSidesWindows, + "desert/Tiles/building_dark_sides_windows", + [Building, Desert] + ), + (CastleBend, "base/Tiles/castle_bend", [Building]), + (CastleCenter, "base/Tiles/castle_center", [Building]), + (CastleCorner, "base/Tiles/castle_corner", [Building]), + (CastleEnd, "exp/Tiles/castle_end", [Building]), + (CastleEndRound, "exp/Tiles/castle_endRound", [Building]), + (CastleEndRuined, "exp/Tiles/castle_endRuined", [Building]), + (CastleGate, "base/Tiles/castle_gate", [Building]), + (CastleGateOpen, "base/Tiles/castle_gateOpen", [Building]), + (CastleSlope, "base/Tiles/castle_slope", [Building]), + (CastleTower, "base/Tiles/castle_tower", [Building]), + ( + CastleTowerCenter, + "exp/Tiles/castle_towerCenter", + [Building] + ), + (CastleTowerBeige, "base/Tiles/castle_towerBeige", [Building]), + ( + CastleTowerBeigeBase, + "exp/Tiles/castle_towerBeigeBase", + [Building] + ), + ( + CastleTowerBeigeTop, + "exp/Tiles/castle_towerBeigeTop", + [Building, Roof] + ), + (CastleTowerBrown, "base/Tiles/castle_towerBrown", [Building]), + ( + CastleTowerBrownBase, + "exp/Tiles/castle_towerBrownBase", + [Building] + ), + ( + CastleTowerBrownTop, + "exp/Tiles/castle_towerBrownTop", + [Building, Roof] + ), + (CastleTowerGreen, "base/Tiles/castle_towerGreen", [Building]), + ( + CastleTowerGreenBase, + "exp/Tiles/castle_towerGreenBase", + [Building] + ), + ( + CastleTowerGreenTop, + "exp/Tiles/castle_towerGreenTop", + [Building, Roof] + ), + ( + CastleTowerPurple, + "base/Tiles/castle_towerPurple", + [Building] + ), + ( + CastleTowerPurpleBase, + "exp/Tiles/castle_towerPurpleBase", + [Building] + ), + ( + CastleTowerPurpleTop, + "exp/Tiles/castle_towerPurpleTop", + [Building, Roof] + ), + (CastleWall, "base/Tiles/castle_wall", [Building]), + (CastleWindow, "base/Tiles/castle_window", [Building]), + (Cliff, "exp/Tiles/cliff", [Block]), + (CliffCorner, "exp/Tiles/cliff_corner", [Block]), + (CliffCornerInner, "exp/Tiles/cliff_cornerInner", [Block]), + (CliffEntrance, "exp/Tiles/cliff_entrance", [Block]), + (CliffTop, "exp/Tiles/cliff_top", [Block]), + (CliffTopEntrance, "exp/Tiles/cliff_topEntrance", [Block]), + (CliffTopCorner, "exp/Tiles/cliff_topCorner", [Block]), + ( + CliffTopCornerInner, + "exp/Tiles/cliff_topCornerInner", + [Block] + ), + (DirtCenter, "base/Tiles/dirt_center", [Block]), + (DirtCorner, "exp/Tiles/dirt_corner", [Block]), + (DirtLow, "base/Tiles/dirt_low", [Block]), + (Fence, "exp/Tiles/fence_wood", [Wood]), + (FenceCorner, "exp/Tiles/fence_woodCorner", [Wood]), + (FenceCurve, "exp/Tiles/fence_woodCurve", [Wood]), + (FenceEnd, "exp/Tiles/fence_woodEnd", [Wood]), + (FenceDouble, "exp/Tiles/fence_woodDouble", [Wood]), + ( + FenceDoubleCorner, + "exp/Tiles/fence_woodDoubleCorner", + [Wood] + ), + (FenceDoubleCurve, "exp/Tiles/fence_woodDoubleCurve", [Wood]), + (FenceDoubleEnd, "exp/Tiles/fence_woodDoubleEnd", [Wood]), + (Furrow, "exp/Tiles/furrow", [Plant]), + (FurrowCropWheat, "exp/Tiles/furrow_cropWheat", [Plant]), + (FurrowCrop, "exp/Tiles/furrow_crop", [Plant]), + (FurrowEnd, "exp/Tiles/furrow_end", [Plant]), + (Grass, "exp/Tiles/grass_block", [Block]), + (GrassCenter, "base/Tiles/grass_center", [Block]), + (GrassCorner, "base/Tiles/grass_corner", [Block]), + (GrassSlope, "base/Tiles/grass_slope", [Block]), + (GrassSlopeConcave, "base/Tiles/grass_slopeConcave", [Block]), + (GrassSlopeConvex, "base/Tiles/grass_slopeConvex", [Block]), + (GrassPath, "base/Tiles/grass_path", [Block]), + (GrassPathBend, "base/Tiles/grass_pathBend", [Block]), + (GrassPathCorner, "base/Tiles/grass_pathCorner", [Block]), + (GrassPathCrossing, "base/Tiles/grass_pathCrossing", [Block]), + (GrassPathEnd, "base/Tiles/grass_pathEnd", [Block]), + ( + GrassPathEndSquare, + "base/Tiles/grass_pathEndSquare", + [Block] + ), + (GrassPathSlope, "base/Tiles/grass_pathSlope", [Block]), + (GrassPathSplit, "base/Tiles/grass_pathSplit", [Block]), + (GrassRiver, "base/Tiles/grass_river", [Block, Water]), + (GrassRiverBend, "base/Tiles/grass_riverBend", [Block, Water]), + ( + GrassRiverBridge, + "base/Tiles/grass_riverBridge", + [Block, Water] + ), + ( + GrassRiverCorner, + "base/Tiles/grass_riverCorner", + [Block, Water] + ), + ( + GrassRiverCrossing, + "base/Tiles/grass_riverCrossing", + [Block, Water] + ), + (GrassRiverEnd, "base/Tiles/grass_riverEnd", [Block, Water]), + ( + GrassRiverEndSquare, + "base/Tiles/grass_riverEndSquare", + [Block, Water] + ), + ( + GrassRiverSlope, + "base/Tiles/grass_riverSlope", + [Block, Water] + ), + ( + GrassRiverSplit, + "base/Tiles/grass_riverSplit", + [Block, Water] + ), + (GrassWater, "base/Tiles/grass_water", [Block, Water]), + ( + GrassWaterConcave, + "base/Tiles/grass_waterConcave", + [Block, Water] + ), + ( + GrassWaterConvex, + "base/Tiles/grass_waterConvex", + [Block, Water] + ), + ( + GrassWaterRiver, + "base/Tiles/grass_waterRiver", + [Block, Water] + ), + (DesertGrass, "desert/Tiles/grass_center", [Block, Desert]), + ( + DesertGrassSlope, + "desert/Tiles/grass_slope", + [Block, Desert] + ), + ( + DesertGrassSlopeConcave, + "desert/Tiles/grass_slopeConcave", + [Block, Desert] + ), + ( + DesertGrassSlopeConvex, + "desert/Tiles/grass_slopeConvex", + [Block, Desert] + ), + ( + DesertGrassCorner, + "desert/Tiles/grass_corner", + [Block, Desert] + ), + (DesertGrassPath, "desert/Tiles/grass_path", [Block, Desert]), + ( + DesertGrassPathBend, + "desert/Tiles/grass_pathBend", + [Block, Desert] + ), + ( + DesertGrassPathCorner, + "desert/Tiles/grass_pathCorner", + [Block, Desert] + ), + ( + DesertGrassPathCrossing, + "desert/Tiles/grass_pathCrossing", + [Block, Desert] + ), + ( + DesertGrassPathEnd, + "desert/Tiles/grass_pathEnd", + [Block, Desert] + ), + ( + DesertGrassPathEndSquare, + "desert/Tiles/grass_pathEndSquare", + [Block, Desert] + ), + ( + DesertGrassPathSlope, + "desert/Tiles/grass_pathSlope", + [Block, Desert] + ), + ( + DesertGrassPathSplit, + "desert/Tiles/grass_pathSplit", + [Block, Desert] + ), + ( + DesertGrassRiver, + "desert/Tiles/grass_river", + [Block, Desert, Water] + ), + ( + DesertGrassRiverBend, + "desert/Tiles/grass_riverBend", + [Block, Desert, Water] + ), + ( + DesertGrassRiverBridge, + "desert/Tiles/grass_riverBridge", + [Block, Desert, Water] + ), + ( + DesertGrassRiverCorner, + "desert/Tiles/grass_riverCorner", + [Block, Desert, Water] + ), + ( + DesertGrassRiverCrossing, + "desert/Tiles/grass_riverCrossing", + [Block, Desert, Water] + ), + ( + DesertGrassRiverEnd, + "desert/Tiles/grass_riverEnd", + [Block, Desert, Water] + ), + ( + DesertGrassRiverEndSquare, + "desert/Tiles/grass_riverEndSquare", + [Block, Desert, Water] + ), + ( + DesertGrassRiverSlope, + "desert/Tiles/grass_riverSlope", + [Block, Desert, Water] + ), + ( + DesertGrassRiverSplit, + "desert/Tiles/grass_riverSplit", + [Block, Desert, Water] + ), + ( + DesertGrassWater, + "desert/Tiles/grass_water", + [Block, Desert, Water] + ), + ( + DesertGrassWaterConcave, + "desert/Tiles/grass_waterConcave", + [Block, Desert, Water] + ), + ( + DesertGrassWaterConvex, + "desert/Tiles/grass_waterConvex", + [Block, Desert, Water] + ), + ( + DesertGrassWaterRiver, + "desert/Tiles/grass_waterRiver", + [Block, Desert, Water] + ), + (RocksDirt, "base/Tiles/rocks_dirt", [Plant]), + (RocksGrass, "base/Tiles/rocks_grass", [Plant]), + (RocksDesert, "desert/Tiles/rocks", [Plant, Desert]), + (DesertOverhang, "desert/Tiles/overhang", [Building, Desert]), + ( + DesertOverhangSmall, + "desert/Tiles/overhang_small", + [Building, Desert] + ), + ( + RoofChurchBeige, + "base/Tiles/roof_churchBeige", + [Building, Roof] + ), + ( + RoofChuchBrown, + "base/Tiles/roof_churchBrown", + [Building, Roof] + ), + ( + RoofChurchGreen, + "base/Tiles/roof_churchGreen", + [Building, Roof] + ), + ( + RoofChurchPurple, + "base/Tiles/roof_churchPurple", + [Building, Roof] + ), + ( + RoofGableBeige, + "base/Tiles/roof_gableBeige", + [Building, Roof] + ), + ( + RoofGableCornerBeige, + "exp/Tiles/roof_gableCornerBeige", + [Building, Roof] + ), + ( + RoofGableBrown, + "base/Tiles/roof_gableBrown", + [Building, Roof] + ), + ( + RoofGableCornerBrown, + "exp/Tiles/roof_gableCornerBrown", + [Building, Roof] + ), + ( + RoofGableGreen, + "base/Tiles/roof_gableGreen", + [Building, Roof] + ), + ( + RoofGableCornerGreen, + "exp/Tiles/roof_gableCornerGreen", + [Building, Roof] + ), + ( + RoofGablePurple, + "base/Tiles/roof_gablePurple", + [Building, Roof] + ), + ( + RoofGableCornerPurple, + "exp/Tiles/roof_gableCornerPurple", + [Building, Roof] + ), + ( + RoofPointBeige, + "base/Tiles/roof_pointBeige", + [Building, Roof] + ), + ( + RoofPointBrown, + "base/Tiles/roof_pointBrown", + [Building, Roof] + ), + ( + RoofPointGreen, + "base/Tiles/roof_pointGreen", + [Building, Roof] + ), + ( + RoofPointPurple, + "base/Tiles/roof_pointPurple", + [Building, Roof] + ), + ( + RoofRoundBeige, + "base/Tiles/roof_roundBeige", + [Building, Roof] + ), + ( + RoofRoundCornerBeige, + "exp/Tiles/roof_roundCornerBeige", + [Building, Roof] + ), + ( + RoofRoundBrown, + "base/Tiles/roof_roundBrown", + [Building, Roof] + ), + ( + RoofRoundCornerBrown, + "exp/Tiles/roof_roundCornerBrown", + [Building, Roof] + ), + ( + RoofRoundGreen, + "base/Tiles/roof_roundGreen", + [Building, Roof] + ), + ( + RoofRoundCornerGreen, + "exp/Tiles/roof_roundCornerGreen", + [Building, Roof] + ), + ( + RoofRoundPurple, + "base/Tiles/roof_roundPurple", + [Building, Roof] + ), + ( + RoofRoundCornerPurple, + "exp/Tiles/roof_roundCornerPurple", + [Building, Roof] + ), + ( + RoofRoundedBeige, + "base/Tiles/roof_roundedBeige", + [Building, Roof] + ), + ( + RoofRoundedBrown, + "base/Tiles/roof_roundedBrown", + [Building, Roof] + ), + ( + RoofRoundedGreen, + "base/Tiles/roof_roundedGreen", + [Building, Roof] + ), + ( + RoofRoundedPurple, + "base/Tiles/roof_roundedPurple", + [Building, Roof] + ), + ( + RoofSlantBeige, + "base/Tiles/roof_slantBeige", + [Building, Roof] + ), + ( + RoofSlantCornerBeige, + "exp/Tiles/roof_slantCornerBeige", + [Building, Roof] + ), + ( + RoofSlantCornerInnerBeige, + "exp/Tiles/roof_slantCornerInnerBeige", + [Building, Roof] + ), + ( + RoofSlantBrown, + "base/Tiles/roof_slantBrown", + [Building, Roof] + ), + ( + RoofSlantCornerBrown, + "exp/Tiles/roof_slantCornerBrown", + [Building, Roof] + ), + ( + RoofSlantCornerInnerBrown, + "exp/Tiles/roof_slantCornerInnerBrown", + [Building, Roof] + ), + ( + RoofSlantGreen, + "base/Tiles/roof_slantGreen", + [Building, Roof] + ), + ( + RoofSlantCornerGreen, + "exp/Tiles/roof_slantCornerGreen", + [Building, Roof] + ), + ( + RoofSlantCornerInnerGreen, + "exp/Tiles/roof_slantCornerInnerGreen", + [Building, Roof] + ), + ( + RoofSlantPurple, + "base/Tiles/roof_slantPurple", + [Building, Roof] + ), + ( + RoofSlantCornerPurple, + "exp/Tiles/roof_slantCornerPurple", + [Building, Roof] + ), + ( + RoofSlantCornerInnerPurple, + "exp/Tiles/roof_slantCornerInnerPurple", + [Building, Roof] + ), + (DesertDome, "desert/Tiles/dome", [Building, Desert, Roof]), + ( + DesertDomeSmall, + "desert/Tiles/dome_small", + [Building, Desert, Roof] + ), + (DesertStairs, "desert/Tiles/stairs_full", [Building, Desert]), + ( + DesertStairsLeft, + "desert/Tiles/stairs_left", + [Building, Desert] + ), + ( + DesertStairsRight, + "desert/Tiles/stairs_right", + [Building, Desert] + ), + (StructureArch, "base/Tiles/structure_arch", [Wood]), + (StructureHigh, "base/Tiles/structure_high", [Wood]), + (StructureLow, "base/Tiles/structure_low", [Wood]), + ( + StructureTent, + "desert/Tiles/structure_tent", + [Building, Wood, Desert] + ), + ( + StructureTentSlant, + "desert/Tiles/structure_tentSlant", + [Building, Wood, Desert] + ), + (DesertTiles, "desert/Tiles/tiles", [Block, Desert]), + ( + DesertTilesCrumbled, + "desert/Tiles/tiles_crumbled", + [Block, Desert] + ), + ( + DesertTilesDecorated, + "desert/Tiles/tiles_decorated", + [Block, Desert] + ), + ( + DesertTilesSteps, + "desert/Tiles/tiles_steps", + [Block, Desert] + ), + (Trees, "base/Tiles/tree_multiple", [Plant]), + (Tree, "base/Tiles/tree_single", [Plant]), + (Pine, "exp/Tiles/tree_pine", [Plant]), + (PineLarge, "exp/Tiles/tree_pineLarge", [Plant]), + (PalmTree, "desert/Tiles/tree", [Plant, Desert]), + (PalmTrees, "desert/Tiles/trees", [Plant, Desert]), + (DesertWalls, "desert/Tiles/walls_square", [Desert, Building]), + ( + DesertWallsBroken, + "desert/Tiles/walls_broken", + [Desert, Building] + ), + ( + DesertWallsCorner, + "desert/Tiles/walls_corner", + [Desert, Building] + ), + (DesertWallsEnd, "desert/Tiles/walls_end", [Desert, Building]), + ( + DesertWallsLeft, + "desert/Tiles/walls_left", + [Desert, Building] + ), + ( + DesertWallsRight, + "desert/Tiles/walls_right", + [Desert, Building] + ), + (WaterCenter, "base/Tiles/water_center", [Block, Water]), + (WaterFall, "base/Tiles/water_fall", [Block, Water]), + (Well, "exp/Tiles/well", [Water]) ); impl Default for Block { fn default() -> Self { @@ -418,7 +859,7 @@ impl Category { Self::Water => "Water & River", Self::Wood => "Wood", Self::All => "All", - Self::Desert => "Desert" + Self::Desert => "Desert", } } } diff --git a/src/game/camera.rs b/src/game/camera.rs index 4d98814..9431f61 100644 --- a/src/game/camera.rs +++ b/src/game/camera.rs @@ -6,14 +6,14 @@ pub struct Camera { /// the centered pixel pub center: (f32, f32), /// scales the texture - pub scale: f32 + pub scale: f32, } impl Camera { /// initialize new camera pub fn new() -> Self { Self { center: (0.0, 0.0), - scale: 1.0 + scale: 1.0, } } } diff --git a/src/game/inventory.rs b/src/game/inventory.rs index 3557257..579a137 100644 --- a/src/game/inventory.rs +++ b/src/game/inventory.rs @@ -1,10 +1,7 @@ +use crate::game::blocks::{Block, Category}; use crate::game::types::Direction; -use crate::game::blocks::{ - Block, - Category -}; -use std::collections::HashMap; use nanoserde::{DeJson, SerJson}; +use std::collections::HashMap; /// The players inventory #[derive(SerJson, DeJson, Clone)] @@ -19,7 +16,7 @@ pub struct Inventory { /// in which direction the block should be facing pub direction: Direction, /// category page currently being shown - pub category: Category + pub category: Category, } impl Inventory { @@ -29,7 +26,7 @@ impl Inventory { contents: HashMap::new(), selected: None, direction: Direction::North, - category: Category::All + category: Category::All, } } /// adds an item to the inventory diff --git a/src/game/mod.rs b/src/game/mod.rs index 2f4cd3a..6bc96eb 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -1,11 +1,11 @@ -pub mod camera; pub mod blocks; +pub mod camera; pub mod inventory; pub mod types; pub mod world; -use crate::textures::AssetStore; use crate::screens::Screen; +use crate::textures::AssetStore; /// A basic Game component /// which can be drawn @@ -31,5 +31,5 @@ pub enum GameEvent { /// Exit game Quit, /// Change View - ChangeScreen(Screen) + ChangeScreen(Screen), } diff --git a/src/game/types.rs b/src/game/types.rs index 011a2ff..48ed1f0 100644 --- a/src/game/types.rs +++ b/src/game/types.rs @@ -8,35 +8,30 @@ use std::cmp::Ordering; /// / /// / /// x -#[derive(Debug,Eq,Hash,PartialEq, DeJson, SerJson, Clone)] +#[derive(Debug, Eq, Hash, PartialEq, DeJson, SerJson, Clone)] pub struct Pos3 { pub x: i64, pub y: i64, - pub z: i64 + pub z: i64, } impl Pos3 { /// initialize a new 3 dimensional position pub fn new(x: i64, y: i64, z: i64) -> Self { - Self { - x, - y, - z - } + Self { x, y, z } } pub fn cmp(&self, pos: &Self) -> Ordering { if self == pos { - return Ordering::Equal; + return Ordering::Equal; } - if self.x + self.y == pos.x+pos.y { + if self.x + self.y == pos.x + pos.y { return self.z.cmp(&pos.z); } - (self.x+self.y).cmp(&(pos.x+pos.y)) + (self.x + self.y).cmp(&(pos.x + pos.y)) } } - /// Directions #[derive(Clone, DeJson, SerJson)] pub enum Direction { @@ -51,7 +46,7 @@ pub enum Direction { North, /// Down /// (bottom edge of screen) - South + South, } impl Direction { /// tries to extract the direction from an angle @@ -60,9 +55,9 @@ impl Direction { return Some(Self::North); } else if deg % 270 == 0 { return Some(Self::West); - } else if deg%180 == 0 { + } else if deg % 180 == 0 { return Some(Self::South); - } else if deg%90 == 0 { + } else if deg % 90 == 0 { return Some(Self::East); } @@ -74,7 +69,7 @@ impl Direction { Self::North => 360, Self::West => 270, Self::South => 180, - Self::East => 90 + Self::East => 90, } } /// rotate counter clock wise diff --git a/src/game/world.rs b/src/game/world.rs index 4e591cf..7d58433 100644 --- a/src/game/world.rs +++ b/src/game/world.rs @@ -1,26 +1,13 @@ -use super::inventory::Inventory; -use super::camera::Camera; -use super::types::{ - Direction, - Pos3 -}; use super::blocks::Block; -use std::collections::HashMap; -use nanoserde::{SerJson, DeJson}; +use super::camera::Camera; +use super::inventory::Inventory; +use super::types::{Direction, Pos3}; use directories_next::ProjectDirs; +use nanoserde::{DeJson, SerJson}; +use std::collections::HashMap; +use std::fs::{read_dir, DirBuilder, File, OpenOptions}; +use std::io::{BufReader, Read, Write}; use std::path::Path; -use std::fs::{ - File, - OpenOptions, - DirBuilder, - read_dir -}; -use std::io::{ - BufReader, - Read, - Write -}; - /// returns the OS specific data dir as a string /// if there is no such dir, None will be returned @@ -62,7 +49,7 @@ impl World { grid: map, cam: Camera::new(), inventory: inv, - sandbox + sandbox, } } @@ -101,7 +88,7 @@ impl World { // place block even though it is not in inventory if self.sandbox { - self.grid.insert(pos.clone(), (block, dir)); + self.grid.insert(pos.clone(), (block, dir)); } false @@ -113,12 +100,10 @@ impl World { if let Ok(rd) = &mut read_dir(dir) { let mut builder = Vec::new(); - for entry in rd.by_ref() { - if let Ok(entry) = entry { - if let Ok(ftype) = entry.file_type() && ftype.is_file() { - if let Some(name) = entry.file_name().to_str() { - builder.push(name.to_string()); - } + 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()); } } } @@ -154,7 +139,6 @@ impl World { None } - /// tries saving the map to disk pub fn to_disk(&self, name: &str) { if let Some(dir) = get_data_dir() { @@ -162,9 +146,10 @@ impl World { DirBuilder::new() .recursive(true) - .create(Path::new(&dir)).unwrap(); + .create(Path::new(&dir)) + .unwrap(); - let mut file = OpenOptions::new() + let mut file = OpenOptions::new() .write(true) .create(true) .truncate(true) @@ -179,5 +164,4 @@ impl World { } } } - } diff --git a/src/main.rs b/src/main.rs index 44d5df5..8cd0710 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,24 +9,17 @@ use macroquad::prelude::*; mod screens; #[macro_use] mod textures; -mod ui; mod game; +mod ui; #[cfg(feature = "multiplayer")] mod p2p; -use quad_snd::{ - Sound, - AudioContext, - PlaySoundParams -}; +use quad_snd::{AudioContext, PlaySoundParams, Sound}; -use game::{ - GameComponent, - GameEvent -}; -use textures::AssetStore; +use game::{GameComponent, GameEvent}; use screens::Screen; +use textures::AssetStore; #[macroquad::main("Little Town")] async fn main() { @@ -34,13 +27,16 @@ async fn main() { let mut screen = Screen::default(); - let mut ctx = AudioContext::new(); - let sound = Sound::load(&mut ctx, include_bytes!("../assets/music.wav")); + let ctx = AudioContext::new(); + let sound = Sound::load(&ctx, include_bytes!("../assets/music.wav")); let mut vol = 0.0; - sound.play(&mut ctx, PlaySoundParams{ - looped: true, - volume: vol - }); + sound.play( + &ctx, + PlaySoundParams { + looped: true, + volume: vol, + }, + ); loop { clear_background(Color::from_rgba(215, 189, 165, 255)); @@ -56,7 +52,7 @@ async fn main() { match screen.ev_loop() { GameEvent::Quit => break, GameEvent::ChangeScreen(s) => screen = s, - _ => () + _ => (), } next_frame().await diff --git a/src/p2p.rs b/src/p2p.rs index 675238c..09b37c8 100644 --- a/src/p2p.rs +++ b/src/p2p.rs @@ -1,45 +1,28 @@ +use crate::game::blocks::Block; +use crate::game::types::{Direction, Pos3}; +use crate::game::world::World; use futures::{ + channel::mpsc::{self, UnboundedSender}, prelude::stream::StreamExt, - channel:: mpsc::{ - self, - UnboundedSender, - }, select, }; use libp2p::{ - gossipsub, - identity, - mdns, - tcp, - mplex, - noise, core::upgrade, + gossipsub, identity, mdns, + mplex::MplexConfig, swarm::keep_alive, - swarm::SwarmEvent, swarm::NetworkBehaviour, - PeerId, Swarm, - Transport -}; -use std::{ - sync::{ - Arc, - RwLock, - }, - thread, - time::{ - UNIX_EPOCH, - SystemTime - } + swarm::{SwarmBuilder, SwarmEvent}, + tcp, PeerId, Transport, }; +use nanoserde::{DeJson, SerJson}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::time::Duration; -use nanoserde::{SerJson, DeJson}; -use crate::game::blocks::Block; -use crate::game::world::World; -use crate::game::types::{ - Pos3, - Direction +use std::{ + sync::{Arc, RwLock}, + thread, + time::{SystemTime, UNIX_EPOCH}, }; /// A custom network behaviour that combines floodsub, ping and `mDNS`. @@ -78,7 +61,7 @@ enum ChannelEvent { /// process game action Action(GameAction), /// leave the p2p session - Quit + Quit, } /// struct to manage all relevant options for connection with poemhub p2p network @@ -97,7 +80,7 @@ pub struct Peer { /// the host should not change their local state /// when receiving Transmit* actions /// true if this client is the host - is_host: bool + is_host: bool, } impl Peer { /// create a new peer @@ -107,7 +90,7 @@ impl Peer { bridge: None, port: None, incoming: Arc::new(RwLock::new(Vec::new())), - is_host: false + is_host: false, }; this.connect(); this @@ -119,7 +102,7 @@ impl Peer { bridge: None, port: None, incoming: Arc::new(RwLock::new(Vec::new())), - is_host: true + is_host: true, }; this.connect(); this @@ -177,168 +160,169 @@ impl Peer { /// NOTE: Before running connect please make sure that the old instance has been stopped pub fn connect(&mut self) { let (tx, mut rx) = mpsc::unbounded::(); - self.bridge=Some(tx); + self.bridge = Some(tx); let port = self.port; let inbox = self.incoming.clone(); let is_host = self.is_host; - thread::spawn(move ||async_std::task::block_on(async { - let local_key = identity::Keypair::generate_ed25519(); - let local_peer_id = PeerId::from(local_key.public()); + thread::spawn(move || { + async_std::task::block_on(async { + let local_key = identity::Keypair::generate_ed25519(); + let local_peer_id = PeerId::from(local_key.public()); - let transport = tcp::async_io::Transport::new(tcp::Config::default().nodelay(true)) - .upgrade(upgrade::Version::V1) - .authenticate( - noise::NoiseAuthenticated::xx(&local_key) - .expect("Signing libp2p-noise static DH keypair failed."), - ) - .multiplex(mplex::MplexConfig::new()) - .boxed(); + let transport = tcp::async_io::Transport::new(tcp::Config::default().nodelay(true)) + .upgrade(upgrade::Version::V1) + .authenticate(libp2p::noise::Config::new(&local_key).unwrap()) + .multiplex(MplexConfig::new()) + .boxed(); - // To content-address message, we can take the hash of message and use it as an ID. - let message_id_fn = |message: &gossipsub::Message| { - let mut s = DefaultHasher::new(); - message.data.hash(&mut s); - gossipsub::MessageId::from(s.finish().to_string()) - }; + // To content-address message, we can take the hash of message and use it as an ID. + let message_id_fn = |message: &gossipsub::Message| { + let mut s = DefaultHasher::new(); + message.data.hash(&mut s); + gossipsub::MessageId::from(s.finish().to_string()) + }; - // Set a custom gossipsub configuration - let gossipsub_config = gossipsub::ConfigBuilder::default() - .heartbeat_interval(Duration::from_secs(10)) // This is set to aid debugging by not cluttering the log space - .validation_mode(gossipsub::ValidationMode::Strict) // This sets the kind of message validation. The default is Strict (enforce message signing) - .message_id_fn(message_id_fn) // content-address messages. No two messages of the same content will be propagated. - .build() - .expect("Valid config"); + // Set a custom gossipsub configuration + let gossipsub_config = gossipsub::ConfigBuilder::default() + .heartbeat_interval(Duration::from_secs(10)) // This is set to aid debugging by not cluttering the log space + .validation_mode(gossipsub::ValidationMode::Strict) // This sets the kind of message validation. The default is Strict (enforce message signing) + .message_id_fn(message_id_fn) // content-address messages. No two messages of the same content will be propagated. + .build() + .expect("Valid config"); - let mut gossipsub = gossipsub::Behaviour::new( - gossipsub::MessageAuthenticity::Signed(local_key), - gossipsub_config, - ) + let mut gossipsub = gossipsub::Behaviour::new( + gossipsub::MessageAuthenticity::Signed(local_key), + gossipsub_config, + ) .expect("Correct configuration"); - // Create a topic - let topic = gossipsub::IdentTopic::new(TOPIC); - gossipsub.subscribe(&topic); + // Create a topic + let topic = gossipsub::IdentTopic::new(TOPIC); + let _ = gossipsub.subscribe(&topic); - // Create a Swarm to manage peers and events - let mut swarm = { - let mdns = mdns::Behaviour::new(mdns::Config::default(), local_peer_id).unwrap(); + // Create a Swarm to manage peers and events + let mut swarm = { + let mdns = + mdns::Behaviour::new(mdns::Config::default(), local_peer_id).unwrap(); - let behaviour = PeerBehaviour { - gossipsub, - mdns, - keep_alive: Default::default() + let behaviour = PeerBehaviour { + gossipsub, + mdns, + keep_alive: Default::default(), + }; + SwarmBuilder::with_async_std_executor(transport, behaviour, local_peer_id) + .build() }; - Swarm::with_async_std_executor(transport, behaviour, local_peer_id) - }; - // Listen on all interfaces and whatever port the OS assigns - quad_rand::srand(SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs()); - let port = port.unwrap_or(quad_rand::gen_range(4000, 9999)); - println!("Setting up port {}", port); - swarm.listen_on( - format!( - "/ip4/0.0.0.0/tcp/{}",port) - .parse() - .expect("Failed to parse provided port")) - .expect("Failed to start p2p network"); + // Listen on all interfaces and whatever port the OS assigns + quad_rand::srand( + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(), + ); + let port = port.unwrap_or(quad_rand::gen_range(4000, 9999)); + println!("Setting up port {}", port); + swarm + .listen_on( + format!("/ip4/0.0.0.0/tcp/{}", port) + .parse() + .expect("Failed to parse provided port"), + ) + .expect("Failed to start p2p network"); - loop { - select!{ - bridge_event = rx.select_next_some() => match bridge_event { - ChannelEvent::Action(act) => { - let json = act.serialize_json(); - swarm - .behaviour_mut() - .gossipsub - .publish(topic.clone(), json.as_bytes()); + loop { + select! { + bridge_event = rx.select_next_some() => match bridge_event { + ChannelEvent::Action(act) => { + let json = act.serialize_json(); + let _ = swarm + .behaviour_mut() + .gossipsub + .publish(topic.clone(), json.as_bytes()); + }, + ChannelEvent::Quit => break, }, - ChannelEvent::Quit => break, - }, - event = swarm.select_next_some() => match event { - SwarmEvent::NewListenAddr { address, .. } => { - println!("Listening on {:?}", address); - } - SwarmEvent::Behaviour(PeerBehaviourEvent::Gossipsub( - gossipsub::Event::Message{ - propagation_source: _, - message_id: _, - message + event = swarm.select_next_some() => match event { + SwarmEvent::NewListenAddr { address, .. } => { + println!("Listening on {:?}", address); } - )) => { - // parse incoming action - let text = String::from_utf8_lossy(&message.data); - if let Ok(act) = GameAction::deserialize_json(&text) { - // hand on act to game instance - let may_process = if is_host { - match act { - GameAction::TransmitWorld(_) => false, - _ => true + SwarmEvent::Behaviour(PeerBehaviourEvent::Gossipsub( + gossipsub::Event::Message{ + propagation_source: _, + message_id: _, + message + } + )) => { + // parse incoming action + let text = String::from_utf8_lossy(&message.data); + if let Ok(act) = GameAction::deserialize_json(&text) { + // hand on act to game instance + let may_process = if is_host { + !matches!(act, GameAction::TransmitWorld(_)) + } else { + !matches!(act, GameAction::RequestWorld) + }; + + if may_process { + println!("Adding act to queue"); + inbox.write().unwrap().push(act); } - } else { - match act { - GameAction::RequestWorld => false, - _ => true + } + }, + SwarmEvent::Behaviour(PeerBehaviourEvent::Gossipsub( + gossipsub::Event::Subscribed {..} + )) => { + println!("Subscribed"); + // ask game to broadcast world map and inventory + // game should then send ChannelEvent::Action as quickly as possible + if !is_host { + // request data + // in case host lost the request + { + let act = GameAction::RequestWorld; + let json = act.serialize_json(); + let _ = swarm + .behaviour_mut() + .gossipsub + .publish(topic.clone(), json.as_bytes()); } - }; - - if may_process { - println!("Adding act to queue"); - inbox.write().unwrap().push(act); } - } - }, - SwarmEvent::Behaviour(PeerBehaviourEvent::Gossipsub( - gossipsub::Event::Subscribed {..} - )) => { - println!("Subscribed"); - // ask game to broadcast world map and inventory - // game should then send ChannelEvent::Action as quickly as possible - if !is_host { - // request data - // in case host lost the request - { - let act = GameAction::RequestWorld; - let json = act.serialize_json(); + }, + SwarmEvent::Behaviour(PeerBehaviourEvent::Mdns( + mdns::Event::Discovered(list) + )) => { + for (peer, _) in list { + println!("Discovered {:?}", peer); swarm .behaviour_mut() .gossipsub - .publish(topic.clone(), json.as_bytes()); + .add_explicit_peer(&peer); } } - }, - SwarmEvent::Behaviour(PeerBehaviourEvent::Mdns( - mdns::Event::Discovered(list) - )) => { - for (peer, _) in list { - println!("Discovered {:?}", peer); - swarm - .behaviour_mut() - .gossipsub - .add_explicit_peer(&peer); - } - } - SwarmEvent::Behaviour(PeerBehaviourEvent::Mdns( - mdns::Event::Expired( - list - ))) => { - for (peer, _) in list { - println!("Disconnected {:?}", peer); - if !swarm.behaviour_mut().mdns.has_node(&peer) { - swarm - .behaviour_mut() - .gossipsub - .remove_explicit_peer(&peer); + SwarmEvent::Behaviour(PeerBehaviourEvent::Mdns( + mdns::Event::Expired( + list + ))) => { + for (peer, _) in list { + println!("Disconnected {:?}", peer); + if !swarm.behaviour_mut().mdns.has_node(&peer) { + swarm + .behaviour_mut() + .gossipsub + .remove_explicit_peer(&peer); + } } - } - }, - // ping events can be ignored - _ => {} + }, + // ping events can be ignored + _ => {} + } } } - } - })); + }) + }); } } diff --git a/src/screens/build.rs b/src/screens/build.rs index a66b0b2..ed26e5b 100644 --- a/src/screens/build.rs +++ b/src/screens/build.rs @@ -1,29 +1,17 @@ -use macroquad::prelude::*; -use crate::textures::AssetStore; +use super::Screen; use crate::game::{ - GameComponent, - GameEvent, + blocks::{Block, Category, Face}, inventory::Inventory, - blocks::{Face, Block, Category}, + types::{Direction, Pos3}, world::World, - types::{ - Pos3, - Direction - }}; -use crate::ui::{ - ItemFrame, - ButtonEvent, - Widget, - CenteredText, - TextButton + GameComponent, GameEvent, }; -use super::Screen; +use crate::textures::AssetStore; +use crate::ui::{ButtonEvent, CenteredText, ItemFrame, TextButton, Widget}; +use macroquad::prelude::*; #[cfg(feature = "multiplayer")] -use crate::p2p::{ - Peer, - GameAction -}; +use crate::p2p::{GameAction, Peer}; /// image width pub const TEXTURE_WIDTH: f32 = 256.0; @@ -49,15 +37,11 @@ fn get_screen_coords(pos: &Pos3, scale: f32, center: (f32, f32)) -> (f32, f32) { let dx = pos.y - pos.x; let dy = pos.y + pos.x; - let x = screen_width() / 2.0 - + dx as f32 * w_i / 2.0 - + center.0 - - width / 2.0; - let y = (pos.z as f32).mul_add(-h_i, screen_height() / 2.0 + dy as f32 * h_i / 2.0) - + center.1 + let x = screen_width() / 2.0 + dx as f32 * w_i / 2.0 + center.0 - width / 2.0; + let y = (pos.z as f32).mul_add(-h_i, screen_height() / 2.0 + dy as f32 * h_i / 2.0) + center.1 - height / 2.0; - (x,y) + (x, y) } struct InventoryWidgets { @@ -76,7 +60,7 @@ struct InventoryWidgets { /// and on how many slots to draw per page /// see SLOTS_PER_PAGE for more page: usize, - pub shown: bool + pub shown: bool, } impl InventoryWidgets { fn new() -> Self { @@ -87,11 +71,9 @@ impl InventoryWidgets { ItemFrame::new(0.35, 0.35, size), ItemFrame::new(0.5, 0.35, size), ItemFrame::new(0.65, 0.35, size), - ItemFrame::new(0.35, 0.5, size), ItemFrame::new(0.5, 0.5, size), ItemFrame::new(0.65, 0.5, size), - ItemFrame::new(0.35, 0.65, size), ItemFrame::new(0.5, 0.65, size), ItemFrame::new(0.65, 0.65, size), @@ -99,7 +81,7 @@ impl InventoryWidgets { widget_back: TextButton::new("Back", 0.2, 0.2), widget_categories: TextButton::new("All", 0.8, 0.2), widget_page_indicator: CenteredText::new("0", 0.5, 0.8), - page: 0 + page: 0, } } /// loads the first page for the last used category @@ -108,21 +90,20 @@ impl InventoryWidgets { } /// loads a new category fn load_category(&mut self, cat: Category, inv: &mut Inventory) { - let page = if inv.category != cat { - 0 - } else { self.page }; + let page = if inv.category != cat { 0 } else { self.page }; inv.category = cat; 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); - self.widget_page_indicator.set_text(&format!("{}/{}", self.page+1, page_count)); - self.widget_categories.set_text(&format!("{title}")); + self.widget_page_indicator + .set_text(&format!("{}/{}", self.page + 1, page_count)); + self.widget_categories.set_text(title); self.load_page(page, inv); } /// loads the entries of the given page in the current category - fn load_page(&mut self, page: usize, inv: &mut Inventory) { + 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); @@ -134,21 +115,22 @@ impl InventoryWidgets { slot.empty(); } } - self.widget_page_indicator.set_text(&format!("{}/{}", self.page+1, max_page)); + self.widget_page_indicator + .set_text(&format!("{}/{}", self.page + 1, max_page)); } /// go one page down - fn page_down(&mut self, inv: &mut Inventory) { + fn page_down(&mut self, inv: &Inventory) { let list = inv.category.get_blocks(); let mut page = self.page; if page > 0 { page -= 1; } else { - page = list.len().div_ceil(9)-1; + page = list.len().div_ceil(9) - 1; } self.load_page(page, inv); } /// go one page up - fn page_up(&mut self, inv: &mut Inventory) { + 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); @@ -170,21 +152,21 @@ pub struct BuildScreen { /// where the mouse is currently at mouse_position: Option<(f32, f32)>, /// the p2p backend used for multiplayer mode - #[cfg(feature="multiplayer")] + #[cfg(feature = "multiplayer")] multiplayer: Option, /// indicator widget showing the currently selected item and its orientation item_indicator_widget: ItemFrame, /// show the inventory popup - inventory_widgets: InventoryWidgets + inventory_widgets: InventoryWidgets, } impl BuildScreen { /// attempts to load a world from disk pub fn from_disk(file_name: &str) -> Option { World::from_disk(file_name).map(|world| Self { - world: Some(world), - file_name: Some(file_name.to_string()), - ..Self::empty() - }) + world: Some(world), + file_name: Some(file_name.to_string()), + ..Self::empty() + }) } /// create a new empty world pub fn new(file_name: &str, sandbox: bool) -> Self { @@ -201,10 +183,10 @@ impl BuildScreen { world: None, mouse_position: None, file_name: None, - #[cfg(feature="multiplayer")] + #[cfg(feature = "multiplayer")] multiplayer: None, item_indicator_widget: ItemFrame::new(0.95, 0.05, 0.05), - inventory_widgets: InventoryWidgets::new() + inventory_widgets: InventoryWidgets::new(), } } /// Creates an empty build screen @@ -212,7 +194,7 @@ impl BuildScreen { /// when the World transmission is received, /// the build screen will be upgraded /// to a room with map - #[cfg(feature="multiplayer")] + #[cfg(feature = "multiplayer")] pub fn join() -> Self { Self { multiplayer: Some(Peer::client()), @@ -226,8 +208,8 @@ impl BuildScreen { } /// Launch an existing build screen in game host mode /// initializes the p2p backend - #[cfg(feature="multiplayer")] - pub fn as_host(self) -> Self { + #[cfg(feature = "multiplayer")] + pub fn with_host_mode(self) -> Self { Self { multiplayer: Some(Peer::host()), ..self @@ -246,7 +228,10 @@ impl GameComponent for BuildScreen { slot.draw(assets).await; } - self.inventory_widgets.widget_page_indicator.draw(assets).await; + self.inventory_widgets + .widget_page_indicator + .draw(assets) + .await; return; } @@ -260,25 +245,25 @@ impl GameComponent for BuildScreen { let width = TEXTURE_WIDTH * world.cam.scale; let height = TEXTURE_HEIGHT * world.cam.scale; - let (x,y) = get_screen_coords(pos, world.cam.scale, world.cam.center); - - if x >= -width && x <= screen_width() - && y >= -height && y <= screen_height() { - // render block - draw_texture_ex( - texture, - x, - y, - WHITE, - DrawTextureParams { - dest_size: Some(Vec2::new(width, height)), - source: None, - rotation: 0.0, - flip_x: false, - flip_y: false, - pivot: Some(Vec2::new(width / 2.0, height / 2.0)) - }); - } + let (x, y) = get_screen_coords(pos, world.cam.scale, world.cam.center); + + if x >= -width && x <= screen_width() && y >= -height && y <= screen_height() { + // render block + draw_texture_ex( + texture, + x, + y, + WHITE, + DrawTextureParams { + dest_size: Some(Vec2::new(width, height)), + source: None, + rotation: 0.0, + flip_x: false, + flip_y: false, + pivot: Some(Vec2::new(width / 2.0, height / 2.0)), + }, + ); + } } // Draw selected item (top right) @@ -289,202 +274,211 @@ impl GameComponent for BuildScreen { if let Some(world) = &mut self.world { if self.inventory_widgets.shown { // process input - match self.inventory_widgets.widget_back.ev_loop() { - ButtonEvent::LeftClick => { - self.inventory_widgets.shown = false; - } - _ => () + if let ButtonEvent::LeftClick = self.inventory_widgets.widget_back.ev_loop() { + self.inventory_widgets.shown = false; } - if is_key_pressed(KeyCode::Q) || is_key_pressed(KeyCode::Escape) || is_key_pressed(KeyCode::I) { + if is_key_pressed(KeyCode::Q) + || is_key_pressed(KeyCode::Escape) + || is_key_pressed(KeyCode::I) + { self.inventory_widgets.shown = false; } if is_key_pressed(KeyCode::Left) { - self.inventory_widgets.page_down(&mut world.inventory); + self.inventory_widgets.page_down(&world.inventory); } if is_key_pressed(KeyCode::Right) { - self.inventory_widgets.page_up(&mut world.inventory); + self.inventory_widgets.page_up(&world.inventory); } - match self.inventory_widgets.widget_categories.ev_loop() { - ButtonEvent::LeftClick => { - // change category - let categories = Category::all(); - let current = &world.inventory.category; - let index = categories.iter().position(|c| &c == ¤t).unwrap(); - if index + 1 >= categories.len() { - self.inventory_widgets.load_category( - categories.get(0).unwrap().clone(), - &mut world.inventory - ); - } else { - self.inventory_widgets.load_category( - categories.get(index+1).unwrap().clone(), - &mut world.inventory - ); - } + if let ButtonEvent::LeftClick = self.inventory_widgets.widget_categories.ev_loop() { + // change category + let categories = Category::all(); + let current = &world.inventory.category; + let index = categories.iter().position(|c| c == current).unwrap(); + if index + 1 >= categories.len() { + self.inventory_widgets.load_category( + categories.get(0).unwrap().clone(), + &mut world.inventory, + ); + } else { + self.inventory_widgets.load_category( + categories.get(index + 1).unwrap().clone(), + &mut world.inventory, + ); } - _ => () } for (i, slot) in self.inventory_widgets.widgets_slots.iter_mut().enumerate() { slot.update_dir(&world.inventory.direction); - match slot.ev_loop() { - ButtonEvent::LeftClick => { - // user selected block - let items = world.inventory.category.get_blocks(); - if let Some(block) = items.get(self.inventory_widgets.page * 9 + i) { - world.inventory.selected = Some(block.clone()); - self.inventory_widgets.shown = false; - } - }, - _ => () + if let ButtonEvent::LeftClick = slot.ev_loop() { + // user selected block + let items = world.inventory.category.get_blocks(); + if let Some(block) = items.get(self.inventory_widgets.page * 9 + i) { + world.inventory.selected = Some(block.clone()); + self.inventory_widgets.shown = false; + } } } - } else { // process inventory events if is_key_down(KeyCode::I) { // open inventory self.inventory_widgets.shown = true; - self.inventory_widgets.load_current_category(&mut world.inventory); + self.inventory_widgets + .load_current_category(&mut world.inventory); } - match self.item_indicator_widget.ev_loop() { - ButtonEvent::LeftClick => { - // open inventory - self.inventory_widgets.shown = true; - self.inventory_widgets.load_current_category(&mut world.inventory); - } - _ => () + if let ButtonEvent::LeftClick = self.item_indicator_widget.ev_loop() { + // open inventory + self.inventory_widgets.shown = true; + self.inventory_widgets + .load_current_category(&mut world.inventory); } // update the top-right item indicator { let amount = if let Some(block) = &world.inventory.selected { world.inventory.contents.get(block).copied() - } else { None }; - self.item_indicator_widget.update(&world.inventory.selected, &world.inventory.direction, &amount); + } else { + None + }; + self.item_indicator_widget.update( + &world.inventory.selected, + &world.inventory.direction, + &amount, + ); } if is_mouse_button_pressed(MouseButton::Left) - || is_mouse_button_pressed(MouseButton::Right) { - - // determine which block / side was clicked - let (mx, my) = mouse_position(); - - // virtual render cycle - let render_order: Vec<(&Pos3, &(Block, Direction))> = world.grid.iter().collect(); - - // list of positions in render que for given pixel - // (mx, my) - let mut in_path:Vec<&Pos3> = Vec::new(); - - for (pos, _) in &render_order { - let (x,y) = get_screen_coords(pos, world.cam.scale, world.cam.center); - - if mx >= x - && mx <= TEXTURE_WIDTH.mul_add(world.cam.scale, x) - && my >= TEXTURE_Y_WHITESPACE.mul_add(world.cam.scale, y) - && my <= TEXTURE_HEIGHT.mul_add(world.cam.scale, y) { - - // check if mouse is above transparent area - // and skip block if necessary - if Face::from_xy(mx-x, my-y, world.cam.scale).is_none() { - continue; - } + || is_mouse_button_pressed(MouseButton::Right) + { + // determine which block / side was clicked + let (mx, my) = mouse_position(); + + // virtual render cycle + let render_order: Vec<(&Pos3, &(Block, Direction))> = + world.grid.iter().collect(); + + // list of positions in render que for given pixel + // (mx, my) + let mut in_path: Vec<&Pos3> = Vec::new(); + + for (pos, _) in &render_order { + let (x, y) = get_screen_coords(pos, world.cam.scale, world.cam.center); + + if mx >= x + && mx <= TEXTURE_WIDTH.mul_add(world.cam.scale, x) + && my >= TEXTURE_Y_WHITESPACE.mul_add(world.cam.scale, y) + && my <= TEXTURE_HEIGHT.mul_add(world.cam.scale, y) + { + // check if mouse is above transparent area + // and skip block if necessary + if Face::from_xy(mx - x, my - y, world.cam.scale).is_none() { + continue; + } - // block in mouse path - in_path.push(pos); - } + // block in mouse path + in_path.push(pos); } - // weight axis - in_path.sort_by(|p1, p2| p1.cmp(p2)); - if let Some(pos) = in_path.last() { - // position of clicked block - // because it is the last block in de render queue - // for a given pixel - let mut pos = Pos3::new(pos.x, pos.y, pos.z); - - if is_key_down(KeyCode::LeftControl) { - if let Some(block) = world.grid.get_mut(&pos) { - if is_mouse_button_pressed(MouseButton::Left) { - // rotate block CCW - block.1 = block.1.rotate_ccw(); - } else if is_mouse_button_pressed(MouseButton::Right) { - // rotate block CW - block.1 = block.1.rotate_cw(); - } + } + // weight axis + in_path.sort_by(|p1, p2| p1.cmp(p2)); + if let Some(pos) = in_path.last() { + // position of clicked block + // because it is the last block in de render queue + // for a given pixel + let mut pos = Pos3::new(pos.x, pos.y, pos.z); + + if is_key_down(KeyCode::LeftControl) { + if let Some(block) = world.grid.get_mut(&pos) { + if is_mouse_button_pressed(MouseButton::Left) { + // rotate block CCW + block.1 = block.1.rotate_ccw(); + } else if is_mouse_button_pressed(MouseButton::Right) { + // rotate block CW + block.1 = block.1.rotate_cw(); } - } else { - if is_mouse_button_pressed(MouseButton::Right) { - // if grid has only one block - // the block can not be removed - // because the palyer would not be able to place - // new blocks if no block exists - if world.grid.len() > 1 { - - // destroy block - if let Some((block, _)) = world.destroy_block(&pos) { - // transmit block destruction - // if multiplayer mode enabled - #[cfg(feature = "multiplayer")] - #[cfg(feature = "multiplayer")] - if let Some(mp) = &mut self.multiplayer { - mp.perform_action(GameAction::RemoveBlock(pos.clone(), block)); - } + } + } else { + if is_mouse_button_pressed(MouseButton::Right) { + // if grid has only one block + // the block can not be removed + // because the palyer would not be able to place + // new blocks if no block exists + if world.grid.len() > 1 { + // destroy block + if let Some((block, _)) = world.destroy_block(&pos) { + // transmit block destruction + // if multiplayer mode enabled + #[cfg(feature = "multiplayer")] + #[cfg(feature = "multiplayer")] + if let Some(mp) = &mut self.multiplayer { + mp.perform_action(GameAction::RemoveBlock( + pos.clone(), + block, + )); } } } + } - if is_mouse_button_pressed(MouseButton::Left) { - // place block - let (x,y) = get_screen_coords(&pos, world.cam.scale, world.cam.center); - let face = Face::from_xy(mx-x, my-y, world.cam.scale); - - // invert coordinate when left shift is pressed - // allows placing blocks below & behind other block - let factor = if is_key_down(KeyCode::LeftShift) { - -1 - } else { - 1 - }; - - match face.unwrap() { - Face::Top => { - pos.z+=factor; - }, - Face::Left => { - pos.x+=factor; - }, - Face::Right => { - pos.y+=factor; - } + if is_mouse_button_pressed(MouseButton::Left) { + // place block + let (x, y) = + get_screen_coords(&pos, world.cam.scale, world.cam.center); + let face = Face::from_xy(mx - x, my - y, world.cam.scale); + + // invert coordinate when left shift is pressed + // allows placing blocks below & behind other block + let factor = if is_key_down(KeyCode::LeftShift) { + -1 + } else { + 1 + }; + + match face.unwrap() { + Face::Top => { + pos.z += factor; } + Face::Left => { + pos.x += factor; + } + Face::Right => { + pos.y += factor; + } + } - if let Some(block) = &world.inventory.selected.clone() { - if world.place_block(&pos, block.clone(), world.inventory.direction.clone()) { - - // transmit block placement - // if multiplayer mode enabled - #[cfg(feature = "multiplayer")] - if let Some(mp) = &mut self.multiplayer { - mp.perform_action(GameAction::PlaceBlock(pos, block.clone(), world.inventory.direction.clone())); - } + if let Some(block) = &world.inventory.selected.clone() { + if world.place_block( + &pos, + block.clone(), + world.inventory.direction.clone(), + ) { + // transmit block placement + // if multiplayer mode enabled + #[cfg(feature = "multiplayer")] + if let Some(mp) = &mut self.multiplayer { + mp.perform_action(GameAction::PlaceBlock( + pos, + block.clone(), + world.inventory.direction.clone(), + )); } } } } } } + } // zoom with Ctrl-MouseWheel if is_key_down(KeyCode::LeftControl) { let mut scale = world.cam.scale; let (_, wy) = mouse_wheel(); - scale += wy * 1.0/10.0; + scale += wy * 1.0 / 10.0; if scale > 0.05 && scale < 6.0 { world.cam.scale = scale; @@ -492,22 +486,22 @@ impl GameComponent for BuildScreen { } else { let (mx, my) = mouse_wheel(); - world.cam.center.0 += mx * 5.0 * (1.0/world.cam.scale); - world.cam.center.1 += my * 5.0 * (1.0/world.cam.scale); + world.cam.center.0 += mx * 5.0 * (1.0 / world.cam.scale); + world.cam.center.1 += my * 5.0 * (1.0 / world.cam.scale); } // keyboard control if is_key_down(KeyCode::Down) { - world.cam.center.1 -= 1.0 * (1.0/world.cam.scale); + world.cam.center.1 -= 1.0 * (1.0 / world.cam.scale); } if is_key_down(KeyCode::Up) { - world.cam.center.1 += 1.0 * (1.0/world.cam.scale); + world.cam.center.1 += 1.0 * (1.0 / world.cam.scale); } if is_key_down(KeyCode::Left) { - world.cam.center.0 += 1.0 * (1.0/world.cam.scale); + world.cam.center.0 += 1.0 * (1.0 / world.cam.scale); } if is_key_down(KeyCode::Right) { - world.cam.center.0 -= 1.0 * (1.0/world.cam.scale); + world.cam.center.0 -= 1.0 * (1.0 / world.cam.scale); } if is_key_down(KeyCode::C) { world.cam.center = (0.0, 0.0); @@ -515,7 +509,6 @@ impl GameComponent for BuildScreen { if is_mouse_button_down(MouseButton::Middle) { let (nx, ny) = mouse_position(); if let Some((ox, oy)) = self.mouse_position { - let dx = nx - ox; let dy = ny - oy; @@ -531,24 +524,24 @@ impl GameComponent for BuildScreen { // save the world if is_key_pressed(KeyCode::S) || is_key_pressed(KeyCode::Q) - || is_key_pressed(KeyCode::Escape) { - // save game - - if let Some(file_name) = &self.file_name { - world.to_disk(file_name); - } - - if is_key_pressed(KeyCode::Q) || is_key_pressed(KeyCode::Escape) { + || is_key_pressed(KeyCode::Escape) + { + // save game - #[cfg(feature = "multiplayer")] - if let Some(mp) = &mut self.multiplayer { - mp.close(); - } + if let Some(file_name) = &self.file_name { + world.to_disk(file_name); + } - // close game - return GameEvent::ChangeScreen(Screen::default()); + if is_key_pressed(KeyCode::Q) || is_key_pressed(KeyCode::Escape) { + #[cfg(feature = "multiplayer")] + if let Some(mp) = &mut self.multiplayer { + mp.close(); } + + // close game + return GameEvent::ChangeScreen(Screen::default()); } + } } // change block direction @@ -569,12 +562,15 @@ impl GameComponent for BuildScreen { } } else { // game has no world - if is_key_pressed(KeyCode::Q) || is_key_pressed(KeyCode::Escape) || is_key_pressed(KeyCode::I) { + if is_key_pressed(KeyCode::Q) + || is_key_pressed(KeyCode::Escape) + || is_key_pressed(KeyCode::I) + { return GameEvent::Quit; } } - #[cfg(feature="multiplayer")] + #[cfg(feature = "multiplayer")] { // maybe user is waiting in lobby // still check for p2p connections @@ -585,24 +581,23 @@ impl GameComponent for BuildScreen { match task { GameAction::RequestWorld => { if let Some(world) = &mut self.world { - mp.perform_action( - GameAction::TransmitWorld(world.clone())); + mp.perform_action(GameAction::TransmitWorld(world.clone())); } - }, + } GameAction::PlaceBlock(pos, block, dir) => { if let Some(world) = &mut self.world { // remove block from inventory world.place_block(&pos, block, dir); } - }, + } GameAction::RemoveBlock(pos, _block) => { if let Some(world) = &mut self.world { world.destroy_block(&pos); } - }, + } GameAction::TransmitWorld(world) => { self.upgrade(world); - }, + } } } } diff --git a/src/screens/map_creator.rs b/src/screens/map_creator.rs index fa5c816..9f6ca13 100644 --- a/src/screens/map_creator.rs +++ b/src/screens/map_creator.rs @@ -1,20 +1,11 @@ -use macroquad::prelude::*; -use crate::game::{ - GameComponent, - GameEvent, - world::World -}; -use crate::textures::AssetStore; -use super::map_select::SelectScreen; use super::build::BuildScreen; +use super::map_select::SelectScreen; use super::Screen; +use crate::game::{world::World, GameComponent, GameEvent}; +use crate::textures::AssetStore; +use macroquad::prelude::*; -use crate::ui::{ - TextButton, - Widget, - ButtonEvent, - SelectableText -}; +use crate::ui::{ButtonEvent, SelectableText, TextButton, Widget}; /// The welcome screen pub struct MapCreatorScreen { @@ -27,7 +18,7 @@ pub struct MapCreatorScreen { /// and return to world list widget_create: TextButton, /// String contianing the world name - name: String + name: String, } impl MapCreatorScreen { /// create a new World creation Screen instance @@ -37,31 +28,37 @@ impl MapCreatorScreen { .with_font_size(50) .with_font_color(LIGHTGRAY), widget_container: SelectableText::new("type here...", 0.5, 0.5), - widget_create: TextButton::new("Create", 0.7, 0.7) - .with_font_size(40), - name: String::new() + widget_create: TextButton::new("Create", 0.7, 0.7).with_font_size(40), + name: String::new(), } } } impl GameComponent for MapCreatorScreen { async fn draw(&self, assets: &AssetStore) { - { // draw background image let dim: f32 = if screen_width() < screen_height() { - screen_width() * 2.0/3.0 - } else { screen_height() * 2.0/3.0 }; + screen_width() * 2.0 / 3.0 + } else { + screen_height() * 2.0 / 3.0 + }; draw_texture_ex( assets.icon, - screen_width()/2.0 - dim/2.0, - screen_height()/2.0 - dim/2.0, + screen_width() / 2.0 - dim / 2.0, + screen_height() / 2.0 - dim / 2.0, WHITE, DrawTextureParams { dest_size: Some(Vec2::new(dim, dim)), ..Default::default() - } + }, + ); + draw_rectangle( + 0.0, + 0.0, + screen_width(), + screen_height(), + Color::from_rgba(0, 0, 0, 100), ); - draw_rectangle(0.0, 0.0, screen_width(), screen_height(), Color::from_rgba(0, 0, 0, 100)); } self.widget_back.draw(assets).await; @@ -69,7 +66,6 @@ impl GameComponent for MapCreatorScreen { self.widget_container.draw(assets).await; } fn ev_loop(&mut self) -> GameEvent { - { // process text input if is_key_pressed(KeyCode::Backspace) { @@ -82,7 +78,6 @@ impl GameComponent for MapCreatorScreen { } } - if self.name.len() < 10 && is_key_pressed(KeyCode::A) { self.name.push('a'); self.widget_container.set_text(&self.name); @@ -189,32 +184,26 @@ impl GameComponent for MapCreatorScreen { } } - match self.widget_create.ev_loop() { - ButtonEvent::LeftClick => { - if !self.name.is_empty() && self.name.len() <= 10 { - let name = format!("{}.world", self.name); - if !World::get_list().contains(&name) { - let bscr = BuildScreen::new(&name, true); - if let Some(world) = bscr.world { - world.to_disk(&name); - } - return GameEvent::ChangeScreen(Screen::Select(SelectScreen::new())); + if let ButtonEvent::LeftClick = self.widget_create.ev_loop() { + if !self.name.is_empty() && self.name.len() <= 10 { + let name = format!("{}.world", self.name); + if !World::get_list().contains(&name) { + let bscr = BuildScreen::new(&name, true); + if let Some(world) = bscr.world { + world.to_disk(&name); } + return GameEvent::ChangeScreen(Screen::Select(SelectScreen::new())); } - }, - _ => () + } } - match self.widget_back.ev_loop() { - ButtonEvent::LeftClick => { - return GameEvent::ChangeScreen(Screen::default()) - } - _ => () + if let ButtonEvent::LeftClick = self.widget_back.ev_loop() { + return GameEvent::ChangeScreen(Screen::default()); } // return to welcome screen if is_key_pressed(KeyCode::Escape) { - return GameEvent::ChangeScreen(Screen::default()) + return GameEvent::ChangeScreen(Screen::default()); } GameEvent::None diff --git a/src/screens/map_select.rs b/src/screens/map_select.rs index 427fe79..57930c7 100644 --- a/src/screens/map_select.rs +++ b/src/screens/map_select.rs @@ -1,21 +1,8 @@ -use macroquad::prelude::*; -use crate::game::{ - GameComponent, - GameEvent, - world::World -}; +use super::{build::BuildScreen, map_creator::MapCreatorScreen, Screen}; +use crate::game::{world::World, GameComponent, GameEvent}; use crate::textures::AssetStore; -use crate::ui::{ - TextButton, - Widget, - ButtonEvent, - SelectableText -}; -use super::{ - Screen, - build::BuildScreen, - map_creator::MapCreatorScreen -}; +use crate::ui::{ButtonEvent, SelectableText, TextButton, Widget}; +use macroquad::prelude::*; /// The map select screen /// also allows creation of new maps @@ -40,7 +27,7 @@ pub struct SelectScreen { /// currently selected slot selected: Option, /// currently visible page - page: usize + page: usize, } impl SelectScreen { /// create a new `MapSelectorScreen` instance @@ -52,12 +39,9 @@ impl SelectScreen { .with_font_size(50) .with_font_color(LIGHTGRAY), #[cfg(feature = "multiplayer")] - widget_host: TextButton::new("Host", 0.35, 0.8) - .with_font_size(30), - widget_play: TextButton::new("Play", 0.65, 0.8) - .with_font_size(30), - widget_new: TextButton::new("New", 0.5, 0.8) - .with_font_size(30), + widget_host: TextButton::new("Host", 0.35, 0.8).with_font_size(30), + widget_play: TextButton::new("Play", 0.65, 0.8).with_font_size(30), + widget_new: TextButton::new("New", 0.5, 0.8).with_font_size(30), level_select_widgets: vec![ SelectableText::new(levels.get(0).unwrap_or(&"???".to_string()), 0.5, 0.4) .with_visibility(!levels.is_empty()), @@ -67,7 +51,7 @@ impl SelectScreen { .with_visibility(levels.len() >= 3), ], selected: None, - page: 0 + page: 0, } } } @@ -76,19 +60,27 @@ impl GameComponent for SelectScreen { { // draw background image let dim: f32 = if screen_width() < screen_height() { - screen_width() * 2.0/3.0 - } else { screen_height() * 2.0/3.0 }; + screen_width() * 2.0 / 3.0 + } else { + screen_height() * 2.0 / 3.0 + }; draw_texture_ex( assets.icon, - screen_width()/2.0 - dim/2.0, - screen_height()/2.0 - dim/2.0, + screen_width() / 2.0 - dim / 2.0, + screen_height() / 2.0 - dim / 2.0, WHITE, DrawTextureParams { dest_size: Some(Vec2::new(dim, dim)), ..Default::default() - } + }, + ); + draw_rectangle( + 0.0, + 0.0, + screen_width(), + screen_height(), + Color::from_rgba(0, 0, 0, 100), ); - draw_rectangle(0.0, 0.0, screen_width(), screen_height(), Color::from_rgba(0, 0, 0, 100)); } self.widget_back.draw(assets).await; @@ -103,63 +95,48 @@ impl GameComponent for SelectScreen { self.widget_play.draw(assets).await; } fn ev_loop(&mut self) -> GameEvent { - match self.widget_back.ev_loop() { - ButtonEvent::LeftClick => { - // return to welcome screen - return GameEvent::ChangeScreen(Screen::default()) - }, - _ => () + if let ButtonEvent::LeftClick = self.widget_back.ev_loop() { + // return to welcome screen + return GameEvent::ChangeScreen(Screen::default()); } #[cfg(feature = "multiplayer")] { - match self.widget_host.ev_loop() { - ButtonEvent::LeftClick => { - if let Some(file_name) = &self.selected { - if let Some(scr) = BuildScreen::from_disk(file_name) { - return GameEvent::ChangeScreen(Screen::Build(scr.as_host())); - } + if let ButtonEvent::LeftClick = self.widget_host.ev_loop() { + if let Some(file_name) = &self.selected { + if let Some(scr) = BuildScreen::from_disk(file_name) { + return GameEvent::ChangeScreen(Screen::Build(scr.with_host_mode())); } } - _ => () } } - match self.widget_new.ev_loop() { - ButtonEvent::LeftClick => { - return GameEvent::ChangeScreen(Screen::Create(MapCreatorScreen::new())) - }, - _ => () + if let ButtonEvent::LeftClick = self.widget_new.ev_loop() { + return GameEvent::ChangeScreen(Screen::Create(MapCreatorScreen::new())); } - match self.widget_play.ev_loop() { - ButtonEvent::LeftClick => { - if let Some(file_name) = &self.selected { - if let Some(scr) = BuildScreen::from_disk(file_name) { - return GameEvent::ChangeScreen(Screen::Build(scr)); - } + if let ButtonEvent::LeftClick = self.widget_play.ev_loop() { + if let Some(file_name) = &self.selected { + if let Some(scr) = BuildScreen::from_disk(file_name) { + return GameEvent::ChangeScreen(Screen::Build(scr)); } } - _ => () } for slot in &mut self.level_select_widgets { slot.set_selected(false); - match slot.ev_loop() { - ButtonEvent::LeftClick => { - if let Some(sel) = &self.selected && sel == &slot.get_text() { - // already selected - // deselect - self.selected = None; - } else { - // user selected this item - self.selected = Some(slot.get_text().to_string()); - } - }, - _ => () + if let ButtonEvent::LeftClick = slot.ev_loop() { + if let Some(sel) = &self.selected && sel == slot.get_text() { + // already selected + // deselect + self.selected = None; + } else { + // user selected this item + self.selected = Some(slot.get_text().to_string()); + } } } if let Some(selection) = &self.selected { for slot in &mut self.level_select_widgets { - if &slot.get_text() == selection { + if slot.get_text() == selection { slot.set_selected(true); } } @@ -167,15 +144,18 @@ impl GameComponent for SelectScreen { // return to welcome screen if is_key_pressed(KeyCode::Q) || is_key_pressed(KeyCode::Escape) { - return GameEvent::ChangeScreen(Screen::default()) + return GameEvent::ChangeScreen(Screen::default()); } - if is_key_pressed(KeyCode::Down) && self.list.len() >= self.level_select_widgets.len() && self.page < self.list.len() - self.level_select_widgets.len() { + if is_key_pressed(KeyCode::Down) + && self.list.len() >= self.level_select_widgets.len() + && self.page < self.list.len() - self.level_select_widgets.len() + { self.page += 1; // update widget text for (i, slot) in self.level_select_widgets.iter_mut().enumerate() { - if let Some(text) = self.list.get(i+self.page) { + if let Some(text) = self.list.get(i + self.page) { slot.set_visibility(true); slot.set_text(text); } else { @@ -186,10 +166,9 @@ impl GameComponent for SelectScreen { if is_key_pressed(KeyCode::Up) && self.page > 0 { self.page -= 1; - // update widget text for (i, slot) in self.level_select_widgets.iter_mut().enumerate() { - if let Some(text) = self.list.get(i+self.page) { + if let Some(text) = self.list.get(i + self.page) { slot.set_visibility(true); slot.set_text(text); } else { diff --git a/src/screens/mod.rs b/src/screens/mod.rs index faa3b2d..19951e2 100644 --- a/src/screens/mod.rs +++ b/src/screens/mod.rs @@ -1,17 +1,14 @@ -mod welcome; pub mod build; -mod map_select; mod map_creator; +mod map_select; +mod welcome; -use welcome::WelcomeScreen; +use crate::game::{GameComponent, GameEvent}; +use crate::textures::AssetStore; use build::BuildScreen; -use map_select::SelectScreen; use map_creator::MapCreatorScreen; -use crate::textures::AssetStore; -use crate::game::{ - GameEvent, - GameComponent -}; +use map_select::SelectScreen; +use welcome::WelcomeScreen; /// Possible screens /// that can be shown diff --git a/src/screens/welcome.rs b/src/screens/welcome.rs index 754c30f..7a28b95 100644 --- a/src/screens/welcome.rs +++ b/src/screens/welcome.rs @@ -1,19 +1,11 @@ -use macroquad::prelude::*; -use crate::game::{ - GameComponent, - GameEvent -}; -use crate::textures::AssetStore; -use crate::ui::{ - TextButton, - CenteredText, - Widget, - ButtonEvent -}; -use super::map_select::SelectScreen; #[cfg(feature = "multiplayer")] use super::build::BuildScreen; +use super::map_select::SelectScreen; use super::Screen; +use crate::game::{GameComponent, GameEvent}; +use crate::textures::AssetStore; +use crate::ui::{ButtonEvent, CenteredText, TextButton, Widget}; +use macroquad::prelude::*; /// The welcome screen pub struct WelcomeScreen { @@ -32,40 +24,42 @@ impl WelcomeScreen { /// create a new `WelcomeScreen` instance pub fn new() -> Self { Self { - widget_title: CenteredText::new("LittleTown", 0.5,0.45) - .with_font_size(100), - widget_select: TextButton::new("Maps", 0.35, 0.55) - .with_font_size(40), + widget_title: CenteredText::new("LittleTown", 0.5, 0.45).with_font_size(100), + widget_select: TextButton::new("Maps", 0.35, 0.55).with_font_size(40), #[cfg(feature = "multiplayer")] - widget_join: TextButton::new("Join", 0.5, 0.55) - .with_font_size(40), - widget_quit: TextButton::new("Quit", 0.65, 0.55) - .with_font_size(40) + widget_join: TextButton::new("Join", 0.5, 0.55).with_font_size(40), + widget_quit: TextButton::new("Quit", 0.65, 0.55).with_font_size(40), } } } impl GameComponent for WelcomeScreen { async fn draw(&self, assets: &AssetStore) { - { // draw background image let dim: f32 = if screen_width() < screen_height() { - screen_width() * 2.0/3.0 - } else { screen_height() * 2.0/3.0 }; + screen_width() * 2.0 / 3.0 + } else { + screen_height() * 2.0 / 3.0 + }; draw_texture_ex( assets.icon, - screen_width()/2.0 - dim/2.0, - screen_height()/2.0 - dim/2.0, + screen_width() / 2.0 - dim / 2.0, + screen_height() / 2.0 - dim / 2.0, WHITE, DrawTextureParams { dest_size: Some(Vec2::new(dim, dim)), ..Default::default() - } + }, + ); + draw_rectangle( + 0.0, + 0.0, + screen_width(), + screen_height(), + Color::from_rgba(0, 0, 0, 100), ); - draw_rectangle(0.0, 0.0, screen_width(), screen_height(), Color::from_rgba(0, 0, 0, 100)); } - self.widget_title.draw(assets).await; self.widget_select.draw(assets).await; @@ -76,18 +70,15 @@ impl GameComponent for WelcomeScreen { fn ev_loop(&mut self) -> GameEvent { self.widget_title.ev_loop(); - match self.widget_select.ev_loop() { - ButtonEvent::LeftClick => return GameEvent::ChangeScreen(Screen::Select(SelectScreen::new())), - _ => () + if let ButtonEvent::LeftClick = self.widget_select.ev_loop() { + return GameEvent::ChangeScreen(Screen::Select(SelectScreen::new())); } #[cfg(feature = "multiplayer")] - match self.widget_join.ev_loop() { - ButtonEvent::LeftClick => return GameEvent::ChangeScreen(Screen::Build(BuildScreen::join())), - _ => () + if let ButtonEvent::LeftClick = self.widget_join.ev_loop() { + return GameEvent::ChangeScreen(Screen::Build(BuildScreen::join())); } - match self.widget_quit.ev_loop() { - ButtonEvent::LeftClick => return GameEvent::Quit, - _ => () + if let ButtonEvent::LeftClick = self.widget_quit.ev_loop() { + return GameEvent::Quit; } GameEvent::None diff --git a/src/textures.rs b/src/textures.rs index 25abc18..26e50c6 100644 --- a/src/textures.rs +++ b/src/textures.rs @@ -1,5 +1,5 @@ -use macroquad::prelude::*; use crate::game::types::Direction; +use macroquad::prelude::*; /// Collection of textures required by game pub struct AssetStore { @@ -13,7 +13,7 @@ pub struct UIAssetCollection { pub panel_brown: (Texture2D, Texture2D), pub arrow_left: Texture2D, pub arrow_right: Texture2D, - pub close_button: Texture2D + pub close_button: Texture2D, } #[derive(Clone)] pub struct DirectionalTexture { @@ -28,7 +28,7 @@ impl DirectionalTexture { Direction::North => self.north, Direction::South => self.south, Direction::East => self.east, - Direction::West => self.west + Direction::West => self.west, } } } @@ -36,24 +36,20 @@ impl DirectionalTexture { /// macro used to include png assets macro_rules! include_img_asset { ($name:literal) => { - Texture2D::from_image( - &Image::from_file_with_format( - include_bytes!(concat!("../assets/", $name)), - Some(ImageFormat::Png) - ) - ) + Texture2D::from_image(&Image::from_file_with_format( + include_bytes!(concat!("../assets/", $name)), + Some(ImageFormat::Png), + )) }; } /// macro used to include .png tiles from an asset pack macro_rules! include_tile { ($name:literal, $dir:literal) => { - Texture2D::from_image( - &Image::from_file_with_format( - include_bytes!(concat!("../../assets/", $name, "_", $dir, ".png")), - Some(ImageFormat::Png) - ) - ) + Texture2D::from_image(&Image::from_file_with_format( + include_bytes!(concat!("../../assets/", $name, "_", $dir, ".png")), + Some(ImageFormat::Png), + )) }; ($name:literal) => { DirectionalTexture { @@ -62,19 +58,17 @@ macro_rules! include_tile { east: include_tile!($name, "E"), west: include_tile!($name, "W"), } - } + }; } /// macro used to include ui elements /// from the ui asset pack macro_rules! include_ui_img { ($name:literal) => { - Texture2D::from_image( - &Image::from_file_with_format( - include_bytes!(concat!("../assets/ui/PNG/", $name, ".png")), - Some(ImageFormat::Png) - ) - ) + Texture2D::from_image(&Image::from_file_with_format( + include_bytes!(concat!("../assets/ui/PNG/", $name, ".png")), + Some(ImageFormat::Png), + )) }; } @@ -83,17 +77,26 @@ impl AssetStore { pub async fn init() -> Self { Self { icon: include_img_asset!("icon.png"), - font: load_ttf_font_from_bytes(include_bytes!("../assets/fonts/Fonts/Kenney Pixel.ttf")).expect("Failed to load font"), + font: load_ttf_font_from_bytes(include_bytes!( + "../assets/fonts/Fonts/Kenney Pixel.ttf" + )) + .expect("Failed to load font"), ui: UIAssetCollection { - long_button: (include_ui_img!("buttonLong_brown"), - include_ui_img!("buttonLong_brown_pressed")), - panel_blue: (include_ui_img!("panel_blue"), - include_ui_img!("panelInset_blue")), - panel_brown: (include_ui_img!("panel_brown"), - include_ui_img!("panelInset_brown")), + long_button: ( + include_ui_img!("buttonLong_brown"), + include_ui_img!("buttonLong_brown_pressed"), + ), + panel_blue: ( + include_ui_img!("panel_blue"), + include_ui_img!("panelInset_blue"), + ), + panel_brown: ( + include_ui_img!("panel_brown"), + include_ui_img!("panelInset_brown"), + ), arrow_left: include_ui_img!("arrowBrown_left"), arrow_right: include_ui_img!("arrowBrown_right"), - close_button: include_ui_img!("iconCross_brown") + close_button: include_ui_img!("iconCross_brown"), }, } } diff --git a/src/ui/centered_text.rs b/src/ui/centered_text.rs index 8e2fdaa..23f5a2d 100644 --- a/src/ui/centered_text.rs +++ b/src/ui/centered_text.rs @@ -1,6 +1,6 @@ -use macroquad::prelude::*; -use crate::textures::AssetStore; use super::Widget; +use crate::textures::AssetStore; +use macroquad::prelude::*; /// UI Widget /// used to draw centered text @@ -21,7 +21,7 @@ pub struct CenteredText { font: Option, /// text color /// defaults to white - color: Option + color: Option, } impl CenteredText { /// create new centered-text widget @@ -32,7 +32,7 @@ impl CenteredText { text: text.to_string(), font_size: None, font: None, - color: None + color: None, } } /// sets the font size @@ -68,7 +68,7 @@ impl CenteredText { impl Widget for CenteredText { type Event = bool; async fn draw(&self, _assets: &AssetStore) { - let (x,y) = (screen_width() * self.x, screen_height() * self.y); + let (x, y) = (screen_width() * self.x, screen_height() * self.y); let mut title_params = TextParams { font_size: self.font_size.unwrap_or(60), @@ -83,22 +83,21 @@ impl Widget for CenteredText { self.font, self.font_size.unwrap_or(60), 1.0, - 0.0); + 0.0, + ); draw_text_ex( &self.text, x - title_center.x, - y- title_center.y, - title_params); + y - title_center.y, + title_params, + ); } fn ev_loop(&mut self) -> Self::Event { true } fn get_dimensions(&self) -> (f32, f32) { - let text_dim: TextDimensions = measure_text( - &self.text, - self.font, - self.font_size.unwrap_or(60), - 1.0); + let text_dim: TextDimensions = + measure_text(&self.text, self.font, self.font_size.unwrap_or(60), 1.0); (text_dim.width, text_dim.height) } } diff --git a/src/ui/item_frame.rs b/src/ui/item_frame.rs index e6a1bac..1b2587b 100644 --- a/src/ui/item_frame.rs +++ b/src/ui/item_frame.rs @@ -1,8 +1,8 @@ -use macroquad::prelude::*; -use crate::textures::AssetStore; +use super::{ButtonEvent, CenteredText, Widget}; use crate::game::blocks::Block; use crate::game::types::Direction; -use super::{Widget, ButtonEvent, CenteredText}; +use crate::textures::AssetStore; +use macroquad::prelude::*; pub struct ItemFrame { /// middle of button (x axis) @@ -24,12 +24,11 @@ pub struct ItemFrame { /// widget used to display count widget_amount: CenteredText, /// the direciton the block is facing - direction: Direction + direction: Direction, } impl ItemFrame { - type Event = ButtonEvent; /// creates a new widget - pub fn new(x: f32, y:f32, size: f32) -> Self { + pub fn new(x: f32, y: f32, size: f32) -> Self { Self { x, y, @@ -38,8 +37,7 @@ impl ItemFrame { selected: false, block: None, direction: Direction::North, - widget_amount: CenteredText::new("", x, y) - .with_font_size(30) + widget_amount: CenteredText::new("", x, y).with_font_size(30), } } /// adds a block to the item frame @@ -83,7 +81,12 @@ impl ItemFrame { } /// update block, direction and amount in one go #[allow(dead_code)] - pub fn update(&mut self, selected: &Option, direction: &Direction, amount: &Option) { + pub fn update( + &mut self, + selected: &Option, + direction: &Direction, + amount: &Option, + ) { if let Some(block) = selected { self.block = Some(block.clone()); self.amount = Some(0); @@ -103,11 +106,15 @@ impl ItemFrame { impl Widget for ItemFrame { type Event = ButtonEvent; fn get_dimensions(&self) -> (f32, f32) { - let smallest = if screen_width() < screen_height() { screen_width() } else { screen_height() }; + let smallest = if screen_width() < screen_height() { + screen_width() + } else { + screen_height() + }; (self.size * smallest, self.size * smallest) } async fn draw(&self, assets: &AssetStore) { - let (x,y) = (screen_width() * self.x, screen_height() * self.y); + let (x, y) = (screen_width() * self.x, screen_height() * self.y); let (size, _) = self.get_dimensions(); let mut bg = assets.ui.panel_brown.0; @@ -119,47 +126,44 @@ impl Widget for ItemFrame { // draw background draw_texture_ex( bg, - x - size/2.0, - y - size/2.0, + x - size / 2.0, + y - size / 2.0, WHITE, DrawTextureParams { dest_size: Some(Vec2::new(size, size)), ..Default::default() - } + }, ); // draw brown foreground { - let scale = size/100.0; + let scale = size / 100.0; let dim = scale * 93.0; draw_texture_ex( assets.ui.panel_brown.1, - x - dim/2.0, - y - dim/2.0, + x - dim / 2.0, + y - dim / 2.0, WHITE, DrawTextureParams { dest_size: Some(Vec2::new(dim, dim)), ..Default::default() - } + }, ); } if let Some(block) = &self.block { // draw block - let width = size * 2.0/3.0; + let width = size * 2.0 / 3.0; let height = (width * 352.0) / 256.0; draw_texture_ex( block.get_texture().await.get_dir(&self.direction), x - width / 2.0, - y - (height * 238.0)/352.0, - + y - (height * 238.0) / 352.0, WHITE, DrawTextureParams { - dest_size: Some(Vec2::new( - width, - height)), + dest_size: Some(Vec2::new(width, height)), ..Default::default() - } + }, ); // draw amount self.widget_amount.draw(assets).await; @@ -169,17 +173,20 @@ impl Widget for ItemFrame { let (width, height) = self.get_dimensions(); let (mx, my) = mouse_position(); - let (x,y) = (screen_width() * self.x, screen_height() * self.y); + let (x, y) = (screen_width() * self.x, screen_height() * self.y); - if mx >= x - width/2.0 && mx <= x + width/2.0 - && my >= y - height/2.0 && my <= y + height/2.0 { - if is_mouse_button_pressed(MouseButton::Left) { - return Self::Event::LeftClick; - } - if is_mouse_button_pressed(MouseButton::Right) { - return Self::Event::RightClick; - } + if mx >= x - width / 2.0 + && mx <= x + width / 2.0 + && my >= y - height / 2.0 + && my <= y + height / 2.0 + { + if is_mouse_button_pressed(MouseButton::Left) { + return Self::Event::LeftClick; + } + if is_mouse_button_pressed(MouseButton::Right) { + return Self::Event::RightClick; } + } Self::Event::None } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 31deb94..aa8a8d0 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,5 +1,5 @@ -use macroquad::prelude::*; use crate::textures::AssetStore; +use macroquad::prelude::*; mod centered_text; mod item_frame; @@ -19,7 +19,7 @@ pub enum ButtonEvent { /// user clicked on button with left mouse button LeftClick, /// user clicked on button with right mouse button - RightClick + RightClick, } /// A UI item that can be rendered diff --git a/src/ui/selectable_text.rs b/src/ui/selectable_text.rs index 1bc2e35..b2f9921 100644 --- a/src/ui/selectable_text.rs +++ b/src/ui/selectable_text.rs @@ -1,6 +1,6 @@ -use macroquad::prelude::*; +use super::{ButtonEvent, Widget}; use crate::textures::AssetStore; -use super::{Widget, ButtonEvent}; +use macroquad::prelude::*; /// A widget similar to a button, /// but it can be selected @@ -24,7 +24,7 @@ pub struct SelectableText { /// true if widget option is selected selected: bool, /// if the widget is visible or not - visible: bool + visible: bool, } impl SelectableText { /// creates a new text button widget @@ -37,7 +37,7 @@ impl SelectableText { font_color: None, font_size: None, selected: false, - visible: true + visible: true, } } /// set the visibility @@ -96,19 +96,16 @@ impl SelectableText { impl Widget for SelectableText { type Event = ButtonEvent; fn get_dimensions(&self) -> (f32, f32) { - let text_dim: TextDimensions = measure_text( - &self.text, - self.font, - self.font_size.unwrap_or(60), - 1.0); - (text_dim.width + 30.0, text_dim.height+20.0) + let text_dim: TextDimensions = + measure_text(&self.text, self.font, self.font_size.unwrap_or(60), 1.0); + (text_dim.width + 30.0, text_dim.height + 20.0) } async fn draw(&self, assets: &AssetStore) { if !self.visible { return; } - let (x,y) = (screen_width() * self.x, screen_height() * self.y); + let (x, y) = (screen_width() * self.x, screen_height() * self.y); let (width, height) = self.get_dimensions(); let mut bg = assets.ui.panel_brown.0; @@ -119,13 +116,13 @@ impl Widget for SelectableText { // draw background draw_texture_ex( bg, - x - width/2.0, - y - height/2.0, + x - width / 2.0, + y - height / 2.0, WHITE, DrawTextureParams { dest_size: Some(Vec2::new(width, height)), ..Default::default() - } + }, ); let text_center = get_text_center( @@ -133,7 +130,8 @@ impl Widget for SelectableText { self.font, self.font_size.unwrap_or(60), 1.0, - 0.0); + 0.0, + ); draw_text_ex( &self.text, x - text_center.x, @@ -142,7 +140,8 @@ impl Widget for SelectableText { font_size: self.font_size.unwrap_or(60), color: self.font_color.unwrap_or(WHITE), ..Default::default() - }); + }, + ); } fn ev_loop(&mut self) -> Self::Event { if !self.visible { @@ -152,20 +151,21 @@ impl Widget for SelectableText { let (width, height) = self.get_dimensions(); let (mx, my) = mouse_position(); - let (x,y) = (screen_width() * self.x, screen_height() * self.y); + let (x, y) = (screen_width() * self.x, screen_height() * self.y); - if mx >= x - width/2.0 && mx <= x + width/2.0 - && my >= y - height/2.0 && my <= y + height/2.0 { - if is_mouse_button_pressed(MouseButton::Left) { - return Self::Event::LeftClick; - } - if is_mouse_button_pressed(MouseButton::Right) { - return Self::Event::RightClick; - } + if mx >= x - width / 2.0 + && mx <= x + width / 2.0 + && my >= y - height / 2.0 + && my <= y + height / 2.0 + { + if is_mouse_button_pressed(MouseButton::Left) { + return Self::Event::LeftClick; } - + if is_mouse_button_pressed(MouseButton::Right) { + return Self::Event::RightClick; + } + } Self::Event::None - } } diff --git a/src/ui/text_button.rs b/src/ui/text_button.rs index 2a52c84..699d7a3 100644 --- a/src/ui/text_button.rs +++ b/src/ui/text_button.rs @@ -1,6 +1,6 @@ -use macroquad::prelude::*; +use super::{ButtonEvent, Widget}; use crate::textures::AssetStore; -use super::{Widget, ButtonEvent}; +use macroquad::prelude::*; /// UI Widget /// a clickable button with text on it @@ -20,7 +20,7 @@ pub struct TextButton { /// custom font size to use font_size: Option, /// true if mouse is over button - hovered: bool + hovered: bool, } impl TextButton { /// creates a new text button widget @@ -32,7 +32,7 @@ impl TextButton { font: None, font_color: None, font_size: None, - hovered: false + hovered: false, } } /// sets the custom font @@ -68,19 +68,20 @@ impl TextButton { impl Widget for TextButton { type Event = ButtonEvent; fn get_dimensions(&self) -> (f32, f32) { - let text_dim: TextDimensions = measure_text( - &self.text, - self.font, - self.font_size.unwrap_or(60), - 1.0); - (text_dim.width + 30.0, text_dim.height+20.0) + let text_dim: TextDimensions = + measure_text(&self.text, self.font, self.font_size.unwrap_or(60), 1.0); + (text_dim.width + 30.0, text_dim.height + 20.0) } async fn draw(&self, assets: &AssetStore) { - let (x,y) = (screen_width() * self.x, screen_height() * self.y); + let (x, y) = (screen_width() * self.x, screen_height() * self.y); let (width, height) = self.get_dimensions(); draw_texture_ex( - if self.hovered { assets.ui.long_button.1 } else { assets.ui.long_button.0 }, + if self.hovered { + assets.ui.long_button.1 + } else { + assets.ui.long_button.0 + }, x - width / 2.0, y - height / 2.0, WHITE, @@ -90,15 +91,17 @@ impl Widget for TextButton { rotation: 0.0, flip_x: false, flip_y: false, - pivot: None - }); + pivot: None, + }, + ); let text_center = get_text_center( &self.text, self.font, self.font_size.unwrap_or(60), 1.0, - 0.0); + 0.0, + ); draw_text_ex( &self.text, x - text_center.x, @@ -107,7 +110,8 @@ impl Widget for TextButton { font_size: self.font_size.unwrap_or(60), color: self.font_color.unwrap_or(WHITE), ..Default::default() - }); + }, + ); } fn ev_loop(&mut self) -> Self::Event { self.hovered = false; @@ -115,20 +119,22 @@ impl Widget for TextButton { let (width, height) = self.get_dimensions(); let (mx, my) = mouse_position(); - let (x,y) = (screen_width() * self.x, screen_height() * self.y); + let (x, y) = (screen_width() * self.x, screen_height() * self.y); - if mx >= x - width/2.0 && mx <= x + width/2.0 - && my >= y - height/2.0 && my <= y + height/2.0 { - self.hovered = true; + if mx >= x - width / 2.0 + && mx <= x + width / 2.0 + && my >= y - height / 2.0 + && my <= y + height / 2.0 + { + self.hovered = true; - if is_mouse_button_pressed(MouseButton::Left) { - return Self::Event::LeftClick; - } - if is_mouse_button_pressed(MouseButton::Right) { - return Self::Event::RightClick; - } + if is_mouse_button_pressed(MouseButton::Left) { + return Self::Event::LeftClick; } - + if is_mouse_button_pressed(MouseButton::Right) { + return Self::Event::RightClick; + } + } Self::Event::None } -- 2.38.5