| @@ -1,3 +0,0 @@ | |||||
| mod player_visual; | |||||
| pub use player_visual::PlayerVisual; | |||||
| @@ -1,12 +0,0 @@ | |||||
| use glc::vector::Vector4f; | |||||
| use serde::{Deserialize, Serialize}; | |||||
| use specs::{Component, HashMapStorage}; | |||||
| #[derive(Clone, Debug, Serialize, Deserialize)] | |||||
| pub struct PlayerVisual { | |||||
| pub color: Vector4f, | |||||
| } | |||||
| impl Component for PlayerVisual { | |||||
| type Storage = HashMapStorage<Self>; | |||||
| } | |||||
| @@ -1,10 +1,9 @@ | |||||
| pub mod components; | |||||
| pub mod constants; | |||||
| pub mod error; | |||||
| pub mod misc; | |||||
| pub mod render; | |||||
| pub mod resources; | |||||
| pub mod systems; | |||||
| mod constants; | |||||
| mod error; | |||||
| mod misc; | |||||
| mod render; | |||||
| mod resources; | |||||
| mod systems; | |||||
| use specs::{Dispatcher, DispatcherBuilder, World}; | use specs::{Dispatcher, DispatcherBuilder, World}; | ||||
| @@ -51,17 +51,15 @@ fn run(vfs: Vfs) -> Result<(), Error> { | |||||
| fn create_world(world: &mut World) { | fn create_world(world: &mut World) { | ||||
| use glc::vector::{Vector2f, Vector4f}; | use glc::vector::{Vector2f, Vector4f}; | ||||
| use space_crush_app::{components::PlayerVisual, misc::PersistWorld}; | |||||
| use space_crush_common::{ | use space_crush_common::{ | ||||
| components::{Owned, Planet, Player, Position, Ship, ShipType, Velocity}, | components::{Owned, Planet, Player, Position, Ship, ShipType, Velocity}, | ||||
| misc::Persistence, | |||||
| misc::{PersistWorld, Persistence}, | |||||
| }; | }; | ||||
| use specs::{saveload::MarkedBuilder, Builder}; | use specs::{saveload::MarkedBuilder, Builder}; | ||||
| let player1 = world | let player1 = world | ||||
| .create_entity() | .create_entity() | ||||
| .with(Player {}) | |||||
| .with(PlayerVisual { | |||||
| .with(Player { | |||||
| color: Vector4f::new(0.0, 0.5, 1.0, 0.1), | color: Vector4f::new(0.0, 0.5, 1.0, 0.1), | ||||
| }) | }) | ||||
| .build(); | .build(); | ||||
| @@ -107,8 +105,7 @@ fn create_world(world: &mut World) { | |||||
| fn load_world(world: &mut World, path: &str) -> Result<bool, Error> { | fn load_world(world: &mut World, path: &str) -> Result<bool, Error> { | ||||
| use serde_json::de::{Deserializer, IoRead}; | use serde_json::de::{Deserializer, IoRead}; | ||||
| use space_crush_app::misc::PersistWorld; | |||||
| use space_crush_common::misc::{Persistence, WorldHelper}; | |||||
| use space_crush_common::misc::{PersistWorld, Persistence, WorldHelper}; | |||||
| PersistWorld::setup(world); | PersistWorld::setup(world); | ||||
| @@ -128,8 +125,7 @@ fn load_world(world: &mut World, path: &str) -> Result<bool, Error> { | |||||
| fn save_world(world: &mut World, path: &str) -> Result<(), Error> { | fn save_world(world: &mut World, path: &str) -> Result<(), Error> { | ||||
| use serde_json::Serializer; | use serde_json::Serializer; | ||||
| use space_crush_app::misc::PersistWorld; | |||||
| use space_crush_common::misc::WorldHelper; | |||||
| use space_crush_common::misc::{PersistWorld, WorldHelper}; | |||||
| let vfs = world.resource::<Vfs>()?; | let vfs = world.resource::<Vfs>()?; | ||||
| let mut file = vfs.join(path)?.create_file()?; | let mut file = vfs.join(path)?.create_file()?; | ||||
| @@ -6,4 +6,4 @@ mod world; | |||||
| pub use events::{Events, KeyboardEvent, MouseButton, MouseEvent, VirtualKeyCode, WindowEvent}; | pub use events::{Events, KeyboardEvent, MouseButton, MouseEvent, VirtualKeyCode, WindowEvent}; | ||||
| pub use text::{Text, TextCache, TextManager}; | pub use text::{Text, TextCache, TextManager}; | ||||
| pub use window::Window; | pub use window::Window; | ||||
| pub use world::{PersistWorld, WorldHelper}; | |||||
| pub use world::WorldHelper; | |||||
| @@ -5,31 +5,10 @@ use glc::{ | |||||
| shader::{Program, Shader, Type}, | shader::{Program, Shader, Type}, | ||||
| texture::{Data, FilterMag, FilterMin, Target, Texture, Wrap}, | texture::{Data, FilterMag, FilterMin, Target, Texture, Wrap}, | ||||
| }; | }; | ||||
| use space_crush_common::{ | |||||
| components::{Owned, Planet, Player, Position, Ship, Velocity}, | |||||
| misc::{Persistence, Vfs}, | |||||
| }; | |||||
| use specs::{saveload::SimpleMarker, World}; | |||||
| use crate::{components::PlayerVisual, Error}; | |||||
| /* PersistWorld */ | |||||
| pub struct PersistWorld; | |||||
| pub struct PersistWorldMarker; | |||||
| impl Persistence for PersistWorld { | |||||
| type Marker = SimpleMarker<PersistWorldMarker>; | |||||
| type Components = ( | |||||
| Position, | |||||
| Velocity, | |||||
| Planet, | |||||
| Ship, | |||||
| Owned, | |||||
| Player, | |||||
| PlayerVisual, | |||||
| ); | |||||
| } | |||||
| use space_crush_common::misc::Vfs; | |||||
| use specs::World; | |||||
| use crate::Error; | |||||
| /* WorldHelper */ | /* WorldHelper */ | ||||
| @@ -6,13 +6,12 @@ use glc::{ | |||||
| vector::Vector4f, | vector::Vector4f, | ||||
| }; | }; | ||||
| use space_crush_common::{ | use space_crush_common::{ | ||||
| components::{Owned, Planet, Position}, | |||||
| components::{Owned, Planet, Player, Position}, | |||||
| misc::LogResult, | misc::LogResult, | ||||
| }; | }; | ||||
| use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | ||||
| use crate::{ | use crate::{ | ||||
| components::PlayerVisual, | |||||
| constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | ||||
| misc::WorldHelper, | misc::WorldHelper, | ||||
| resources::Geometry, | resources::Geometry, | ||||
| @@ -60,7 +59,7 @@ pub struct PlanetsData<'a> { | |||||
| position: ReadStorage<'a, Position>, | position: ReadStorage<'a, Position>, | ||||
| planet: ReadStorage<'a, Planet>, | planet: ReadStorage<'a, Planet>, | ||||
| owned: ReadStorage<'a, Owned>, | owned: ReadStorage<'a, Owned>, | ||||
| player_visual: ReadStorage<'a, PlayerVisual>, | |||||
| player: ReadStorage<'a, Player>, | |||||
| } | } | ||||
| impl<'a> System<'a> for Planets { | impl<'a> System<'a> for Planets { | ||||
| @@ -72,7 +71,7 @@ impl<'a> System<'a> for Planets { | |||||
| position, | position, | ||||
| planet, | planet, | ||||
| owned, | owned, | ||||
| player_visual, | |||||
| player, | |||||
| } = data; | } = data; | ||||
| gl::enable(gl::BLEND); | gl::enable(gl::BLEND); | ||||
| @@ -86,7 +85,7 @@ impl<'a> System<'a> for Planets { | |||||
| let p_y = p.pos.y; | let p_y = p.pos.y; | ||||
| let s = p.size; | let s = p.size; | ||||
| let c = match owned.and_then(|owned| player_visual.get(owned.owner)) { | |||||
| let c = match owned.and_then(|owned| player.get(owned.owner)) { | |||||
| Some(pv) => &pv.color, | Some(pv) => &pv.color, | ||||
| None => &*PLAYER_COLOR_DEFAULT, | None => &*PLAYER_COLOR_DEFAULT, | ||||
| }; | }; | ||||
| @@ -6,13 +6,12 @@ use glc::{ | |||||
| vector::Vector4f, | vector::Vector4f, | ||||
| }; | }; | ||||
| use space_crush_common::{ | use space_crush_common::{ | ||||
| components::{Owned, Position, Ship, ShipType, Velocity}, | |||||
| components::{Owned, Player, Position, Ship, ShipType, Velocity}, | |||||
| misc::LogResult, | misc::LogResult, | ||||
| }; | }; | ||||
| use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | ||||
| use crate::{ | use crate::{ | ||||
| components::PlayerVisual, | |||||
| constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | ||||
| misc::WorldHelper, | misc::WorldHelper, | ||||
| resources::Geometry, | resources::Geometry, | ||||
| @@ -67,7 +66,7 @@ pub struct ShipsData<'a> { | |||||
| velocity: ReadStorage<'a, Velocity>, | velocity: ReadStorage<'a, Velocity>, | ||||
| ship: ReadStorage<'a, Ship>, | ship: ReadStorage<'a, Ship>, | ||||
| owned: ReadStorage<'a, Owned>, | owned: ReadStorage<'a, Owned>, | ||||
| player_visual: ReadStorage<'a, PlayerVisual>, | |||||
| player: ReadStorage<'a, Player>, | |||||
| } | } | ||||
| impl<'a> System<'a> for Ships { | impl<'a> System<'a> for Ships { | ||||
| @@ -80,7 +79,7 @@ impl<'a> System<'a> for Ships { | |||||
| velocity, | velocity, | ||||
| ship, | ship, | ||||
| owned, | owned, | ||||
| player_visual, | |||||
| player, | |||||
| } = data; | } = data; | ||||
| gl::enable(gl::BLEND); | gl::enable(gl::BLEND); | ||||
| @@ -95,7 +94,7 @@ impl<'a> System<'a> for Ships { | |||||
| ShipType::Transporter => BindGuard::new(&self.texture_transporter), | ShipType::Transporter => BindGuard::new(&self.texture_transporter), | ||||
| }; | }; | ||||
| let c = match owned.and_then(|owned| player_visual.get(owned.owner)) { | |||||
| let c = match owned.and_then(|owned| player.get(owned.owner)) { | |||||
| Some(pv) => &pv.color, | Some(pv) => &pv.color, | ||||
| None => &*PLAYER_COLOR_DEFAULT, | None => &*PLAYER_COLOR_DEFAULT, | ||||
| }; | }; | ||||
| @@ -1,9 +1,12 @@ | |||||
| use glc::vector::Vector4f; | |||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||
| use specs::{Component, NullStorage}; | |||||
| use specs::{Component, HashMapStorage}; | |||||
| #[derive(Clone, Debug, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, Default, Serialize, Deserialize)] | ||||
| pub struct Player {} | |||||
| pub struct Player { | |||||
| pub color: Vector4f, | |||||
| } | |||||
| impl Component for Player { | impl Component for Player { | ||||
| type Storage = NullStorage<Self>; | |||||
| type Storage = HashMapStorage<Self>; | |||||
| } | } | ||||
| @@ -1,9 +1,11 @@ | |||||
| mod log; | mod log; | ||||
| mod log_result; | mod log_result; | ||||
| mod persistence; | |||||
| mod vfs; | mod vfs; | ||||
| mod world; | mod world; | ||||
| pub use self::log::init as init_logger; | pub use self::log::init as init_logger; | ||||
| pub use self::vfs::{Vfs, VfsError}; | pub use self::vfs::{Vfs, VfsError}; | ||||
| pub use log_result::LogResult; | pub use log_result::LogResult; | ||||
| pub use world::{Persistence, WorldHelper}; | |||||
| pub use persistence::{PersistWorld, Persistence}; | |||||
| pub use world::WorldHelper; | |||||
| @@ -0,0 +1,143 @@ | |||||
| use serde::{de::Deserializer, ser::Serializer}; | |||||
| use specs::{ | |||||
| error::NoError, | |||||
| saveload::{ConvertSaveload, DeserializeComponents, Marker, SerializeComponents, SimpleMarker}, | |||||
| Component, Entities, ReadStorage, World, WorldExt, Write, WriteStorage, | |||||
| }; | |||||
| use crate::components::{Owned, Planet, Player, Position, Ship, Velocity}; | |||||
| /* PersistWorld */ | |||||
| pub struct PersistWorld; | |||||
| pub struct PersistWorldMarker; | |||||
| impl Persistence for PersistWorld { | |||||
| type Marker = SimpleMarker<PersistWorldMarker>; | |||||
| type Components = (Position, Velocity, Planet, Ship, Owned, Player); | |||||
| } | |||||
| /* Persistence */ | |||||
| pub trait Persistence { | |||||
| type Marker: Marker; | |||||
| type Components: PersistenceComponents<Self::Marker>; | |||||
| fn setup(world: &mut World) | |||||
| where | |||||
| <Self::Marker as Component>::Storage: Default, | |||||
| <Self::Marker as Marker>::Allocator: Default, | |||||
| { | |||||
| world.register::<Self::Marker>(); | |||||
| world.insert(<Self::Marker as Marker>::Allocator::default()); | |||||
| } | |||||
| fn serialize<S>(&self, world: &World, serializer: S) -> Result<(), S::Error> | |||||
| where | |||||
| S: Serializer, | |||||
| { | |||||
| Self::Components::serialize(world, serializer) | |||||
| } | |||||
| fn deserialize<'de, D>(&self, world: &World, deserializer: D) -> Result<(), D::Error> | |||||
| where | |||||
| D: Deserializer<'de>, | |||||
| { | |||||
| Self::Components::deserialize(world, deserializer) | |||||
| } | |||||
| } | |||||
| /* PersistenceComponents */ | |||||
| pub trait PersistenceComponents<M> | |||||
| where | |||||
| M: Marker, | |||||
| { | |||||
| fn serialize<S>(world: &World, serializer: S) -> Result<(), S::Error> | |||||
| where | |||||
| S: Serializer; | |||||
| fn deserialize<'de, D>(world: &World, deserializer: D) -> Result<(), D::Error> | |||||
| where | |||||
| D: Deserializer<'de>; | |||||
| } | |||||
| macro_rules! define_persistence_components { | |||||
| ($($T:ident),*) => { | |||||
| #[allow(non_snake_case)] | |||||
| impl<M $(,$T)+> PersistenceComponents<M> for ($($T,)+) | |||||
| where | |||||
| M: Marker, | |||||
| M::Allocator: Default, | |||||
| $($T: Component + ConvertSaveload<M, Error = NoError>,)+ | |||||
| { | |||||
| fn serialize<S>(world: &World, serializer: S) -> Result<(), S::Error> | |||||
| where | |||||
| S: Serializer, | |||||
| { | |||||
| let ( | |||||
| entities, | |||||
| mut marker, | |||||
| mut allocator, | |||||
| $($T,)+ | |||||
| ) = world.system_data::<( | |||||
| Entities, | |||||
| WriteStorage<M>, | |||||
| Write<M::Allocator>, | |||||
| $(ReadStorage<$T>, | |||||
| )+)>(); | |||||
| SerializeComponents::<NoError, M>::serialize_recursive | |||||
| (&($($T,)+), | |||||
| &entities, | |||||
| &mut marker, | |||||
| &mut allocator, | |||||
| serializer, | |||||
| )?; | |||||
| Ok(()) | |||||
| } | |||||
| fn deserialize<'de, D>(world: &World, deserializer: D) -> Result<(), D::Error> | |||||
| where | |||||
| D: Deserializer<'de>, | |||||
| { | |||||
| let ( | |||||
| entities, | |||||
| mut marker, | |||||
| mut allocator, | |||||
| $($T,)+ | |||||
| ) = world.system_data::<( | |||||
| Entities, | |||||
| WriteStorage<M>, | |||||
| Write<M::Allocator>, | |||||
| $(WriteStorage<$T>,)+ | |||||
| )>(); | |||||
| DeserializeComponents::<NoError, M>::deserialize( | |||||
| &mut ($($T,)+), | |||||
| &entities, | |||||
| &mut marker, | |||||
| &mut allocator, | |||||
| deserializer, | |||||
| ) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| define_persistence_components!(T1); | |||||
| define_persistence_components!(T1, T2); | |||||
| define_persistence_components!(T1, T2, T3); | |||||
| define_persistence_components!(T1, T2, T3, T4); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15); | |||||
| @@ -3,14 +3,12 @@ use std::any::type_name; | |||||
| use serde::{de::Deserializer, ser::Serializer}; | use serde::{de::Deserializer, ser::Serializer}; | ||||
| use shred::{Fetch, FetchMut, Resource}; | use shred::{Fetch, FetchMut, Resource}; | ||||
| use shrev::{Event, EventChannel, ReaderId}; | use shrev::{Event, EventChannel, ReaderId}; | ||||
| use specs::{ | |||||
| error::NoError, | |||||
| saveload::{ConvertSaveload, DeserializeComponents, Marker, SerializeComponents}, | |||||
| Component, Entities, ReadStorage, World, WorldExt, Write, WriteStorage, | |||||
| }; | |||||
| use specs::World; | |||||
| use crate::Error; | use crate::Error; | ||||
| use super::Persistence; | |||||
| /* WorldHelper */ | /* WorldHelper */ | ||||
| pub trait WorldHelper { | pub trait WorldHelper { | ||||
| @@ -77,128 +75,3 @@ impl WorldHelper for World { | |||||
| persistence.deserialize(self, deserializer) | persistence.deserialize(self, deserializer) | ||||
| } | } | ||||
| } | } | ||||
| /* Persistence */ | |||||
| pub trait Persistence { | |||||
| type Marker: Marker; | |||||
| type Components: PersistenceComponents<Self::Marker>; | |||||
| fn setup(world: &mut World) | |||||
| where | |||||
| <Self::Marker as Component>::Storage: Default, | |||||
| <Self::Marker as Marker>::Allocator: Default, | |||||
| { | |||||
| world.register::<Self::Marker>(); | |||||
| world.insert(<Self::Marker as Marker>::Allocator::default()); | |||||
| } | |||||
| fn serialize<S>(&self, world: &World, serializer: S) -> Result<(), S::Error> | |||||
| where | |||||
| S: Serializer, | |||||
| { | |||||
| Self::Components::serialize(world, serializer) | |||||
| } | |||||
| fn deserialize<'de, D>(&self, world: &World, deserializer: D) -> Result<(), D::Error> | |||||
| where | |||||
| D: Deserializer<'de>, | |||||
| { | |||||
| Self::Components::deserialize(world, deserializer) | |||||
| } | |||||
| } | |||||
| /* PersistenceComponents */ | |||||
| pub trait PersistenceComponents<M> | |||||
| where | |||||
| M: Marker, | |||||
| { | |||||
| fn serialize<S>(world: &World, serializer: S) -> Result<(), S::Error> | |||||
| where | |||||
| S: Serializer; | |||||
| fn deserialize<'de, D>(world: &World, deserializer: D) -> Result<(), D::Error> | |||||
| where | |||||
| D: Deserializer<'de>; | |||||
| } | |||||
| macro_rules! define_persistence_components { | |||||
| ($($T:ident),*) => { | |||||
| #[allow(non_snake_case)] | |||||
| impl<M $(,$T)+> PersistenceComponents<M> for ($($T,)+) | |||||
| where | |||||
| M: Marker, | |||||
| M::Allocator: Default, | |||||
| $($T: Component + ConvertSaveload<M, Error = NoError>,)+ | |||||
| { | |||||
| fn serialize<S>(world: &World, serializer: S) -> Result<(), S::Error> | |||||
| where | |||||
| S: Serializer, | |||||
| { | |||||
| let ( | |||||
| entities, | |||||
| mut marker, | |||||
| mut allocator, | |||||
| $($T,)+ | |||||
| ) = world.system_data::<( | |||||
| Entities, | |||||
| WriteStorage<M>, | |||||
| Write<M::Allocator>, | |||||
| $(ReadStorage<$T>, | |||||
| )+)>(); | |||||
| SerializeComponents::<NoError, M>::serialize_recursive | |||||
| (&($($T,)+), | |||||
| &entities, | |||||
| &mut marker, | |||||
| &mut allocator, | |||||
| serializer, | |||||
| )?; | |||||
| Ok(()) | |||||
| } | |||||
| fn deserialize<'de, D>(world: &World, deserializer: D) -> Result<(), D::Error> | |||||
| where | |||||
| D: Deserializer<'de>, | |||||
| { | |||||
| let ( | |||||
| entities, | |||||
| mut marker, | |||||
| mut allocator, | |||||
| $($T,)+ | |||||
| ) = world.system_data::<( | |||||
| Entities, | |||||
| WriteStorage<M>, | |||||
| Write<M::Allocator>, | |||||
| $(WriteStorage<$T>,)+ | |||||
| )>(); | |||||
| DeserializeComponents::<NoError, M>::deserialize( | |||||
| &mut ($($T,)+), | |||||
| &entities, | |||||
| &mut marker, | |||||
| &mut allocator, | |||||
| deserializer, | |||||
| ) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| define_persistence_components!(T1); | |||||
| define_persistence_components!(T1, T2); | |||||
| define_persistence_components!(T1, T2, T3); | |||||
| define_persistence_components!(T1, T2, T3, T4); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15); | |||||