Skip to content

Commit 7d14199

Browse files
authored
Merge branch 'main' into traffic_lights
2 parents 7c7a1c9 + 8b5a3b8 commit 7d14199

77 files changed

Lines changed: 1724 additions & 316 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ jobs:
337337
fetch-depth: 0
338338
persist-credentials: false
339339
- name: Run Markdown Lint
340-
uses: super-linter/super-linter/slim@61abc07d755095a68f4987d1c2c3d1d64408f1f9 # v8.5.0
340+
uses: super-linter/super-linter/slim@9e863354e3ff62e0727d37183162c4a88873df41 # v8.6.0
341341
env:
342342
MULTI_STATUS: false
343343
VALIDATE_ALL_CODEBASE: false
@@ -374,7 +374,7 @@ jobs:
374374
with:
375375
persist-credentials: false
376376
- name: Check for typos
377-
uses: crate-ci/typos@631208b7aac2daa8b707f55e7331f9112b0e062d # v1.44.0
377+
uses: crate-ci/typos@02ea592e44b3a53c302f697cddca7641cd051c3d # v1.45.0
378378
- name: Typos info
379379
if: failure()
380380
run: |
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
title: "`InputFocus` fields are no longer public"
3+
pull_requests: [23723]
4+
---
5+
6+
The `.0` field on `InputFocus` is no longer public.
7+
Use the getter and setters methods instead.
8+
9+
Before:
10+
11+
```rust
12+
let focused_entity = input_focus.0;
13+
input_focus.0 = Some(entity);
14+
input_focus.0 = None;
15+
```
16+
17+
After:
18+
19+
```rust
20+
let focused_entity = input_focus.get();
21+
input_focus.set(entity);
22+
input_focus.clear();
23+
```
24+
25+
Additionally, the core setup of `InputFocus` and related resources now occurs in `InputFocusPlugin`,
26+
rather than `InputDispatchPlugin`.
27+
This is part of `DefaultPlugins`, so most users will not need to make any changes.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
title: "`Skybox` `image` is now optional"
3+
pull_requests: [23691]
4+
---
5+
6+
The `image` field of the `Skybox` component now has the type `Option<Handle<Image>>` instead of `Handle<Image>`.
7+
A `Skybox` component without an image will not draw anything, just like it was not present.
8+
9+
If you were creating a skybox with an image, wrap the image handle in `Some`:
10+
11+
```rust
12+
// 0.18
13+
Skybox {
14+
image: my_skybox,
15+
brightness: 1000.0,
16+
..default()
17+
}
18+
19+
// 0.19
20+
Skybox {
21+
image: Some(my_skybox),
22+
brightness: 1000.0,
23+
..default()
24+
}
25+
```
26+
27+
If you were previously creating a `Skybox` component with a placeholder image to be changed later, you can now remove the placeholder:
28+
29+
```rust
30+
// 0.18
31+
Skybox {
32+
image: cubemap_image_that_will_not_actually_be_seen,
33+
brightness: 1000.0,
34+
..default()
35+
}
36+
37+
// 0.19
38+
Skybox {
39+
brightness: 1000.0,
40+
..default()
41+
}
42+
```

crates/bevy_camera_controller/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.19.0-dev", default-featu
2222
bevy_time = { path = "../bevy_time", version = "0.19.0-dev", default-features = false }
2323
bevy_transform = { path = "../bevy_transform", version = "0.19.0-dev", default-features = false }
2424
bevy_window = { path = "../bevy_window", version = "0.19.0-dev", default-features = false }
25+
bevy_picking = { path = "../bevy_picking", version = "0.19.0-dev", default-features = false }
2526

2627
[features]
2728
default = ["bevy_reflect"]

crates/bevy_camera_controller/src/pan_camera.rs

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@
66
//! To configure the settings of this controller, modify the fields of the [`PanCamera`] component.
77
88
use bevy_app::{App, Plugin, RunFixedMainLoop, RunFixedMainLoopSystems};
9-
use bevy_camera::Camera;
9+
use bevy_camera::{Camera, RenderTarget};
1010
use bevy_ecs::prelude::*;
1111
use bevy_input::keyboard::KeyCode;
12-
use bevy_input::mouse::{AccumulatedMouseScroll, MouseScrollUnit};
12+
use bevy_input::mouse::{AccumulatedMouseScroll, MouseButton, MouseScrollUnit};
1313
use bevy_input::ButtonInput;
1414
use bevy_math::{Vec2, Vec3};
15+
use bevy_picking::events::{Drag, DragEnd, DragStart, Pointer};
1516
use bevy_time::{Real, Time};
17+
use bevy_transform::components::GlobalTransform;
1618
use bevy_transform::prelude::Transform;
17-
19+
use bevy_window::{PrimaryWindow, WindowRef};
1820
use core::{f32::consts::*, fmt};
1921

2022
/// A plugin that enables 2D camera panning and zooming controls.
@@ -28,7 +30,9 @@ impl Plugin for PanCameraPlugin {
2830
app.add_systems(
2931
RunFixedMainLoop,
3032
run_pancamera_controller.in_set(RunFixedMainLoopSystems::BeforeFixedMainLoop),
31-
);
33+
)
34+
.add_observer(add_window_observer)
35+
.add_observer(remove_window_observer);
3236
}
3337
}
3438

@@ -68,6 +72,16 @@ pub struct PanCamera {
6872
pub key_rotate_ccw: Option<KeyCode>,
6973
/// [`KeyCode`] for clockwise rotation.
7074
pub key_rotate_cw: Option<KeyCode>,
75+
/// Mouse pan settings.
76+
pub mouse_pan_settings: MousePanSettings,
77+
}
78+
79+
/// Settings for mouse panning for the [`PanCamera`] controller.
80+
pub struct MousePanSettings {
81+
/// Whether the mouse panning is enabled.
82+
pub enabled: bool,
83+
/// The mouse button to use for panning.
84+
pub button: MouseButton,
7185
}
7286

7387
/// Provides the default values for the `PanCamera` controller.
@@ -105,6 +119,10 @@ impl Default for PanCamera {
105119
rotation_speed: PI,
106120
key_rotate_ccw: Some(KeyCode::KeyQ),
107121
key_rotate_cw: Some(KeyCode::KeyE),
122+
mouse_pan_settings: MousePanSettings {
123+
enabled: true,
124+
button: MouseButton::Left,
125+
},
108126
}
109127
}
110128
}
@@ -235,3 +253,83 @@ fn run_pancamera_controller(
235253

236254
transform.scale = Vec3::splat(controller.zoom_factor);
237255
}
256+
257+
/// A component attached to window entities that holds the id of an
258+
/// active `handle_mouse_pan` observer. It is None if there is no
259+
/// such observer.
260+
#[derive(Component)]
261+
struct HandleMousePanObserver(Option<Entity>);
262+
263+
fn add_window_observer(
264+
drag_start: On<Pointer<DragStart>>,
265+
mut commands: Commands,
266+
render_targets: Query<&RenderTarget, With<PanCamera>>,
267+
primary_window: Single<Entity, With<PrimaryWindow>>,
268+
) {
269+
for render_target in render_targets.iter() {
270+
if let RenderTarget::Window(window) = render_target {
271+
let entity = match window {
272+
WindowRef::Primary => primary_window.entity(),
273+
WindowRef::Entity(entity) => *entity,
274+
};
275+
if entity == drag_start.entity {
276+
let observer_id = commands
277+
.spawn(Observer::new(handle_mouse_pan).with_entity(entity))
278+
.id();
279+
commands
280+
.entity(entity)
281+
.insert(HandleMousePanObserver(Some(observer_id)));
282+
}
283+
}
284+
}
285+
}
286+
287+
fn remove_window_observer(
288+
drag_end: On<Pointer<DragEnd>>,
289+
mut commands: Commands,
290+
render_targets: Query<&RenderTarget, With<PanCamera>>,
291+
mut handle_mouse_pan_observer: Query<&mut HandleMousePanObserver>,
292+
primary_window: Single<Entity, With<PrimaryWindow>>,
293+
) {
294+
for render_target in render_targets.iter() {
295+
if let RenderTarget::Window(window) = render_target {
296+
let entity = match window {
297+
WindowRef::Primary => primary_window.entity(),
298+
WindowRef::Entity(entity) => *entity,
299+
};
300+
if entity == drag_end.entity
301+
&& let Ok(mut observer) = handle_mouse_pan_observer.get_mut(entity)
302+
&& let Some(observer_entity) = observer.0.take()
303+
{
304+
commands.entity(observer_entity).despawn();
305+
}
306+
}
307+
}
308+
}
309+
310+
fn handle_mouse_pan(
311+
drag: On<Pointer<Drag>>,
312+
mut pan_cameras: Query<(&Camera, &GlobalTransform, &mut Transform, &PanCamera)>,
313+
) {
314+
for (camera, global_transform, mut transform, pan_camera_controller) in pan_cameras.iter_mut() {
315+
if !pan_camera_controller.enabled || !pan_camera_controller.mouse_pan_settings.enabled {
316+
return;
317+
}
318+
319+
let Ok(camera_screen_position) =
320+
camera.world_to_viewport(global_transform, transform.translation)
321+
else {
322+
continue;
323+
};
324+
325+
let offset_camera_screen_position = camera_screen_position + drag.delta * -1.; // inverted feels more natural
326+
327+
let Ok(new_camera_position) =
328+
camera.viewport_to_world_2d(global_transform, offset_camera_screen_position)
329+
else {
330+
continue;
331+
};
332+
333+
transform.translation = new_camera_position.extend(transform.translation.z);
334+
}
335+
}

crates/bevy_core_pipeline/src/skybox/mod.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,17 +227,18 @@ fn prepare_skybox_bind_groups(
227227
views: Query<(Entity, &Skybox, &DynamicUniformIndex<SkyboxUniforms>)>,
228228
) {
229229
for (entity, skybox, skybox_uniform_index) in &views {
230-
if let (Some(skybox), Some(view_uniforms), Some(skybox_uniforms)) = (
231-
images.get(&skybox.image),
230+
if let (Some(image_handle), Some(view_uniforms), Some(skybox_uniforms)) = (
231+
&skybox.image,
232232
view_uniforms.uniforms.binding(),
233233
skybox_uniforms.binding(),
234-
) {
234+
) && let Some(image) = images.get(image_handle)
235+
{
235236
let bind_group = render_device.create_bind_group(
236237
"skybox_bind_group",
237238
&pipeline_cache.get_bind_group_layout(&pipeline.bind_group_layout),
238239
&BindGroupEntries::sequential((
239-
&skybox.texture_view,
240-
&skybox.sampler,
240+
&image.texture_view,
241+
&image.sampler,
241242
view_uniforms,
242243
skybox_uniforms,
243244
)),
@@ -246,6 +247,8 @@ fn prepare_skybox_bind_groups(
246247
commands
247248
.entity(entity)
248249
.insert(SkyboxBindGroup((bind_group, skybox_uniform_index.index())));
250+
} else {
251+
commands.entity(entity).remove::<SkyboxBindGroup>();
249252
}
250253
}
251254
}

crates/bevy_ecs/macros/src/component.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,15 @@ pub fn derive_resource(input: TokenStream) -> TokenStream {
6666
ast.generics
6767
.make_where_clause()
6868
.predicates
69-
.push(parse_quote! { Self: Send + Sync + 'static });
69+
.push(parse_quote! { Self: ::core::marker::Send + ::core::marker::Sync + 'static });
7070

7171
let struct_name = &ast.ident;
7272
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
7373

7474
let mut register_required = Vec::with_capacity(1);
7575
// We add the component_id existence check here to avoid recursive init during required components initialization.
7676
register_required.push(quote! {
77-
let resource_component_id = if let Some(id) = required_components.components_registrator().component_id::<#struct_name #type_generics>() {
77+
let resource_component_id = if let ::core::option::Option::Some(id) = required_components.components_registrator().component_id::<#struct_name #type_generics>() {
7878
id
7979
} else {
8080
required_components.components_registrator().register_component::<#struct_name #type_generics>()
@@ -107,8 +107,8 @@ pub fn derive_resource(input: TokenStream) -> TokenStream {
107107

108108
#map_entities
109109

110-
fn relationship_accessor() -> Option<#bevy_ecs_path::relationship::ComponentRelationshipAccessor<Self>> {
111-
None
110+
fn relationship_accessor() -> ::core::option::Option<#bevy_ecs_path::relationship::ComponentRelationshipAccessor<Self>> {
111+
::core::option::Option::None
112112
}
113113
}
114114
});
@@ -243,7 +243,7 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
243243
ast.generics
244244
.make_where_clause()
245245
.predicates
246-
.push(parse_quote! { Self: Send + Sync + 'static });
246+
.push(parse_quote! { Self: ::core::marker::Send + ::core::marker::Sync + 'static });
247247

248248
let requires = &attrs.requires;
249249
let mut register_required = Vec::with_capacity(attrs.requires.iter().len());
@@ -252,7 +252,7 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
252252
let ident = &require.path;
253253
let constructor = match &require.func {
254254
Some(func) => quote! { || { let x: #ident = (#func)().into(); x } },
255-
None => quote! { <#ident as Default>::default },
255+
None => quote! { <#ident as ::core::default::Default>::default },
256256
};
257257
register_required.push(quote! {
258258
required_components.register_required::<#ident>(#constructor);
@@ -306,7 +306,7 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
306306
let relationship_member = field.ident.clone().map_or(Member::from(0), Member::Named);
307307
if relationship.is_some() {
308308
quote! {
309-
Some(
309+
::core::option::Option::Some(
310310
// Safety: we pass valid offset of a field containing Entity (obtained via offset_off!)
311311
unsafe {
312312
#bevy_ecs_path::relationship::ComponentRelationshipAccessor::<Self>::relationship(
@@ -317,11 +317,11 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
317317
}
318318
} else {
319319
quote! {
320-
Some(#bevy_ecs_path::relationship::ComponentRelationshipAccessor::<Self>::relationship_target())
320+
::core::option::Option::Some(#bevy_ecs_path::relationship::ComponentRelationshipAccessor::<Self>::relationship_target())
321321
}
322322
}
323323
} else {
324-
quote! {None}
324+
quote! {::core::option::Option::None}
325325
};
326326

327327
// This puts `register_required` before `register_recursive_requires` to ensure that the constructors of _all_ top
@@ -350,7 +350,7 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
350350

351351
#map_entities
352352

353-
fn relationship_accessor() -> Option<#bevy_ecs_path::relationship::ComponentRelationshipAccessor<Self>> {
353+
fn relationship_accessor() -> ::core::option::Option<#bevy_ecs_path::relationship::ComponentRelationshipAccessor<Self>> {
354354
#relationship_accessor
355355
}
356356
}

crates/bevy_ecs/macros/src/event.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub fn derive_event(input: TokenStream) -> TokenStream {
1919
ast.generics
2020
.make_where_clause()
2121
.predicates
22-
.push(parse_quote! { Self: Send + Sync + 'static });
22+
.push(parse_quote! { Self: ::core::marker::Send + ::core::marker::Sync + 'static });
2323

2424
let mut processed_attrs = Vec::new();
2525
let mut trigger: Option<Type> = None;
@@ -63,7 +63,7 @@ pub fn derive_entity_event(input: TokenStream) -> TokenStream {
6363
ast.generics
6464
.make_where_clause()
6565
.predicates
66-
.push(parse_quote! { Self: Send + Sync + 'static });
66+
.push(parse_quote! { Self: ::core::marker::Send + ::core::marker::Sync + 'static });
6767

6868
let mut auto_propagate = false;
6969
let mut propagate = false;
@@ -139,7 +139,7 @@ pub fn derive_entity_event(input: TokenStream) -> TokenStream {
139139
quote! {
140140
impl #impl_generics #bevy_ecs_path::event::SetEntityEventTarget for #struct_name #type_generics #where_clause {
141141
fn set_event_target(&mut self, entity: #bevy_ecs_path::entity::Entity) {
142-
self.#entity_field = Into::into(entity);
142+
self.#entity_field = ::core::convert::Into::into(entity);
143143
}
144144
}
145145
}

0 commit comments

Comments
 (0)