1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 06:16:04 +00:00

start trying to fix tests

This commit is contained in:
Ubuntu 2023-01-27 21:15:31 +00:00
parent eb1c9f14bf
commit 4c6657fe40
5 changed files with 258 additions and 149 deletions

1
Cargo.lock generated
View file

@ -356,6 +356,7 @@ version = "0.5.0"
dependencies = [
"azalea-block",
"azalea-core",
"azalea-registry",
"azalea-world",
"bevy_app",
"bevy_ecs",

View file

@ -32,10 +32,8 @@ use azalea_protocol::{
},
resolver, ServerAddress,
};
use azalea_world::{
entity::Entity, EntityInfos, EntityPlugin, Local, PartialWorld, World, WorldContainer,
};
use bevy_app::App;
use azalea_world::{entity::Entity, EntityPlugin, Local, PartialWorld, World, WorldContainer};
use bevy_app::{App, Plugin};
use bevy_ecs::{
prelude::Component,
schedule::{IntoSystemDescriptor, Schedule, Stage, SystemSet},
@ -443,6 +441,39 @@ impl Client {
}
}
pub struct AzaleaPlugin;
impl Plugin for AzaleaPlugin {
fn build(&self, app: &mut App) {
app.add_event::<StartWalkEvent>()
.add_event::<StartSprintEvent>();
app.add_fixed_timestep(Duration::from_millis(50), "tick");
app.add_fixed_timestep_system_set(
"tick",
0,
SystemSet::new()
.with_system(send_position)
.with_system(update_in_loaded_chunk)
.with_system(sprint_listener.label("sprint_listener").before("travel"))
.with_system(walk_listener.label("walk_listener").before("travel"))
.with_system(
local_player_ai_step
.before("ai_step")
.after("sprint_listener"),
),
);
// fire the Death event when the player dies.
app.add_system(death_event.after("tick").after("packet"));
app.add_plugin(PacketHandlerPlugin);
app.add_plugin(EntityPlugin);
app.add_plugin(PhysicsPlugin);
app.add_plugin(TimePlugin); // from bevy_time
app.init_resource::<WorldContainer>();
}
}
/// Create the [`App`]. This won't actually run anything yet.
///
/// Note that you usually only need this if you're creating a client manually,
@ -458,36 +489,7 @@ pub fn init_ecs_app() -> App {
// you might be able to just drop the lock or put it in its own scope to fix
let mut app = App::new();
app.add_event::<StartWalkEvent>()
.add_event::<StartSprintEvent>();
app.add_fixed_timestep(Duration::from_millis(50), "tick");
app.add_fixed_timestep_system_set(
"tick",
0,
SystemSet::new()
.with_system(send_position)
.with_system(update_in_loaded_chunk)
.with_system(sprint_listener.label("sprint_listener").before("travel"))
.with_system(walk_listener.label("walk_listener").before("travel"))
.with_system(
local_player_ai_step
.before("ai_step")
.after("sprint_listener"),
),
);
// fire the Death event when the player dies.
app.add_system(death_event.after("tick").after("packet"));
app.add_plugin(PacketHandlerPlugin);
app.add_plugin(EntityPlugin);
app.add_plugin(PhysicsPlugin);
app.add_plugin(TimePlugin); // from bevy_time
app.init_resource::<WorldContainer>();
app.init_resource::<EntityInfos>();
app.add_plugin(AzaleaPlugin);
app
}

View file

@ -9,9 +9,10 @@ version = "0.5.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
azalea-block = {path = "../azalea-block", version = "^0.5.0" }
azalea-core = {path = "../azalea-core", version = "^0.5.0" }
azalea-world = {path = "../azalea-world", version = "^0.5.0" }
azalea-block = { path = "../azalea-block", version = "^0.5.0" }
azalea-core = { path = "../azalea-core", version = "^0.5.0" }
azalea-world = { path = "../azalea-world", version = "^0.5.0" }
azalea-registry = { path = "../azalea-registry", version = "^0.5.0" }
bevy_app = { version = "0.9.1", default-features = false }
bevy_ecs = { version = "0.9.1", default-features = false }
iyes_loopless = "0.9.1"

View file

@ -128,6 +128,7 @@ pub fn ai_step(
>,
mut force_jump_events: EventWriter<ForceJumpEvent>,
) {
println!("ai step");
for (entity, mut physics, jumping) in &mut query {
// vanilla does movement interpolation here, doesn't really matter much for a
// bot though
@ -306,131 +307,219 @@ fn jump_boost_power() -> f64 {
#[cfg(test)]
mod tests {
use std::{sync::Arc, time::Duration};
use super::*;
use azalea_core::ChunkPos;
use azalea_core::{ChunkPos, ResourceLocation};
use azalea_world::{
entity::{metadata, EntityMetadata},
Chunk, PartialWorld,
entity::{EntityBundle, MinecraftEntityId},
Chunk, EntityPlugin, PartialWorld,
};
use bevy_app::App;
use iyes_loopless::fixedtimestep::FixedTimestepStageLabel;
use parking_lot::RwLock;
use uuid::Uuid;
/// You need an app to spawn entities in the world and do updates.
fn make_test_app() -> App {
let mut app = App::new();
app.add_fixed_timestep(Duration::from_secs(1), "tick")
.add_plugin(PhysicsPlugin)
.add_plugin(EntityPlugin)
.init_resource::<WorldContainer>();
app
}
#[test]
fn test_gravity() {
let mut world = PartialWorld::default();
let mut app = make_test_app();
let world_lock = app.world.resource_mut::<WorldContainer>().insert(
ResourceLocation::new("minecraft:overworld").unwrap(),
384,
-64,
);
let mut partial_world = PartialWorld::default();
world.add_entity(
0,
EntityData::new(
Uuid::nil(),
Vec3 {
x: 0.,
y: 70.,
z: 0.,
},
EntityMetadata::Player(metadata::Player::default()),
),
);
let mut entity = world.entity_mut(0).unwrap();
// y should start at 70
assert_eq!(entity.pos().y, 70.);
entity.ai_step();
// delta is applied before gravity, so the first tick only sets the delta
assert_eq!(entity.pos().y, 70.);
assert!(entity.delta.y < 0.);
entity.ai_step();
// the second tick applies the delta to the position, so now it should go down
assert!(
entity.pos().y < 70.,
"Entity y ({}) didn't go down after physics steps",
entity.pos().y
);
let entity = app
.world
.spawn((
EntityBundle::new(
Uuid::nil(),
Vec3 {
x: 0.,
y: 70.,
z: 0.,
},
azalea_registry::EntityKind::Zombie,
ResourceLocation::new("minecraft:overworld").unwrap(),
),
MinecraftEntityId(0),
Local,
))
.id();
{
let entity_pos = app.world.get::<Position>(entity).unwrap().clone();
// y should start at 70
assert_eq!(entity_pos.y, 70.);
}
app.update();
{
let entity_pos = app.world.get::<Position>(entity).unwrap().clone();
// delta is applied before gravity, so the first tick only sets the delta
assert_eq!(entity_pos.y, 70.);
let entity_physics = app.world.get::<Physics>(entity).unwrap().clone();
assert!(entity_physics.delta.y < 0.);
}
app.update();
{
let entity_pos = app.world.get::<Position>(entity).unwrap().clone();
// the second tick applies the delta to the position, so now it should go down
assert!(
entity_pos.y < 70.,
"Entity y ({}) didn't go down after physics steps",
entity_pos.y
);
}
}
#[test]
fn test_collision() {
let mut world = PartialWorld::default();
world
.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
.unwrap();
world.add_entity(
0,
EntityData::new(
Uuid::nil(),
Vec3 {
x: 0.5,
y: 70.,
z: 0.5,
},
EntityMetadata::Player(metadata::Player::default()),
),
let mut app = make_test_app();
let world_lock = app.world.resource_mut::<WorldContainer>().insert(
ResourceLocation::new("minecraft:overworld").unwrap(),
384,
-64,
);
let mut partial_world = PartialWorld::default();
partial_world.chunks.set(
&ChunkPos { x: 0, z: 0 },
Some(Arc::new(RwLock::new(Chunk::default()))),
&mut world_lock.write().chunks,
);
let entity = app
.world
.spawn((
EntityBundle::new(
Uuid::nil(),
Vec3 {
x: 0.5,
y: 70.,
z: 0.5,
},
azalea_registry::EntityKind::Player,
ResourceLocation::new("minecraft:overworld").unwrap(),
),
MinecraftEntityId(0),
Local,
))
.id();
let block_state = partial_world.chunks.set_block_state(
&BlockPos { x: 0, y: 69, z: 0 },
BlockState::Stone,
&mut world_lock.write().chunks,
);
let block_state = world.set_block_state(&BlockPos { x: 0, y: 69, z: 0 }, BlockState::Stone);
assert!(
block_state.is_some(),
"Block state should exist, if this fails that means the chunk wasn't loaded and the block didn't get placed"
);
let mut entity = world.entity_mut(0).unwrap();
entity.ai_step();
// delta will change, but it won't move until next tick
assert_eq!(entity.pos().y, 70.);
assert!(entity.delta.y < 0.);
entity.ai_step();
// the second tick applies the delta to the position, but it also does collision
assert_eq!(entity.pos().y, 70.);
app.update();
{
let entity_pos = app.world.get::<Position>(entity).unwrap().clone();
// delta will change, but it won't move until next tick
assert_eq!(entity_pos.y, 70.);
let entity_physics = app.world.get::<Physics>(entity).unwrap().clone();
assert!(entity_physics.delta.y < 0.);
}
app.update();
{
let entity_pos = app.world.get::<Position>(entity).unwrap().clone();
// the second tick applies the delta to the position, but it also does collision
assert_eq!(entity_pos.y, 70.);
}
}
#[test]
fn test_slab_collision() {
let mut world = PartialWorld::default();
world
.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
.unwrap();
world.add_entity(
0,
EntityData::new(
Uuid::nil(),
Vec3 {
x: 0.5,
y: 71.,
z: 0.5,
},
EntityMetadata::Player(metadata::Player::default()),
),
let mut app = make_test_app();
let world_lock = app.world.resource_mut::<WorldContainer>().insert(
ResourceLocation::new("minecraft:overworld").unwrap(),
384,
-64,
);
let block_state = world.set_block_state(
let mut partial_world = PartialWorld::default();
partial_world.chunks.set(
&ChunkPos { x: 0, z: 0 },
Some(Arc::new(RwLock::new(Chunk::default()))),
&mut world_lock.write().chunks,
);
let entity = app
.world
.spawn((
EntityBundle::new(
Uuid::nil(),
Vec3 {
x: 0.5,
y: 71.,
z: 0.5,
},
azalea_registry::EntityKind::Player,
ResourceLocation::new("minecraft:overworld").unwrap(),
),
MinecraftEntityId(0),
Local,
))
.id();
let block_state = partial_world.chunks.set_block_state(
&BlockPos { x: 0, y: 69, z: 0 },
BlockState::StoneSlab_BottomFalse,
&mut world_lock.write().chunks,
);
assert!(
block_state.is_some(),
"Block state should exist, if this fails that means the chunk wasn't loaded and the block didn't get placed"
);
let mut entity = world.entity_mut(0).unwrap();
// do a few steps so we fall on the slab
for _ in 0..20 {
entity.ai_step();
app.update();
}
assert_eq!(entity.pos().y, 69.5);
let entity_pos = app.world.get::<Position>(entity).unwrap();
assert_eq!(entity_pos.y, 69.5);
}
#[test]
fn test_top_slab_collision() {
let mut world = PartialWorld::default();
world
.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
.unwrap();
world.add_entity(
0,
EntityData::new(
Uuid::nil(),
Vec3 {
x: 0.5,
y: 71.,
z: 0.5,
},
EntityMetadata::Player(metadata::Player::default()),
),
let mut app = make_test_app();
let world_lock = app.world.resource_mut::<WorldContainer>().insert(
ResourceLocation::new("minecraft:overworld").unwrap(),
384,
-64,
);
let block_state = world.set_block_state(
let mut partial_world = PartialWorld::default();
partial_world.chunks.set(
&ChunkPos { x: 0, z: 0 },
Some(Arc::new(RwLock::new(Chunk::default()))),
&mut world_lock.write().chunks,
);
let entity = app
.world
.spawn((
EntityBundle::new(
Uuid::nil(),
Vec3 {
x: 0.5,
y: 71.,
z: 0.5,
},
azalea_registry::EntityKind::Player,
ResourceLocation::new("minecraft:overworld").unwrap(),
),
MinecraftEntityId(0),
Local,
))
.id();
let block_state = world_lock.write().chunks.set_block_state(
&BlockPos { x: 0, y: 69, z: 0 },
BlockState::StoneSlab_TopFalse,
);
@ -438,33 +527,47 @@ mod tests {
block_state.is_some(),
"Block state should exist, if this fails that means the chunk wasn't loaded and the block didn't get placed"
);
let mut entity = world.entity_mut(0).unwrap();
// do a few steps so we fall on the slab
for _ in 0..20 {
entity.ai_step();
app.update();
}
assert_eq!(entity.pos().y, 70.);
let entity_pos = app.world.get::<Position>(entity).unwrap();
assert_eq!(entity_pos.y, 70.);
}
#[test]
fn test_weird_wall_collision() {
let mut world = PartialWorld::default();
world
.set_chunk(&ChunkPos { x: 0, z: 0 }, Some(Chunk::default()))
.unwrap();
world.add_entity(
0,
EntityData::new(
Uuid::nil(),
Vec3 {
x: 0.5,
y: 73.,
z: 0.5,
},
EntityMetadata::Player(metadata::Player::default()),
),
let mut app = make_test_app();
let world_lock = app.world.resource_mut::<WorldContainer>().insert(
ResourceLocation::new("minecraft:overworld").unwrap(),
384,
-64,
);
let block_state = world.set_block_state(
let mut partial_world = PartialWorld::default();
partial_world.chunks.set(
&ChunkPos { x: 0, z: 0 },
Some(Arc::new(RwLock::new(Chunk::default()))),
&mut world_lock.write().chunks,
);
let entity = app
.world
.spawn((
EntityBundle::new(
Uuid::nil(),
Vec3 {
x: 0.5,
y: 73.,
z: 0.5,
},
azalea_registry::EntityKind::Player,
ResourceLocation::new("minecraft:overworld").unwrap(),
),
MinecraftEntityId(0),
Local,
))
.id();
let block_state = world_lock.write().chunks.set_block_state(
&BlockPos { x: 0, y: 69, z: 0 },
BlockState::CobblestoneWall_LowLowLowFalseFalseLow,
);
@ -472,11 +575,12 @@ mod tests {
block_state.is_some(),
"Block state should exist, if this fails that means the chunk wasn't loaded and the block didn't get placed"
);
let mut entity = world.entity_mut(0).unwrap();
// do a few steps so we fall on the slab
for _ in 0..20 {
entity.ai_step();
app.update();
}
assert_eq!(entity.pos().y, 70.5);
let entity_pos = app.world.get::<Position>(entity).unwrap();
assert_eq!(entity_pos.y, 70.5);
}
}

View file

@ -48,7 +48,8 @@ impl Plugin for EntityPlugin {
.with_system(debug_detect_updates_received_on_local_entities)
.with_system(update_entity_by_id_index)
.with_system(debug_new_entity),
);
)
.init_resource::<EntityInfos>();
}
}