Skip to content

Commit

Permalink
add functionally to load preferences/override from a toml file (#77)
Browse files Browse the repository at this point in the history
* loading maybe working

* kinda working

* start on list

* working vec string

* working string/number/bool arrays

* change list loading

* rename

* add todo

* working unit enums

* add a struct with enum varient test

* add more comments to testing file

* working enum in list

* remove wrong comment

* support all base types

* support struct with tuple

* enum tuple in struct

* struct enum

* add comments to example config

* working value loading

* better value tests

* remove old load file

* full deserilizing support

* add comment

* add default enum value

* fmt

* fix typo

* cleanup

* cargo fix

* add settings key

* dont use prelude

* fix pie warnings

* fix pie

* allow dea code for now

* fix life times

* fix safty message

* fix returns

* add another test

* fmt

* fix clippy
  • Loading branch information
n1ght-hunter authored Dec 25, 2024
1 parent 6d3b457 commit 78d2081
Show file tree
Hide file tree
Showing 24 changed files with 1,907 additions and 223 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "89d094e50f10fc56
bevy_derive = { git = "https://github.com/bevyengine/bevy.git", rev = "89d094e50f10fc56ec3c4b046c830c650f9f09d5" }
thiserror = "1"
serde = { version = "1", features = ["derive"] }
tracing-test = "0.2.5"
tracing = "0.1.40"
atomicow = "1.0.0"
rfd = "0.15"
ron = "0.8.1"
Expand Down Expand Up @@ -71,3 +73,4 @@ bevy_transform_gizmos = { path = "crates/bevy_transform_gizmos" }
bevy_undo = { path = "crates/bevy_undo" }
bevy_infinite_grid = { path = "crates/bevy_infinite_grid" }
bevy_editor_cam = { path = "crates/bevy_editor_cam" }

40 changes: 40 additions & 0 deletions crates/bevy_editor_settings/Bevy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

# basic struct
[basic_settings]
name = "bevy_editor_settings"


# list with replace
[list_testing]
list = ["three", "four"]

# list with append
[list_testing_append]
list = [3, 4]

# top level enum
[enum_testing]
variant = "Two"

# enum in a struct
# and enum tuple
[enum_settings]
test1 = {Tuple = ["hello", 42]}

# a struct enum on a struct
[enum_settings.test2.Struct]
name = "four"
age = 4

# a struct with a list of enums
[enum_settings_list]
settings = ["Three"]

# top level tuple struct
# adds the fields field to the tuple struct. this is ONLY done for a top level tuple struct
[tuple_struct]
fields = [2, "two"]

# tuple struct in a struct
[struct_with_tuple]
tuple = [3, "three"]
10 changes: 4 additions & 6 deletions crates/bevy_editor_settings/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,17 @@ name = "bevy_editor_settings"
version = "0.1.0"
edition = "2021"

[features]
default = []
schema = ["schemars"]

[dependencies]
bevy.workspace = true
serde.workspace = true
thiserror.workspace = true
toml = "0.8.19"
directories = "5.0.1"
heck = "0.5.0"

# used for generating a json schema which can be used with toml
schemars = { version = "0.8.21", features = ["semver"], optional = true}
[dev-dependencies]
tracing.workspace = true
tracing-test.workspace = true

[lints]
workspace = true
63 changes: 63 additions & 0 deletions crates/bevy_editor_settings/src/file_system/de/array.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use bevy::{
prelude::warn,
reflect::{Array, ArrayInfo},
};

use super::LoadStructure;

pub struct LoadArray<'a> {
pub array_info: &'a ArrayInfo,
pub array: &'a mut dyn Array,
pub toml_array: &'a toml::value::Array,
}

impl LoadArray<'_> {
pub fn load_array(self) {
if self.toml_array.len() != self.array_info.capacity() {
warn!(
"Preferences: Expected Array length {}, got {}",
self.array_info.capacity(),
self.toml_array.len()
);
return;
}

for i in 0..self.array_info.capacity() {
let Some(toml_value) = self.toml_array.get(i) else {
continue;
};

let field_mut = self.array.get_mut(i).unwrap();

LoadStructure {
type_info: field_mut.get_represented_type_info().unwrap(),
table: toml_value,
structure: field_mut,
custom_attributes: None,
}
.load();
}
}
}

#[cfg(test)]
mod tests {
use bevy::reflect::DynamicTyped as _;

use super::*;

#[tracing_test::traced_test]
#[test]
fn load_array() {
let mut array = [0, 0];

let toml_value = toml::Value::Array(vec![toml::Value::Integer(1), toml::Value::Integer(2)]);
LoadArray {
array_info: array.reflect_type_info().as_array().unwrap(),
toml_array: toml_value.as_array().unwrap(),
array: &mut array,
}
.load_array();
assert_eq!(array, [1, 2]);
}
}
118 changes: 118 additions & 0 deletions crates/bevy_editor_settings/src/file_system/de/default.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use bevy::reflect::{
ArrayInfo, DynamicEnum, DynamicList, DynamicMap, DynamicSet, DynamicStruct, DynamicTuple,
EnumInfo, ListInfo, MapInfo, PartialReflect, SetInfo, Type, TypeInfo,
};

use super::{struct_utils::StructLikeInfo, tuple_utils::TupleLikeInfo};

pub fn default_data_type(type_info: &TypeInfo) -> Option<Box<dyn PartialReflect>> {
match type_info {
TypeInfo::Opaque(opaque_info) => default_value(opaque_info.ty()),
TypeInfo::Struct(struct_info) => {
default_struct(struct_info).map(|s| Box::new(s) as Box<dyn PartialReflect>)
}
TypeInfo::TupleStruct(tuple_struct_info) => {
default_tuple(tuple_struct_info).map(|t| Box::new(t) as Box<dyn PartialReflect>)
}
TypeInfo::Tuple(tuple_info) => {
default_tuple(tuple_info).map(|t| Box::new(t) as Box<dyn PartialReflect>)
}
TypeInfo::Array(type_info) => {
default_array(type_info).map(|a| Box::new(a) as Box<dyn PartialReflect>)
}
TypeInfo::List(type_info) => {
default_list(type_info).map(|l| Box::new(l) as Box<dyn PartialReflect>)
}
TypeInfo::Map(type_info) => {
default_map(type_info).map(|m| Box::new(m) as Box<dyn PartialReflect>)
}
TypeInfo::Set(type_info) => {
default_set(type_info).map(|s| Box::new(s) as Box<dyn PartialReflect>)
}
TypeInfo::Enum(type_info) => {
default_enum(type_info).map(|e| Box::new(e) as Box<dyn PartialReflect>)
}
}
}

pub fn default_enum(_type_info: &EnumInfo) -> Option<DynamicEnum> {
Some(DynamicEnum::default())
}

pub fn default_set(_type_info: &SetInfo) -> Option<DynamicSet> {
let output = DynamicSet::default();
Some(output)
}

pub fn default_map(_type_info: &MapInfo) -> Option<DynamicMap> {
let output = DynamicMap::default();
Some(output)
}

pub fn default_list(_type_info: &ListInfo) -> Option<DynamicList> {
let output = DynamicList::default();
Some(output)
}

pub fn default_array(_type_info: &ArrayInfo) -> Option<DynamicList> {
let output = DynamicList::default();
Some(output)
}

pub fn default_value(type_info: &Type) -> Option<Box<dyn PartialReflect>> {
if type_info.is::<String>() {
Some(Box::new(String::default()))
} else if type_info.is::<f64>() {
Some(Box::new(f64::default()))
} else if type_info.is::<f32>() {
Some(Box::new(f32::default()))
} else if type_info.is::<i64>() {
Some(Box::new(i64::default()))
} else if type_info.is::<i32>() {
Some(Box::new(i32::default()))
} else if type_info.is::<i16>() {
Some(Box::new(i16::default()))
} else if type_info.is::<i8>() {
Some(Box::new(i8::default()))
} else if type_info.is::<u64>() {
Some(Box::new(u64::default()))
} else if type_info.is::<u32>() {
Some(Box::new(u32::default()))
} else if type_info.is::<u16>() {
Some(Box::new(u16::default()))
} else if type_info.is::<u8>() {
Some(Box::new(u8::default()))
} else if type_info.is::<bool>() {
Some(Box::new(bool::default()))
} else {
None
}
}

pub fn default_struct<S: StructLikeInfo>(type_info: &S) -> Option<DynamicStruct> {
let mut dyn_struct = DynamicStruct::default();
// dyn_struct.set_represented_type(type_info);

for i in 0..type_info.field_len() {
let field_at = type_info.field_at(i).unwrap();

let value = default_data_type(field_at.type_info().unwrap())?;

dyn_struct.insert_boxed(field_at.name(), value);
}

Some(dyn_struct)
}

pub fn default_tuple<S: TupleLikeInfo>(type_info: &S) -> Option<DynamicTuple> {
let mut tuple = DynamicTuple::default();

for i in 0..type_info.field_len() {
let field_at = type_info.field_at(i).unwrap();

let value = default_data_type(field_at.type_info().unwrap())?;
tuple.insert_boxed(value);
}

Some(tuple)
}
Loading

0 comments on commit 78d2081

Please sign in to comment.