mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'build-mode' into 'master'
Build mode and crosshair See merge request veloren/veloren!290
This commit is contained in:
commit
4de3a64d7b
BIN
assets/voxygen/element/misc_bg/crosshair.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/misc_bg/crosshair.vox
(Stored with Git LFS)
Binary file not shown.
@ -12,7 +12,7 @@ use common::{
|
||||
msg::{ClientMsg, ClientState, ServerInfo, ServerMsg},
|
||||
net::PostBox,
|
||||
state::State,
|
||||
terrain::{chonk::ChonkMetrics, TerrainChunk, TerrainChunkSize},
|
||||
terrain::{block::Block, chonk::ChonkMetrics, TerrainChunk, TerrainChunkSize},
|
||||
vol::VolSize,
|
||||
};
|
||||
use log::{info, log_enabled, warn};
|
||||
@ -185,6 +185,14 @@ impl Client {
|
||||
self.pending_chunks.clear();
|
||||
}
|
||||
|
||||
pub fn place_block(&mut self, pos: Vec3<i32>, block: Block) {
|
||||
self.postbox.send_message(ClientMsg::PlaceBlock(pos, block));
|
||||
}
|
||||
|
||||
pub fn remove_block(&mut self, pos: Vec3<i32>) {
|
||||
self.postbox.send_message(ClientMsg::BreakBlock(pos));
|
||||
}
|
||||
|
||||
/// Execute a single client tick, handle input and update the game state by the given duration.
|
||||
#[allow(dead_code)]
|
||||
pub fn tick(
|
||||
|
@ -28,6 +28,9 @@ pub struct Rolling {
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct OnGround;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct CanBuild;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Jumping;
|
||||
|
||||
@ -85,6 +88,10 @@ impl Component for OnGround {
|
||||
type Storage = NullStorage<Self>;
|
||||
}
|
||||
|
||||
impl Component for CanBuild {
|
||||
type Storage = FlaggedStorage<Self, NullStorage<Self>>;
|
||||
}
|
||||
|
||||
impl Component for Jumping {
|
||||
type Storage = NullStorage<Self>;
|
||||
}
|
||||
|
@ -15,7 +15,9 @@ pub use agent::Agent;
|
||||
pub use animation::{Animation, AnimationInfo};
|
||||
pub use body::{humanoid, quadruped, quadruped_medium, Body};
|
||||
pub use controller::Controller;
|
||||
pub use inputs::{Attacking, Gliding, Jumping, MoveDir, OnGround, Respawning, Rolling, Wielding};
|
||||
pub use inputs::{
|
||||
Attacking, CanBuild, Gliding, Jumping, MoveDir, OnGround, Respawning, Rolling, Wielding,
|
||||
};
|
||||
pub use inventory::{item, Inventory};
|
||||
pub use phys::{ForceUpdate, Ori, Pos, Vel};
|
||||
pub use player::Player;
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::ClientState;
|
||||
use crate::comp;
|
||||
use crate::terrain::block::Block;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@ -14,6 +15,8 @@ pub enum ClientMsg {
|
||||
Controller(comp::Controller),
|
||||
RequestState(ClientState),
|
||||
SetViewDistance(u32),
|
||||
BreakBlock(Vec3<i32>),
|
||||
PlaceBlock(Vec3<i32>, Block),
|
||||
Ping,
|
||||
Pong,
|
||||
Chat(String),
|
||||
|
@ -22,6 +22,7 @@ sphynx::sum_type! {
|
||||
Ori(comp::Ori),
|
||||
Body(comp::Body),
|
||||
Player(comp::Player),
|
||||
CanBuild(comp::CanBuild),
|
||||
Stats(comp::Stats),
|
||||
}
|
||||
}
|
||||
@ -35,6 +36,7 @@ sphynx::sum_type! {
|
||||
Ori(PhantomData<comp::Ori>),
|
||||
Body(PhantomData<comp::Body>),
|
||||
Player(PhantomData<comp::Player>),
|
||||
CanBuild(PhantomData<comp::CanBuild>),
|
||||
Stats(PhantomData<comp::Stats>),
|
||||
}
|
||||
}
|
||||
|
@ -129,6 +129,7 @@ impl State {
|
||||
ecs.register_synced::<comp::Body>();
|
||||
ecs.register_synced::<comp::Player>();
|
||||
ecs.register_synced::<comp::Stats>();
|
||||
ecs.register_synced::<comp::CanBuild>();
|
||||
|
||||
// Register components synced by other means
|
||||
ecs.register::<comp::Pos>();
|
||||
|
@ -2,7 +2,7 @@ use crate::vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DynaErr {
|
||||
OutOfBounds,
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use fxhash::FxHashMap;
|
||||
use std::{collections::hash_map, fmt::Debug, marker::PhantomData, sync::Arc};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum VolMap2dErr<V: BaseVol> {
|
||||
NoSuchChunk,
|
||||
ChunkErr(V::Err),
|
||||
|
@ -7,9 +7,7 @@ use common::{
|
||||
comp,
|
||||
msg::ServerMsg,
|
||||
npc::{get_npc_name, NpcKind},
|
||||
state::{TerrainChange, TimeOfDay},
|
||||
terrain::Block,
|
||||
vol::Vox,
|
||||
state::TimeOfDay,
|
||||
};
|
||||
use specs::{Builder, Entity as EcsEntity, Join};
|
||||
use vek::*;
|
||||
@ -106,18 +104,6 @@ lazy_static! {
|
||||
"/players : Show the online players list",
|
||||
handle_players,
|
||||
),
|
||||
ChatCommand::new(
|
||||
"solid",
|
||||
"{}",
|
||||
"/solid : Make the blocks around you solid",
|
||||
handle_solid,
|
||||
),
|
||||
ChatCommand::new(
|
||||
"empty",
|
||||
"{}",
|
||||
"/empty : Make the blocks around you empty",
|
||||
handle_empty,
|
||||
),
|
||||
ChatCommand::new(
|
||||
"help", "", "/help: Display this message", handle_help),
|
||||
ChatCommand::new(
|
||||
@ -125,7 +111,13 @@ lazy_static! {
|
||||
"{}",
|
||||
"/health : Set your current health",
|
||||
handle_health,
|
||||
)
|
||||
),
|
||||
ChatCommand::new(
|
||||
"build",
|
||||
"",
|
||||
"/build : Toggles build mode on and off",
|
||||
handle_build,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@ -359,41 +351,32 @@ fn handle_players(server: &mut Server, entity: EcsEntity, _args: String, _action
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_solid(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
|
||||
match server.state.read_component_cloned::<comp::Pos>(entity) {
|
||||
Some(current_pos) => {
|
||||
server.state.ecs().write_resource::<TerrainChange>().set(
|
||||
current_pos.0.map(|e| e.floor() as i32),
|
||||
Block::new(1, Rgb::broadcast(255)),
|
||||
);
|
||||
}
|
||||
None => server.clients.notify(
|
||||
fn handle_build(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
|
||||
if server
|
||||
.state
|
||||
.read_storage::<comp::CanBuild>()
|
||||
.get(entity)
|
||||
.is_some()
|
||||
{
|
||||
server
|
||||
.state
|
||||
.ecs()
|
||||
.write_storage::<comp::CanBuild>()
|
||||
.remove(entity);
|
||||
server.clients.notify(
|
||||
entity,
|
||||
ServerMsg::Chat(String::from("You have no position!")),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_empty(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
|
||||
match server.state.read_component_cloned::<comp::Pos>(entity) {
|
||||
Some(current_pos) => {
|
||||
let mut terrain_change = server.state.ecs().write_resource::<TerrainChange>();
|
||||
|
||||
for i in -1..2 {
|
||||
for j in -1..2 {
|
||||
for k in -2..1 {
|
||||
terrain_change.set(
|
||||
current_pos.0.map(|e| e.floor() as i32) + Vec3::new(i, j, k),
|
||||
Block::empty(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => server.clients.notify(
|
||||
ServerMsg::Chat(String::from("Toggled off build mode!")),
|
||||
);
|
||||
} else {
|
||||
let _ = server
|
||||
.state
|
||||
.ecs()
|
||||
.write_storage::<comp::CanBuild>()
|
||||
.insert(entity, comp::CanBuild);
|
||||
server.clients.notify(
|
||||
entity,
|
||||
ServerMsg::Chat(String::from("You have no position!")),
|
||||
),
|
||||
ServerMsg::Chat(String::from("Toggled on build mode!")),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,10 @@ use common::{
|
||||
comp,
|
||||
msg::{ClientMsg, ClientState, RequestStateError, ServerInfo, ServerMsg},
|
||||
net::PostOffice,
|
||||
state::{State, Uid},
|
||||
terrain::{TerrainChunk, TerrainChunkSize, TerrainMap},
|
||||
state::{State, TerrainChange, Uid},
|
||||
terrain::{block::Block, TerrainChunk, TerrainChunkSize, TerrainMap},
|
||||
vol::VolSize,
|
||||
vol::Vox,
|
||||
};
|
||||
use log::debug;
|
||||
use specs::{join::Join, world::EntityBuilder as EcsEntityBuilder, Builder, Entity as EcsEntity};
|
||||
@ -500,6 +501,30 @@ impl Server {
|
||||
// Only characters can send positions.
|
||||
_ => client.error_state(RequestStateError::Impossible),
|
||||
},
|
||||
ClientMsg::BreakBlock(pos) => {
|
||||
if state
|
||||
.ecs_mut()
|
||||
.read_storage::<comp::CanBuild>()
|
||||
.get(entity)
|
||||
.is_some()
|
||||
{
|
||||
let mut terrain_change =
|
||||
state.ecs().write_resource::<TerrainChange>();
|
||||
terrain_change.set(pos, Block::empty());
|
||||
}
|
||||
}
|
||||
ClientMsg::PlaceBlock(pos, block) => {
|
||||
if state
|
||||
.ecs_mut()
|
||||
.read_storage::<comp::CanBuild>()
|
||||
.get(entity)
|
||||
.is_some()
|
||||
{
|
||||
let mut terrain_change =
|
||||
state.ecs().write_resource::<TerrainChange>();
|
||||
terrain_change.set(pos, block);
|
||||
}
|
||||
}
|
||||
ClientMsg::TerrainChunkRequest { key } => match client.client_state {
|
||||
ClientState::Connected
|
||||
| ClientState::Registered
|
||||
|
@ -49,9 +49,6 @@ image_ids! {
|
||||
chat_arrow_mo: "voxygen/element/buttons/arrow_down_hover.vox",
|
||||
chat_arrow_press: "voxygen/element/buttons/arrow_down_press.vox",
|
||||
|
||||
// Crosshair
|
||||
crosshair: "voxygen/element/misc_bg/crosshair.vox",
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
<VoxelMs9Graphic>
|
||||
|
||||
@ -122,6 +119,9 @@ image_ids! {
|
||||
button_hover: "voxygen/element/buttons/button_hover.vox",
|
||||
button_press: "voxygen/element/buttons/button_press.vox",
|
||||
|
||||
// Crosshair
|
||||
crosshair: "voxygen/element/misc_bg/crosshair.vox",
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
<ImageGraphic>
|
||||
|
||||
|
@ -48,6 +48,9 @@ const MANA_COLOR: Color = Color::Rgba(0.42, 0.41, 0.66, 1.0);
|
||||
|
||||
widget_ids! {
|
||||
struct Ids {
|
||||
// Crosshair
|
||||
crosshair,
|
||||
|
||||
// Character Names
|
||||
name_tags[],
|
||||
// Health Bars
|
||||
@ -330,6 +333,13 @@ impl Hud {
|
||||
let mut health_id_walker = self.ids.health_bars.walk();
|
||||
let mut health_back_id_walker = self.ids.health_bar_backs.walk();
|
||||
|
||||
// Crosshair
|
||||
Image::new(self.imgs.crosshair)
|
||||
.w_h(21.0 * 2.0, 21.0 * 2.0)
|
||||
.middle_of(ui_widgets.window)
|
||||
.color(Some(Color::Rgba(1.0, 1.0, 1.0, 1.0)))
|
||||
.set(self.ids.crosshair, ui_widgets);
|
||||
|
||||
// Render Name Tags
|
||||
for (pos, name) in (&entities, &pos, &stats, player.maybe())
|
||||
.join()
|
||||
|
@ -8,7 +8,9 @@ use crate::{
|
||||
Direction, Error, GlobalState, PlayState, PlayStateResult,
|
||||
};
|
||||
use client::{self, Client};
|
||||
use common::{clock::Clock, comp, comp::Pos, msg::ClientState};
|
||||
use common::{
|
||||
clock::Clock, comp, comp::Pos, msg::ClientState, ray::Ray, terrain::block::Block, vol::ReadVol,
|
||||
};
|
||||
use log::{error, warn};
|
||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||
use vek::*;
|
||||
@ -108,17 +110,75 @@ impl PlayState for SessionState {
|
||||
return PlayStateResult::Shutdown;
|
||||
}
|
||||
Event::InputUpdate(GameInput::Attack, state) => {
|
||||
// Check the existence of CanBuild component. If it's here, use LMB to
|
||||
// place blocks, if not, use it to attack
|
||||
if state {
|
||||
if let ClientState::Character = current_client_state {
|
||||
self.controller.attack = state;
|
||||
let mut client = self.client.borrow_mut();
|
||||
if client
|
||||
.state()
|
||||
.read_storage::<comp::CanBuild>()
|
||||
.get(client.entity())
|
||||
.is_some()
|
||||
{
|
||||
let (view_mat, _, cam_pos) =
|
||||
self.scene.camera().compute_dependents(&client);
|
||||
let cam_dir =
|
||||
(self.scene.camera().get_focus_pos() - cam_pos).normalized();
|
||||
|
||||
let (d, b) = {
|
||||
let terrain = client.state().terrain();
|
||||
let ray =
|
||||
terrain.ray(cam_pos, cam_pos + cam_dir * 100.0).cast();
|
||||
(ray.0, if let Ok(Some(_)) = ray.1 { true } else { false })
|
||||
};
|
||||
|
||||
if b {
|
||||
let pos =
|
||||
(cam_pos + cam_dir * (d - 0.01)).map(|e| e.floor() as i32);
|
||||
client.place_block(pos, Block::new(1, Rgb::broadcast(255))); // TODO: Handle block color with a command
|
||||
}
|
||||
} else {
|
||||
self.controller.respawn = state; // TODO: Don't do both
|
||||
if let ClientState::Character = current_client_state {
|
||||
self.controller.attack = state
|
||||
} else {
|
||||
self.controller.respawn = state; // TODO: Don't do both
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.controller.attack = state;
|
||||
self.controller.respawn = state;
|
||||
}
|
||||
}
|
||||
Event::InputUpdate(GameInput::SecondAttack, state) => {
|
||||
if state {
|
||||
let mut client = self.client.borrow_mut();
|
||||
if client
|
||||
.state()
|
||||
.read_storage::<comp::CanBuild>()
|
||||
.get(client.entity())
|
||||
.is_some()
|
||||
{
|
||||
let (view_mat, _, cam_pos) =
|
||||
self.scene.camera().compute_dependents(&client);
|
||||
let cam_dir =
|
||||
(self.scene.camera().get_focus_pos() - cam_pos).normalized();
|
||||
|
||||
let (d, b) = {
|
||||
let terrain = client.state().terrain();
|
||||
let ray =
|
||||
terrain.ray(cam_pos, cam_pos + cam_dir * 100.0).cast();
|
||||
(ray.0, if let Ok(Some(_)) = ray.1 { true } else { false })
|
||||
};
|
||||
|
||||
if b {
|
||||
let pos = (cam_pos + cam_dir * d).map(|e| e.floor() as i32);
|
||||
client.remove_block(pos);
|
||||
}
|
||||
} else {
|
||||
// TODO: Handle secondary attack
|
||||
}
|
||||
}
|
||||
}
|
||||
Event::InputUpdate(GameInput::Roll, state) => {
|
||||
self.controller.roll = state;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ pub struct ControlSettings {
|
||||
pub screenshot: KeyMouse,
|
||||
pub toggle_ingame_ui: KeyMouse,
|
||||
pub attack: KeyMouse,
|
||||
pub second_attack: KeyMouse,
|
||||
pub roll: KeyMouse,
|
||||
}
|
||||
|
||||
@ -60,6 +61,7 @@ impl Default for ControlSettings {
|
||||
screenshot: KeyMouse::Key(VirtualKeyCode::F4),
|
||||
toggle_ingame_ui: KeyMouse::Key(VirtualKeyCode::F6),
|
||||
attack: KeyMouse::Mouse(MouseButton::Left),
|
||||
second_attack: KeyMouse::Mouse(MouseButton::Right),
|
||||
roll: KeyMouse::Mouse(MouseButton::Middle),
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ pub enum GameInput {
|
||||
Screenshot,
|
||||
ToggleIngameUi,
|
||||
Attack,
|
||||
SecondAttack,
|
||||
Roll,
|
||||
Respawn,
|
||||
}
|
||||
@ -138,6 +139,7 @@ impl Window {
|
||||
GameInput::ToggleIngameUi,
|
||||
);
|
||||
key_map.insert(settings.controls.attack, GameInput::Attack);
|
||||
key_map.insert(settings.controls.second_attack, GameInput::SecondAttack);
|
||||
key_map.insert(settings.controls.roll, GameInput::Roll);
|
||||
|
||||
let keypress_map = HashMap::new();
|
||||
|
Loading…
Reference in New Issue
Block a user