experimental functionality to link handle types together

This commit is contained in:
Dmitry Stepanov
2025-03-01 12:02:58 +03:00
parent 755459e325
commit 54f369d477
7 changed files with 620 additions and 83 deletions
+1
View File
@@ -45,6 +45,7 @@
<sourceFolder url="file://$MODULE_DIR$/fyrox-graphics/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/fyrox-build-tools/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/fyrox-texture/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/fyrox-autotile/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
<excludeFolder url="file://$MODULE_DIR$/examples/wasm/target" />
</content>
+15 -1
View File
@@ -39,6 +39,7 @@ use crate::{
};
use fxhash::FxHashMap;
use fyrox_resource::{Resource, ResourceData};
use std::any::TypeId;
use std::{
collections::VecDeque,
error::Error,
@@ -52,6 +53,7 @@ use value::{nlerp, TrackValue, ValueBinding};
use crate::container::TrackDataContainer;
use crate::track::TrackBinding;
pub use fyrox_core as core;
use fyrox_core::reflect::{DerivedEntityListContainer, DerivedEntityListProvider};
use fyrox_resource::untyped::ResourceKind;
pub use pose::{AnimationPose, NodePose};
pub use signal::{AnimationEvent, AnimationSignal};
@@ -287,6 +289,18 @@ pub struct Animation<T: EntityId> {
events: VecDeque<AnimationEvent>,
}
impl<T: EntityId> DerivedEntityListContainer for Animation<T> {
fn derived_entity_list() -> &'static [TypeId] {
&[]
}
}
impl<T: EntityId> DerivedEntityListProvider for Animation<T> {
fn query_derived_entity_list(&self) -> &'static [TypeId] {
&[]
}
}
#[derive(Visit, Default)]
struct OldTrack<T: EntityId> {
binding: ValueBinding,
@@ -360,7 +374,7 @@ pub trait EntityId:
{
}
impl<T: 'static> EntityId for Handle<T> {}
impl<T: DerivedEntityListContainer + 'static> EntityId for Handle<T> {}
impl EntityId for ErasedHandle {}
/// Root motion settings. It allows you to set a node (root) from which the motion will be taken
+149 -4
View File
@@ -18,11 +18,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
use crate::reflect::{DerivedEntityListContainer, DerivedEntityListProvider, ReflectHandle};
use crate::{
combine_uuids, pool::INVALID_GENERATION, reflect::prelude::*, uuid_provider,
visitor::prelude::*, TypeUuidProvider,
};
use serde::{Deserialize, Serialize};
use std::any::{type_name, Any, TypeId};
use std::{
cmp::Ordering,
fmt::{Debug, Display, Formatter},
@@ -35,21 +37,164 @@ use uuid::Uuid;
/// Handle is some sort of non-owning reference to content in a pool. It stores
/// index of object and additional information that allows to ensure that handle
/// is still valid (points to the same object as when handle was created).
#[derive(Reflect, Serialize, Deserialize)]
#[derive(Serialize, Deserialize)]
pub struct Handle<T> {
/// Index of object in pool.
#[reflect(read_only, description = "Index of an object in a pool.")]
pub(super) index: u32,
/// Generation number, if it is same as generation of pool record at
/// index of handle then this is valid handle.
#[reflect(read_only, description = "Generation of an object in a pool.")]
pub(super) generation: u32,
/// Type holder.
#[reflect(hidden)]
#[serde(skip)]
pub(super) type_marker: PhantomData<T>,
}
impl<T: DerivedEntityListContainer> DerivedEntityListProvider for Handle<T> {
fn query_derived_entity_list(&self) -> &'static [TypeId] {
T::derived_entity_list()
}
}
impl<T: DerivedEntityListContainer> ReflectHandle for Handle<T> {
fn reflect_is_some(&self) -> bool {
self.is_some()
}
fn reflect_set_index(&mut self, index: u32) {
self.index = index;
}
fn reflect_index(&self) -> u32 {
self.index
}
fn reflect_set_generation(&mut self, generation: u32) {
self.generation = generation;
}
fn reflect_generation(&self) -> u32 {
self.generation
}
}
impl<T: DerivedEntityListContainer + 'static> Reflect for Handle<T> {
fn source_path() -> &'static str {
file!()
}
fn type_name(&self) -> &'static str {
type_name::<Self>()
}
fn doc(&self) -> &'static str {
""
}
fn assembly_name(&self) -> &'static str {
env!("CARGO_PKG_NAME")
}
fn type_assembly_name() -> &'static str {
env!("CARGO_PKG_NAME")
}
fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) {
func(&[
FieldInfo {
owner_type_id: TypeId::of::<Self>(),
name: "Index",
display_name: "Index",
description: "",
tag: "",
type_name: type_name::<u32>(),
value: &self.index,
reflect_value: &self.index,
read_only: false,
immutable_collection: false,
min_value: None,
max_value: None,
step: None,
precision: None,
doc: "",
},
FieldInfo {
owner_type_id: TypeId::of::<Self>(),
name: "Generation",
display_name: "Generation",
description: "",
tag: "",
type_name: type_name::<u32>(),
value: &self.generation,
reflect_value: &self.generation,
read_only: false,
immutable_collection: false,
min_value: None,
max_value: None,
step: None,
precision: None,
doc: "",
},
])
}
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn as_any(&self, func: &mut dyn FnMut(&dyn Any)) {
func(self)
}
fn as_any_mut(&mut self, func: &mut dyn FnMut(&mut dyn Any)) {
func(self)
}
fn as_reflect(&self, func: &mut dyn FnMut(&dyn Reflect)) {
func(self)
}
fn as_reflect_mut(&mut self, func: &mut dyn FnMut(&mut dyn Reflect)) {
func(self)
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<Box<dyn Reflect>, Box<dyn Reflect>> {
let this = std::mem::replace(self, value.take()?);
Ok(Box::new(this))
}
fn fields(&self, func: &mut dyn FnMut(&[&dyn Reflect])) {
func(&[&self.index, &self.generation])
}
fn fields_mut(&mut self, func: &mut dyn FnMut(&mut [&mut dyn Reflect])) {
func(&mut [&mut self.index, &mut self.generation])
}
fn field(&self, name: &str, func: &mut dyn FnMut(Option<&dyn Reflect>)) {
func(match name {
"Index" => Some(&self.index),
"Generation" => Some(&self.generation),
_ => None,
})
}
fn field_mut(&mut self, name: &str, func: &mut dyn FnMut(Option<&mut dyn Reflect>)) {
func(match name {
"Index" => Some(&mut self.index),
"Generation" => Some(&mut self.generation),
_ => None,
})
}
fn as_handle(&self, func: &mut dyn FnMut(Option<&dyn ReflectHandle>)) {
func(Some(self))
}
fn as_handle_mut(&mut self, func: &mut dyn FnMut(Option<&mut dyn ReflectHandle>)) {
func(Some(self))
}
}
impl<T> Copy for Handle<T> {}
impl<T> Eq for Handle<T> {}
+49
View File
@@ -318,6 +318,55 @@ pub trait Reflect: ReflectBase {
fn as_hash_map_mut(&mut self, func: &mut dyn FnMut(Option<&mut dyn ReflectHashMap>)) {
func(None)
}
fn as_handle(&self, func: &mut dyn FnMut(Option<&dyn ReflectHandle>)) {
func(None)
}
fn as_handle_mut(&mut self, func: &mut dyn FnMut(Option<&mut dyn ReflectHandle>)) {
func(None)
}
}
pub trait DerivedEntityListContainer {
fn derived_entity_list() -> &'static [TypeId];
}
pub trait DerivedEntityListProvider {
fn query_derived_entity_list(&self) -> &'static [TypeId];
}
#[macro_export]
macro_rules! export_derived_entity_list {
($ty:ty = [$($trait_name:ty),*]) => {
impl $crate::reflect::DerivedEntityListContainer for $ty {
fn derived_entity_list() -> &'static [std::any::TypeId] {
static ARRAY: std::sync::LazyLock<Vec<std::any::TypeId>> = std::sync::LazyLock::new(|| vec![
$(
// Fucking "this stuff is unstable in const fn", typical Rust.
// TODO: Remove LazyLock when it is finally stable.
std::any::TypeId::of::<$trait_name>()
),*
]);
&ARRAY
}
}
impl $crate::reflect::DerivedEntityListProvider for $ty {
fn query_derived_entity_list(&self) -> &'static [std::any::TypeId] {
<$ty as $crate::reflect::DerivedEntityListContainer>::derived_entity_list()
}
}
};
}
pub trait ReflectHandle: DerivedEntityListProvider {
fn reflect_is_some(&self) -> bool;
fn reflect_set_index(&mut self, index: u32);
fn reflect_index(&self) -> u32;
fn reflect_set_generation(&mut self, generation: u32);
fn reflect_generation(&self) -> u32;
}
/// [`Reflect`] sub trait for working with slices.
+400 -78
View File
@@ -26,6 +26,7 @@ pub mod constructor;
use fxhash::FxHashMap;
use fyrox_core::pool::ErasedHandle;
use fyrox_core::reflect::{DerivedEntityListContainer, ReflectHandle};
use fyrox_core::{
log::{Log, MessageKind},
pool::Handle,
@@ -82,7 +83,7 @@ impl<N> Clone for NodeHandleMap<N> {
impl<N> NodeHandleMap<N>
where
N: Reflect + NameProvider,
N: Reflect + NameProvider + DerivedEntityListContainer,
{
/// Adds new `original -> copy` handle mapping.
#[inline]
@@ -127,6 +128,23 @@ where
}
}
/// Tries to map a handle to a handle of its origin. If it exists, the method returns true or false otherwise.
/// It should be used when you not sure that respective origin exists.
#[inline]
pub fn try_map_reflect(&self, reflect_handle: &mut dyn ReflectHandle) -> bool {
let handle = Handle::new(
reflect_handle.reflect_index(),
reflect_handle.reflect_generation(),
);
if let Some(new_handle) = self.map.get(&handle) {
reflect_handle.reflect_set_index(new_handle.index());
reflect_handle.reflect_set_generation(new_handle.generation());
true
} else {
false
}
}
/// Tries to map each handle in the slice to a handle of its origin. If it exists, the method returns true or false otherwise.
/// It should be used when you not sure that respective origin exists.
#[inline]
@@ -203,15 +221,21 @@ where
return;
}
entity.downcast_mut::<Vec<Handle<N>>>(&mut |vec| {
if let Some(vec) = vec {
for handle in vec {
if handle.is_some() && !self.try_map(handle) {
Log::warn(format!(
"Failed to remap handle {} in array of node {}!",
*handle, node_name
));
}
// Handle derived entities handles.
entity.as_handle_mut(&mut |handle| {
if let Some(handle) = handle {
if handle
.query_derived_entity_list()
.contains(&TypeId::of::<N>())
&& handle.reflect_is_some()
&& !self.try_map_reflect(handle)
{
Log::warn(format!(
"Failed to remap handle {}:{} of node {}!",
handle.reflect_index(),
handle.reflect_generation(),
node_name
));
}
mapped = true;
}
@@ -338,26 +362,6 @@ where
return;
}
entity.downcast_mut::<Vec<Handle<N>>>(&mut |result| {
if let Some(vec) = result {
if do_map {
for handle in vec {
if handle.is_some() && !self.try_map(handle) {
Log::warn(format!(
"Failed to remap handle {} in array of node {}!",
*handle, node_name
));
}
}
}
mapped = true;
}
});
if mapped {
return;
}
entity.as_array_mut(&mut |result| {
if let Some(array) = result {
// Look in every array item.
@@ -435,7 +439,7 @@ pub trait AbstractSceneNode: ComponentProvider + Reflect + NameProvider {}
impl<T: SceneGraphNode> AbstractSceneNode for T {}
pub trait SceneGraphNode: AbstractSceneNode + Clone + 'static {
pub trait SceneGraphNode: AbstractSceneNode + DerivedEntityListContainer + Clone + 'static {
type Base: Clone;
type SceneGraph: SceneGraph<Node = Self>;
type ResourceData: PrefabData<Graph = Self::SceneGraph>;
@@ -1390,18 +1394,23 @@ where
#[cfg(test)]
mod test {
use crate::{
AbstractSceneGraph, AbstractSceneNode, BaseSceneGraph, NodeMapping, PrefabData, SceneGraph,
SceneGraphNode,
AbstractSceneGraph, AbstractSceneNode, BaseSceneGraph, NodeHandleMap, NodeMapping,
PrefabData, SceneGraph, SceneGraphNode,
};
use fyrox_core::pool::ErasedHandle;
use fyrox_core::pool::{ErasedHandle, PayloadContainer};
use fyrox_core::reflect::DerivedEntityListProvider;
use fyrox_core::{
export_derived_entity_list,
pool::{Handle, Pool},
reflect::prelude::*,
type_traits::prelude::*,
visitor::prelude::*,
NameProvider,
};
use fyrox_resource::untyped::UntypedResource;
use fyrox_resource::{Resource, ResourceData};
use std::any::{Any, TypeId};
use std::fmt::Debug;
use std::{
error::Error,
ops::{Deref, DerefMut, Index, IndexMut},
@@ -1409,7 +1418,7 @@ mod test {
};
#[derive(Default, Visit, Reflect, Debug, Clone)]
struct Base {
pub struct Base {
name: String,
self_handle: Handle<Node>,
is_resource_instance_root: bool,
@@ -1419,14 +1428,129 @@ mod test {
children: Vec<Handle<Node>>,
}
#[derive(Clone, ComponentProvider, Visit, Reflect, Debug, Default)]
struct Node {
base: Base,
/// A set of useful methods that is possible to auto-implement.
pub trait BaseNodeTrait: Any + Debug + Deref<Target = Base> + DerefMut + Send {
/// This method creates raw copy of a node, it should never be called in normal circumstances
/// because internally nodes may (and most likely will) contain handles to other nodes. To
/// correctly clone a node you have to use [copy_node](struct.Graph.html#method.copy_node).
fn clone_box(&self) -> Node;
}
impl<T> BaseNodeTrait for T
where
T: Clone + NodeTrait + 'static,
{
fn clone_box(&self) -> Node {
Node(Box::new(self.clone()))
}
}
pub trait NodeTrait:
BaseNodeTrait + Reflect + Visit + ComponentProvider + DerivedEntityListProvider
{
}
#[derive(ComponentProvider, Debug)]
pub struct Node(Box<dyn NodeTrait>);
impl Clone for Node {
fn clone(&self) -> Self {
self.0.clone_box()
}
}
impl Node {
fn new(node: impl NodeTrait) -> Self {
Self(Box::new(node))
}
}
export_derived_entity_list!(Node = []);
impl Visit for Node {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
self.0.visit(name, visitor)
}
}
impl Reflect for Node {
fn source_path() -> &'static str {
file!()
}
fn type_name(&self) -> &'static str {
self.0.deref().type_name()
}
fn doc(&self) -> &'static str {
self.0.deref().doc()
}
fn assembly_name(&self) -> &'static str {
self.0.deref().assembly_name()
}
fn type_assembly_name() -> &'static str {
env!("CARGO_PKG_NAME")
}
fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) {
self.0.deref().fields_info(func)
}
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self.0.into_any()
}
fn as_any(&self, func: &mut dyn FnMut(&dyn Any)) {
self.0.deref().as_any(func)
}
fn as_any_mut(&mut self, func: &mut dyn FnMut(&mut dyn Any)) {
self.0.deref_mut().as_any_mut(func)
}
fn as_reflect(&self, func: &mut dyn FnMut(&dyn Reflect)) {
self.0.deref().as_reflect(func)
}
fn as_reflect_mut(&mut self, func: &mut dyn FnMut(&mut dyn Reflect)) {
self.0.deref_mut().as_reflect_mut(func)
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<Box<dyn Reflect>, Box<dyn Reflect>> {
self.0.deref_mut().set(value)
}
fn set_field(
&mut self,
field: &str,
value: Box<dyn Reflect>,
func: &mut dyn FnMut(Result<Box<dyn Reflect>, Box<dyn Reflect>>),
) {
self.0.deref_mut().set_field(field, value, func)
}
fn fields(&self, func: &mut dyn FnMut(&[&dyn Reflect])) {
self.0.deref().fields(func)
}
fn fields_mut(&mut self, func: &mut dyn FnMut(&mut [&mut dyn Reflect])) {
self.0.deref_mut().fields_mut(func)
}
fn field(&self, name: &str, func: &mut dyn FnMut(Option<&dyn Reflect>)) {
self.0.deref().field(name, func)
}
fn field_mut(&mut self, name: &str, func: &mut dyn FnMut(Option<&mut dyn Reflect>)) {
self.0.deref_mut().field_mut(name, func)
}
}
impl NameProvider for Node {
fn name(&self) -> &str {
&self.base.name
&self.name
}
}
@@ -1434,13 +1558,57 @@ mod test {
type Target = Base;
fn deref(&self) -> &Self::Target {
&self.base
self.0.deref()
}
}
impl DerefMut for Node {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
self.0.deref_mut()
}
}
/// A wrapper for node pool record that allows to define custom visit method to have full
/// control over instantiation process at deserialization.
#[derive(Debug, Default, Reflect)]
pub struct NodeContainer(Option<Node>);
impl Visit for NodeContainer {
fn visit(&mut self, _name: &str, _visitor: &mut Visitor) -> VisitResult {
// Dummy impl.
Ok(())
}
}
impl PayloadContainer for NodeContainer {
type Element = Node;
fn new_empty() -> Self {
Self(None)
}
fn new(element: Self::Element) -> Self {
Self(Some(element))
}
fn is_some(&self) -> bool {
self.0.is_some()
}
fn as_ref(&self) -> Option<&Self::Element> {
self.0.as_ref()
}
fn as_mut(&mut self) -> Option<&mut Self::Element> {
self.0.as_mut()
}
fn replace(&mut self, element: Self::Element) -> Option<Self::Element> {
self.0.replace(element)
}
fn take(&mut self) -> Option<Self::Element> {
self.0.take()
}
}
@@ -1450,51 +1618,51 @@ mod test {
type ResourceData = Graph;
fn base(&self) -> &Self::Base {
&self.base
&**self
}
fn set_base(&mut self, base: Self::Base) {
self.base = base;
**self = base;
}
fn is_resource_instance_root(&self) -> bool {
self.base.is_resource_instance_root
self.is_resource_instance_root
}
fn original_handle_in_resource(&self) -> Handle<Self> {
self.base.original_handle_in_resource
self.original_handle_in_resource
}
fn set_original_handle_in_resource(&mut self, handle: Handle<Self>) {
self.base.original_handle_in_resource = handle;
self.original_handle_in_resource = handle;
}
fn resource(&self) -> Option<Resource<Self::ResourceData>> {
self.base.resource.clone()
self.resource.clone()
}
fn self_handle(&self) -> Handle<Self> {
self.base.self_handle
self.self_handle
}
fn parent(&self) -> Handle<Self> {
self.base.parent
self.parent
}
fn children(&self) -> &[Handle<Self>] {
&self.base.children
&self.children
}
fn children_mut(&mut self) -> &mut [Handle<Self>] {
&mut self.base.children
&mut self.children
}
}
#[derive(Default, TypeUuidProvider, Visit, Reflect, Debug)]
#[type_uuid(id = "fc887063-7780-44af-8710-5e0bcf9a83fd")]
struct Graph {
pub struct Graph {
root: Handle<Node>,
nodes: Pool<Node>,
nodes: Pool<Node, NodeContainer>,
}
impl ResourceData for Graph {
@@ -1573,8 +1741,8 @@ mod test {
}
fn add_node(&mut self, mut node: Self::Node) -> Handle<Self::Node> {
let children = node.base.children.clone();
node.base.children.clear();
let children = node.children.clone();
node.children.clear();
let handle = self.nodes.spawn(node);
if self.root.is_none() {
@@ -1588,7 +1756,7 @@ mod test {
}
let node = &mut self.nodes[handle];
node.base.self_handle = handle;
node.self_handle = handle;
handle
}
@@ -1603,8 +1771,8 @@ mod test {
fn link_nodes(&mut self, child: Handle<Self::Node>, parent: Handle<Self::Node>) {
self.isolate_node(child);
self.nodes[child].base.parent = parent;
self.nodes[parent].base.children.push(child);
self.nodes[child].parent = parent;
self.nodes[parent].children.push(child);
}
fn unlink_node(&mut self, node_handle: Handle<Self::Node>) {
@@ -1614,11 +1782,11 @@ mod test {
fn isolate_node(&mut self, node_handle: Handle<Self::Node>) {
let parent_handle =
std::mem::replace(&mut self.nodes[node_handle].base.parent, Handle::NONE);
std::mem::replace(&mut self.nodes[node_handle].parent, Handle::NONE);
if let Some(parent) = self.nodes.try_borrow_mut(parent_handle) {
if let Some(i) = parent.children().iter().position(|h| *h == node_handle) {
parent.base.children.remove(i);
parent.children.remove(i);
}
}
}
@@ -1646,15 +1814,137 @@ mod test {
}
}
fn remap_handles(old_new_mapping: &NodeHandleMap<Node>, dest_graph: &mut Graph) {
// Iterate over instantiated nodes and remap handles.
for (_, &new_node_handle) in old_new_mapping.inner().iter() {
old_new_mapping.remap_handles(
&mut dest_graph.nodes[new_node_handle],
&[TypeId::of::<UntypedResource>()],
);
}
}
fn clear_links(mut node: Node) -> Node {
node.children.clear();
node.parent = Handle::NONE;
node
}
impl Graph {
#[inline]
pub fn copy_node(
&self,
node_handle: Handle<Node>,
dest_graph: &mut Graph,
) -> (Handle<Node>, NodeHandleMap<Node>) {
let mut old_new_mapping = NodeHandleMap::default();
let root_handle = self.copy_node_raw(node_handle, dest_graph, &mut old_new_mapping);
remap_handles(&old_new_mapping, dest_graph);
(root_handle, old_new_mapping)
}
fn copy_node_raw(
&self,
root_handle: Handle<Node>,
dest_graph: &mut Graph,
old_new_mapping: &mut NodeHandleMap<Node>,
) -> Handle<Node> {
let src_node = &self.nodes[root_handle];
let dest_node = clear_links(src_node.clone());
let dest_copy_handle = dest_graph.add_node(dest_node);
old_new_mapping.insert(root_handle, dest_copy_handle);
for &src_child_handle in src_node.children() {
let dest_child_handle =
self.copy_node_raw(src_child_handle, dest_graph, old_new_mapping);
if !dest_child_handle.is_none() {
dest_graph.link_nodes(dest_child_handle, dest_copy_handle);
}
}
dest_copy_handle
}
}
#[derive(Clone, Reflect, Visit, Default, Debug, ComponentProvider)]
pub struct Pivot {
base: Base,
}
export_derived_entity_list!(Pivot = [Node]);
impl NodeTrait for Pivot {}
impl Deref for Pivot {
type Target = Base;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl DerefMut for Pivot {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}
#[derive(Clone, Reflect, Visit, Default, Debug, ComponentProvider)]
pub struct RigidBody {
base: Base,
}
export_derived_entity_list!(RigidBody = [Node]);
impl NodeTrait for RigidBody {}
impl Deref for RigidBody {
type Target = Base;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl DerefMut for RigidBody {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}
#[derive(Clone, Reflect, Visit, Default, Debug, ComponentProvider)]
pub struct Joint {
base: Base,
connected_body1: Handle<RigidBody>,
connected_body2: Handle<RigidBody>,
}
export_derived_entity_list!(Joint = [Node]);
impl NodeTrait for Joint {}
impl Deref for Joint {
type Target = Base;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl DerefMut for Joint {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}
#[test]
fn test_set_child_position() {
let mut graph = Graph::default();
let root = graph.add_node(Node::default());
let a = graph.add_node(Node::default());
let b = graph.add_node(Node::default());
let c = graph.add_node(Node::default());
let d = graph.add_node(Node::default());
let root = graph.add_node(Node::new(Pivot::default()));
let a = graph.add_node(Node::new(Pivot::default()));
let b = graph.add_node(Node::new(Pivot::default()));
let c = graph.add_node(Node::new(Pivot::default()));
let d = graph.add_node(Node::new(Pivot::default()));
graph.link_nodes(a, root);
graph.link_nodes(b, root);
graph.link_nodes(c, root);
@@ -1697,6 +1987,44 @@ mod test {
assert_eq!(root_ref.children[3], c);
}
#[test]
fn test_derived_handles_mapping() {
let mut prefab_graph = Graph::default();
let root = prefab_graph.add_node(Node::new(Pivot::default()));
let rigid_body = prefab_graph.add_node(Node::new(RigidBody::default()));
let rigid_body2 = prefab_graph.add_node(Node::new(RigidBody::default()));
let joint = prefab_graph.add_node(Node::new(Joint {
base: Base::default(),
connected_body1: rigid_body.transmute(),
connected_body2: rigid_body2.transmute(),
}));
let mut scene_graph = Graph::default();
let root = scene_graph.add_node(Node::new(Pivot::default()));
let (prefab_copy_root, mapping) = prefab_graph.copy_node(root, &mut scene_graph);
let rigid_body_copy = mapping
.inner()
.get(&rigid_body)
.cloned()
.unwrap()
.transmute::<RigidBody>();
let rigid_body2_copy = mapping
.inner()
.get(&rigid_body2)
.cloned()
.unwrap()
.transmute::<RigidBody>();
let joint_copy = mapping.inner().get(&joint).cloned().unwrap();
let joint_copy_ref = scene_graph.nodes[joint_copy]
.component_ref::<Joint>()
.unwrap();
assert_eq!(joint_copy_ref.connected_body1, rigid_body_copy);
assert_eq!(joint_copy_ref.connected_body2, rigid_body2_copy);
}
#[test]
fn test_change_root() {
let mut graph = Graph::default();
@@ -1706,27 +2034,21 @@ mod test {
// |_B
// |_C_
// |_D
let root = graph.add_node(Node {
base: Base::default(),
});
let d = graph.add_node(Node {
base: Base::default(),
});
let c = graph.add_node(Node {
let root = graph.add_node(Node::new(Pivot::default()));
let d = graph.add_node(Node::new(Pivot::default()));
let c = graph.add_node(Node::new(Pivot {
base: Base {
children: vec![d],
..Default::default()
},
});
let b = graph.add_node(Node {
base: Base::default(),
});
let a = graph.add_node(Node {
}));
let b = graph.add_node(Node::new(Pivot::default()));
let a = graph.add_node(Node::new(Pivot {
base: Base {
children: vec![b, c],
..Default::default()
},
});
}));
graph.link_nodes(a, root);
dbg!(root, a, b, c, d);
+3
View File
@@ -23,6 +23,7 @@
use crate::effects::{Effect, EffectRenderTrait};
use fyrox_core::{
export_derived_entity_list,
pool::{Handle, Pool, Ticket},
reflect::prelude::*,
visitor::prelude::*,
@@ -313,6 +314,8 @@ pub struct AudioBusGraph {
root: Handle<AudioBus>,
}
export_derived_entity_list!(AudioBus = []);
impl AudioBusGraph {
/// The name of the audio bus that output samples directly to an audio playback device.
pub const PRIMARY_BUS: &'static str = "Primary";
+3
View File
@@ -38,6 +38,7 @@ use crate::{
source::{SoundSource, Status},
};
use fyrox_core::{
export_derived_entity_list,
pool::{Handle, Pool},
reflect::prelude::*,
uuid_provider,
@@ -144,6 +145,8 @@ pub struct State {
pub serialization_options: SerializationOptions,
}
export_derived_entity_list!(SoundSource = []);
impl State {
/// Extracts a source from the context and reserves its handle. It is used to temporarily take
/// ownership over source, and then put node back using given ticket.