mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
experimental functionality to link handle types together
This commit is contained in:
Generated
+1
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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> {}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user