2020-05-11 10:06:53 +00:00
|
|
|
use crate::{
|
2020-09-22 16:21:31 +00:00
|
|
|
client::Client, persistence::PersistedComponents, sys::sentinel::DeletedEntities, SpawnPoint,
|
2020-05-11 10:06:53 +00:00
|
|
|
};
|
2020-03-10 02:27:32 +00:00
|
|
|
use common::{
|
2020-09-17 23:02:14 +00:00
|
|
|
character::CharacterId,
|
2020-06-04 11:44:33 +00:00
|
|
|
comp,
|
2020-03-10 02:27:32 +00:00
|
|
|
effect::Effect,
|
Redo Network Frontend.
Rather than having a single Stream to handle ALL data, seperate into multiple streams:
- Ping Stream, for seperate PINGS
- Register Stream, only used till the client is registered, then no longer used!
- General Stream, used for msg that can occur always
- NotInGame Stream, used for everything NOT ingame, e.g. Character Screen
- InGame Stream, used for all GAME data, players, terrain, entities, etc...
This version does compile, and gets the client registered (with auth too) but doesnt get to the char screen yet.
This fixes also the ignoring messages problem we had, as we are not sending data to the register stream!
This fixes also the problem that the server had to sleep for the Stream Creation, as the Server is now creating the streams and client has to sleep.
2020-10-04 18:20:18 +00:00
|
|
|
msg::{
|
2020-10-06 11:15:20 +00:00
|
|
|
CharacterInfo, ClientIngame, PlayerListUpdate, ServerCharacterScreenMsg, ServerGeneralMsg,
|
|
|
|
ServerInGameMsg,
|
Redo Network Frontend.
Rather than having a single Stream to handle ALL data, seperate into multiple streams:
- Ping Stream, for seperate PINGS
- Register Stream, only used till the client is registered, then no longer used!
- General Stream, used for msg that can occur always
- NotInGame Stream, used for everything NOT ingame, e.g. Character Screen
- InGame Stream, used for all GAME data, players, terrain, entities, etc...
This version does compile, and gets the client registered (with auth too) but doesnt get to the char screen yet.
This fixes also the ignoring messages problem we had, as we are not sending data to the register stream!
This fixes also the problem that the server had to sleep for the Stream Creation, as the Server is now creating the streams and client has to sleep.
2020-10-04 18:20:18 +00:00
|
|
|
},
|
2020-03-10 02:27:32 +00:00
|
|
|
state::State,
|
2020-06-05 01:48:26 +00:00
|
|
|
sync::{Uid, UidAllocator, WorldSyncExt},
|
2020-03-28 01:31:22 +00:00
|
|
|
util::Dir,
|
2020-03-10 02:27:32 +00:00
|
|
|
};
|
2020-06-05 01:48:26 +00:00
|
|
|
use specs::{
|
|
|
|
saveload::MarkerAllocator, Builder, Entity as EcsEntity, EntityBuilder as EcsEntityBuilder,
|
|
|
|
Join, WorldExt,
|
|
|
|
};
|
2020-06-21 14:26:06 +00:00
|
|
|
use tracing::warn;
|
2020-03-10 02:27:32 +00:00
|
|
|
use vek::*;
|
|
|
|
|
|
|
|
pub trait StateExt {
|
2020-06-16 01:00:32 +00:00
|
|
|
/// Updates a component associated with the entity based on the `Effect`
|
2020-03-10 02:27:32 +00:00
|
|
|
fn apply_effect(&mut self, entity: EcsEntity, effect: Effect);
|
2020-06-16 01:00:32 +00:00
|
|
|
/// Build a non-player character
|
2020-03-10 02:27:32 +00:00
|
|
|
fn create_npc(
|
|
|
|
&mut self,
|
|
|
|
pos: comp::Pos,
|
|
|
|
stats: comp::Stats,
|
2020-02-26 17:04:43 +00:00
|
|
|
loadout: comp::Loadout,
|
2020-03-10 02:27:32 +00:00
|
|
|
body: comp::Body,
|
|
|
|
) -> EcsEntityBuilder;
|
2020-06-16 01:00:32 +00:00
|
|
|
/// Build a static object entity
|
2020-03-10 02:27:32 +00:00
|
|
|
fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder;
|
2020-06-16 01:00:32 +00:00
|
|
|
/// Build a projectile
|
2020-03-10 02:27:32 +00:00
|
|
|
fn create_projectile(
|
|
|
|
&mut self,
|
|
|
|
pos: comp::Pos,
|
|
|
|
vel: comp::Vel,
|
|
|
|
body: comp::Body,
|
|
|
|
projectile: comp::Projectile,
|
|
|
|
) -> EcsEntityBuilder;
|
2020-08-08 22:22:21 +00:00
|
|
|
/// Build a shockwave entity
|
|
|
|
fn create_shockwave(
|
|
|
|
&mut self,
|
|
|
|
properties: comp::shockwave::Properties,
|
|
|
|
pos: comp::Pos,
|
|
|
|
ori: comp::Ori,
|
|
|
|
) -> EcsEntityBuilder;
|
2020-09-05 16:27:36 +00:00
|
|
|
/// Build a beam entity
|
|
|
|
fn create_beam(
|
|
|
|
&mut self,
|
|
|
|
properties: comp::beam::Properties,
|
|
|
|
pos: comp::Pos,
|
|
|
|
ori: comp::Ori,
|
|
|
|
) -> EcsEntityBuilder;
|
2020-06-16 01:00:32 +00:00
|
|
|
/// Insert common/default components for a new character joining the server
|
2020-09-17 23:02:14 +00:00
|
|
|
fn initialize_character_data(&mut self, entity: EcsEntity, character_id: CharacterId);
|
2020-06-16 01:00:32 +00:00
|
|
|
/// Update the components associated with the entity's current character.
|
|
|
|
/// Performed after loading component data from the database
|
|
|
|
fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents);
|
|
|
|
/// Iterates over registered clients and send each `ServerMsg`
|
2020-07-12 20:18:57 +00:00
|
|
|
fn send_chat(&self, msg: comp::UnresolvedChatMsg);
|
2020-10-05 08:07:34 +00:00
|
|
|
fn notify_registered_clients(&self, msg: ServerGeneralMsg);
|
2020-06-16 01:00:32 +00:00
|
|
|
/// Delete an entity, recording the deletion in [`DeletedEntities`]
|
2020-03-10 02:27:32 +00:00
|
|
|
fn delete_entity_recorded(
|
|
|
|
&mut self,
|
|
|
|
entity: EcsEntity,
|
|
|
|
) -> Result<(), specs::error::WrongGeneration>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl StateExt for State {
|
|
|
|
fn apply_effect(&mut self, entity: EcsEntity, effect: Effect) {
|
|
|
|
match effect {
|
|
|
|
Effect::Health(change) => {
|
|
|
|
self.ecs()
|
|
|
|
.write_storage::<comp::Stats>()
|
|
|
|
.get_mut(entity)
|
|
|
|
.map(|stats| stats.health.change_by(change));
|
|
|
|
},
|
|
|
|
Effect::Xp(xp) => {
|
|
|
|
self.ecs()
|
|
|
|
.write_storage::<comp::Stats>()
|
|
|
|
.get_mut(entity)
|
|
|
|
.map(|stats| stats.exp.change_by(xp));
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn create_npc(
|
|
|
|
&mut self,
|
|
|
|
pos: comp::Pos,
|
|
|
|
stats: comp::Stats,
|
2020-02-26 17:04:43 +00:00
|
|
|
loadout: comp::Loadout,
|
2020-03-10 02:27:32 +00:00
|
|
|
body: comp::Body,
|
|
|
|
) -> EcsEntityBuilder {
|
|
|
|
self.ecs_mut()
|
|
|
|
.create_entity_synced()
|
|
|
|
.with(pos)
|
|
|
|
.with(comp::Vel(Vec3::zero()))
|
2020-03-28 01:31:22 +00:00
|
|
|
.with(comp::Ori::default())
|
2020-04-26 14:37:13 +00:00
|
|
|
.with(comp::Collider::Box {
|
2020-08-24 17:24:44 +00:00
|
|
|
radius: body.radius(),
|
2020-04-26 14:37:13 +00:00
|
|
|
z_min: 0.0,
|
2020-08-24 17:24:44 +00:00
|
|
|
z_max: body.height(),
|
2020-04-26 14:37:13 +00:00
|
|
|
})
|
2020-03-10 02:27:32 +00:00
|
|
|
.with(comp::Controller::default())
|
|
|
|
.with(body)
|
|
|
|
.with(stats)
|
|
|
|
.with(comp::Alignment::Npc)
|
|
|
|
.with(comp::Energy::new(500))
|
|
|
|
.with(comp::Gravity(1.0))
|
|
|
|
.with(comp::CharacterState::default())
|
2020-02-26 17:04:43 +00:00
|
|
|
.with(loadout)
|
2020-03-10 02:27:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder {
|
|
|
|
self.ecs_mut()
|
|
|
|
.create_entity_synced()
|
|
|
|
.with(pos)
|
|
|
|
.with(comp::Vel(Vec3::zero()))
|
2020-03-28 01:31:22 +00:00
|
|
|
.with(comp::Ori::default())
|
2020-07-05 12:39:28 +00:00
|
|
|
.with(comp::Mass(5.0))
|
2020-04-26 14:37:13 +00:00
|
|
|
.with(comp::Collider::Box {
|
2020-08-24 17:24:44 +00:00
|
|
|
radius: comp::Body::Object(object).radius(),
|
2020-04-26 14:37:13 +00:00
|
|
|
z_min: 0.0,
|
2020-08-24 17:24:44 +00:00
|
|
|
z_max: comp::Body::Object(object).height(),
|
2020-04-26 14:37:13 +00:00
|
|
|
})
|
2020-08-24 17:24:44 +00:00
|
|
|
.with(comp::Body::Object(object))
|
2020-03-10 02:27:32 +00:00
|
|
|
.with(comp::Gravity(1.0))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn create_projectile(
|
|
|
|
&mut self,
|
|
|
|
pos: comp::Pos,
|
|
|
|
vel: comp::Vel,
|
|
|
|
body: comp::Body,
|
|
|
|
projectile: comp::Projectile,
|
|
|
|
) -> EcsEntityBuilder {
|
|
|
|
self.ecs_mut()
|
|
|
|
.create_entity_synced()
|
|
|
|
.with(pos)
|
|
|
|
.with(vel)
|
2020-03-28 01:31:22 +00:00
|
|
|
.with(comp::Ori(Dir::from_unnormalized(vel.0).unwrap_or_default()))
|
2020-03-10 02:27:32 +00:00
|
|
|
.with(comp::Mass(0.0))
|
2020-04-26 14:37:13 +00:00
|
|
|
.with(comp::Collider::Point)
|
2020-03-10 02:27:32 +00:00
|
|
|
.with(body)
|
|
|
|
.with(projectile)
|
|
|
|
.with(comp::Sticky)
|
|
|
|
}
|
|
|
|
|
2020-08-08 22:22:21 +00:00
|
|
|
fn create_shockwave(
|
|
|
|
&mut self,
|
|
|
|
properties: comp::shockwave::Properties,
|
|
|
|
pos: comp::Pos,
|
|
|
|
ori: comp::Ori,
|
|
|
|
) -> EcsEntityBuilder {
|
|
|
|
self.ecs_mut()
|
|
|
|
.create_entity_synced()
|
|
|
|
.with(pos)
|
|
|
|
.with(ori)
|
|
|
|
.with(comp::Shockwave {
|
|
|
|
properties,
|
|
|
|
creation: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-09-05 16:27:36 +00:00
|
|
|
fn create_beam(
|
|
|
|
&mut self,
|
|
|
|
properties: comp::beam::Properties,
|
|
|
|
pos: comp::Pos,
|
|
|
|
ori: comp::Ori,
|
|
|
|
) -> EcsEntityBuilder {
|
|
|
|
self.ecs_mut()
|
|
|
|
.create_entity_synced()
|
|
|
|
.with(pos)
|
|
|
|
.with(ori)
|
2020-09-24 02:02:30 +00:00
|
|
|
.with(comp::BeamSegment {
|
2020-09-05 16:27:36 +00:00
|
|
|
properties,
|
|
|
|
creation: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-09-17 23:02:14 +00:00
|
|
|
fn initialize_character_data(&mut self, entity: EcsEntity, character_id: CharacterId) {
|
2020-03-10 02:27:32 +00:00
|
|
|
let spawn_point = self.ecs().read_resource::<SpawnPoint>().0;
|
|
|
|
|
|
|
|
self.write_component(entity, comp::Energy::new(1000));
|
|
|
|
self.write_component(entity, comp::Controller::default());
|
|
|
|
self.write_component(entity, comp::Pos(spawn_point));
|
|
|
|
self.write_component(entity, comp::Vel(Vec3::zero()));
|
2020-03-28 01:31:22 +00:00
|
|
|
self.write_component(entity, comp::Ori::default());
|
2020-04-26 14:37:13 +00:00
|
|
|
self.write_component(entity, comp::Collider::Box {
|
|
|
|
radius: 0.4,
|
|
|
|
z_min: 0.0,
|
|
|
|
z_max: 1.75,
|
|
|
|
});
|
2020-03-10 02:27:32 +00:00
|
|
|
self.write_component(entity, comp::Gravity(1.0));
|
|
|
|
self.write_component(entity, comp::CharacterState::default());
|
2020-07-07 00:11:37 +00:00
|
|
|
self.write_component(
|
|
|
|
entity,
|
2020-08-23 20:29:40 +00:00
|
|
|
comp::Alignment::Owned(self.read_component_copied(entity).unwrap()),
|
2020-07-07 00:11:37 +00:00
|
|
|
);
|
2020-03-15 14:27:06 +00:00
|
|
|
|
2020-08-23 20:17:16 +00:00
|
|
|
// Make sure physics components are updated
|
|
|
|
self.write_component(entity, comp::ForceUpdate);
|
|
|
|
|
2020-04-25 13:41:27 +00:00
|
|
|
// Set the character id for the player
|
|
|
|
// TODO this results in a warning in the console: "Error modifying synced
|
|
|
|
// component, it doesn't seem to exist"
|
|
|
|
// It appears to be caused by the player not yet existing on the client at this
|
|
|
|
// point, despite being able to write the data on the server
|
2020-06-16 01:00:32 +00:00
|
|
|
self.ecs()
|
2020-04-25 13:41:27 +00:00
|
|
|
.write_storage::<comp::Player>()
|
|
|
|
.get_mut(entity)
|
|
|
|
.map(|player| {
|
|
|
|
player.character_id = Some(character_id);
|
|
|
|
});
|
|
|
|
|
2020-06-16 01:00:32 +00:00
|
|
|
// Tell the client its request was successful.
|
|
|
|
if let Some(client) = self.ecs().write_storage::<Client>().get_mut(entity) {
|
Redo Network Frontend.
Rather than having a single Stream to handle ALL data, seperate into multiple streams:
- Ping Stream, for seperate PINGS
- Register Stream, only used till the client is registered, then no longer used!
- General Stream, used for msg that can occur always
- NotInGame Stream, used for everything NOT ingame, e.g. Character Screen
- InGame Stream, used for all GAME data, players, terrain, entities, etc...
This version does compile, and gets the client registered (with auth too) but doesnt get to the char screen yet.
This fixes also the ignoring messages problem we had, as we are not sending data to the register stream!
This fixes also the problem that the server had to sleep for the Stream Creation, as the Server is now creating the streams and client has to sleep.
2020-10-04 18:20:18 +00:00
|
|
|
client.in_game = Some(ClientIngame::Character);
|
2020-10-06 11:15:20 +00:00
|
|
|
client.send_character_screen(ServerCharacterScreenMsg::CharacterSuccess)
|
2020-06-16 01:00:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents) {
|
|
|
|
let (body, stats, inventory, loadout) = components;
|
2020-06-01 07:31:13 +00:00
|
|
|
|
2020-08-23 20:29:40 +00:00
|
|
|
if let Some(player_uid) = self.read_component_copied::<Uid>(entity) {
|
2020-08-23 20:17:16 +00:00
|
|
|
// Notify clients of a player list update
|
2020-10-05 08:07:34 +00:00
|
|
|
self.notify_registered_clients(ServerGeneralMsg::PlayerListUpdate(
|
2020-08-23 20:17:16 +00:00
|
|
|
PlayerListUpdate::SelectedCharacter(player_uid, CharacterInfo {
|
|
|
|
name: String::from(&stats.name),
|
|
|
|
level: stats.level.level(),
|
|
|
|
}),
|
|
|
|
));
|
2020-06-16 01:00:32 +00:00
|
|
|
|
2020-08-23 20:17:16 +00:00
|
|
|
self.write_component(entity, comp::Collider::Box {
|
|
|
|
radius: body.radius(),
|
|
|
|
z_min: 0.0,
|
|
|
|
z_max: body.height(),
|
|
|
|
});
|
|
|
|
self.write_component(entity, body);
|
|
|
|
self.write_component(entity, stats);
|
|
|
|
self.write_component(entity, inventory);
|
|
|
|
self.write_component(entity, loadout);
|
2020-06-16 01:00:32 +00:00
|
|
|
|
2020-08-23 20:17:16 +00:00
|
|
|
self.write_component(
|
|
|
|
entity,
|
|
|
|
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::default()),
|
|
|
|
);
|
|
|
|
}
|
2020-03-10 02:27:32 +00:00
|
|
|
}
|
|
|
|
|
2020-06-05 01:48:26 +00:00
|
|
|
/// Send the chat message to the proper players. Say and region are limited
|
|
|
|
/// by location. Faction and group are limited by component.
|
2020-07-12 20:18:57 +00:00
|
|
|
fn send_chat(&self, msg: comp::UnresolvedChatMsg) {
|
2020-06-05 01:48:26 +00:00
|
|
|
let ecs = self.ecs();
|
2020-06-11 05:16:42 +00:00
|
|
|
let is_within =
|
|
|
|
|target, a: &comp::Pos, b: &comp::Pos| a.0.distance_squared(b.0) < target * target;
|
2020-07-12 20:18:57 +00:00
|
|
|
|
|
|
|
let group_manager = ecs.read_resource::<comp::group::GroupManager>();
|
|
|
|
let resolved_msg = msg.clone().map_group(|group_id| {
|
|
|
|
group_manager
|
|
|
|
.group_info(group_id)
|
|
|
|
.map_or_else(|| "???".into(), |i| i.name.clone())
|
|
|
|
});
|
|
|
|
|
2020-06-05 01:48:26 +00:00
|
|
|
match &msg.chat_type {
|
2020-09-06 19:42:32 +00:00
|
|
|
comp::ChatType::Online(_)
|
|
|
|
| comp::ChatType::Offline(_)
|
2020-06-12 07:43:20 +00:00
|
|
|
| comp::ChatType::CommandInfo
|
|
|
|
| comp::ChatType::CommandError
|
2020-07-01 19:05:44 +00:00
|
|
|
| comp::ChatType::Loot
|
2020-09-06 19:42:32 +00:00
|
|
|
| comp::ChatType::Kill(_, _)
|
2020-06-28 17:10:01 +00:00
|
|
|
| comp::ChatType::Meta
|
2020-06-05 01:48:26 +00:00
|
|
|
| comp::ChatType::World(_) => {
|
2020-10-05 08:07:34 +00:00
|
|
|
self.notify_registered_clients(ServerGeneralMsg::ChatMsg(resolved_msg))
|
2020-06-05 01:48:26 +00:00
|
|
|
},
|
|
|
|
comp::ChatType::Tell(u, t) => {
|
|
|
|
for (client, uid) in (
|
|
|
|
&mut ecs.write_storage::<Client>(),
|
|
|
|
&ecs.read_storage::<Uid>(),
|
|
|
|
)
|
|
|
|
.join()
|
|
|
|
{
|
|
|
|
if uid == u || uid == t {
|
2020-10-05 08:07:34 +00:00
|
|
|
client.send_msg(ServerGeneralMsg::ChatMsg(resolved_msg.clone()));
|
2020-06-05 01:48:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-06-11 05:16:42 +00:00
|
|
|
comp::ChatType::Say(uid) => {
|
|
|
|
let entity_opt =
|
|
|
|
(*ecs.read_resource::<UidAllocator>()).retrieve_entity_internal(uid.0);
|
|
|
|
let positions = ecs.read_storage::<comp::Pos>();
|
|
|
|
if let Some(speaker_pos) = entity_opt.and_then(|e| positions.get(e)) {
|
|
|
|
for (client, pos) in (&mut ecs.write_storage::<Client>(), &positions).join() {
|
|
|
|
if is_within(comp::ChatMsg::SAY_DISTANCE, pos, speaker_pos) {
|
2020-10-05 08:07:34 +00:00
|
|
|
client.send_msg(ServerGeneralMsg::ChatMsg(resolved_msg.clone()));
|
2020-06-11 05:16:42 +00:00
|
|
|
}
|
2020-06-05 01:48:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2020-06-11 05:16:42 +00:00
|
|
|
comp::ChatType::Region(uid) => {
|
|
|
|
let entity_opt =
|
|
|
|
(*ecs.read_resource::<UidAllocator>()).retrieve_entity_internal(uid.0);
|
|
|
|
let positions = ecs.read_storage::<comp::Pos>();
|
|
|
|
if let Some(speaker_pos) = entity_opt.and_then(|e| positions.get(e)) {
|
|
|
|
for (client, pos) in (&mut ecs.write_storage::<Client>(), &positions).join() {
|
|
|
|
if is_within(comp::ChatMsg::REGION_DISTANCE, pos, speaker_pos) {
|
2020-10-05 08:07:34 +00:00
|
|
|
client.send_msg(ServerGeneralMsg::ChatMsg(resolved_msg.clone()));
|
2020-06-11 05:16:42 +00:00
|
|
|
}
|
2020-06-05 01:48:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2020-06-11 05:16:42 +00:00
|
|
|
comp::ChatType::Npc(uid, _r) => {
|
|
|
|
let entity_opt =
|
|
|
|
(*ecs.read_resource::<UidAllocator>()).retrieve_entity_internal(uid.0);
|
|
|
|
let positions = ecs.read_storage::<comp::Pos>();
|
|
|
|
if let Some(speaker_pos) = entity_opt.and_then(|e| positions.get(e)) {
|
|
|
|
for (client, pos) in (&mut ecs.write_storage::<Client>(), &positions).join() {
|
|
|
|
if is_within(comp::ChatMsg::NPC_DISTANCE, pos, speaker_pos) {
|
2020-10-05 08:07:34 +00:00
|
|
|
client.send_msg(ServerGeneralMsg::ChatMsg(resolved_msg.clone()));
|
2020-06-11 05:16:42 +00:00
|
|
|
}
|
2020-06-05 01:48:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-06-12 17:44:29 +00:00
|
|
|
comp::ChatType::FactionMeta(s) | comp::ChatType::Faction(_, s) => {
|
2020-06-05 01:48:26 +00:00
|
|
|
for (client, faction) in (
|
|
|
|
&mut ecs.write_storage::<Client>(),
|
|
|
|
&ecs.read_storage::<comp::Faction>(),
|
|
|
|
)
|
|
|
|
.join()
|
|
|
|
{
|
|
|
|
if s == &faction.0 {
|
2020-10-05 08:07:34 +00:00
|
|
|
client.send_msg(ServerGeneralMsg::ChatMsg(resolved_msg.clone()));
|
2020-06-05 01:48:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2020-07-12 20:18:57 +00:00
|
|
|
comp::ChatType::GroupMeta(g) | comp::ChatType::Group(_, g) => {
|
2020-06-05 01:48:26 +00:00
|
|
|
for (client, group) in (
|
|
|
|
&mut ecs.write_storage::<Client>(),
|
2020-07-12 20:18:57 +00:00
|
|
|
&ecs.read_storage::<comp::Group>(),
|
2020-06-05 01:48:26 +00:00
|
|
|
)
|
|
|
|
.join()
|
|
|
|
{
|
2020-07-12 20:18:57 +00:00
|
|
|
if g == group {
|
2020-10-05 08:07:34 +00:00
|
|
|
client.send_msg(ServerGeneralMsg::ChatMsg(resolved_msg.clone()));
|
2020-06-05 01:48:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sends the message to all connected clients
|
2020-10-05 08:07:34 +00:00
|
|
|
fn notify_registered_clients(&self, msg: ServerGeneralMsg) {
|
2020-03-10 02:27:32 +00:00
|
|
|
for client in (&mut self.ecs().write_storage::<Client>())
|
|
|
|
.join()
|
Redo Network Frontend.
Rather than having a single Stream to handle ALL data, seperate into multiple streams:
- Ping Stream, for seperate PINGS
- Register Stream, only used till the client is registered, then no longer used!
- General Stream, used for msg that can occur always
- NotInGame Stream, used for everything NOT ingame, e.g. Character Screen
- InGame Stream, used for all GAME data, players, terrain, entities, etc...
This version does compile, and gets the client registered (with auth too) but doesnt get to the char screen yet.
This fixes also the ignoring messages problem we had, as we are not sending data to the register stream!
This fixes also the problem that the server had to sleep for the Stream Creation, as the Server is now creating the streams and client has to sleep.
2020-10-04 18:20:18 +00:00
|
|
|
.filter(|c| c.registered)
|
2020-03-10 02:27:32 +00:00
|
|
|
{
|
Redo Network Frontend.
Rather than having a single Stream to handle ALL data, seperate into multiple streams:
- Ping Stream, for seperate PINGS
- Register Stream, only used till the client is registered, then no longer used!
- General Stream, used for msg that can occur always
- NotInGame Stream, used for everything NOT ingame, e.g. Character Screen
- InGame Stream, used for all GAME data, players, terrain, entities, etc...
This version does compile, and gets the client registered (with auth too) but doesnt get to the char screen yet.
This fixes also the ignoring messages problem we had, as we are not sending data to the register stream!
This fixes also the problem that the server had to sleep for the Stream Creation, as the Server is now creating the streams and client has to sleep.
2020-10-04 18:20:18 +00:00
|
|
|
client.send_msg(msg.clone());
|
2020-03-10 02:27:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn delete_entity_recorded(
|
|
|
|
&mut self,
|
|
|
|
entity: EcsEntity,
|
|
|
|
) -> Result<(), specs::error::WrongGeneration> {
|
2020-04-26 17:03:19 +00:00
|
|
|
// Remove entity from a group if they are in one
|
|
|
|
{
|
|
|
|
let mut clients = self.ecs().write_storage::<Client>();
|
|
|
|
let uids = self.ecs().read_storage::<Uid>();
|
|
|
|
let mut group_manager = self.ecs().write_resource::<comp::group::GroupManager>();
|
2020-07-12 03:12:03 +00:00
|
|
|
group_manager.entity_deleted(
|
2020-04-26 17:03:19 +00:00
|
|
|
entity,
|
|
|
|
&mut self.ecs().write_storage(),
|
|
|
|
&self.ecs().read_storage(),
|
|
|
|
&uids,
|
|
|
|
&self.ecs().entities(),
|
|
|
|
&mut |entity, group_change| {
|
|
|
|
clients
|
|
|
|
.get_mut(entity)
|
|
|
|
.and_then(|c| {
|
|
|
|
group_change
|
|
|
|
.try_map(|e| uids.get(e).copied())
|
|
|
|
.map(|g| (g, c))
|
|
|
|
})
|
Redo Network Frontend.
Rather than having a single Stream to handle ALL data, seperate into multiple streams:
- Ping Stream, for seperate PINGS
- Register Stream, only used till the client is registered, then no longer used!
- General Stream, used for msg that can occur always
- NotInGame Stream, used for everything NOT ingame, e.g. Character Screen
- InGame Stream, used for all GAME data, players, terrain, entities, etc...
This version does compile, and gets the client registered (with auth too) but doesnt get to the char screen yet.
This fixes also the ignoring messages problem we had, as we are not sending data to the register stream!
This fixes also the problem that the server had to sleep for the Stream Creation, as the Server is now creating the streams and client has to sleep.
2020-10-04 18:20:18 +00:00
|
|
|
.map(|(g, c)| c.send_in_game(ServerInGameMsg::GroupUpdate(g)));
|
2020-04-26 17:03:19 +00:00
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-03-10 02:27:32 +00:00
|
|
|
let (maybe_uid, maybe_pos) = (
|
|
|
|
self.ecs().read_storage::<Uid>().get(entity).copied(),
|
|
|
|
self.ecs().read_storage::<comp::Pos>().get(entity).copied(),
|
|
|
|
);
|
|
|
|
let res = self.ecs_mut().delete_entity(entity);
|
|
|
|
if res.is_ok() {
|
|
|
|
if let (Some(uid), Some(pos)) = (maybe_uid, maybe_pos) {
|
|
|
|
if let Some(region_key) = self
|
|
|
|
.ecs()
|
|
|
|
.read_resource::<common::region::RegionMap>()
|
|
|
|
.find_region(entity, pos.0)
|
|
|
|
{
|
|
|
|
self.ecs()
|
|
|
|
.write_resource::<DeletedEntities>()
|
|
|
|
.record_deleted_entity(uid, region_key);
|
|
|
|
} else {
|
|
|
|
// Don't panic if the entity wasn't found in a region maybe it was just created
|
|
|
|
// and then deleted before the region manager had a chance to assign it a
|
|
|
|
// region
|
|
|
|
warn!(
|
2020-06-21 21:47:49 +00:00
|
|
|
?uid,
|
|
|
|
?pos,
|
2020-03-10 02:27:32 +00:00
|
|
|
"Failed to find region containing entity during entity deletion, assuming \
|
|
|
|
it wasn't sent to any clients and so deletion doesn't need to be \
|
|
|
|
recorded for sync purposes"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res
|
|
|
|
}
|
|
|
|
}
|