use std::ops::DerefMut;
use std::sync::Mutex;
use crate::client::resource::{Authentication, Client};
use bevy::prelude::IntoSystemSetConfigs;
use bevy::prelude::{
apply_deferred, not, resource_exists, App, Condition, FixedUpdate, IntoSystemConfigs,
Plugin as PluginType, PostUpdate, PreUpdate,
};
use crate::client::events::{ConnectEvent, DisconnectEvent, EntityDespawnEvent, EntitySpawnEvent};
use crate::client::input::InputPlugin;
use crate::client::interpolation::plugin::InterpolationPlugin;
use crate::client::prediction::plugin::{is_in_rollback, PredictionPlugin};
use crate::client::prediction::Rollback;
use crate::client::systems::{is_ready_to_send, receive, send, sync_update};
use crate::protocol::component::ComponentProtocol;
use crate::protocol::message::MessageProtocol;
use crate::protocol::Protocol;
use crate::shared::plugin::SharedPlugin;
use crate::shared::replication::resources::ReplicationData;
use crate::shared::sets::{FixedUpdateSet, MainSet};
use crate::shared::systems::tick::increment_tick;
use crate::transport::io::Io;
use super::config::ClientConfig;
pub struct PluginConfig<P: Protocol> {
client_config: ClientConfig,
io: Io,
protocol: P,
auth: Authentication,
}
impl<P: Protocol> PluginConfig<P> {
pub fn new(client_config: ClientConfig, io: Io, protocol: P, auth: Authentication) -> Self {
PluginConfig {
client_config,
io,
protocol,
auth,
}
}
}
pub struct ClientPlugin<P: Protocol> {
config: Mutex<Option<PluginConfig<P>>>,
}
impl<P: Protocol> ClientPlugin<P> {
pub fn new(config: PluginConfig<P>) -> Self {
Self {
config: Mutex::new(Some(config)),
}
}
}
impl<P: Protocol> PluginType for ClientPlugin<P> {
fn build(&self, app: &mut App) {
let config = self.config.lock().unwrap().deref_mut().take().unwrap();
let client = Client::new(
config.client_config.clone(),
config.io,
config.auth,
config.protocol,
);
let fixed_timestep = config.client_config.shared.tick.tick_duration;
P::Components::add_events::<()>(app);
P::Message::add_events::<()>(app);
app
.add_plugins(SharedPlugin {
config: config.client_config.shared.clone(),
})
.add_plugins(InputPlugin::<P>::default())
.add_plugins(PredictionPlugin::<P>::new(config.client_config.prediction))
.add_plugins(InterpolationPlugin::<P>::new(
config.client_config.interpolation.clone(),
))
.insert_resource(client)
.configure_sets(PreUpdate, (MainSet::Receive, MainSet::ReceiveFlush).chain())
.configure_sets(
FixedUpdate,
(
FixedUpdateSet::TickUpdate,
FixedUpdateSet::Main,
FixedUpdateSet::MainFlush,
)
.chain(),
)
.configure_sets(
PostUpdate,
(MainSet::Send.run_if(is_ready_to_send::<P>), MainSet::Sync),
)
.add_event::<ConnectEvent>()
.add_event::<DisconnectEvent>()
.add_event::<EntitySpawnEvent>()
.add_event::<EntityDespawnEvent>()
.add_systems(
PreUpdate,
(
(receive::<P>).in_set(MainSet::Receive),
apply_deferred.in_set(MainSet::ReceiveFlush),
),
)
.add_systems(
FixedUpdate,
(
increment_tick::<Client<P>>
.in_set(FixedUpdateSet::TickUpdate)
.run_if((not(resource_exists::<Rollback>())).or_else(not(is_in_rollback))),
apply_deferred.in_set(FixedUpdateSet::MainFlush),
),
)
.add_systems(
PostUpdate,
(
send::<P>.in_set(MainSet::Send),
sync_update::<P>.in_set(MainSet::Sync),
),
);
}
}