aboutsummaryrefslogtreecommitdiff
path: root/azalea/src/swarm/plugins.rs
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2022-11-27 16:25:07 -0600
committerGitHub <noreply@github.com>2022-11-27 16:25:07 -0600
commit631ed63dbdc7167df4de02a55b5c2ef1cea909e9 (patch)
tree104e567c332f2aeb30ea6acefef8c73f9b2f158b /azalea/src/swarm/plugins.rs
parent962b9fcaae917c7e5bef718469fba31f6ff7c3cb (diff)
downloadazalea-drasl-631ed63dbdc7167df4de02a55b5c2ef1cea909e9.tar.xz
Swarm (#36)
* make azalea-pathfinder dir * start writing d* lite impl * more work on d* lite * work more on implementing d* lite * full d* lite impl * updated edges * add next() function * add NoPathError * why does dstar lite not work * fix d* lite implementation * make the test actually check the coords * replace while loop with if statement * fix clippy complaints * make W only have to be PartialOrd * fix PartialOrd issues * implement mtd* lite * add a test to mtd* lite * remove normal d* lite * make heuristic only take in one arg * add `success` function * Update README.md * evil black magic to make .entity not need dimension * start adding moves * slightly improve the vec3/position situation new macro that implements all the useful functions * moves stuff * make it compile * update deps in az-pathfinder * make it compile again * more pathfinding stuff * add Bot::look_at * replace EntityMut and EntityRef with just Entity * block pos pathfinding stuff * rename movedirection to walkdirection * execute path every tick * advance path * change az-pf version * make azalea_client keep plugin state * fix Plugins::get * why does it think there is air * start debugging incorrect air * update some From methods to use rem_euclid * start adding swarm * fix deadlock i still don't understand why it was happening but the solution was to keep the Client::player lock for shorter so it didn't overlap with the Client::dimension lock * make lookat actually work probably * fix going too fast * Update main.rs * make a thing immutable * direction_looking_at * fix rotations * import swarm in an example * fix stuff from merge * remove azalea_pathfinder import * delete azalea-pathfinder crate already in azalea::pathfinder module * swarms * start working on shared dimensions * Shared worlds work * start adding Swarm::add_account * add_account works * change "client" to "bot" in some places * Fix issues from merge * Update world.rs * add SwarmEvent::Disconnect(Account) * almost add SwarmEvent::Chat and new plugin system it panics rn * make plugins have to provide the State associated type * improve comments * make fn build slightly cleaner * fix SwarmEvent::Chat * change a println in bot/main.rs * Client::shutdown -> disconnect * polish fix clippy warnings + improve some docs a bit * fix shared worlds* *there's a bug that entities and bots will have their positions exaggerated because the relative movement packet is applied for every entity once per bot * i am being trolled by rust for some reason some stuff is really slow for literally no reason and it makes no sense i am going insane * make world an RwLock again * remove debug messages * fix skipping event ticks unfortunately now sending events is `.send().await?` instead of just `.send()` * fix deadlock + warnings * turns out my floor_mod impl was wrong and i32::rem_euclid has the correct behavior LOL * still errors with lots of bots * make swarm iter & fix new chunks not loading * improve docs * start fixing tests * fix all the tests except the examples i don't know how to exclude them from the tests * improve docs some more
Diffstat (limited to 'azalea/src/swarm/plugins.rs')
-rw-r--r--azalea/src/swarm/plugins.rs134
1 files changed, 134 insertions, 0 deletions
diff --git a/azalea/src/swarm/plugins.rs b/azalea/src/swarm/plugins.rs
new file mode 100644
index 00000000..0c7cf2ae
--- /dev/null
+++ b/azalea/src/swarm/plugins.rs
@@ -0,0 +1,134 @@
+use crate::{Swarm, SwarmEvent};
+use async_trait::async_trait;
+use nohash_hasher::NoHashHasher;
+use std::{
+ any::{Any, TypeId},
+ collections::HashMap,
+ hash::BuildHasherDefault,
+};
+
+type U64Hasher = BuildHasherDefault<NoHashHasher<u64>>;
+
+// kind of based on https://docs.rs/http/latest/src/http/extensions.rs.html
+/// A map of plugin ids to [`SwarmPlugin`] trait objects. The client stores
+/// this so we can keep the state for our [`Swarm`] plugins.
+///
+/// If you're using azalea, you should generate this from the `swarm_plugins!` macro.
+#[derive(Clone, Default)]
+pub struct SwarmPlugins<S> {
+ map: Option<HashMap<TypeId, Box<dyn SwarmPlugin<S>>, U64Hasher>>,
+}
+
+#[derive(Clone)]
+pub struct SwarmPluginStates<S> {
+ map: Option<HashMap<TypeId, Box<dyn SwarmPluginState<S>>, U64Hasher>>,
+}
+
+impl<S> SwarmPluginStates<S> {
+ pub fn get<T: SwarmPluginState<S>>(&self) -> Option<&T> {
+ self.map
+ .as_ref()
+ .and_then(|map| map.get(&TypeId::of::<T>()))
+ .and_then(|boxed| (boxed.as_ref() as &dyn Any).downcast_ref::<T>())
+ }
+}
+
+impl<S> SwarmPlugins<S>
+where
+ S: 'static,
+{
+ /// Create a new empty set of plugins.
+ pub fn new() -> Self {
+ Self { map: None }
+ }
+
+ /// Add a new plugin to this set.
+ pub fn add<T: SwarmPlugin<S>>(&mut self, plugin: T) {
+ if self.map.is_none() {
+ self.map = Some(HashMap::with_hasher(BuildHasherDefault::default()));
+ }
+ self.map
+ .as_mut()
+ .unwrap()
+ .insert(TypeId::of::<T>(), Box::new(plugin));
+ }
+
+ /// Build our plugin states from this set of plugins. Note that if you're
+ /// using `azalea` you'll probably never need to use this as it's called
+ /// for you.
+ pub fn build(self) -> SwarmPluginStates<S> {
+ if self.map.is_none() {
+ return SwarmPluginStates { map: None };
+ }
+ let mut map = HashMap::with_hasher(BuildHasherDefault::default());
+ for (id, plugin) in self.map.unwrap().into_iter() {
+ map.insert(id, plugin.build());
+ }
+ SwarmPluginStates { map: Some(map) }
+ }
+}
+
+impl<S> IntoIterator for SwarmPluginStates<S> {
+ type Item = Box<dyn SwarmPluginState<S>>;
+ type IntoIter = std::vec::IntoIter<Self::Item>;
+
+ /// Iterate over the plugin states.
+ fn into_iter(self) -> Self::IntoIter {
+ self.map
+ .map(|map| map.into_values().collect::<Vec<_>>())
+ .unwrap_or_default()
+ .into_iter()
+ }
+}
+
+/// A `SwarmPluginState` keeps the current state of a plugin for a client. All
+/// the fields must be atomic. Unique `SwarmPluginState`s are built from
+/// [`SwarmPlugin`]s.
+#[async_trait]
+pub trait SwarmPluginState<S>: Send + Sync + SwarmPluginStateClone<S> + Any + 'static {
+ async fn handle(self: Box<Self>, event: SwarmEvent, swarm: Swarm<S>);
+}
+
+/// Swarm plugins can keep their own personal state ([`SwarmPluginState`]),
+/// listen to [`SwarmEvent`]s, and add new functions to [`Swarm`].
+pub trait SwarmPlugin<S>: Send + Sync + SwarmPluginClone<S> + Any + 'static {
+ fn build(&self) -> Box<dyn SwarmPluginState<S>>;
+}
+
+/// An internal trait that allows SwarmPluginState to be cloned.
+#[doc(hidden)]
+pub trait SwarmPluginStateClone<S> {
+ fn clone_box(&self) -> Box<dyn SwarmPluginState<S>>;
+}
+impl<T, S> SwarmPluginStateClone<S> for T
+where
+ T: 'static + SwarmPluginState<S> + Clone,
+{
+ fn clone_box(&self) -> Box<dyn SwarmPluginState<S>> {
+ Box::new(self.clone())
+ }
+}
+impl<S> Clone for Box<dyn SwarmPluginState<S>> {
+ fn clone(&self) -> Self {
+ self.clone_box()
+ }
+}
+
+/// An internal trait that allows SwarmPlugin to be cloned.
+#[doc(hidden)]
+pub trait SwarmPluginClone<S> {
+ fn clone_box(&self) -> Box<dyn SwarmPlugin<S>>;
+}
+impl<T, S> SwarmPluginClone<S> for T
+where
+ T: 'static + SwarmPlugin<S> + Clone,
+{
+ fn clone_box(&self) -> Box<dyn SwarmPlugin<S>> {
+ Box::new(self.clone())
+ }
+}
+impl<S> Clone for Box<dyn SwarmPlugin<S>> {
+ fn clone(&self) -> Self {
+ self.clone_box()
+ }
+}