1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
use std::{sync::Arc, time::Duration};
use azalea_client::PhysicsState;
use azalea_core::{ResourceLocation, Vec3};
use azalea_entity::{
attributes::AttributeInstance, metadata::Sprinting, Attributes, EntityDimensions, Physics,
Position,
};
use azalea_world::{ChunkStorage, Instance, InstanceContainer, InstanceName, MinecraftEntityId};
use bevy_app::{App, FixedUpdate};
use bevy_ecs::prelude::*;
use bevy_time::fixed_timestep::FixedTime;
use parking_lot::RwLock;
#[derive(Bundle, Clone)]
pub struct SimulatedPlayerBundle {
pub position: Position,
pub physics: Physics,
pub physics_state: PhysicsState,
pub attributes: Attributes,
}
impl SimulatedPlayerBundle {
pub fn new(position: Vec3) -> Self {
let dimensions = EntityDimensions {
width: 0.6,
height: 1.8,
};
SimulatedPlayerBundle {
position: Position::new(position),
physics: Physics::new(dimensions, &position),
physics_state: PhysicsState::default(),
attributes: Attributes {
speed: AttributeInstance::new(0.1),
attack_speed: AttributeInstance::new(4.0),
},
}
}
}
/// Simulate the Minecraft world to see if certain movements would be possible.
pub struct Simulation {
pub app: App,
pub entity: Entity,
_instance: Arc<RwLock<Instance>>,
}
impl Simulation {
pub fn new(chunks: ChunkStorage, player: SimulatedPlayerBundle) -> Self {
let instance_name = ResourceLocation::new("azalea:simulation");
let instance = Arc::new(RwLock::new(Instance {
chunks,
..Default::default()
}));
let mut app = App::new();
// we don't use all the default azalea plugins because we don't need all of them
app.add_plugins((
azalea_physics::PhysicsPlugin,
azalea_entity::EntityPlugin,
azalea_client::movement::PlayerMovePlugin,
super::PathfinderPlugin,
crate::BotPlugin,
azalea_client::task_pool::TaskPoolPlugin::default(),
))
// make sure it doesn't do fixed ticks without us telling it to
.insert_resource(FixedTime::new(Duration::from_secs(60)))
.insert_resource(InstanceContainer {
worlds: [(instance_name.clone(), Arc::downgrade(&instance.clone()))]
.iter()
.cloned()
.collect(),
});
app.edit_schedule(bevy_app::Main, |schedule| {
schedule.set_executor_kind(bevy_ecs::schedule::ExecutorKind::SingleThreaded);
});
let entity = app
.world
.spawn((
MinecraftEntityId(0),
InstanceName(instance_name),
azalea_entity::LocalEntity,
azalea_entity::Jumping::default(),
azalea_entity::LookDirection::default(),
Sprinting(true),
azalea_entity::metadata::Player,
azalea_entity::EyeHeight::new(player.physics.dimensions.height * 0.85),
player,
))
.id();
Self {
app,
entity,
_instance: instance,
}
}
pub fn tick(&mut self) {
self.app.world.run_schedule(FixedUpdate);
self.app.update();
}
pub fn position(&self) -> Vec3 {
**self.app.world.get::<Position>(self.entity).unwrap()
}
}
|