mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Implement fast respawn
Former-commit-id: 17f9aceba5c40a5d3ddc2e0fd6795479487753fd
This commit is contained in:
parent
0344f3eba8
commit
1826a2b4f9
@ -5,6 +5,7 @@ use vek::*;
|
||||
pub enum InputEvent {
|
||||
Jump,
|
||||
Attack,
|
||||
Respawn,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
|
@ -18,5 +18,6 @@ pub use inputs::Actions;
|
||||
pub use inputs::InputEvent;
|
||||
pub use inputs::Inputs;
|
||||
pub use player::Player;
|
||||
pub use player::Respawn;
|
||||
pub use stats::Dying;
|
||||
pub use stats::Stats;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use specs::{Component, FlaggedStorage, VecStorage};
|
||||
use specs::{Component, NullStorage, FlaggedStorage, VecStorage};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Player {
|
||||
@ -18,3 +18,10 @@ impl Player {
|
||||
impl Component for Player {
|
||||
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct Respawn;
|
||||
impl Component for Respawn {
|
||||
type Storage = NullStorage<Self>;
|
||||
}
|
||||
|
@ -12,5 +12,6 @@ pub enum ClientState {
|
||||
Connected,
|
||||
Registered,
|
||||
Spectator,
|
||||
Dead,
|
||||
Character,
|
||||
}
|
||||
|
@ -103,6 +103,7 @@ impl State {
|
||||
ecs.register_synced::<comp::Actor>();
|
||||
ecs.register_synced::<comp::Player>();
|
||||
ecs.register_synced::<comp::Stats>();
|
||||
ecs.register_synced::<comp::Actions>();
|
||||
ecs.register::<comp::phys::ForceUpdate>();
|
||||
|
||||
// Register unsynced (or synced by other means) components.
|
||||
@ -111,8 +112,8 @@ impl State {
|
||||
ecs.register::<comp::phys::Dir>();
|
||||
ecs.register::<comp::AnimationInfo>();
|
||||
ecs.register::<comp::Inputs>();
|
||||
ecs.register::<comp::Actions>();
|
||||
ecs.register::<comp::Dying>();
|
||||
ecs.register::<comp::Respawn>();
|
||||
ecs.register::<comp::Agent>();
|
||||
ecs.register::<inventory::Inventory>();
|
||||
|
||||
|
@ -6,7 +6,7 @@ use vek::*;
|
||||
use crate::{
|
||||
comp::{
|
||||
phys::{Dir, ForceUpdate, Pos, Vel},
|
||||
Actions, Animation, AnimationInfo, InputEvent, Inputs, Stats,
|
||||
Actions, Animation, AnimationInfo, Respawn, InputEvent, Inputs, Stats,
|
||||
},
|
||||
state::{DeltaTime, Time},
|
||||
terrain::TerrainMap,
|
||||
@ -29,6 +29,7 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Dir>,
|
||||
WriteStorage<'a, AnimationInfo>,
|
||||
WriteStorage<'a, Stats>,
|
||||
WriteStorage<'a, Respawn>,
|
||||
WriteStorage<'a, ForceUpdate>,
|
||||
);
|
||||
|
||||
@ -46,6 +47,7 @@ impl<'a> System<'a> for Sys {
|
||||
mut directions,
|
||||
mut animation_infos,
|
||||
mut stats,
|
||||
mut respawns,
|
||||
mut force_updates,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
@ -133,12 +135,9 @@ impl<'a> System<'a> for Sys {
|
||||
},
|
||||
);
|
||||
}
|
||||
for (entity, inputs, mut action, pos, dir) in (
|
||||
for (entity, inputs) in (
|
||||
&entities,
|
||||
&mut inputs,
|
||||
&mut actions,
|
||||
&positions,
|
||||
&mut directions,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
@ -147,24 +146,26 @@ impl<'a> System<'a> for Sys {
|
||||
match event {
|
||||
InputEvent::Attack => {
|
||||
// Attack delay
|
||||
if action.attack_time.is_some() {
|
||||
continue;
|
||||
}
|
||||
for (b, pos_b, mut stat_b, mut vel_b) in
|
||||
(&entities, &positions, &mut stats, &mut velocities).join()
|
||||
{
|
||||
if entity != b
|
||||
&& pos.0.distance_squared(pos_b.0) < 50.0
|
||||
&& dir.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0
|
||||
if let (Some(pos), Some(dir), Some(action)) = (positions.get(entity), directions.get(entity), actions.get_mut(entity)) {
|
||||
for (b, pos_b, mut stat_b, mut vel_b) in
|
||||
(&entities, &positions, &mut stats, &mut velocities).join()
|
||||
{
|
||||
action.attack_time = Some(0.0);
|
||||
stat_b.hp.change_by(-10); // TODO: variable damage
|
||||
vel_b.0 += (pos_b.0 - pos.0).normalized() * 20.0;
|
||||
vel_b.0.z = 20.0;
|
||||
force_updates.insert(b, ForceUpdate);
|
||||
if entity != b
|
||||
&& pos.0.distance_squared(pos_b.0) < 50.0
|
||||
&& dir.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0
|
||||
{
|
||||
action.attack_time = Some(0.0);
|
||||
stat_b.hp.change_by(-10); // TODO: variable damage
|
||||
vel_b.0 += (pos_b.0 - pos.0).normalized() * 20.0;
|
||||
vel_b.0.z = 20.0;
|
||||
force_updates.insert(b, ForceUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
InputEvent::Respawn => {
|
||||
respawns.insert(entity, Respawn);
|
||||
}
|
||||
InputEvent::Jump => {}
|
||||
}
|
||||
}
|
||||
|
@ -200,6 +200,52 @@ impl Server {
|
||||
// Tick the world
|
||||
self.world.tick(dt);
|
||||
|
||||
// Sync deaths.
|
||||
let todo_kill = (
|
||||
&self.state.ecs().entities(),
|
||||
&self.state.ecs().read_storage::<comp::Dying>(),
|
||||
)
|
||||
.join()
|
||||
.map(|(entity, _)| entity)
|
||||
.collect::<Vec<EcsEntity>>();
|
||||
|
||||
for entity in todo_kill {
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Dying>()
|
||||
.remove(entity);
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Actions>()
|
||||
.remove(entity);
|
||||
if let Some(client) = self.clients.get_mut(&entity) {
|
||||
client.force_state(ClientState::Dead);
|
||||
} else {
|
||||
//self.state.ecs_mut().delete_entity_synced(entity);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle respawns
|
||||
let todo_respawn = (
|
||||
&self.state.ecs().entities(),
|
||||
&self.state.ecs().read_storage::<comp::Respawn>(),
|
||||
)
|
||||
.join()
|
||||
.map(|(entity, _)| entity)
|
||||
.collect::<Vec<EcsEntity>>();
|
||||
|
||||
for entity in todo_respawn {
|
||||
if let Some(client) = self.clients.get_mut(&entity) {
|
||||
client.allow_state(ClientState::Character);
|
||||
self.state.ecs_mut().write_storage::<comp::Respawn>().remove(entity);
|
||||
self.state.write_component(entity, comp::Stats::default());
|
||||
self.state.write_component(entity, comp::Actions::default());
|
||||
self.state.write_component(entity, comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0)));
|
||||
self.state.write_component(entity, comp::phys::Vel(Vec3::zero()));
|
||||
self.state.write_component(entity, comp::phys::ForceUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
// 5) Fetch any generated `TerrainChunk`s and insert them into the terrain.
|
||||
// Also, send the chunk data to anybody that is close by.
|
||||
if let Ok((key, chunk)) = self.chunk_rx.try_recv() {
|
||||
@ -331,9 +377,9 @@ impl Server {
|
||||
ClientState::Registered => {
|
||||
client.error_state(RequestStateError::Already)
|
||||
}
|
||||
ClientState::Spectator | ClientState::Character => {
|
||||
client.allow_state(ClientState::Registered)
|
||||
}
|
||||
ClientState::Spectator
|
||||
| ClientState::Character
|
||||
| ClientState::Dead => client.allow_state(ClientState::Registered),
|
||||
},
|
||||
ClientState::Spectator => match requested_state {
|
||||
// Become Registered first.
|
||||
@ -343,14 +389,15 @@ impl Server {
|
||||
ClientState::Spectator => {
|
||||
client.error_state(RequestStateError::Already)
|
||||
}
|
||||
ClientState::Registered | ClientState::Character => {
|
||||
client.allow_state(ClientState::Spectator)
|
||||
}
|
||||
ClientState::Registered
|
||||
| ClientState::Character
|
||||
| ClientState::Dead => client.allow_state(ClientState::Spectator),
|
||||
},
|
||||
// Use ClientMsg::Character instead.
|
||||
ClientState::Character => {
|
||||
client.error_state(RequestStateError::WrongMessage)
|
||||
}
|
||||
ClientState::Dead => client.error_state(RequestStateError::Impossible),
|
||||
},
|
||||
ClientMsg::Register { player } => match client.client_state {
|
||||
ClientState::Connected => {
|
||||
@ -374,7 +421,9 @@ impl Server {
|
||||
ClientState::Connected => {
|
||||
client.error_state(RequestStateError::Impossible)
|
||||
}
|
||||
ClientState::Registered | ClientState::Spectator => {
|
||||
ClientState::Registered
|
||||
| ClientState::Spectator
|
||||
| ClientState::Dead => {
|
||||
Self::create_player_character(state, entity, client, name, body)
|
||||
}
|
||||
ClientState::Character => {
|
||||
@ -387,17 +436,21 @@ impl Server {
|
||||
}
|
||||
ClientState::Registered
|
||||
| ClientState::Spectator
|
||||
| ClientState::Dead
|
||||
| ClientState::Character => new_chat_msgs.push((entity, msg)),
|
||||
},
|
||||
ClientMsg::PlayerInputs(mut inputs) => {
|
||||
state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Inputs>()
|
||||
.get_mut(entity)
|
||||
.map(|s| {
|
||||
s.events.append(&mut inputs.events);
|
||||
});
|
||||
}
|
||||
ClientMsg::PlayerInputs(mut inputs) => match client.client_state {
|
||||
ClientState::Character | ClientState::Dead => {
|
||||
state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Inputs>()
|
||||
.get_mut(entity)
|
||||
.map(|s| {
|
||||
s.events.append(&mut inputs.events);
|
||||
});
|
||||
}
|
||||
_ => client.error_state(RequestStateError::Impossible),
|
||||
},
|
||||
ClientMsg::PlayerAnimation(animation_info) => {
|
||||
match client.client_state {
|
||||
ClientState::Character => {
|
||||
@ -417,7 +470,9 @@ impl Server {
|
||||
_ => client.error_state(RequestStateError::Impossible),
|
||||
},
|
||||
ClientMsg::TerrainChunkRequest { key } => match client.client_state {
|
||||
ClientState::Connected | ClientState::Registered => {
|
||||
ClientState::Connected
|
||||
| ClientState::Registered
|
||||
| ClientState::Dead => {
|
||||
client.error_state(RequestStateError::Impossible);
|
||||
}
|
||||
ClientState::Spectator | ClientState::Character => {
|
||||
@ -571,58 +626,12 @@ impl Server {
|
||||
}
|
||||
}
|
||||
|
||||
// Sync deaths.
|
||||
let todo_kill = (
|
||||
&self.state.ecs().entities(),
|
||||
&self.state.ecs().read_storage::<comp::Dying>(),
|
||||
)
|
||||
.join()
|
||||
.map(|(entity, _)| entity)
|
||||
.collect::<Vec<EcsEntity>>();
|
||||
|
||||
for entity in todo_kill {
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Dying>()
|
||||
.remove(entity);
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Actor>()
|
||||
.remove(entity);
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Stats>()
|
||||
.remove(entity);
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::phys::Pos>()
|
||||
.remove(entity);
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::phys::Vel>()
|
||||
.remove(entity);
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::phys::Dir>()
|
||||
.remove(entity);
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::AnimationInfo>()
|
||||
.remove(entity);
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Inputs>()
|
||||
.remove(entity);
|
||||
if let Some(client) = self.clients.get_mut(&entity) {
|
||||
client.force_state(ClientState::Registered);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all force flags.
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::phys::ForceUpdate>()
|
||||
.clear();
|
||||
|
||||
}
|
||||
|
||||
pub fn generate_chunk(&mut self, key: Vec2<i32>) {
|
||||
|
@ -12,6 +12,7 @@ use crate::{
|
||||
};
|
||||
use client::Client;
|
||||
use common::{
|
||||
msg::ClientState,
|
||||
assets,
|
||||
comp::{
|
||||
self,
|
||||
@ -457,22 +458,26 @@ impl FigureMgr {
|
||||
let tick = client.get_tick();
|
||||
let ecs = client.state().ecs();
|
||||
|
||||
for (entity, actor) in (&ecs.entities(), &ecs.read_storage::<comp::Actor>()).join() {
|
||||
match actor {
|
||||
comp::Actor::Character { body, .. } => {
|
||||
if let Some((locals, bone_consts)) = match body {
|
||||
Body::Humanoid(_) => self
|
||||
.character_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
Body::Quadruped(_) => self
|
||||
.quadruped_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
} {
|
||||
let model = self.model_cache.get_or_create_model(renderer, *body, tick);
|
||||
for (entity, actor, _) in (&ecs.entities(), &ecs.read_storage::<comp::Actor>(), &ecs.read_storage::<comp::Actions>()).join() {
|
||||
// Check if player is alive
|
||||
|
||||
{
|
||||
match actor {
|
||||
comp::Actor::Character { body, .. } => {
|
||||
if let Some((locals, bone_consts)) = match body {
|
||||
Body::Humanoid(_) => self
|
||||
.character_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
Body::Quadruped(_) => self
|
||||
.quadruped_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
} {
|
||||
let model = self.model_cache.get_or_create_model(renderer, *body, tick);
|
||||
|
||||
renderer.render_figure(model, globals, locals, bone_consts);
|
||||
renderer.render_figure(model, globals, locals, bone_consts);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
Direction, Error, GlobalState, PlayState, PlayStateResult,
|
||||
};
|
||||
use client::{self, Client};
|
||||
use common::{comp, clock::Clock, msg::ClientState};
|
||||
use common::{clock::Clock, comp, msg::ClientState};
|
||||
use glutin::MouseButton;
|
||||
use std::{cell::RefCell, mem, rc::Rc, time::Duration};
|
||||
use vek::*;
|
||||
@ -131,44 +131,53 @@ impl PlayState for SessionState {
|
||||
// Game loop
|
||||
while self.client.borrow().is_request_pending()
|
||||
|| self.client.borrow().get_client_state() == Some(ClientState::Character)
|
||||
|| self.client.borrow().get_client_state() == Some(ClientState::Dead)
|
||||
{
|
||||
let alive = self.client.borrow().get_client_state() == Some(ClientState::Character);
|
||||
|
||||
// Handle window events.
|
||||
for event in global_state.window.fetch_events() {
|
||||
// Pass all events to the ui first.
|
||||
if self.hud.handle_event(event.clone(), global_state) {
|
||||
continue;
|
||||
}
|
||||
let _handled = match event {
|
||||
|
||||
match event {
|
||||
Event::Close => {
|
||||
return PlayStateResult::Shutdown;
|
||||
}
|
||||
// Attack key pressed
|
||||
Event::Click(MouseButton::Left, state) => {
|
||||
self.input_events.push(comp::InputEvent::Attack)
|
||||
Event::Click(MouseButton::Left, state) => match alive {
|
||||
true => {
|
||||
self.input_events.push(comp::InputEvent::Attack);
|
||||
}
|
||||
false => {
|
||||
self.input_events.push(comp::InputEvent::Respawn);
|
||||
}
|
||||
_ => unreachable!()
|
||||
}
|
||||
// Movement key pressed
|
||||
Event::KeyDown(Key::MoveForward) => self.key_state.up = true,
|
||||
Event::KeyDown(Key::MoveBack) => self.key_state.down = true,
|
||||
Event::KeyDown(Key::MoveLeft) => self.key_state.left = true,
|
||||
Event::KeyDown(Key::MoveRight) => self.key_state.right = true,
|
||||
Event::KeyDown(Key::Jump) => {
|
||||
Event::KeyDown(Key::MoveForward) if alive => self.key_state.up = true,
|
||||
Event::KeyDown(Key::MoveBack) if alive => self.key_state.down = true,
|
||||
Event::KeyDown(Key::MoveLeft) if alive => self.key_state.left = true,
|
||||
Event::KeyDown(Key::MoveRight) if alive => self.key_state.right = true,
|
||||
Event::KeyDown(Key::Jump) if alive => {
|
||||
self.input_events.push(comp::InputEvent::Jump);
|
||||
self.key_state.jump = true;
|
||||
}
|
||||
Event::KeyDown(Key::Glide) => self.key_state.glide = true,
|
||||
Event::KeyDown(Key::Glide) if alive => self.key_state.glide = true,
|
||||
// Movement key released
|
||||
Event::KeyUp(Key::MoveForward) => self.key_state.up = false,
|
||||
Event::KeyUp(Key::MoveBack) => self.key_state.down = false,
|
||||
Event::KeyUp(Key::MoveLeft) => self.key_state.left = false,
|
||||
Event::KeyUp(Key::MoveRight) => self.key_state.right = false,
|
||||
Event::KeyUp(Key::Jump) => self.key_state.jump = false,
|
||||
Event::KeyUp(Key::Glide) => self.key_state.glide = false,
|
||||
Event::KeyUp(Key::MoveForward) if alive => self.key_state.up = false,
|
||||
Event::KeyUp(Key::MoveBack) if alive => self.key_state.down = false,
|
||||
Event::KeyUp(Key::MoveLeft) if alive => self.key_state.left = false,
|
||||
Event::KeyUp(Key::MoveRight) if alive => self.key_state.right = false,
|
||||
Event::KeyUp(Key::Jump) if alive => self.key_state.jump = false,
|
||||
Event::KeyUp(Key::Glide) if alive => self.key_state.glide = false,
|
||||
// Pass all other events to the scene
|
||||
event => {
|
||||
self.scene.handle_input_event(event);
|
||||
}
|
||||
};
|
||||
// TODO: Do something if the event wasn't handled?
|
||||
} // TODO: Do something if the event wasn't handled?
|
||||
}
|
||||
}
|
||||
|
||||
// Perform an in-game tick.
|
||||
|
Loading…
Reference in New Issue
Block a user