Block saving invalid brushes
Some checks are pending
CI / Format, lint, test, build (push) Waiting to run
Some checks are pending
CI / Format, lint, test, build (push) Waiting to run
This commit is contained in:
parent
015ae6da63
commit
11b0df2b5f
@ -404,6 +404,9 @@ fn format_actor_validation(err: ActorValidationError) -> String {
|
||||
ActorValidationError::BrushHasModelRef => {
|
||||
"Save failed: Brush actor cannot have ModelRef".into()
|
||||
}
|
||||
ActorValidationError::InvalidBrushGeometry(message) => {
|
||||
format!("Save failed: invalid brush geometry: {message}")
|
||||
}
|
||||
ActorValidationError::StaticMeshMissingPrimitive => {
|
||||
"Save failed: StaticMesh actor requires Primitive or StaticMeshRenderer with a mesh slot"
|
||||
.into()
|
||||
|
||||
@ -4,9 +4,9 @@ use bevy::ecs::world::EntityRef;
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ActorKind, BrushDesc, LevelObject, LightDesc, ModelRef, ObjectiveMarker, PlayerSpawn,
|
||||
PostProcessVolumeDesc, PrefabInstance, PrefabRef, Primitive, StaticMeshRenderer, TeamSpawn,
|
||||
TriggerVolume, WeaponSpawn,
|
||||
brush_math::validate_brush, ActorKind, BrushDesc, LevelObject, LightDesc, ModelRef,
|
||||
ObjectiveMarker, PlayerSpawn, PostProcessVolumeDesc, PrefabInstance, PrefabRef, Primitive,
|
||||
StaticMeshRenderer, TeamSpawn, TriggerVolume, WeaponSpawn,
|
||||
};
|
||||
|
||||
/// One-shot deterministic kind from authoring components (scene migration only).
|
||||
@ -59,6 +59,7 @@ pub enum ActorValidationError {
|
||||
BrushHasStaticMeshRenderer,
|
||||
BrushHasLight,
|
||||
BrushHasModelRef,
|
||||
InvalidBrushGeometry(String),
|
||||
StaticMeshMissingPrimitive,
|
||||
StaticMeshHasLight,
|
||||
StaticMeshHasModelRef,
|
||||
@ -99,9 +100,9 @@ pub fn validate_actor(entity: EntityRef<'_>) -> Result<(), ActorValidationError>
|
||||
|
||||
match kind {
|
||||
ActorKind::Brush => {
|
||||
if entity.get::<BrushDesc>().is_none() {
|
||||
let Some(brush) = entity.get::<BrushDesc>() else {
|
||||
return Err(ActorValidationError::BrushMissingDesc);
|
||||
}
|
||||
};
|
||||
if entity.get::<Primitive>().is_some() {
|
||||
return Err(ActorValidationError::BrushHasPrimitive);
|
||||
}
|
||||
@ -114,6 +115,18 @@ pub fn validate_actor(entity: EntityRef<'_>) -> Result<(), ActorValidationError>
|
||||
if entity.get::<ModelRef>().is_some() {
|
||||
return Err(ActorValidationError::BrushHasModelRef);
|
||||
}
|
||||
let report = validate_brush(brush);
|
||||
if !report.is_valid() {
|
||||
let message = report
|
||||
.diagnostics
|
||||
.into_iter()
|
||||
.find(|diagnostic| {
|
||||
diagnostic.severity == crate::brush_math::BrushDiagnosticSeverity::Error
|
||||
})
|
||||
.map(|diagnostic| diagnostic.message)
|
||||
.unwrap_or_else(|| "Brush geometry is invalid.".to_string());
|
||||
return Err(ActorValidationError::InvalidBrushGeometry(message));
|
||||
}
|
||||
}
|
||||
ActorKind::StaticMesh => {
|
||||
let has_static_mesh_renderer = entity
|
||||
@ -262,6 +275,20 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_brush_rejects_invalid_geometry() {
|
||||
let mut world = World::new();
|
||||
let mut brush = BrushDesc::default();
|
||||
brush.faces[0].vertices.clear();
|
||||
let e = level_entity(&mut world, (ActorKind::Brush, brush));
|
||||
assert_eq!(
|
||||
validate_actor(world.entity(e)),
|
||||
Err(ActorValidationError::InvalidBrushGeometry(
|
||||
"Face has fewer than three vertices.".into()
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_post_process_volume_ok() {
|
||||
let mut world = World::new();
|
||||
|
||||
@ -10,6 +10,7 @@ Brushes are persisted blockout geometry stored as `ActorKind::Brush + BrushDesc`
|
||||
- Brush actors validate separately from primitives and imported/static mesh actors.
|
||||
- The Actor Inspector Add Component shelf can add a **Brush** component. The Brush card exposes kind, face count, shadow flags, and cube reset.
|
||||
- The Brush card runs shared validation and reports invalid faces inline. Fatal geometry errors prevent hydration; warnings call out authoring issues that can still render. **Reset Cube Brush** is the MVP repair path.
|
||||
- Scene save runs the same fatal brush validation and blocks writing unrecoverable invalid brush geometry.
|
||||
- Draw Brush mode (`B`, toolbar pencil, or command `brush.draw`) creates additive prism brushes from snapped floor points. LMB places points, Backspace removes the last point, Enter commits through undo history, and Esc/right-click cancels without scene mutation.
|
||||
|
||||
## Element Modes
|
||||
|
||||
Loading…
Reference in New Issue
Block a user