mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add battle_mode server setting and player flag
This commit is contained in:
parent
e6ef678c28
commit
7d4a8cbfa4
@ -71,6 +71,13 @@ pub struct TargetInfo<'a> {
|
||||
pub char_state: Option<&'a CharacterState>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct AttackOptions {
|
||||
pub target_dodging: bool,
|
||||
pub target_group: GroupTarget,
|
||||
pub avoid_harm: bool,
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)] // TODO: Yeet clone derive
|
||||
pub struct Attack {
|
||||
@ -158,28 +165,47 @@ impl Attack {
|
||||
1.0 - (1.0 - damage_reduction) * (1.0 - block_reduction)
|
||||
}
|
||||
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn apply_attack(
|
||||
&self,
|
||||
target_group: GroupTarget,
|
||||
attacker: Option<AttackerInfo>,
|
||||
target: TargetInfo,
|
||||
dir: Dir,
|
||||
target_dodging: bool,
|
||||
// Currently just modifies damage, maybe look into modifying strength of other effects?
|
||||
options: AttackOptions,
|
||||
// Currently strength_modifier just modifies damage,
|
||||
// maybe look into modifying strength of other effects?
|
||||
strength_modifier: f32,
|
||||
attack_source: AttackSource,
|
||||
mut emit: impl FnMut(ServerEvent),
|
||||
mut emit_outcome: impl FnMut(Outcome),
|
||||
) -> bool {
|
||||
let mut is_applied = false;
|
||||
let AttackOptions {
|
||||
target_dodging,
|
||||
target_group,
|
||||
avoid_harm,
|
||||
} = options;
|
||||
// target == OutOfGroup is basic heuristic that this
|
||||
// "attack" has negative effects.
|
||||
//
|
||||
// so if target dodges this "attack" or we don't want to harm target,
|
||||
// it should avoid such "damage" or effect
|
||||
let avoid_damage = |attack_damage: &AttackDamage| {
|
||||
matches!(attack_damage.target, Some(GroupTarget::OutOfGroup))
|
||||
&& (target_dodging || avoid_harm)
|
||||
};
|
||||
let avoid_effect = |attack_effect: &AttackEffect| {
|
||||
matches!(attack_effect.target, Some(GroupTarget::OutOfGroup))
|
||||
&& (target_dodging || avoid_harm)
|
||||
};
|
||||
let is_crit = thread_rng().gen::<f32>() < self.crit_chance;
|
||||
let mut is_applied = false;
|
||||
let mut accumulated_damage = 0.0;
|
||||
for damage in self
|
||||
.damages
|
||||
.iter()
|
||||
.filter(|d| d.target.map_or(true, |t| t == target_group))
|
||||
.filter(|d| !(matches!(d.target, Some(GroupTarget::OutOfGroup)) && target_dodging))
|
||||
.filter(|d| !avoid_damage(d))
|
||||
{
|
||||
is_applied = true;
|
||||
let damage_reduction = Attack::compute_damage_reduction(
|
||||
@ -294,7 +320,7 @@ impl Attack {
|
||||
.effects
|
||||
.iter()
|
||||
.filter(|e| e.target.map_or(true, |t| t == target_group))
|
||||
.filter(|e| !(matches!(e.target, Some(GroupTarget::OutOfGroup)) && target_dodging))
|
||||
.filter(|e| !avoid_effect(e))
|
||||
{
|
||||
if effect.requirements.iter().all(|req| match req {
|
||||
CombatRequirement::AnyDamage => accumulated_damage > 0.0 && target.health.is_some(),
|
||||
|
@ -3,6 +3,8 @@ use specs::{Component, DerefFlaggedStorage, NullStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::resources::BattleMode;
|
||||
|
||||
const MAX_ALIAS_LEN: usize = 32;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -17,11 +19,34 @@ pub enum DisconnectReason {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Player {
|
||||
pub alias: String,
|
||||
pub battle_mode: BattleMode,
|
||||
uuid: Uuid,
|
||||
}
|
||||
|
||||
impl Player {
|
||||
pub fn new(alias: String, uuid: Uuid) -> Self { Self { alias, uuid } }
|
||||
pub fn new(alias: String, battle_mode: BattleMode, uuid: Uuid) -> Self {
|
||||
Self {
|
||||
alias,
|
||||
battle_mode,
|
||||
uuid,
|
||||
}
|
||||
}
|
||||
|
||||
/// Currently we allow attacking only if both players are opt-in to PvP.
|
||||
///
|
||||
/// Simple as tea, if they don't want the tea, don't make them drink the tea.
|
||||
pub fn allow_harm(&self, other: &Player) -> bool {
|
||||
// TODO: discuss if we want to keep self-harm
|
||||
matches!(
|
||||
(self.battle_mode, other.battle_mode),
|
||||
(BattleMode::PvP, BattleMode::PvP)
|
||||
)
|
||||
}
|
||||
|
||||
/// Inverse of `allow_harm`. Read its doc to learn more.
|
||||
pub fn disallow_harm(&self, other: &Player) -> bool {
|
||||
!self.allow_harm(other)
|
||||
}
|
||||
|
||||
pub fn is_valid(&self) -> bool { Self::alias_validate(&self.alias).is_ok() }
|
||||
|
||||
|
@ -28,6 +28,15 @@ impl Effect {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_harm(&self) -> bool {
|
||||
match self {
|
||||
Effect::Health(c) => c.amount < 0,
|
||||
Effect::PoiseChange(c) => c.amount < 0,
|
||||
Effect::Damage(_) => true,
|
||||
Effect::Buff(e) => !e.kind.is_buff(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modify_strength(&mut self, modifier: f32) {
|
||||
match self {
|
||||
Effect::Health(change) => {
|
||||
|
@ -74,3 +74,13 @@ impl PlayerPhysicsSetting {
|
||||
pub struct PlayerPhysicsSettings {
|
||||
pub settings: hashbrown::HashMap<uuid::Uuid, PlayerPhysicsSetting>,
|
||||
}
|
||||
|
||||
/// Describe how players interact with other players.
|
||||
///
|
||||
/// Probably will be removed when we will discover better way
|
||||
/// to handle duels and murders
|
||||
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
|
||||
pub enum BattleMode {
|
||||
PvP,
|
||||
PvE,
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
use common::{
|
||||
combat::{AttackSource, AttackerInfo, TargetInfo},
|
||||
combat::{AttackOptions, AttackSource, AttackerInfo, TargetInfo},
|
||||
comp::{
|
||||
agent::{Sound, SoundKind},
|
||||
Beam, BeamSegment, Body, CharacterState, Combo, Energy, Group, Health, HealthSource,
|
||||
Inventory, Ori, Pos, Scale, Stats,
|
||||
Inventory, Ori, Player, Pos, Scale, Stats,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
outcome::Outcome,
|
||||
@ -26,6 +26,7 @@ use vek::*;
|
||||
#[derive(SystemData)]
|
||||
pub struct ReadData<'a> {
|
||||
entities: Entities<'a>,
|
||||
players: ReadStorage<'a, Player>,
|
||||
server_bus: Read<'a, EventBus<ServerEvent>>,
|
||||
time: Read<'a, Time>,
|
||||
dt: Read<'a, DeltaTime>,
|
||||
@ -212,12 +213,32 @@ impl<'a> System<'a> for Sys {
|
||||
char_state: read_data.character_states.get(target),
|
||||
};
|
||||
|
||||
beam_segment.properties.attack.apply_attack(
|
||||
// No luck with dodging beams
|
||||
let is_dodge = false;
|
||||
let avoid_harm = {
|
||||
let players = &read_data.players;
|
||||
beam_owner.map_or(false, |attacker| {
|
||||
if let (Some(attacker), Some(target)) =
|
||||
(players.get(attacker), players.get(target))
|
||||
{
|
||||
attacker.disallow_harm(target)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let attack_options = AttackOptions {
|
||||
target_dodging: is_dodge,
|
||||
target_group,
|
||||
avoid_harm,
|
||||
};
|
||||
|
||||
beam_segment.properties.attack.apply_attack(
|
||||
attacker_info,
|
||||
target_info,
|
||||
ori.look_dir(),
|
||||
false,
|
||||
attack_options,
|
||||
1.0,
|
||||
AttackSource::Beam,
|
||||
|e| server_events.push(e),
|
||||
|
@ -1,9 +1,9 @@
|
||||
use common::{
|
||||
combat::{AttackSource, AttackerInfo, TargetInfo},
|
||||
combat::{AttackOptions, AttackSource, AttackerInfo, TargetInfo},
|
||||
comp::{
|
||||
agent::{Sound, SoundKind},
|
||||
Body, CharacterState, Combo, Energy, Group, Health, Inventory, Melee, Ori, Pos, Scale,
|
||||
Stats,
|
||||
Body, CharacterState, Combo, Energy, Group, Health, Inventory, Melee, Ori, Player, Pos,
|
||||
Scale, Stats,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
outcome::Outcome,
|
||||
@ -22,6 +22,7 @@ use vek::*;
|
||||
pub struct ReadData<'a> {
|
||||
time: Read<'a, Time>,
|
||||
entities: Entities<'a>,
|
||||
players: ReadStorage<'a, Player>,
|
||||
uids: ReadStorage<'a, Uid>,
|
||||
positions: ReadStorage<'a, Pos>,
|
||||
orientations: ReadStorage<'a, Ori>,
|
||||
@ -161,12 +162,40 @@ impl<'a> System<'a> for Sys {
|
||||
char_state: read_data.char_states.get(target),
|
||||
};
|
||||
|
||||
let is_applied = melee_attack.attack.apply_attack(
|
||||
let avoid_harm = {
|
||||
let players = &read_data.players;
|
||||
if let (Some(attacker), Some(target)) =
|
||||
(players.get(attacker), players.get(target))
|
||||
{
|
||||
attacker.disallow_harm(target)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
// FIXME: printf debugging, this shouldn't go to master
|
||||
if let Some(attacker) = read_data.players.get(attacker) {
|
||||
println!("attacker battle_mode: {:?}", attacker.battle_mode);
|
||||
} else {
|
||||
println!("attacker special casing")
|
||||
}
|
||||
if let Some(target) = read_data.players.get(target) {
|
||||
println!("target battle_mode: {:?}", target.battle_mode);
|
||||
} else {
|
||||
println!("target special casing")
|
||||
}
|
||||
|
||||
let attack_options = AttackOptions {
|
||||
target_dodging: is_dodge,
|
||||
target_group,
|
||||
avoid_harm,
|
||||
};
|
||||
|
||||
let is_applied = melee_attack.attack.apply_attack(
|
||||
attacker_info,
|
||||
target_info,
|
||||
dir,
|
||||
is_dodge,
|
||||
attack_options,
|
||||
1.0,
|
||||
AttackSource::Melee,
|
||||
|e| server_emitter.emit(e),
|
||||
|
@ -1,9 +1,9 @@
|
||||
use common::{
|
||||
combat::{AttackSource, AttackerInfo, TargetInfo},
|
||||
combat::{AttackOptions, AttackSource, AttackerInfo, TargetInfo},
|
||||
comp::{
|
||||
agent::{Sound, SoundKind},
|
||||
projectile, Body, CharacterState, Combo, Energy, Group, Health, HealthSource, Inventory,
|
||||
Ori, PhysicsState, Pos, Projectile, Stats, Vel,
|
||||
Ori, PhysicsState, Player, Pos, Projectile, Stats, Vel,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
outcome::Outcome,
|
||||
@ -25,6 +25,7 @@ use vek::*;
|
||||
pub struct ReadData<'a> {
|
||||
time: Read<'a, Time>,
|
||||
entities: Entities<'a>,
|
||||
players: ReadStorage<'a, Player>,
|
||||
dt: Read<'a, DeltaTime>,
|
||||
uid_allocator: Read<'a, UidAllocator>,
|
||||
server_bus: Read<'a, EventBus<ServerEvent>>,
|
||||
@ -152,6 +153,22 @@ impl<'a> System<'a> for Sys {
|
||||
char_state: read_data.character_states.get(target),
|
||||
};
|
||||
|
||||
// They say witchers can dodge arrows,
|
||||
// but we don't have witchers
|
||||
let is_dodge = false;
|
||||
let avoid_harm = {
|
||||
let players = &read_data.players;
|
||||
projectile_owner.map_or(false, |attacker| {
|
||||
if let (Some(attacker), Some(target)) =
|
||||
(players.get(attacker), players.get(target))
|
||||
{
|
||||
attacker.disallow_harm(target)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
if let Some(&body) = read_data.bodies.get(entity) {
|
||||
outcomes.push(Outcome::ProjectileHit {
|
||||
pos: pos.0,
|
||||
@ -165,12 +182,16 @@ impl<'a> System<'a> for Sys {
|
||||
});
|
||||
}
|
||||
|
||||
attack.apply_attack(
|
||||
let attack_options = AttackOptions {
|
||||
target_dodging: is_dodge,
|
||||
target_group,
|
||||
avoid_harm,
|
||||
};
|
||||
attack.apply_attack(
|
||||
attacker_info,
|
||||
target_info,
|
||||
dir,
|
||||
false,
|
||||
attack_options,
|
||||
1.0,
|
||||
AttackSource::Projectile,
|
||||
|e| server_emitter.emit(e),
|
||||
|
@ -1,9 +1,9 @@
|
||||
use common::{
|
||||
combat::{AttackSource, AttackerInfo, TargetInfo},
|
||||
combat::{AttackOptions, AttackSource, AttackerInfo, TargetInfo},
|
||||
comp::{
|
||||
agent::{Sound, SoundKind},
|
||||
Body, CharacterState, Combo, Energy, Group, Health, HealthSource, Inventory, Ori,
|
||||
PhysicsState, Pos, Scale, Shockwave, ShockwaveHitEntities, Stats,
|
||||
PhysicsState, Player, Pos, Scale, Shockwave, ShockwaveHitEntities, Stats,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
outcome::Outcome,
|
||||
@ -25,6 +25,7 @@ pub struct ReadData<'a> {
|
||||
entities: Entities<'a>,
|
||||
server_bus: Read<'a, EventBus<ServerEvent>>,
|
||||
time: Read<'a, Time>,
|
||||
players: ReadStorage<'a, Player>,
|
||||
dt: Read<'a, DeltaTime>,
|
||||
uid_allocator: Read<'a, UidAllocator>,
|
||||
uids: ReadStorage<'a, Uid>,
|
||||
@ -208,12 +209,32 @@ impl<'a> System<'a> for Sys {
|
||||
char_state: read_data.character_states.get(target),
|
||||
};
|
||||
|
||||
shockwave.properties.attack.apply_attack(
|
||||
// Trying roll during earthquake isn't the best idea
|
||||
let is_dodge = false;
|
||||
let avoid_harm = {
|
||||
let players = &read_data.players;
|
||||
shockwave_owner.map_or(false, |attacker| {
|
||||
if let (Some(attacker), Some(target)) =
|
||||
(players.get(attacker), players.get(target))
|
||||
{
|
||||
attacker.disallow_harm(target)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let attack_options = AttackOptions {
|
||||
target_dodging: is_dodge,
|
||||
target_group,
|
||||
avoid_harm,
|
||||
};
|
||||
|
||||
shockwave.properties.attack.apply_attack(
|
||||
attacker_info,
|
||||
target_info,
|
||||
dir,
|
||||
false,
|
||||
attack_options,
|
||||
1.0,
|
||||
AttackSource::Shockwave,
|
||||
|e| server_emitter.emit(e),
|
||||
|
@ -819,6 +819,7 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
|
||||
let energies = &ecs.read_storage::<comp::Energy>();
|
||||
let combos = &ecs.read_storage::<comp::Combo>();
|
||||
let inventories = &ecs.read_storage::<comp::Inventory>();
|
||||
let players = &ecs.read_storage::<comp::Player>();
|
||||
for (
|
||||
entity_b,
|
||||
pos_b,
|
||||
@ -887,12 +888,31 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
|
||||
char_state: char_state_b_maybe,
|
||||
};
|
||||
|
||||
attack.apply_attack(
|
||||
let avoid_harm = {
|
||||
owner_entity.map_or(false, |attacker| {
|
||||
if let (Some(attacker), Some(target)) =
|
||||
(players.get(attacker), players.get(entity_b))
|
||||
{
|
||||
attacker.disallow_harm(target)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let attack_options = combat::AttackOptions {
|
||||
// cool guyz maybe don't look at explosions
|
||||
// but they still got hurt, it's not Hollywood
|
||||
target_dodging: false,
|
||||
target_group,
|
||||
avoid_harm,
|
||||
};
|
||||
|
||||
attack.apply_attack(
|
||||
attacker_info,
|
||||
target_info,
|
||||
dir,
|
||||
false,
|
||||
attack_options,
|
||||
strength,
|
||||
combat::AttackSource::Explosion,
|
||||
|e| server_eventbus.emit_now(e),
|
||||
@ -902,6 +922,7 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
|
||||
}
|
||||
},
|
||||
RadiusEffect::Entity(mut effect) => {
|
||||
let players = &ecs.read_storage::<comp::Player>();
|
||||
for (entity_b, pos_b, body_b_maybe) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<comp::Pos>(),
|
||||
@ -921,9 +942,23 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
|
||||
.read_storage::<comp::Health>()
|
||||
.get(entity_b)
|
||||
.map_or(true, |h| !h.is_dead);
|
||||
|
||||
if is_alive {
|
||||
let avoid_harm = {
|
||||
owner_entity.map_or(false, |attacker| {
|
||||
if let (Some(attacker), Some(target)) =
|
||||
(players.get(attacker), players.get(entity_b))
|
||||
{
|
||||
attacker.disallow_harm(target)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
};
|
||||
effect.modify_strength(strength);
|
||||
server.state().apply_effect(entity_b, effect.clone(), owner);
|
||||
if !(effect.is_harm() && avoid_harm) {
|
||||
server.state().apply_effect(entity_b, effect.clone(), owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ pub use server_description::ServerDescription;
|
||||
pub use whitelist::{Whitelist, WhitelistInfo, WhitelistRecord};
|
||||
|
||||
use chrono::Utc;
|
||||
use common::resources::BattleMode;
|
||||
use core::time::Duration;
|
||||
use portpicker::pick_unused_port;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -48,7 +49,7 @@ pub struct Settings {
|
||||
pub quic_files: Option<X509FilePair>,
|
||||
pub max_players: usize,
|
||||
pub world_seed: u32,
|
||||
//pub pvp_enabled: bool,
|
||||
pub battle_mode: BattleMode,
|
||||
pub server_name: String,
|
||||
pub start_time: f64,
|
||||
/// When set to None, loads the default map file (if available); otherwise,
|
||||
@ -73,6 +74,7 @@ impl Default for Settings {
|
||||
world_seed: DEFAULT_WORLD_SEED,
|
||||
server_name: "Veloren Alpha".into(),
|
||||
max_players: 100,
|
||||
battle_mode: BattleMode::PvP,
|
||||
start_time: 9.0 * 3600.0,
|
||||
map_file: None,
|
||||
max_view_distance: Some(65),
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
client::Client,
|
||||
login_provider::{LoginProvider, PendingLogin},
|
||||
metrics::PlayerMetrics,
|
||||
EditableSettings,
|
||||
EditableSettings, Settings,
|
||||
};
|
||||
use common::{
|
||||
comp::{Admin, Player, Stats},
|
||||
@ -17,7 +17,8 @@ use common_net::msg::{
|
||||
use hashbrown::HashMap;
|
||||
use plugin_api::Health;
|
||||
use specs::{
|
||||
storage::StorageEntry, Entities, Join, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage,
|
||||
shred::ResourceId, storage::StorageEntry, Entities, Join, Read, ReadExpect, ReadStorage,
|
||||
SystemData, World, WriteExpect, WriteStorage,
|
||||
};
|
||||
use tracing::trace;
|
||||
|
||||
@ -29,26 +30,32 @@ type ReadPlugin<'a> = Read<'a, PluginMgr>;
|
||||
#[cfg(not(feature = "plugins"))]
|
||||
type ReadPlugin<'a> = Option<Read<'a, ()>>;
|
||||
|
||||
#[derive(SystemData)]
|
||||
pub struct ReadData<'a> {
|
||||
entities: Entities<'a>,
|
||||
stats: ReadStorage<'a, Stats>,
|
||||
uids: ReadStorage<'a, Uid>,
|
||||
clients: ReadStorage<'a, Client>,
|
||||
server_event_bus: Read<'a, EventBus<ServerEvent>>,
|
||||
_health_comp: ReadStorage<'a, Health>, // used by plugin feature
|
||||
_plugin_mgr: ReadPlugin<'a>, // used by plugin feature
|
||||
_uid_allocator: Read<'a, UidAllocator>, // used by plugin feature
|
||||
}
|
||||
|
||||
/// This system will handle new messages from clients
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
ReadData<'a>,
|
||||
ReadExpect<'a, PlayerMetrics>,
|
||||
ReadStorage<'a, Health>,
|
||||
ReadStorage<'a, Uid>,
|
||||
ReadStorage<'a, Client>,
|
||||
WriteStorage<'a, Player>,
|
||||
WriteStorage<'a, PendingLogin>,
|
||||
Read<'a, UidAllocator>,
|
||||
ReadPlugin<'a>,
|
||||
ReadStorage<'a, Stats>,
|
||||
WriteExpect<'a, LoginProvider>,
|
||||
WriteStorage<'a, Admin>,
|
||||
ReadExpect<'a, Settings>,
|
||||
ReadExpect<'a, EditableSettings>,
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
WriteStorage<'a, Player>,
|
||||
WriteStorage<'a, Admin>,
|
||||
WriteStorage<'a, PendingLogin>,
|
||||
WriteExpect<'a, LoginProvider>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "msg::register";
|
||||
@ -58,24 +65,23 @@ impl<'a> System<'a> for Sys {
|
||||
fn run(
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
entities,
|
||||
read_data,
|
||||
player_metrics,
|
||||
_health_comp, // used by plugin feature
|
||||
uids,
|
||||
clients,
|
||||
mut players,
|
||||
mut pending_logins,
|
||||
_uid_allocator, // used by plugin feature
|
||||
_plugin_mgr, // used by plugin feature
|
||||
stats,
|
||||
mut login_provider,
|
||||
mut admins,
|
||||
settings,
|
||||
editable_settings,
|
||||
server_event_bus,
|
||||
mut players,
|
||||
mut admins,
|
||||
mut pending_logins,
|
||||
mut login_provider,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
// Player list to send new players.
|
||||
let player_list = (&uids, &players, stats.maybe(), admins.maybe())
|
||||
let player_list = (
|
||||
&read_data.uids,
|
||||
&players,
|
||||
read_data.stats.maybe(),
|
||||
admins.maybe(),
|
||||
)
|
||||
.join()
|
||||
.map(|(uid, player, stats, admin)| {
|
||||
(*uid, PlayerInfo {
|
||||
@ -92,7 +98,7 @@ impl<'a> System<'a> for Sys {
|
||||
let mut new_players = Vec::new();
|
||||
|
||||
// defer auth lockup
|
||||
for (entity, client) in (&entities, &clients).join() {
|
||||
for (entity, client) in (&read_data.entities, &read_data.clients).join() {
|
||||
let _ = super::try_recv_all(client, 0, |_, msg: ClientRegister| {
|
||||
trace!(?msg.token_or_username, "defer auth lockup");
|
||||
let pending = login_provider.verify(&msg.token_or_username);
|
||||
@ -103,15 +109,17 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
let mut finished_pending = vec![];
|
||||
let mut retries = vec![];
|
||||
for (entity, client, mut pending) in (&entities, &clients, &mut pending_logins).join() {
|
||||
for (entity, client, mut pending) in
|
||||
(&read_data.entities, &read_data.clients, &mut pending_logins).join()
|
||||
{
|
||||
if let Err(e) = || -> std::result::Result<(), crate::error::Error> {
|
||||
#[cfg(feature = "plugins")]
|
||||
let ecs_world = EcsWorld {
|
||||
entities: &entities,
|
||||
health: (&_health_comp).into(),
|
||||
uid: (&uids).into(),
|
||||
entities: &read_data.entities,
|
||||
health: (&read_data._health_comp).into(),
|
||||
uid: (&read_data.uids).into(),
|
||||
player: (&players).into(),
|
||||
uid_allocator: &_uid_allocator,
|
||||
uid_allocator: &read_data._uid_allocator,
|
||||
};
|
||||
|
||||
let (username, uuid) = match login_provider.login(
|
||||
@ -119,7 +127,7 @@ impl<'a> System<'a> for Sys {
|
||||
#[cfg(feature = "plugins")]
|
||||
&ecs_world,
|
||||
#[cfg(feature = "plugins")]
|
||||
&_plugin_mgr,
|
||||
&read_data._plugin_mgr,
|
||||
&*editable_settings.admins,
|
||||
&*editable_settings.whitelist,
|
||||
&*editable_settings.banlist,
|
||||
@ -130,10 +138,12 @@ impl<'a> System<'a> for Sys {
|
||||
trace!(?r, "pending login returned");
|
||||
match r {
|
||||
Err(e) => {
|
||||
server_event_bus.emit_now(ServerEvent::ClientDisconnect(
|
||||
entity,
|
||||
common::comp::DisconnectReason::Kicked,
|
||||
));
|
||||
read_data
|
||||
.server_event_bus
|
||||
.emit_now(ServerEvent::ClientDisconnect(
|
||||
entity,
|
||||
common::comp::DisconnectReason::Kicked,
|
||||
));
|
||||
client.send(ServerRegisterAnswer::Err(e))?;
|
||||
return Ok(());
|
||||
},
|
||||
@ -143,15 +153,18 @@ impl<'a> System<'a> for Sys {
|
||||
};
|
||||
|
||||
// Check if user is already logged-in
|
||||
if let Some((old_entity, old_client, _)) = (&entities, &clients, &players)
|
||||
.join()
|
||||
.find(|(_, _, old_player)| old_player.uuid() == uuid)
|
||||
if let Some((old_entity, old_client, _)) =
|
||||
(&read_data.entities, &read_data.clients, &players)
|
||||
.join()
|
||||
.find(|(_, _, old_player)| old_player.uuid() == uuid)
|
||||
{
|
||||
// Remove old client
|
||||
server_event_bus.emit_now(ServerEvent::ClientDisconnect(
|
||||
old_entity,
|
||||
common::comp::DisconnectReason::NewerLogin,
|
||||
));
|
||||
read_data
|
||||
.server_event_bus
|
||||
.emit_now(ServerEvent::ClientDisconnect(
|
||||
old_entity,
|
||||
common::comp::DisconnectReason::NewerLogin,
|
||||
));
|
||||
let _ = old_client.send(ServerGeneral::Disconnect(DisconnectReason::Kicked(
|
||||
String::from("You have logged in from another location."),
|
||||
)));
|
||||
@ -166,7 +179,7 @@ impl<'a> System<'a> for Sys {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let player = Player::new(username, uuid);
|
||||
let player = Player::new(username, settings.battle_mode, uuid);
|
||||
let admin = editable_settings.admins.get(&uuid);
|
||||
|
||||
if !player.is_valid() {
|
||||
@ -215,9 +228,9 @@ impl<'a> System<'a> for Sys {
|
||||
// Handle new players.
|
||||
// Tell all clients to add them to the player list.
|
||||
for entity in new_players {
|
||||
if let (Some(uid), Some(player)) = (uids.get(entity), players.get(entity)) {
|
||||
if let (Some(uid), Some(player)) = (read_data.uids.get(entity), players.get(entity)) {
|
||||
let mut lazy_msg = None;
|
||||
for (_, client) in (&players, &clients).join() {
|
||||
for (_, client) in (&players, &read_data.clients).join() {
|
||||
if lazy_msg.is_none() {
|
||||
lazy_msg = Some(client.prepare(ServerGeneral::PlayerListUpdate(
|
||||
PlayerListUpdate::Add(*uid, PlayerInfo {
|
||||
|
Loading…
Reference in New Issue
Block a user